Click here to load reader

Chapter 8 PL/SQL. Outline Procedures Cursors Triggers

Embed Size (px)

Citation preview

PL/SQL

Chapter 8PL/SQLOutlineProceduresCursorsTriggers

Procedural SQLSQL does not support the conditional execution of procedures as well as looping operations. To overcome the lack of procedural functionality in SQL and to provide standardization, SQL-99 standard defines the use of persistent stored modules (PSM).

What is PSM?A PSM is a block of code containing standard SQL statements and procedural extensions that is stored and executed at the DBMS server.The PSM represents business logic that can be encapsulated, stored and shared among multiple database users.Oracle implements PSMs through its procedural SQL language.What is PL/SQL and where can PL/SQL be used?Procedural SQL (PL/SQL) is a language that makes it possible to use and store procedural code and SQL statements within the database and merge SQL and traditional programming constructs. The procedural code is executed as a unit by the DBMS when it is invoked b the end user.PL/SQL is used to create Anonymous PL/SQL blocks (without name)Stored ProceduresPL/SQL functionsTriggers

PL/SQL blockThe PL/SQL block starts with the DECLARE section in which the variables, the data types or the initial values are declared.The PL/SQL block ends with the word ENDThe PL/SQL block can be executed by typing / and press enter key.Each statement inside the PL/SQL code must end with a semicolon ;.To display the output use the command dbms_output.put_line(any string);.Conditional statement or Looping statements can be used after declare statements;The SELECT statement uses the INTO keyword inside the PL/SQL block of code to assign the output of the query to a PL/SQL variable. If the SELECT statement returns more than one value, you will get an error.7PL/SQL Program Blocks

8Commands included in PL/SQLComments: PL/SQL program includes commands such as Comments statements that are lines of text that explain or document a program step or series of steps.Not executed by interpreterTo create a block of comments enclosed between /* and */ To create one line comment type two hyphens -- at the beginning of the line.PL/SQL programs have Commands to perform arithmetic operationsAssignment statements that assign values to variablesConditional structures to perform decisionsLooping structures to repeat instructions multiple timesSQL commands that retrieve data.

Procedural StatementsSequencesStatement 1;Statement 2;Control StatementsIF THEN statement1;ELSE statement2;ENDID;Looping StructuresDO WHILE LOOP. Statement 1; Statement 2;ENDLOOP10Assignment StatementsAssigns a value to a variableAn assignment statement has the following syntaxvariable_name := value;Value can be a literal:current_s_first_name := 'John';Value can be another variable:current_s_first_name := s_first_name;11Displaying PL/SQL Program Output in SQL*PlusPL/SQL output bufferMemory area on database server Stores programs output values before they are displayed to userShould increase the size of the buffer asSET SERVEROUTPUT ON SIZE buffer_sizeDefault buffer size 2000 bytesTo display more than just a few lines of output, it is better to make the output buffer larger than the default size.Maximum is 1000000 bytes 12Displaying PL/SQL Program Output in SQL*Plus (continued)Display program outputDBMS_OUTPUT.PUT_LINE('display_text');The display_text value can contain literal character strings such as My name is Roohi or variable names such as current_s_first.Display maximum of 255 characters of text data13Executing a PL/SQL Program in SQL*PlusCreate program in text editorCopy and paste program commands into SQL*Plus windowPress Enter after last program commandType front slash ( / )Then press Enter again

14Executing a PL/SQL Program in SQL*PlusDECLARE todays_date DATE; X number;BEGIN

todays_date := SYSDATE;X:= 1; DBMS_OUTPUT.PUT_LINE('Today''s date is '); DBMS_OUTPUT.PUT_LINE(todays_date);DBMS_OUTPUT.PUT_LINE(x);

END;

Write a PL/SQL program to display the current date as shown below Todays date is 27-Feb-2012A Guide to Oracle10g15PL/SQL Data Conversion FunctionsSometimes the PL/SQL interpreter is unable to implicitly convert value and an error occurs.Other times, PL/SQL interpreter performs an implicit conversion and produce unexpected/invalid dataExplicit data conversionsConvert variables to different data types using data conversion functions that are built into PL/SQL.

16Display todays date using concatenated character stringTo concatenate two strings in PL/SQL, you use the double bar (||) operator:new_string := string1 || string2;

SQL> DECLARE 2 todays_date DATE; 3 BEGIN 4 todays_date :=SYSDATE; 5 DBMS_OUTPUT.PUT_LINE('Today''s date is ' || TO_CHAR(todays_date)); 6 END; 7 /

