Why PL/SQL? Database vendors usually provide a procedural language as an extension to SQL. –PL/SQL (ORACLE) –Microsoft SQL Server, Sybase provide their.

Slides:



Advertisements
Similar presentations
BD05/06 PL/SQL  Introduction  Structure of a block  Variables and types  Accessing the database  Control flow  Cursors  Exceptions  Procedures.
Advertisements

AN INTRODUCTION TO PL/SQL Mehdi Azarmi 1. Introduction PL/SQL is Oracle's procedural language extension to SQL, the non-procedural relational database.
PL/SQL.
Lecture 2 Introduction to C Programming
Introduction to C Programming
Introduction to C Programming
Objectives In this chapter, you will learn about:
Library example CREATE TABLE books ( isbn VARCHAR2(13) PRIMARY KEY, title VARCHAR2(200), summary VARCHAR2(2000), author VARCHAR2(200), date_published DATE,
PL/SQL (Procedural Language extensions to SQL) Prepared by: Manoj Kathpalia Edited by: M V Ramakrishna.
Let’s try Oracle. Accessing Oracle The Oracle system, like the SQL Server system, is client / server. For SQL Server, –the client is the Query Analyser.
Procedures Stored in the Schema PL/SQL. Why PL/SQL? Database vendors usually provide a procedural language as an extension to SQL. –PL/SQL (ORACLE) –Microsoft.
Lecture-5 Though SQL is the natural language of the DBA, it suffers from various inherent disadvantages, when used as a conventional programming language.
Chapter 4B: More Advanced PL/SQL Programming
 2007 Pearson Education, Inc. All rights reserved Introduction to C Programming.
CIS101 Introduction to Computing Week 11. Agenda Your questions Copy and Paste Assignment Practice Test JavaScript: Functions and Selection Lesson 06,
A Guide to Oracle9i1 Advanced SQL And PL/SQL Topics Chapter 9.
Introduction to PL/SQL
Introduction to C Programming
Introduction to PL/SQL Lecture 0 – Self Study Akhtar Ali.
Dr. James Dullea, CSC8490 Introduction to PL/SQLSlide 1 of 36 7From Prof. Dullea CSC8490 Introduction to PL/SQL Module 01-9 Revised: June 12, 2005 Dr.
Advanced Databases Advanced PL/SQL Programming: Procedure, Function and Package.
A Guide to SQL, Eighth Edition Chapter Three Creating Tables.
CC0002NI – Computer Programming Computer Programming Er. Saroj Sharan Regmi Week 7.
PL / SQL P rocedural L anguage / S tructured Q uery L anguage Chapter 7 in Lab Reference.
SQL Training Procedures & Functions. Confidential & Proprietary Copyright © 2009 Cardinal Directions, Inc. DB Procedures & Functions Procedures and Functions.
Bordoloi and Bock EXCEPTIONS. Bordoloi and Bock Errors Two types of errors can be found in a program: compilation errors and runtime errors. There is.
Cursor and Exception Handling By Nidhi Bhatnagar.
PHP meets MySQL.
Lecture 4 PL/SQL language. PL/SQL – procedural SQL Allows combining procedural and SQL code PL/SQL code is compiled, including SQL commands PL/SQL code.
INTRODUCTION TO PL/SQL. Class Agenda Introduction Introduction to PL/SQL Declaring PL/SQL Variable Creating the Executable Section Interacting with the.
Hello.java Program Output 1 public class Hello { 2 public static void main( String [] args ) 3 { 4 System.out.println( “Hello!" ); 5 } // end method main.
Overview · What is PL/SQL · Advantages of PL/SQL · Basic Structure of a PL/SQL Block · Procedure · Function · Anonymous Block · Types of Block · Declaring.
CpSc 462/662: Database Management Systems (DBMS) (TEXNH Approach) Stored Procedure James Wang.
CPS120: Introduction to Computer Science Decision Making in Programs.
CS178 Database Management PL/SQL session 8 References: ORACLE 9i PROGRAMMING A Primer Rajshekhar Sunderraman.
Saeed Ghanbartehrani Summer 2015 Lecture Notes #5: Programming Structures IE 212: Computational Methods for Industrial Engineering.
Database Systems Design, Implementation, and Management Coronel | Morris 11e ©2015 Cengage Learning. All Rights Reserved. May not be scanned, copied or.
PL/SQL Block Structure DECLARE - Optional Variables, cursors, user-defined exceptions BEGIN - Mandatory SQL Statements PL/SQL Statements EXCEPTIONS - Optional.
Chapter 15 Introduction to PL/SQL. Chapter Objectives  Explain the benefits of using PL/SQL blocks versus several SQL statements  Identify the sections.
Database Application Development using PL/SQL Programming.
Guide to Oracle 10g ITBIS373 Database Development Lecture 4a - Chapter 4: Using SQL Queries to Insert, Update, Delete, and View Data.
Bordoloi and Bock Control Structures: Iterative Control.
Copyright  Oracle Corporation, All rights reserved. 16 Declaring Variables.
Chapter 9: Advanced SQL and PL/SQL Guide to Oracle 10g.
CREATING STORED PROCEDURES AND FUNCTIONS. Objectives After completing this lecture, you should be able to do the following: Differentiate between anonymous.
A Guide to SQL, Eighth Edition Chapter Eight SQL Functions and Procedures.
A procedure is a module performing one or more actions; it does not need to return any values. The syntax for creating a procedure is as follows: CREATE.
Introduction to PL/SQL As usual, use speaker notes for additional information!
Oracle10g Developer: PL/SQL Programming1 Objectives Named program units How to identify parameters The CREATE PROCEDURE statement Creating a procedure.
 2007 Pearson Education, Inc. All rights reserved. A Simple C Program 1 /* ************************************************* *** Program: hello_world.
A FIRST BOOK OF C++ CHAPTER 14 THE STRING CLASS AND EXCEPTION HANDLING.
Text TCS INTERNAL Oracle PL/SQL – Introduction. TCS INTERNAL PL SQL Introduction PLSQL means Procedural Language extension of SQL. PLSQL is a database.
Advanced SQL: Cursors & Stored Procedures Instructor: Mohamed Eltabakh 1.
Kingdom of Saudi Arabia Ministry of Higher Education Al-Imam Muhammad Ibn Saud Islamic University College of Computer and Information Sciences Overview.
Introduction to PL/SQL N. Dimililer. About PL/SQL –PL/SQL is an extension to SQL with design features of programming languages. –Data manipulation and.
4 - Conditional Control Structures CHAPTER 4. Introduction A Program is usually not limited to a linear sequence of instructions. In real life, a programme.
1 Introduction to Database Systems, CS420 SQL Persistent Stored Modules (PSM) – Stored Procedure.
CS422 Principles of Database Systems Oracle PL/SQL Chengyu Sun California State University, Los Angeles.
CS422 Principles of Database Systems Stored Procedures and Triggers Chengyu Sun California State University, Los Angeles.
FILES AND EXCEPTIONS Topics Introduction to File Input and Output Using Loops to Process Files Processing Records Exceptions.
1 Copyright © 2004, Oracle. All rights reserved. PL/SQL Programming Concepts: Review.
PL/pgSQL
Introduction To Repetition The for loop
Creating Stored Procedures and Functions
Fundamentals of PL/SQL part 1 (Basics)
PL/SQL.
Handling Exceptions.
Chapter 4: Introduction to PL/SQL
Chapter 8 Advanced SQL.
Presentation transcript:

Why PL/SQL? Database vendors usually provide a procedural language as an extension to SQL. –PL/SQL (ORACLE) –Microsoft SQL Server, Sybase provide their languages – similar to PL/SQL Such a language is needed in order to code various business rules, such as: –“When you sell a widget, total the monthly sale figures, and decrease the widget inventory.” –“Only a manager can discount blue widgets by 10%.” Such rules are impossible to be enforced by just using SQL. Before PL/SQL, the only way was to bundle SQL statements in complex procedural programs running outside the DB server, in order to enforce business rules.

“I’d rather use a ‘real’ language like C!” While using a “host language” like C can work, more or less, it has some limitations: The C’s variables store data in different binary format from that of the database. Hence, each time a value is retrieved from the database into a C variable a conversion is being done, which when multiplied by thousands or millions of occurrences, it can turn to be a big impact. Also the range of the data types is different. E.g. where would you store a database INT, which can be 38 digits long? If we are not careful and assign it to a C int or even a long, the value can be truncated. There are missing datatypes in C, which are present in databases e.g. DATE. In such cases we use conversions to strings, which are expensive. Even more expensive is then the string manipulation… A C program running outside the database, which can be invoked only by humans, comes up lacking when we need to protect and secure our data. Surely, the DBA has some control over who can change some data. So Herman in accounting may receive UPDATE privileges on a receivables table. We might try to control what operations he can perform by programming some business rules in the C program that he uses. Well he is supposed to use it anyway! If he happens to have, say, Microsoft Excel, and he happens to also have connector software to let it talk to Oracle, boom! Herman can bypass all our carefully programmed security checks!

PL/SQL advantages PL/SQL offers the following advantages: The PL/SQL variables store data in the same binary format with that of the database. Hence there is no need for data conversions. PL/SQL provides the same data types as the database. There aren’t the C problems related to different datatype ranges or missing datatypes. A PL/SQL program can run without the human invocation (e.g. triggers). Such programs can be used to encode business rules protecting and securing our data, but also for encoding other business rules elegantly and in a centralized way.

The first PL/SQL program You can execute this from the SQLPLUS command prompt: BEGIN DBMS_OUTPUT.PUT_LINE('Hello World!'); END; / This is called an anonymous block – that is a block without a name. A block is surrounded by BEGIN, END keywords. The built-in procedure PUT_LINE, part of the DBMS_OUTPUT package, is being called. This procedure takes a string as input and displays that string on screen. The / indicates that we are finished. However, in order to really see the “Hello world” message on the screen, you should set the SQLPLUS environment variable: SQL> SET SERVEROUTPUT ON

Anonymous blocks There are several forms an anonymous block can have. Previously we saw one: BEGIN statements END; Interestingly, a block is just a long PL/SQL statement; notice that the block itself ends with a semicolon. Hence blocks can be nested as we wish. The second major form of an anonymous block includes a declaration section: DECLARE declarations BEGIN statements END; DECLARE msg VARCHAR(30); --a variable BEGIN msg := ‘Hello world’; DBMS_OUTPUT.PUT_LINE(msg); END; The general form of an anonymous block is: DECLARE declarations BEGIN statements [EXCEPTION exception handlers] END; Exception handlers are statements that will run when certain error conditions occur. An exception section contains the logic that describes how your block will respond to errors that occur inside the execution section.

Variables Every variable before being used should be declared in DECLARE section. PL/SQL data types are a superset of the Oracle data types. I.e. what most of the cases we use is: VARCHAR2(n) INT NUMBER[(n,m)] DATE There are also, other types that are only in PL/SQL: PLS_INTEGER (smaller integer) BOOLEAN ( Can be TRUE, FALSE, NULL) The syntax for declaring variables: variable_name DATATYPE [CONSTANT] [:= | DEFAULT initial_value] If the keyword CONSTANT is present the initial value of the variable cannot be changed. := or DEFAULT are synonyms in this context for assigning a initial value to the variable. The initial value should be a literal adhering to the rules for the datatype. E.g. name VARCHAR2 := 'Oracle'; cur_date DATE := SYSDATE;

Operators := Assignment +Addition -Subtraction / Division * Multiplication **Power AND, OR, NOT Logical operators = Equality !=, <>, ~=, ^= Inequality (four variants) Less than, Greater than = INmembership in a set BETWEENRange test IS NULL, IS NOT NULL LIKE (as in SQL for strings) ||Concatenation of strings Examples: square := x**2; square_root := x**0.5; order_overdue BOOLEAN := ship_date > ADD_MONTHS(order_date, 3) OR priority_level(company_id) = 'High'; full_name = 'Chris' || 'Smith'; IF number_of_pages IS NULL THEN DBMS_OUTPUT.PUT_LINE('Unknown'); END;

Conditional logic –IF statement IF condition1 THEN statements [ELSIF condition2 THEN] statements [ELSE last_statements] END IF; Examples: IF hourly_wage < 10 THEN hourly_wage := hourly_wage * 1.5; ELSE hourly_wage := hourly_wage * 1.1; END IF; IF salary BETWEEN AND THEN bonus := 1500; ELSIF salary > AND salary <= THEN bonus := 1000; ELSE bonus := 0; END IF; Comments: If none of the conditions are true and there is an ELSE clause, then the last_statements are executed. The end of the IF statement is “END IF;” with a space in between. The “otherwise if” is ELSIF not ELSEIF You can put parenthesis around boolean expression after the IF and ELSIF but you don’t have to. You don’t need to put {, } or BEGIN, END to surround several statements between IF and ELSIF/ELSE, or between ELSIF/ELSE and END IF;

Conditional logic –Simple CASE statement CASE selector WHEN expression1 THEN statements [WHEN expression2 THEN statements] [ELSE statements] END CASE; selector can be an expression of any datatype, and it provides the value we are comparing. expressionn is the expression to test for equality with the selector. If no WHEN matches the selector value, then the ELSE clause is executed. If there is no ELSE clause PL/SLQ will implicitly supply: ELSE RAISE CASE_NOT_FOUND; which will terminate the program with an error (if we don’t catch this exception). E.g. DECLARE grade VARCHAR2(1) := 'B'; BEGIN CASE grade WHEN 'A' THEN dbms_output.put_line('Excellent'); WHEN 'B' THEN dbms_output.put_line('Very Good'); WHEN 'C' THEN dbms_output.put_line('Good'); WHEN 'D' THEN dbms_output.put_line('Fair'); WHEN 'F' THEN dbms_output.put_line('Poor'); ELSE dbms_output.put_line('No such grade'); END CASE; END; /

Conditional logic –Searched CASE statement Consider the following IF statement: IF salary BETWEEN AND THEN bonus := 1500; ELSIF salary > AND salary <= THEN bonus := 1000; ELSE bonus := 0; END IF; Can we rewrite this IF statement using the previous simple CASE statement? The answer is No! We need a more powerful statement than the simple CASE – we need the searched CASE. CASE WHEN search_condition1 THEN statements1; [WHEN search_condition2 THEN statements2;]... [ELSE statements;] END CASE; Again, if there is no ELSE clause PL/SLQ will implicitly supply: ELSE RAISE CASE_NOT_FOUND; which will terminate the program with an error (if we don’t catch exception). DECLARE salary INT := 50000; bonus INT; BEGIN CASE WHEN salary BETWEEN AND THEN bonus := 1500; WHEN salary > AND salary <= THEN bonus := 1000; ELSE bonus := 0; END CASE; dbms_output.put_line('Bonus is ' || bonus); END; /

When CASE is an expression instead… A CASE statement can also serve as an expression: DECLARE grade CHAR(1) := 'B'; appraisal VARCHAR2(20); BEGIN DBMS_OUTPUT.PUT_LINE(appraisal); appraisal := CASE grade WHEN 'A' THEN 'Excellent' WHEN 'B' THEN 'Very Good' WHEN 'C' THEN 'Good' WHEN 'D' THEN 'Fair' WHEN 'F' THEN 'Poor' ELSE 'No such grade' END; DBMS_OUTPUT.PUT_LINE(appraisal); END; / Observe how the appraisal variable takes the value. Another example: DECLARE salary INT := 50000; bonus INT; BEGIN bonus := CASE WHEN salary BETWEEN AND THEN 1500 WHEN salary > AND salary <= THEN 1000 ELSE 0 END; dbms_output.put_line('Bonus is ' || bonus); END; / Observe how bonus takes the value. Notice the absence of the terminators “;”. Notice the automatic conversion of bonus into string when we print on the screen. There is no exception thrown if no WHEN gets matched, and there is missing ELSE. The value returned is NULL.

Iterative Control: LOOP and EXIT Statements Another example: E.g. Suppose we wish to categorize salaries according to their number of digits. DECLARE digits INT := 1; salary INT := ; temp INT := salary; BEGIN LOOP temp := temp / 10; IF temp = 0 THEN EXIT; END IF; --Or we can do: EXIT WHEN temp = 0 digits := digits + 1; END LOOP; dbms_output.put_line('Number of digits is ' || digits); END; / LOOP statements let you execute a sequence of statements multiple times. There are three forms of LOOP statements: LOOP, WHILE-LOOP, and FOR-LOOP. LOOP: The simplest form of LOOP statement is the basic (or infinite) loop, which encloses a sequence of statements between the keywords LOOP and END LOOP, as follows: LOOP statements END LOOP; You can use an EXIT statement to complete the loop. There are two forms of EXIT statements: EXIT and EXIT-WHEN.

WHILE-LOOP DECLARE digits INT := 0; salary INT := ; temp INT := salary; BEGIN WHILE temp > 0 LOOP digits := digits + 1; temp := temp / 10; END LOOP; dbms_output.put_line('Number of digits is ' || digits); END; / WHILE condition LOOP statements END LOOP;

FOR Loops FOR loops iterate over a specified range of integers. FOR counter IN [REVERSE] low.. high LOOP sequence_of_statements END LOOP; The range is evaluated when the FOR loop is first entered and is never re- evaluated. By default, iteration proceeds upward from the lower bound to the higher bound. However, if you use the keyword REVERSE, iteration proceeds downward from the higher bound to the lower bound. Nevertheless, you write the range bounds in ascending (not descending) order. Inside a FOR loop, the loop counter can be referenced like a constant but cannot be assigned values. What happens if you had declared the loop control variable before?

Background on the example CREATE TABLE books ( isbn VARCHAR2(13) PRIMARY KEY, title VARCHAR2(200), summary VARCHAR2(2000), author VARCHAR2(200), date_published DATE, page_count NUMBER ); CREATE TABLE book_copies ( barcode_id VARCHAR2(100) PRIMARY KEY, isbn VARCHAR2(13) REFERENCES books(isbn) ); Let’s build a system that will assist in the cataloging and searching of library books. For now, we’d like to address two requirements: Allow the creation of catalog entries for each newly acquired book. Provide means of counting how many copies of a particular book the library owns. A simple E/R schema would be: BooksBook copies Owns

Implementing a stored procedure to add a book CREATE OR REPLACE PROCEDURE add_book ( isbn_in IN VARCHAR2, barcode_id_in IN VARCHAR2, title_in IN VARCHAR2, author_in IN VARCHAR2, page_count_in IN NUMBER, summary_in IN VARCHAR2 DEFAULT NULL, date_published_in IN DATE DEFAULT NULL ) AS BEGIN /*Check for reasonable inputs*/ IF isbn_in IS NULL THEN RAISE VALUE_ERROR; END IF; INSERT INTO books (isbn, title, summary, author, date_published, page_count) VALUES (isbn_in, title_in, summary_in, author_in, date_published_in, page_count_in); /*if barcode is supplied, put a record in the book_copies table*/ if NOT(barcode_id_in IS NULL) then insert into book_copies (isbn, barcode_id) values(isbn_in, barcode_id_in); end if; END add_book; / show errors If you don’t set: show errors and you have compilation, PL/SQL will just tell you the fact that there are errors, but won’t show you them.

Using the procedure to add a book BEGIN add_book( ' ', ' ', 'Oracle PL/SQL Programming', 'Feuerstein, Steven, with Bill Pribyl', 987, 'Reference for PL/SQL developers, ' || 'including examples and best practice recommendations.', TO_DATE('01-Sep-1997', 'DD-MON-YYYY') ); END; /

Adding a book… Parameter names: It’s good if you follow the convention to end the IN parameters with a suffix _in. (similarly _out for the OUT parameters, or _inout for the INOUT parameters). Such naming is not compulsory but helps in avoiding conflicts with the columns names. E.g. If we didn’t put the _in suffix, then it is hard to read code like this: INSERT INTO books (isbn, title, summary, author, date_published, page_count) VALUES (isbn, title, summary, author, date_published, page_count); What are those column names or are they PL/SQL variables? In this particular example it turns out that PL/SQL is able to interpret isbn…page_count of the first line as table columns, while in second as PL/SQL variables. But, what about this: UPDATE Books SET summary = summary WHERE isbn = isbn; The above won’t work!

Retrieving a book count with a function (contin.) CREATE OR REPLACE FUNCTION book_copy_qty (isbn_in VARCHAR2) return NUMBER AS number_of_copies NUMBER := 0; CURSOR bc_cur IS SELECT count(*) FROM book_copies WHERE isbn = isbn_in; BEGIN IF isbn_in IS NOT NULL THEN OPEN bc_cur; FETCH bc_cur INTO number_of_copies; CLOSE bc_cur; END IF; RETURN number_of_copies; END; / show errors bc_cur is cursor; we will talk later about them. For the moment consider it as a vehicle for carrying one- tuple-at-a-time from the set result of a query. We can test this function as: set serveroutput on DECLARE how_many INTEGER; BEGIN dbms_output.put_line( 'Number of copies of : ' || book_copy_qty(' ')); END; /

Dropping, viewing stored programs The REPLACE keyword that we were adding saved us from dropping a procedure or function each time we do a new version of them. However, suppose that we don’t want anymore a procedure or function at all. Then we can drop them: DROP PROCEDURE add_book; DROP FUNCTION book_copy_qty; A natural question about a stored procedure or function is: Since it’s stored, can we view it? The answer is yes: SELECT text FROM User_source WHERE name = 'ADD_BOOK' ORDER BY line; Observe that the name of the procedure or function is stored in upper case.

Stored procedures The syntax to create a stored procedure is as follows: CREATE [OR REPLACE] PROCEDURE procedure_name [(parameter1 MODE DATATYPE [DEFAULT expression], parameter2 MODE DATATYPE [DEFAULT expression], …)] AS [variable1 DATATYPE; variable2 DATATYPE; …] BEGIN statements [EXCEPTION WHEN exception_name THEN statements] END; / MODE can be IN for read-only parameters, OUT for write- only parameters, or IN OUT for both read and write parameters. The DATATYPE can be any of the types we already have mentioned but without the dimensions, e.g. VARCHAR2, NUMBER,…, but not VARCHAR2(20), NUMBER(10,3)…

Functions Before, let’s see the syntax to create a stored function: CREATE [OR REPLACE] FUNCTION function_name [(parameter1 MODE DATATYPE [DEFAULT expression], parameter2 MODE DATATYPE [DEFAULT expression], …)] RETURN DATATYPE AS [variable1 DATATYPE; variable2 DATATYPE; …] BEGIN statements RETURN expression; [EXCEPTION WHEN exception_name THEN statements] END; / If you omit it mode it will implicitly be IN. In the header the RETURN DATATYPE is part of the function declaration and it is required. It tells the compiler what datatype to expect when you invoke the function. RETURN inside the executable section is also required. If you miss the the RETURN clause in the declaration, the program won’t compile. On the other hand, if you miss the RETURN inside the body of the function, the program will execute but at runtime Oracle will give the error ORA-06503: PL/SQL: Function returned without a value.

Creating some data for the examples DECLARE PROCEDURE insert_book_no_complaints (isbn_in IN VARCHAR2, title_in IN VARCHAR2, summary_in IN VARCHAR2, author_in IN VARCHAR2, date_published_in IN DATE, page_count_in IN NUMBER) IS BEGIN INSERT INTO books (isbn, title, summary, author, date_published, page_count) VALUES (isbn_in, title_in, summary_in, author_in, date_published_in, page_count_in); EXCEPTION WHEN DUP_VAL_ON_INDEX THEN NULL; END; PROCEDURE insert_copy_no_complaints (barcode_id_in IN VARCHAR2, isbn_in IN VARCHAR2) IS BEGIN INSERT INTO book_copies (barcode_id, isbn) VALUES (barcode_id_in, isbn_in); EXCEPTION WHEN DUP_VAL_ON_INDEX THEN NULL; END;

BEGIN insert_book_no_complaints (' ', 'Learning Oracle PL/SQL', 'Beginner''s guide to Oracle''s PL/SQL Programming Language', 'Bill Pribyl with Steven Feuerstein', '29-Nov-2001', 401); insert_book_no_complaints (' ', 'Oracle PL/SQL Programming', 'Reference for PL/SQL developers, including examples and best practice ' || 'recommendations.', 'Feuestein, Steven, and Bill Pribyl', '01-SEP-1997', 987); insert_book_no_complaints (' ', 'Oracle PL/SQL Language Pocket Reference', 'Quick-reference guide for Oracle PL/SQL developers. Includes Oracle8i ' || 'coverage.', 'Feuerstein, Steven, Bill Pribyl, Chip Dawes', '01-APR-1999', 94);

insert_book_no_complaints (' ', 'The tragedy of King Richard the Third', 'Modern publication of popular Shakespeare historical play in which a ' || 'treacherous royal attempts to steal the crown but dies horseless ' || 'in battle.', 'Shakespeare, William', '01-AUG-2000', 158); insert_book_no_complaints (' ', 'The Tempest', 'Duke and daughter on enchanted island encounters former enemies in this ' || 'comic tale of mystery, love, magic, and (ultimately) forgiveness.', 'Shakespeare, William', '01-JAN-1959', 120); insert_book_no_complaints (' ', 'Sams Teach Yourself PL/SQL in 21 Days, Second Edition', 'Tutorial for Oracle''s procedural language organized around presenting ' || 'language features in a three-week learning schedule.', 'Gennick, Jonathan, with Tom Luers', '01-DEC-1999', 692);

insert_book_no_complaints (' ', 'Oracle PL/SQL Tips and Techniques', 'Voluminous tome presenting tips, techniques, and reference material on ' || 'Oracle''s PL/SQL.', 'Trezzo, Joseph C.', '01-JUL-1999', 942); insert_book_no_complaints (' ', 'Building Intelligent Databases with Oracle PL/SQL Triggers and Stored ' || 'Procedures-2nd ed.', 'Programmer''s guide to PL/SQL, targeted toward building reusable ' || 'components for large Oracle applications.', 'Owens, Kevin T.', '01-JUN-1999', 544); insert_book_no_complaints (' ', 'Oracle PL/SQL Developer''s Workbook', 'Beginner, intermediate, and advanced exercises designed to test the ' || 'reader''s knowledge of Oracle''s PL/SQL programming language.', 'Feuerstein, Steven, with Andrew Odewahn', '01-May-1999', 588);

insert_copy_no_complaints (' ', ' '); insert_copy_no_complaints (' ', ' '); insert_copy_no_complaints (' ', ' '); insert_copy_no_complaints (' ', ' '); insert_copy_no_complaints (' ', ' '); insert_copy_no_complaints (' ', ' '); insert_copy_no_complaints (' ', ' '); insert_copy_no_complaints (' ', ' '); insert_copy_no_complaints (' ', ' '); END; /

Talking in HTML… Oracle has created mod_plsql Apache module for transparently, “printing” HTML from a PL/SQL program on the browser. HTP.PRN(expression); HTP.PRINT(expression); -- prints also a trailing newline. Let’s print a test page with the current time. CREATE OR REPLACE PROCEDURE show_time AS the_title VARCHAR2(30) := 'What time is it on the server?'; the_time VARCHAR2(20) := TO_CHAR(SYSDATE,'DD-MON-YYYY HH24:MI'); html VARCHAR2(200); BEGIN /* construct the HTML in a variable */ html := ' ' || the_title || ' It is now: ' || the_time || ' '; /* output to the browser */ HTP.PRINT(html); END; / SHOW ERRORS