PL/SQL Hussam A. Halim An-Najah National University 1 Outline • PL/SQL Programming • SQL*Plus and SQL commands 2 PL/SQL Programming • PL/SQL is an extension to SQL with design features of programming languages. • Data manipulation and query statements of SQL are included within procedural units of code. 3 Benefits of PL/SQL • Integration of applications, shared library and Oracle server. • Improve performance. application application SQL IF … THEN SQL ELSE SQL END IF; Other DBMSs Oracle with PL/SQL 4 PL/SQL Block Structure • DECLARE –Optional – Variables, cursors, uer-define exceptions • BEGIN – Mandatory – SQL statements – PL/SQL statements • EXCEPTION – Optional – Actions to perform when errors occur • END; - Mandatory 5 PL/SQL Block Structure(1) DECLARE v_variable VARCHAR2(5); BEGIN SELECT column_name INTO v_variable FROM table_name EXCEPTION … WHEN exception_name THEN END; 6 Block Types [DECLARE] Function Procedure PROCEDURE name IS FUNCTION name RETURN datatype IS BEGIN BEGIN BEGIN -- statements -- statements [EXCETPION] [EXCETPION] -- statements RETURN value; [EXCETPION] END; END; END; 7 Program Constructs • Anonymous Block – Unnamed PL/SQL block that is embedded within an application or is issued interactively • Stored procedure or function Named PL/SQL block stored in Oracle Server that can accept parameters and be invoked repeatedly by name. • Package Named PL/SQL module that groups related procedures, functions and identifiers. Stored in Oracle server or Oracle Developer components – for example, Forms. 8 Handling Variables in PL/SQL • Declare and initialize variables in the declaration section. • Assign new values to variables in the executable section. • Pass values into PL/SQL blocks through parameters. • View results through output variables. 9 Types of PL/SQL Variables • Scalar – BOOLEAN, DATE, NUMBER, VARCHAR2 • Composite – Such as records. • Reference – Pointers • LOB (large objects) – Used to hold large objects such as images. • Non-PL/SQL variables: bind and host variables. 10 Using Bind Variables • To reference a bind variable in PL/SQL, you must prefix its name with a colon (:). •VARIABLE Example g_salary DECLARE v_sal BEGIN SELECT INTO FROM WHERE :g_salary END; / NUMBER emp.sal%TYPE; sal v_sal emp empno = 7369; := v_sal; Declaring PL/SQL Variables • Examples: Declare v_hiredate v_deptno v_location v_tax_rate c_comm DATE; NUMBER(2) NOT NULL :=10; VARCHAR(13) := ‘New York’; NUMBER(3,2) := 3.0; CONSTANT NUMBER := 1400; • Guidelines: – Follow naming conventions. – Initialize variables designated as NOT NULL. – Declare at most one identifier per line. 12 Base Scalar Datatypes • VARCHAR2(maximum_length) – No default size; max = 32767 bytes • NUMBER[(precision, scale)] – For fixed and floating numbers. • CHAR[(maximum_length)] – For fixed-length character string. Default to 1. • BOOLEAN – TURE, FALSE, or NULL • BINARY_INTEGER – Base type of integers between -2,147,483,647 and 2,147,483,647. • PLS_INTEGER – Same range as BINARY_INTEGER but requires less storage and are faster than NUMBER and BINARY_INTEGER values. 13 Declaring Variables with the % TYPE attribute • Declare a variable according to – A database column definition – Another previously declared variables. • Prefix % TYPE • Examples: v_ename v_balance v_min_balance emp.ename%TYPE; NUMBER(7,2); v_balance%TYPE := 10; 14 PL/SQL Block Syntax and Guidelines • Statements can continue over several lines. • Identifiers – Can contain up to 30 characters. – Must begin with alphabetic character. • Literals – Enclosed in single quotation marks. • A PL/SQL block is terminated by a slash / on a line by itself. • Commenting code – Single-line comments with two dashes (--). – Place multi-line comments between /* and */ 15 Comments • Single-line comments DECLARE v_title CHAR(2) -- title can be Mr or Ms … • Multi-line comments DECLARE /* I am a multi-line comment */ Operators • Arithmetic + , -, *, / , **, • Comparison =, <, >, >=, <=, !=, IS NULL, LIKE, BETWEEN, IN • Assignment := • Statement terminator ; • String concatenation || • Logical NOTG, AND , OR 17 SQL Statements in PL/SQL • Extract a row of data from the database by using the SELECT command. Only a single set of values can be returned. • Make changes to rows in the database by using DML commands. (INSERT, UPDATE, DELETE). • Control a transaction with the COMMIT, ROLLBACK or SAVEPOINT command. • Determine DML outcome with implicit cursors. • Does not support DDL (CREATE TABLE, ALTER TABLE, or DROP TABLE) and DCL (GRANT, REVOKE) 18 SELECT Statements in PL/SQL • Retrieve data from the database with SELECT. • Example: DECLARE v_dept_no NUMBER(2); v_loc VARCHAR2(15); BEGIN SELECT deptno, loc INTO v_dept_no, v_loc FROM dept WHERE dname=‘SALES’; END; 19 Manipulating Data Using PL/SQL • INSERT BEGIN INSERT INTO emp(empno, ename, job, deptno) VALUES (empno_sequence.NEXTVAL, ‘Jack’, ‘CTO’, 10); END; • UPDATE BEGIN UPDATE emp SET sal = sal + 10; WHERE job = ‘ANALYST’; END; 20 Manipulating Data Using PL/SQL • DELETE BEGIN DELETE FROM emp WHERE name = ‘JACK’; END; 21 • • -- Command to display the output at the SQL prompt SET SERVEROUTPUT ON • • • -- This PL/SQL block accepts a number from the terminal, and prints out its square. -- You can try this from sql+ -- It has no exception handling code. • • • DECLARE num1 NUMBER(3); num1_sq NUMBER(6); • • • • • • • BEGIN -- prompts user for a value for 'anytemp' num1 := &anytemp; num1_sq := num1 * num1 ; DBMS_OUTPUT.PUT_LINE('THE SQUARE OF ' || num1 || ' IS ' || num1_sq); END; / Retrieving Data in PL/SQL •Return the sum of the salaries for all employees in the specified department. •Example DECLARE v_sum_sal emp.sal%TYPE; v_deptno NUMBER NOT NULL := 10; BEGIN SELECT SUM(sal) -- group function INTO v_sum_sal FROM emp WHERE deptno = v_deptno; END; Updating Data •Increase the salary of all employees in the EMP table who are Analysts. •Example DECLARE v_sal_increase emp.sal%TYPE := 2000; BEGIN UPDATE emp SET sal = sal + v_sal_increase WHERE job = 'ANALYST'; END; Deleting Data •Delete rows that belong to department 10 from the EMP table. •Example DECLARE v_deptno emp.deptno%TYPE := 10; BEGIN DELETE FROM emp WHERE deptno = v_deptno; END; Writing Control Structures • Conditional IF statements. IF v_dept_no = 10 THEN v_bonus := 5000; ELSIF v_dept_no=20 THEN v_bonus := 7500; ELSE v_bonus := 2000; END IF; 26 Writing Control Structures • Iterative control: loop statements – Basic loop – FOR loop – WHIE loop • Basic loop BEGIN LOOP INSERT INTO item(ordid, itemid) VALUES (610, v_counter); v_counter := counter + 1; EXIT WHEN v_counter > 10; END LOOP; COMMIT; END; 27 Writing Control Structures • FOR loop BEGIN FOR i IN 1..100 LOOP …… END LOOP; END; • WHILE loop BEGIN WHILE i <= 100 LOOP …… END LOOP; END; • Nested loop is allowed. 28 EXAMPLES ADDITION • Declare • a number; • b number; • c number; • begin • a:=&a; • b:=&b; • c:=a+b; • dbms_output.put_line('Sum of ' || a || ' and ' || b || ' is ' || c); • End; • Here & is used to take user input at runtime..... SUM OF 100(1…100) NUMBERS • • • • • • • • • • • • Declare a number; s1 number default 0; Begin a:=1; Loop s1:=s1+a; exit when (a=100); a:=a+1; end loop; dbms_output.put_line('Sum between 1 to 100 is '||s1); End; SUM OF odd NUIMBERS USING USER INPUT...for loop declare sum1 number default 0; endvalue number; begin endvalue:=&endvalue; for n in 1.. endvalue loop if mod(n,2)=1 then sum1:=sum1+n; end if; end loop; dbms_output.put_line('sum = ' || sum1); end; SUM OF 100 ODD NUMBER .. WHILE LOOP declare n number; endvalue number; sum1 number default 0; begin endvalue:=&endvalue; n:=1; while (n < endvalue) loop sum1:=sum1+n; n:=n+2; end loop; dbms_output.put_line('Sum of odd numbers between 1 and ' || endvalue || ' is ' || sum1); end; SUM OF 100 ODD NUMBER .. WHILE LOOP declare n number; endvalue number; sum1 number default 0; begin endvalue:=&endvalue; n:=1; while (n < endvalue) loop sum1:=sum1+n; n:=n+2; end loop; dbms_output.put_line('Sum of odd numbers between 1 and ' || endvalue || ' is ' || sum1); end; SUM OF 100 ODD NUMBER .. WHILE LOOP declare n number; endvalue number; sum1 number default 0; begin endvalue:=&endvalue; n:=1; while (n < endvalue) loop sum1:=sum1+n; n:=n+2; end loop; dbms_output.put_line('Sum of odd numbers between 1 and ' || endvalue || ' is ' || sum1); end; SUM OF 100 ODD NUMBER .. WHILE LOOP declare n number; endvalue number; sum1 number default 0; begin endvalue:=&endvalue; n:=1; while (n < endvalue) loop sum1:=sum1+n; n:=n+2; end loop; dbms_output.put_line('Sum of odd numbers between 1 and ' || endvalue || ' is ' || sum1); end; CALCULATION OF NET SALARY declare ename varchar2(15); basic number; da number; hra number; pf number; netsalary number; begin ename:=&ename; basic:=&basic; da:=basic * (41/100); hra:=basic * (15/100); if (basic < 3000) then pf:=basic * (5/100); elsif (basic >= 3000 and basic <= 5000) then pf:=basic * (7/100); elsif (basic >= 5000 and basic <= 8000) then pf:=basic * (8/100); else pf:=basic * (10/100); end if; netsalary:=basic + da + hra -pf; dbms_output.put_line('Employee name : ' || ename); dbms_output.put_line('Providend Fund : ' || pf); dbms_output.put_line('Net salary : ' || netsalary); end; MAXIMUM OF 3 NUMBERS Declare a number; b number; c number; d number; Begin dbms_output.put_line('Enter a:'); a:=&a; dbms_output.put_line('Enter b:'); b:=&b; dbms_output.put_line('Enter c:'); c:=&b; if (a>b) and (a>c) then dbms_output.putline('A is Maximum'); elsif (b>a) and (b>c) then dbms_output.putline('B is Maximum'); else dbms_output.putline('C is Maximum'); end if; End; QUERY EXAMPLE--IS SMITH EARNING ENOUGH declare s1 emp.sal %type; begin select sal into s1 from emp where ename = 'SMITH'; if(no_data_found) then raise_application_error (20001,'smith is not present'); end if; if(s1 > 10000) then raise_application_error (20002,'smith is earning enough'); end if; update emp set sal=sal + 500 where ename='SMITH'; end; PRIME NO OR NOT DECLARE no NUMBER (3) := &no; a NUMBER (4); b NUMBER (2); BEGIN FOR i IN 2..no - 1 LOOP a := no MOD i; IF a = 0 THEN GOTO out; END IF; END LOOP; <out> IF a = 1 THEN DBMS_OUTPUT.PUT_LINE (no || ' is a prime number'); ELSE DBMS_OUTPUT.PUT_LINE (no || ' is not a prime number'); END IF; END; SIMPLE EXAMPLE OF LOOP STATEMENT I.E. EXIT WHEN Declare a number:= 100; begin loop a := a+25; exit when a=250; end loop; dbms_output.put_line (to_Char(a)); end; EXAMPLE OF WHILE LOOP Declare i number:=0; j number:= 0; begin while i <=100 loop j := j+1; i := i +2; end loop; dbms_output.put_line(to_char(i)); end; EXAMPLE OF FOR LOOP Declare begin for i in 1..10 loop dbms_output.put_line(to_char(i)); end loop; end; SEQUENTIAL CONTROL GOTO..... declare --takes the default datatype of the column of the table price cost price.minprice%type; begin select stdprice into cost from price where prodial in (Select prodid from product where prodese = "shampoo"); if cost > 7000 then goto Upd; end if; << Upd >> Update price set minprice = 6999 where prodid=111; end; CALCULATE THE AREA OF A CIRCLE FOR A VALUE OF RADIUS VARYING FROM 3 TO 7. STORE THE RADIUS AND THE CORRESPONDING VALUES OF CALCULATED AREA IN A TABLE AREAS. Declare pi constant number(4,2) := 3.14; radius number(5); area number(14,2); Begin radius := 3; While radius <=7 Loop area := pi* power(radius,2); Insert into areas values (radius, area); radius:= radius+1; end loop; end; Example: INVERTING A NUMBER 5639 TO 9365 Declare given_number varchar(5) := '5639'; str_length number(2); inverted_number varchar(5); Begin str_length := length(given_number); For cntr in reverse 1..str_length loop inverted_number := inverted_number || substr(given_number, cntr, 1); end loop; dbms_output.put_line('The Given no is ' || given_number); dbms_output.put_line('The inverted number is ' || inverted_number); end; Summary – PL/SQL block structure: Nesting blocks and scoping rules – PL/SQL programming: • • • • • Functions Datatype conversions Operators Bind variables Conventions and guidelines DECLARE BEGIN EXCEPTION END; • A cursor is a private SQL work area. Each SQL statement executed by the Oracle Server has an individual cursor associated with it. • There are two types of cursors: – Implicit cursors – Explicit cursors • The Oracle Server uses implicit cursors to parse and execute your SQL statements. • Explicit cursors are explicitly declared by the programmer. 47 SQL Cursor Attributes • Using SQL cursor attributes, you can test the outcome of your SQL statements. SQL%ROWCOUNT Number of rows affected by the most recent SQL statement. (an integer value). SQL%FOUND Boolean attribute that evaluates to TRUE if the most recent SQL statement affects one or more rows. SQL%NOTFOUND Boolean attribute that evaluates to TRUE if the most recent SQL statement does not affect any row. SQL%ISOPEN Always evaluates to FALSE because PL/SQL closes implicit cursors immediately after they are executed. 48 Writing Explicit Cursors • Use explicit cursors to individually process each row returned by a multi-row SELECT statement. Cursor 7369 7430 Active Set SMITH CLERK JONES MANAGER 7788 SCOTT ANALYST 7789 JACK CTO Current Row 49 Writing Explicit Cursors: Example DECLARE v_empno emp.empno%TYPE; v_ename emp.ename%TYPE; CURSOR emp_cursor IS SELECT empno, ename FROM emp; BEGIN OPEN emp_cursor; LOOP FETCH emp_cursor INTO v_empno, v_ename; EXIT WHEN emp_cursor%NOTFOUND; …… END LOOP; CLOSE emp_cursor; 50 Cursors with Parameters • Example: pass the department number and job title to the WHERE clause. DECALRE CURSOR emp_cursor (p_deptno NUMBER, p_job VARCHAR2) IS SELECT empno, ename FROM emp WHERE deptno = v_deptno AND job = v_job; BEGIN OPEN emp_cursor(10, ‘CLERK’); …… 51 Cursors with Subqueries DECALRE CURSOR my_cursor IS SELECT t1.deptno, t1.dname, t2.STAFF FROM dept t1, (SELECT deptno, count(*) STAFF FROM emp GROUP BY deptno) t2 WHERE t1.deptno = t2.deptno AND t2.STAFF >= 5; 52 Using Arrays • Item type: VARRAY (short for Variable-size arrays). • A varray can have only one dimension and must be indexed by integers. • A varray has a maximum size. • Example: DECALRE TYPE list IS VARRAY(25) of NUMBER(3); v1 v_list; BEGIN FOR i IN 1..25 v1(i) := 1; END LOOP; END; 53 Subprograms • Subprograms are named PL/SQL blocks that can take parameters and be invoked. PL/SQL has two types of subprograms called procedures and functions. • Example: a procedure named debit_account, which debits a bank account: 54 PROCEDURE debit_account (acct_id INTEGER, amount REAL) IS old_balance REAL; new_balance REAL; overdrawn EXCEPTION; BEGIN SELECT bal INTO old_balance FROM accts WHERE acct_no = acct_id; new_balance := old_balance - amount; IF new_balance < 0 THEN RAISE overdrawn; ELSE UPDATE accts SET bal = new_balance WHERE acct_no = acct_id; END IF; EXCEPTION WHEN overdrawn THEN ... 55 END debit_account; Writing Functions • Consider the function sal_ok, which determines if a salary is out of range: FUNCTION sal_ok (salary REAL, title VARCHAR2) RETURN BOOLEAN IS min_sal REAL; max_sal REAL; BEGIN SELECT losal, hisal INTO min_sal, max_sal FROM sals WHERE job = title; RETURN (salary >= min_sal) AND (salary <= max_sal); END sal_ok; 56 Parameter Modes • IN mode (the default) – passes values to a subprogram. – actual parameter is passed by reference (a pointer to the value is passed in) • OUT mode (must be specified) – returns values to the caller. – actual parameter is passed by value (a copy of the value is passed out) unless NOCOPY is specified • IN OUT mode (must be specified) – passes initial values to a subprogram and returns updated values to the caller. – actual parameter is passed by value. 57 Declaring Subprograms • You can declare subprograms in any PL/SQL block, subprogram, or package. But, you must declare subprograms at the end of a declarative section after all other program items. • PL/SQL requires that you declare an identifier before using it. Therefore, you must declare a subprogram before calling it. 58 Packaging Subprograms • You can group logically related subprograms in a packages, which is stored in the database. • Packaged subprograms can be shared by many applications, while hiding implementation details. • Package spec: declares the subprograms, and • Package body: implements the subprograms. • Example: 59 • Creating Package Spec: CREATE OR REPLACE PACKAGE emp_actions AS PROCEDURE hire_employee (emp_id INTEGER, name VARCHAR2, ...); PROCEDURE fire_employee (emp_id INTEGER); PROCEDURE raise_salary (emp_id INTEGER, amount REAL); ... END emp_actions; • Creating Package Body: 60 CREATE OR REPALCE PACKAGE BODY emp_actions AS PROCEDURE hire_employee (emp_id INTEGER, name VARCHAR2, ...) IS BEGIN ... INSERT INTO emp VALUES (emp_id, name, ...); END hire_employee; PROCEDURE fire_employee (emp_id INTEGER) IS BEGIN DELETE FROM emp WHERE empno = emp_id; END fire_employee; PROCEDURE raise_salary (emp_id INTEGER, amount REAL) IS BEGIN UPDATE emp SET sal = sal + amount WHERE empno = emp_id; END raise_salary; ... END emp_actions; 61 Packaging Subprograms • You can define subprograms in a package body without declaring their specs in the package spec. However, such subprograms can be called only from inside the package. • Guidelines: – Put package spec and body in separate files. – Compile package spec first before compiling package body. 62 Referencing Package Contents • To reference the types, items, subprograms, and call specs declared within a package spec, use dot notation, as follows: – – – – package_name.type_name package_name.item_name package_name.subprogram_name package_name.call_spec_name • Example: SQL> CALL emp_actions.hire_employee('TATE', 'CLERK', ...); 63 Oracle Packages: DBMS_OUTPUT • Package DBMS_OUTPUT enables you to display output from PL/SQL blocks and subprograms, which makes it easier to test and debug them. • You display the information by calling the procedure get_line or by setting SERVEROUTPUT ON in SQL*Plus. • For example, suppose you create the following stored procedure: 64 CREATE PROCEDURE calc_payroll (payroll OUT NUMBER) AS CURSOR c1 IS SELECT sal, comm FROM emp; BEGIN payroll := 0; FOR c1rec IN c1 LOOP c1rec.comm := NVL(c1rec.comm, 0); payroll := payroll + c1rec.sal + c1rec.comm; END LOOP; /* Display debug info. */ DBMS_OUTPUT.PUT_LINE('Value of payroll: ' || TO_CHAR(payroll)); END; In SQL*Plus SQL> SET SERVEROUTPUT ON SQL> VARIABLE num NUMBER SQL> CALL calc_payroll(:num); Value of payroll: 31225 65 Oracle Packages: UTL_FILE • Package UTL_FILE allows your PL/SQL programs to read and write operating system (OS) text files. • It provides a restricted version of standard OS stream file I/O, including open, put, get, and close operations. 66 UTL_FILE Functions • UTL_FILE.FOPEN ( location IN VARCHAR2, filename IN VARCHAR2, open_mode IN VARCHAR2) RETURN UTL_FILE.FILE_TYPE; • Open_mode: 'r' , 'w‘, 'a‘ • The maximum line size is the default to 1023. • To read a line of max. length > 1023, use • UTL_FILE.FOPEN ( location IN VARCHAR2, filename IN VARCHAR2, open_mode IN VARCHAR2, max_linesize IN BINARY_INTEGER) RETURN file_type; 67 UTL_FILE Functions • UTL_FILE.IS_OPEN (file IN FILE_TYPE) RETURN BOOLEAN; • UTL_FILE.FCLOSE (file IN OUT FILE_TYPE); • UTL_FILE.GET_LINE ( file IN FILE_TYPE, buffer OUT VARCHAR2); • Text is read up to but not including the line terminator, or up to the end of the file. • If the line does not fit in the buffer, then a VALUE_ERROR exception is raised. If no text was read due to "end of file," then the NO_DATA_FOUND exception is raised. • The maximum size of an input record is 1023 bytes. 68 BEGIN v_fid := utl_file.fopen('e:\log','h.log','r'); BEGIN LOOP utl_file.get_line(v_fid,in_row); IF substr(in_row,1,6)='Table' AND substr(in_row,1,1) = ':' THEN h_table_name := rtrim(substr(in_row,7,30),':'); ELSEIF substr(in_row,-7,7) = 'loaded.' THEN h_no_rows := to_number(substr(in_row,3,instr (in_row,'R')-4)); ENDIF; END LOOP; EXCEPTION WHEN NO_DATA_FOUND THEN NULL; utl_file.fclose(v_fid); END; 69 Useful Links • http://oraweb.comp.nus.edu.sg/RDBMS/app dev.816/a77069/toc.htm PL/SQL User's Guide and Reference • http://www.elementkjournals.com/dbm/000 5/dbm0053.htm Using the UTL_FILE package 70 Using SQL*Plus • A client for users to interactively execute commands on Oracle Server. • Useful commands – Describe a table structure: desc <table name> – List all tables under you: select table_name from user_tables. – Run packages: @<package name> 71 SQL*Plus Commands • Show errors: show error; • Edit the previously executed command(s): Edit • Enable output on SQL*PLUS: SET SERVEROUTPUT ON • Solve array overflow problem: SET ARRAYSIZE 1 72 SQL Commands • DROP TABLE employee • CREATE TABLE employee ( empno INTEGER NOT NULL, name VARCHAR2(50) NOT NULL, sal REAL NOT NULL, primary key (empno)); • INSERT INTO employee VALUES (1, 'Jack', 6000) • UPDATE employee SET sal=500 WHERE name=‘Jack’ • DELETE FROM employee WHERE name=‘Jack’; • CREATE INDEX test_index on employee(sal) 73 • DROP INDEX test_index