PL/SQL procedure successfully completed.17PL/SQL Decision Control StructuresUse IF/THEN/ELSE to execute code if condition is true or FALSEIF condition THEN commands that execute if condition is TRUE; ELSE commands that execute if condition is FALSE; END IF;

Evaluates ELSE commands if condition is FALSE18PL/SQL Decision Control StructuresUse IF/ELSIF decision control structure to test for many different conditions.:IF condition1 THEN commands that execute if condition1 is TRUE; ELSIF condition2 THEN commands that execute if condition2 is TRUE; ELSIF condition3 THEN commands that execute if condition3 is TRUE; ... ELSE commands that execute if none of the conditions are TRUE; END IF;19LoopsPL/SQL has 5 loop structuresLOOPEXIT WHENWHILE ..LOOPNumeric FOR loops

20The LOOP...EXIT WHEN LoopThe LOOPEXITWHEN loop can also be either a pretest or a post test loop.LOOP program statements EXIT WHEN condition;END LOOP;

21The WHILE...LOOPThe WHILE.LOOP is a pretest loop that evaluates the exit condition before it executes any program statement.

WHILE condition LOOP program statementsEND LOOP;

22The Numeric FOR LoopDoes not require explicit counter incrementThe loop counter variable and it start and end values are declared in the loops FOR statement.Automatically increments counter variable until it reaches the end value.

FOR counter_variable IN start_value .. end_valueLOOP program statementsEND LOOP;

23Using SQL Queries in PL/SQL ProgramsAction queries can be used as in SQL*Plus

May use variables in action queries

DDL commands may not be used in PL/SQL24Using SQL Commands in PL/SQL Programs

Okay that slide title is figure caption and not heading?PL/SQL block to insert a new row in the VENDOR tableSET SERVEROUTPUT ONBEGIN INSERT INTO VENDORVALUES (25772,Clue Store, Issac Hayes, 456, 323-2009, VA, N); DBMS.OUTPUT.PUT_LINE(New Vendor Added);END;/ -- to execute An anonymous PL/SQL ProgramPL/SQL block to count the number of products having different price rangesDECLAREW_P1 NUMBER(3) := 0;W_p2 number(3) := 10;W_P1 NUMBER(2) := 0;BEGINWHILE W_P2 = P_MIN*2; DBMS_OUTPUT.PUT_LINE ('* * Update finished * *');END;

STORED PROCEDURESTo execute the stored procedure, use the followijg syntax:EXEC procedure_name[(paramenter_list)]

Create a procedure to assign an additional percent discount (an input variable) for all products when the quantity on Hand is more than or equal to twice the minimum quantity.CREATE OR REPLACE PROCEDURE PRC_PROD_DISCOUNT(WPI IN NUMBER) ASBEGIN IF ((WPI = 1)) THEN -- validate WPI parameter DBMS_OUTPUT.PUT_LINE('Error: Value must be greater than 0 and less than 1'); ELSE -- if value is greater than 0 and less than 1UPDATE PRODUCT SET P_DISCOUNT = P_DISCOUNT + WPI WHERE P_QOH >= P_MIN*2;DBMS_OUTPUT.PUT_LINE ('* * Update finished * *'); END IF;END;

Run the ProcedureEXEC PRC_PROD_DISCOUNT (1.5);What is the outcome?EXEC PRC_PROD_DISCOUNT (.05);What is the outcome?

33Oracle SequencesMS Access AutoNumber data type fills a column with unique numeric valuesOracle sequencesIndependent object in the databaseNamed, used anywhere a value expectedNot tied to a table or columnGenerate numeric values that can be assigned to any column in any tableCreated and deleted at any time

34Create a procedure which adds a new invoice.CREATE OR REPLACE PROCEDURE PRC_INV_ADD (W_CUS_CODE IN VARCHAR2, W_DATE IN DATE)AS BEGIN INSERT INTO INVOICE VALUES(INV_NUMBER_SEQ.NEXTVAL, W_CUS_CODE, W_DATE); DBMS_OUTPUT.PUT_LINE('Invoice added');END;

Create a procedure to add a new customerCREATE OR REPLACE PROCEDURE PRC_CUS_ADD(W_LN IN VARCHAR, W_FN IN VARCHAR, W_INIT IN VARCHAR, W_AC IN VARCHAR, W_PH IN VARCHAR)AS BEGIN-- note that the procedure uses the CUS_CODE_SEQ sequence created earlier. Attribute names are required when not giving values for all table attributes INSERT INTO CUSTOMER(CUS_CODE,CUS_LNAME, CUS_FNAME, CUS_INITIAL, CUS_AREACODE, CUS_PHONE) VALUES (CUS_CODE_SEQ.NEXTVAL, W_LN, W_FN, W_INIT, W_AC, W_PH); DBMS_OUTPUT.PUT_LINE ('Customer ' || W_LN || ', ' || W_FN || ' added.');END;/EXEC PRC_CUS_ADD(Walker, James,NULL, 615, 84-HORSE);The result isCustomer Walker, James added.PL/SQL procedure successfully completed.

Create a procedure which adds a new product line row for a given invoice.CREATE OR REPLACE PROCEDURE PRC_LINE_ADD (W_LN IN NUMBER, W_P_CODE IN VARCHAR2, W_LU NUMBER)AS W_LP NUMBER := 0.00;BEGIN -- GET THE PRODUCT PRICESELECT P_PRICE INTO W_LP FROM PRODUCT WHERE P_CODE = W_P_CODE;

-- ADDS THE NEW LINE ROW INSERT INTO LINE VALUES(INV_NUMBER_SEQ.CURRVAL, W_LN, W_P_CODE, W_LU, W_LP,null);

DBMS_OUTPUT.PUT_LINE('Invoice line ' || W_LN || ' added');END;

In order to insert a new record in the LINE table, we need to know the Invoice Number, Product Code, Line Units (the values are obtained from the input parameters), Line Price ( the value is obtained from the Product Price i.e. p_price) in a PRODUCT TableCursorA cursor is a special construct in procedural SQL to hold the data rows returned by an SQL query. A cursor is a reserved area of memory in which the output of the query is stored like an array holding columns and rows.Cursors are held in a reserved memory area in the DBMS server, not in the client computer.CursorsA cursor is a pointer to a memory location on database server that the DBMS uses to process a SQL queryCursors are used to retrieve and manipulate database data in PL/SQL programsTypes:ImplicitExplicit

Implicit Cursor

Implicit CursorsContext areaA memory location on the database serverContains information about query e.g. no. of rows that the query processes, and a machine language representation of the query etc.Created by INSERT, UPDATE, DELETE, or SELECTActive setFor SELECT queries, the context area also stores the active set, which is the set of data rows that query retrievesImplicit cursor is a pointer to the context areaFor Implicit cursor, there is no need to write commands explicitly to create it or retrieve its value.Implicit CursorsExecuting a SELECT query creates an implicit cursor i.e. Implicit cursor can be used to assign the output of a SELECT query to PL/SQL program variables when we are sure that the query will return one and only one record.If the query returns more than one record, or does not return any record, an error occurs.Using an Implicit CursorTo retrieve data values from a querys implicit cursor into PL/SQL program variables add INTO clause : SELECT field1, field2, ...INTO variable1, variable2, ...FROM table1, table2, ...WHERE join_ conditionsAND search_condition_to_retrieve_1_record;The variables must have been declared in the programs declaration sectionThe variables must have the same data types as the associated database fields.Reference VariablesReference variables directly reference specific database field or record and assume data type of the associated field or record%TYPE: is a reference data type which assumes the data type of a database fielddata declaration syntax:variable_name tablename.fieldname%TYPE;e.g. current_c_last Customer.Cus_Lname%TYPE;The current_c_last variable would assume a data type of VARCHAR2(15), because this is the data type of Cus_Lname field in the CUSTOMER tableImplicit Cursors (continued)Useful to use %TYPE reference data type to declare variables used with implicit cursorsvariable_name tablename.fieldname%TYPEe.g. current_c_last customer.cus_lname%TYPEVariable nameTable nameField name in the tableReference Variables%ROWTYPE: is a reference data type which assumes the data type of a database recorddata declaration syntax:row_variable_name tablename%ROWTYPE;e.g. customer_row Customer%ROWTYPE;The CUSTOMER_ROW references all of the fields in the CUSTOMER TABLE, and each field has the same data type as its associated database fields.

Reference VariablesHow do you refer to individual data field within a %ROWTYPE variable?Use the syntax row_variable_name.fieldnameIf u have to refer to f_first name, you can write customer_row.cus_fnameor the balance, you can writecustomer_row.cus_balanceReference Data Type used with Cursors%TYPE: is a reference data type which assumes the data type of a database fielddata declaration syntax:variable_name Cursor_Name.fieldname%TYPE;

e.g. current_c_last cus_cursor.cus_fname%TYPE;%ROWTYPE: is a reference data type which assumes the data type of a database recorddata declaration syntax:variable_name Cursor_Name%ROWTYPE;

e.g. customer_row cus_cursor%ROWTYPE;

SQL> DECLARE 2 current_c_last customer.cus_lname%TYPE; 3 current_c_first customer.cus_fname%TYPE; 4 BEGIN 5 SELECT cus_lname, cus_fname 6 INTO current_C_last, current_C_first 7 FROM customer 8 WHERE cus_code = 10010; 9 DBMS_OUTPUT.PUT_LINE(' The customer ''s name is ' || current_f_first || ' ' || current_f_last); 10 END; 11 /The customer's name is Ramas Alfred

PL/SQL procedure successfully completed.PL/SQL program that displays last name and first name from the CUSTROMER table where cus_code =10010 using an implicit cursorSQL> DECLARE 2 current_c_last customer.cus_lname%TYPE; 3 current_c_first customer.cus_fname%TYPE; 4 BEGIN 5 SELECT cus_lname, cus_fname 6 INTO current_f_last, current_f_first 7 FROM customer 8 WHERE cus_lname LIKE S%; 9 DBMS_OUTPUT.PUT_LINE(' The customer ''s name is ' || current_f_first || ' ' || current_f_last); 10 END; 11 /

DECLARE*ERROR at line 1:ORA-01422: exact fetch returns more than requested number of rowsORA-06512: at line 8Error ORA-01422: exact fetch returns more than requested number of rows Implicit cursor query tried to retrieve multiple recordsWhen implicit cursor query returns no recordsSQL> DECLARE 2 current_c_last customer.cus_lname%TYPE; 3 current_c_first customer.cus_fname%TYPE; 4 BEGIN 5 SELECT cus_lname, cus_fname 6 INTO current_f_last, current_f_first 7 FROM customer 8 WHERE cus_code= 12345; 9 DBMS_OUTPUT.PUT_LINE(' The customer ''s name is ' || current_f_first || ' ' || current_f_last); 10 END; 11 /DECLARE*ERROR at line 1:ORA-01403: no data foundORA-06512: at line 5Explicit CursorsExplicit cursors are created to retrieve and display data in PL/SQL programs for query that might Retrieve multiple recordsReturn no records at allExplicit cursors must be explicitly declared in the programs declaration sectionExplicit commands are written to process the cursor.Steps for creating and using explicit cursorDeclare cursorOpen cursorFetch data rowsClose cursorUsing an Explicit CursorDeclaring an Explicit CursorBy declaring an EC, a memory location is created on the database server that processes query and stores the records that the query retrievesCURSOR cursor_name IS select_query;Cursor_name can be any valid PL/SQL variable name.Select_query is the query that retrieves the desired data value ( simple, complex , nested query etc.)The querys search condition can contain PL/SQL variables as long as the variables are declared before the cursor is declared and are assigned values before the program opens and processes the cursor.Using an Explicit CursorOpen the cursorOPEN cursor_name;When the open command is executed, the PL/SQL interpreter examines or parses the cursors SQL query, confirms that the query contains no syntax errors and translates the query into a machine language format.The system stores the parsed query in the cursors context area and creates the memory structure that will store the active set.The cursor does not retrieve the data values at this stage.

Using an Explicit CursorFetching the data rowsLOOP FETCH cursor_name INTO variable_name(s); EXIT WHEN cursor_name%NOTFOUND;It retrieves the query data from the database into the active set, one row at a time.The FETCH command associates each field value with a program variable.The FETCH command is executed within a loop in order for the query to return several records.The cursor variable or variables are declared using either the %TYPE or %ROWTYPE reference data type.Using an Explicit CursorActive set pointerIt is a pointer that indicates the memory location of next record that is retrieved from databaseWhen the FETCH command executes past the last record of the query, the active set pointer points an empty record.The exit condition cursor_name%NOTFOUND determines whether the last cursor record has been fetched by checking if the active pointer is pointing to the last record and then the loop exits.Closing the cursorClose the cursor after it processes all of the records in the active set so that its memory area and resources are available to the system for other tasks. CLOSE cursor_name;The system automatically closes the cursor when the program that processes the cursor ends.

Explicit Cursor with %TYPEIt is used when a cursor retrieves one data field.

Using cursors create a procedure that lists all products that have a quantity on hand greater than the average quantity on hand for all products.

CREATE OR REPLACE PROCEDURE PRC_CURSOR_EXAMPLE ISW_P_CODEPRODUCT.P_CODE%TYPE;W_P_DESCRIPTPRODUCT.P_DESCRIPT%TYPE;--W_TOTNUMBER(3);

CURSOR PROD_CURSOR IS SELECT P_CODE, P_DESCRIPT FROM PRODUCT WHERE P_QOH > (SELECT AVG(P_QOH) FROM PRODUCT);BEGINDBMS_OUTPUT.PUT_LINE('PRODUCTS WITH P_QOH > AVG(P_QOH)');

DBMS_OUTPUT.PUT_LINE('======================================');OPEN PROD_CURSOR;LOOP FETCH PROD_CURSOR INTO W_P_CODE, W_P_DESCRIPT; EXIT WHEN PROD_CURSOR%NOTFOUND; DBMS_OUTPUT.PUT_LINE(W_P_CODE ||' -> ' || W_P_DESCRIPT );END LOOP;

DBMS_OUTPUT.PUT_LINE('======================================');DBMS_OUTPUT.PUT_LINE('TOTAL PRODUCT PROCESSED ' || PROD_CURSOR%ROWCOUNT); DBMS_OUTPUT.PUT_LINE('--- END OF REPORT ----');

CLOSE PROD_CURSOR;END;/

Write a program that uses an Explicit Cursor to retrieve and display the invoice number value (using %TYPE variable) for every record in the INVOICE table for the customer code 10014.DECLARE current_cus_code NUMBER(4); CURSOR invoice_cursor IS SELECT inv_number FROM invoice WHERE inv_number = current_cus_code; current_inv invoice.inv_number%TYPE;BEGIN

OPEN invoice_cursor; current_inv_num := 1001';DBMS_OUTPUT.PUT_LINE('The current invoice number for ' || current_cus_code || are as follows); LOOP FETCH invoice_cursor INTO current_inv; EXIT WHEN invoice_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(current_nv); END LOOP; CLOSE invoice_cursor;END;/

Explicit Cursor with %ROWTYPEIt is used when a cursor retrieves multiple data fields.Use a single variable that has %ROWTYPE reference data typeAssume the same data type as the row that the cursor retrieves.How to declare a cursor %ROWTYPE variablerow_variable_name cursor_name%ROWTYPE

e.g. customer_row location_cursor%ROWTYPETo reference individual data fields within a %ROWTYPE variable, userow_variable_name.fieldnamee.g. customer_row.room to reference the ROOM field in the location_row variable.Write a program that uses an Explicit Cursor to retrieve and display the invoice number value (using %TYPE variable) for every record in the INVOICE table in which the customer code is 10014.DECLARE current_inv_num NUMBER(4); CURSOR invoice_cursor IS SELECT p_code FROM invoice WHERE inv_number = current_inv_num; current_p_code invoice_cursor%ROWTYPE;BEGIN

OPEN invoice_cursor; current_inv_num := 1001'; LOOP FETCH invoice_cursor INTO invoice_cursor; EXIT WHEN invoice_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE('The current product code in ' || current_inv_num || ' ' || invoice_p_code.p_code); END LOOP; CLOSE invoice_cursor;END;/

TriggersA Trigger is procedural SQL code that is automatically invoked by the RDBMS upon the occurrence of a given data manipulation event.A trigger is invoked before or after a data row is actually inserted, updated or deleted.A trigger is associated within a database table.Each database table may have one or more triggers.A trigger is executed as part of the transaction that triggered it.Uses of TriggersTriggers can be used to enforce constraints that cannot be enforced at the DBMS design and implementation levels.Triggers add functionality by automating critical actions and providing appropriate warnings and suggestions for remedial action.Triggers can be used to update table values, insert records in tables and call other stored procedures.Syntax to create a Trigger in OracleCREATE OR REPLACE TRIGGER trigger_name[BEFORE/AFTER] [DELETE/ INSERT/ UPDATE OF column_name] ON table_name[FOR EACH ROW][DECLARE][varaible_namedata type[:=initial_value] ]BEGIN PL/SQL instructions; .END;Syntax to create a Trigger in OracleThe Triggering timing: BEFORE or AFTER. This timing indicates when the triggers PL/SQL code executes; in this case, before or after the triggering statement is completed. (BEFORE means before the changes are permanently saved to disk but after the changes are made in memory.)

The triggering event: the statement that causes the trigger to execute (INSERT, UPDATE or DELETE).The triggering level: A statement-level trigger is assumed if we omit the FOR EACH ROW keywords. This executes only once before or after the triggering statement is completed.A row-level trigger requires use of the FOR EACH ROW keywords. This is executed once for reach row affected by the triggering statement.The Triggering action: The PL/SQL code enclosed between the BEGIN and END keywords. Each statement inside the PL/SQL code must end with a semicolon.ExampleCreate a trigger which should be activated when a products quantity on hand is updated when the product is sold, the system should automatically check whether the quantity on hand falls below its minimum allowable quantity.

CREATE OR REPLACE TRIGGER TRG_PRODUCT_REORDERAFTER INSERT OR UPDATE OF P_QOH ON PRODUCTBEGIN UPDATE PRODUCTSET P_REORDER = 1 WHER P_QOH