Documente Academic
Documente Profesional
Documente Cultură
PL/SQL is a combination of SQL along with the procedural features of programming languages. It was developed by Oracle Corporation in the early 90s to enhance the capabilities of SQL. 1. Better performance. 2. Procedural features like declaration of variable, condition checking, looping 3. Errors can be handled in a better way using exceptions.
[DECLARE Variable declaration] BEGIN Program Execution [EXCEPTION Exception handling] END; Example :
set serveroutput on DECLARE width INTEGER; height INTEGER := 3; area INTEGER; name varchar(10); BEGIN area := 6; width := area / height; name :='deepa'; DBMS_OUTPUT.PUT_LINE('width = ' || width); DBMS_OUTPUT.PUT_LINE('name = ' || name);
PL/SQL Variables
Few of the datatypes used to define placeholders are as given below. Number (n,m) , Char (n) , Varchar2 (n) , Date , Long , Long raw, Raw, Blob, Clob, Nclob, Bfile
variable_name is the name of the variable. datatype is a valid PL/SQL datatype. NOT NULL is an optional specification on the variable. value or DEFAULT valueis also an optional specification, where you can initialize a variable. Each variable declaration is a separate statement and must be terminated by a semicolon.
Scope of variables
1> DECLARE 2> var_num1 number; 3> var_num2 number; 4> BEGIN 5> var_num1 := 100; 6> var_num2 := 200; 7> DECLARE 8> var_mult number; 9> BEGIN 10> var_mult := var_num1 * var_num2; 11> END; 12> END; 13> /
BEGIN SELECT sal INTO var_salary FROM emp WHERE empno = var_emp_id; /* salary_increase := 100; */ dbms_output.put_line(var_salary); dbms_output.put_line('The employee ' || var_emp_id || ' has salary ' || var_salary); dbms_output.put_line(yearly salary increase||salary_increase);
END;
Constants
constant_name CONSTANT datatype := VALUE;
constant_name is the name of the constant i.e. similar to a variable name. The word CONSTANT is a reserved word and ensures that the value does not change. VALUE - It is a value which must be assigned to a constant when it is declared. You cannot assign a value later.
http://docs.oracle.com/cd/B10500_01/appdev.920/a96624/02_funds.htm
IF condition 1 THEN statement 1; statement 2; ELSIF condtion2 THEN statement 3; ELSE statement 4; END IF; 4) IF condition1 THEN ELSE IF condition2 THEN statement1; END IF; ELSIF condition3 THEN statement2; END IF;
3) Use a EXIT WHEN statement to exit from the Loop. If you use a EXIT statement without WHEN condition, the statements in the loop is executed only once.
declare n number; sum1 number default 0; endvalue number; begin endvalue:=&endvalue; n:=1; 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;
GOTO command
The label is surrounded by double brackets << >>. The label must not have a semicolon after the label name. The Syntax for the GOTO Statement
Goto label_name;
Rules to follow to use: 1.A GOTO label must precede an executable statement or a PL/SQL block. 2. A GOTO statement cannot branch into an IF statement, LOOP statement, or sub-block.
3. To branch to a place that does not have an executable statement, add the NULL statement. 4. From the current block, a GOTO statement can branch to another place in the block or into an enclosing block, but not into an exception handler. From an exception handler, a GOTO statement can branch into an enclosing block, but not into the current block. 5. If you use the GOTO statement to exit a cursor FOR loop prematurely, the cursor is closed automatically. The cursor is also closed automatically if an exception is raised inside the loop. 6. A given label can appear only once in a block. However, the label can appear in other blocks including enclosing blocks and sub-blocks. If a GOTO statement cannot find its target label in the current block, it branches to the first enclosing block in which the label appears.
DECLARE v_Status NUMBER := 1; BEGIN IF v_Status = 1 THEN GOTO mybranch; ELSE v_Status := 1; END IF; BEGIN
<<mybranch>>
dbms_output.put_line('after goto branch'); /*NULL;*/
END; END;
PL/SQL Records
What are records?
DECLARE var_salary number(6); var_emp_id number(6) := 7844; var_name varchar(20); var_job varchar(20); salary_increase CONSTANT number (3) :=10;
BEGIN SELECT sal,ename,job INTO var_salary, var_name, var_job FROM emp WHERE empno = var_emp_id; dbms_output.put_line('The employee '||var_name ||' id '|| var_emp_id || ' has salary ' || var_salary); dbms_output.put_line('role of the employee' ||var_job); dbms_output.put_line('yearly salary hike in percent '||salary_increase); END;
RECORDS
Records are another type of datatypes which oracle allows to be defined as a placeholder. Records are composite datatypes, which means it is a combination of different scalar datatypes like char, varchar, number etc. Each scalar data types in the record holds a value. A record can be visualized as a row of data. It can contain all the contents of a row.
Declaring a record: To declare a record, you must first define a composite datatype; then declare a record for that type. The General Syntax to define a composite datatype is:
TYPE record_type_name IS RECORD (first_col_name column_datatype, second_col_name column_datatype, ...);
record_type_name it is the name of the composite type you want to define. first_col_name, second_col_name, etc.,- it is the names the fields/columns within the record. column_datatype defines the scalar datatype of the fields.
There are different ways you can declare the datatype of the fields. col_name table_name.column_name%type; record_name record_type_name;
Example:
DECLARE TYPE employee_type IS RECORD (employee_id number(5), employee_name emp.ename%type, employee_job emp.job%type, employee_salary emp.sal%type, employee_department emp.deptno%type);
employee_rec employee_type;
%ROWTYPE : if all the fields of a record are based on the columns of a table, we can declare the record as follows:
record_name table_name%ROWTYPE;
Syntax TYPE record_type_name IS RECORD (column_name1 datatype,
col_name table_name.column_name%type;
Usage Dynamically define the datatype of a column based on a database column. Syntax record_name record_type_name; Usage Declare a record based on a user-defined type. Syntax record_name table_name%ROWTYPE; Usage
Dynamically declare a record based on an entire row of a table. Each column in the table corresponds to a field in the record.
DECLARE TYPE employee_type IS RECORD (emp_id number(5), emp_name emp.ename%type, emp_job emp.job%type, emp_sal emp.sal%type, emp_dept emp.deptno%type); employee_rec employee_type; BEGIN SELECT empno, ename, job, sal, deptno INTO employee_rec.emp_id, employee_rec.emp_name, employee_rec.emp_job,employee_rec.emp_sal, employee_rec.emp_dept FROM emp where empno=7844; dbms_output.put_line('---------------EMPLOYEE DETAILS--------------------'); dbms_output.put_line('employee id ' ||employee_rec.emp_id); dbms_output.put_line('employee name ' ||employee_rec.emp_name); dbms_output.put_line('employee job ' ||employee_rec.emp_job); dbms_output.put_line('employee salary ' ||employee_rec.emp_sal);
When you execute DML statements like DELETE, INSERT, UPDATE and SELECT statements, implicit cursors are created to process these statements. Oracle provides few attributes called as implicit cursor attributes to check the status of DML operations. The cursor attributes available are %FOUND, %NOTFOUND, %ROWCOUNT, and %ISOPEN.
DECLARE var_rows number(5); BEGIN UPDATE emp SET sal = sal + 1000; IF SQL%NOTFOUND THEN dbms_output.put_line('None of the salaries where updated'); ELSIF SQL%FOUND THEN var_rows := SQL%ROWCOUNT;
dbms_output.put_line('Salaries for ' || var_rows || 'employees are updated'); END IF; END;
2. Explicit cursors They must be created when you are executing a SELECT statement that returns more than one row. Even though the cursor stores multiple records, only one record can be processed at a time, which is called as current row. When you fetch a row the current row position moves to next row.
cursor_name A suitable name for the cursor. select_statement A select query which returns multiple rows.
How to use Explicit Cursor? There are four steps in using an Explicit Cursor.
DECLARE the cursor in the declaration section. OPEN the cursor in the Execution Section. FETCH the data from cursor into PL/SQL variables or records in the Execution Section. CLOSE the cursor in the Execution Section before you end the PL/SQL Block.
DECLARE CURSOR c1 IS SELECT * FROM emp where deptno=30; /* One more way of declaring a record record_name table_name%ROWTYPE; */ e_rec emp%rowtype; BEGIN OPEN c1; LOOP FETCH c1 INTO e_rec; EXIT WHEN c1%NOTFOUND; DBMS_OUTPUT.PUT_LINE('Number: ' || ' ' || e_rec.empno); DBMS_OUTPUT.PUT_LINE('Name : ' || ' ' || e_rec.ename); DBMS_OUTPUT.PUT_LINE('Salary: ' || ' ' || e_rec.sal); END LOOP; CLOSE c1; END;
-- Display details of Highest 10 salary paid employee DECLARE CURSOR c2 IS SELECT * FROM emp ORDER BY sal DESC; e_rec emp%rowtype; BEGIN Open c2; LOOP
FETCH c2 INTO e_rec; DBMS_OUTPUT.PUT_LINE('Number: ' || ' ' || e_rec.empno); DBMS_OUTPUT.PUT_LINE('Name : ' || ' ' || e_rec.ename); DBMS_OUTPUT.PUT_LINE('Salary: ' || ' ' || e_rec.sal); EXIT WHEN c2%ROWCOUNT >= 10; END LOOP; Close c2; END; Points to remember while fetching a row:
We can fetch the rows in a cursor to a PL/SQL Record or a list of variables created in the PL/SQL Block. If you are fetching a cursor to a PL/SQL Record, the record should have the same structure as the cursor. If you are fetching a cursor to a list of variables, the variables should be listed in the same order in the fetch statement as the columns are present in the cursor.
The DUAL table is a special one-row table present by default in all Oracle database installations. It is suitable for use in selecting a pseudocolumn such as SYSDATE or USER The table has a single VARCHAR2(1) column called DUMMY that has a value of "X"
It's the special table in Oracle, often used for calculation or checking system variable. For example;
"Select 2*4 from dual" prints out the result of the calculation "Select sysdate from dual" prints the server current date.
STRONG Cursors: Ref cursors can be dynamically opened or opened on the logic. DECLARE TYPE ecursor IS REF CURSOR RETURN emp%ROWTYPE; /*CURSOR c2 IS SELECT * FROM emp ORDER BY sal DESC;*/ ecur ecursor; e_rec emp%ROWTYPE; dn NUMBER; BEGIN dn := &deptno; OPEN ecur FOR SELECT * FROM emp WHERE deptno = dn; LOOP fetch ecur into e_rec; DBMS_OUTPUT.PUT_LINE ('Employee No : ' || e_rec.empno); DBMS_OUTPUT.PUT_LINE ('Employee Salary: ' || e_rec.sal); EXIT WHEN ecur%NOTFOUND; END LOOP; close ecur; END;
Weak REF cursors; DECLARE TYPE tcursor IS REF CURSOR; tcur tcursor; e1 emp%ROWTYPE; d1 dept%ROWTYPE; tname varchar(10); BEGIN tname := '&tablename'; IF tname = 'emp' THEN OPEN tcur FOR SELECT * FROM emp; DBMS_OUTPUT.PUT_LINE ('Emp table opened.'); close tcur; DBMS_OUTPUT.PUT_LINE ('Emp table closed.'); ELSIF tname = 'dept' THEN OPEN tcur FOR SELECT * FROM dept; DBMS_OUTPUT.PUT_LINE ('Dept table opened.'); close tcur; DBMS_OUTPUT.PUT_LINE ('Emp table closed.'); ELSE RAISE_APPLICATION_ERROR (-20004, 'Table name is wrong'); END IF; END;
Stored Procedures
What is a Stored Procedure?
A stored procedure or in simple a proc is a named PL/SQL block which performs one or more specific task. This is similar to a procedure in other programming languages. A procedure has a header and a body.
The header consists of the name of the procedure and the parameters or variables passed to the procedure. The body consists or declaration section, execution section and exception section similar to a general PL/SQL Block. A procedure is similar to an anonymous PL/SQL Block but it is named for repeated usage.
We can pass parameters to procedures in three ways. 1) IN-parameters 2) OUT-parameters 3) IN OUT-parameters A procedure may or may not return any value. General Syntax to create a procedure is: CREATE OR REPLACE PROCEDURE [schema] procedure name (argument { IN, OUT, IN OUT} data type, ..) {IS, AS} variable declarations; constant declarations; BEGIN pl/sql subprogram body; EXCEPTION exception pl/sql block; END;
Note:
IS/AS - marks the beginning of the body of the procedure The code between IS and BEGIN forms the Declaration section.
--PROCEDURE USING NO ARGUMENT..AND USING CURSOR CREATE OR REPLACE PROCEDURE P2 IS cursor cur1 is select * from emp; erec emp%rowtype; begin OPEN cur1; LOOP FETCH cur1 INTO erec; EXIT WHEN cur1%NOTFOUND; dbms_output.put_line(erec.ename); end loop; close cur1; end;
In PL/SQL, we can pass parameters to procedures and functions in three ways. 1) IN type parameter: These types of parameters are used to send values to stored procedures. 2) OUT type parameter: These types of parameters are used to get values from stored procedures. This is similar to a return type in functions. 3) IN OUT parameter: These types of parameters are used to send values and get values from stored procedures. 1) IN parameter: This is similar to passing parameters in programming languages. We can pass values to the stored procedure through these parameters or variables. This type of parameter is a read only parameter. We can assign the value of IN type parameter to a variable or use it in a query, but we cannot change its value inside the procedure.
CREATE OR REPLACE PROCEDURE SQR( X IN NUMBER) IS BEGIN dbms_output.put_line(x*x); end;
2) OUT Parameter: The OUT parameters are used to send the OUTPUT from a procedure or a function. This is a write-only parameter i.e, we cannot pass values to OUT paramters while executing the stored procedure, but we can assign values to OUT parameter inside the stored procedure and the calling program can recieve this output value. CREATE OR REPLACE PROCEDURE getempname(id IN NUMBER, salary OUT number) IS BEGIN select sal into salary from emp where empno=id; END;
DECLARE CURSOR cur IS SELECT empno, ename FROM emp; salary number; BEGIN FOR emprec in cur LOOP getempname(emprec.empno, salary); dbms_output.put_line('The employee '|| emprec.ename || ' with id ' || emprec.empno ||' has salary '|| salary); END LOOP; END;
INOUT Parameter create or replace procedure getsal( salary in out number) is begin select sal into salary from emp where empno = salary; end ;
declare salary number := 7900; begin getsal(salary); dbms_output.put_line('The employee salary is' || salary); end ;
Triggers
A trigger is a pl/sql block structure which is fired when a DML statements like Insert, Delete, Update is executed on a database table. A trigger is triggered automatically when an associated DML statement is executed. Advantages of database triggers: ---> Data is generated on it's own ---> Replicate table can be maintained ---> To enforce complex integrity contraints ---> To edit data modifications ---> To auto increment a field
CREATE [OR REPLACE ] TRIGGER trigger_name {BEFORE | AFTER | INSTEAD OF } {INSERT [OR] | UPDATE [OR] | DELETE} [OF col_name] ON table_name [REFERENCING OLD AS o NEW AS n] [FOR EACH ROW] WHEN (condition) /* trigger condition */ BEGIN /* trigger body */ --- sql statements END;
{BEFORE | AFTER | INSTEAD OF } what time should the trigger get fired. i.e for example: before or after updating a table. INSTEAD OF is used to create a trigger on a view. before and after cannot be used to create a trigger on a view. {INSERT [OR] | UPDATE [OR] | DELETE} - This clause determines the triggering event. More than one triggering events can be used together separated by OR keyword. The trigger gets fired at all the specified triggering event. [OF col_name] - This clause is used with update triggers. This clause is used when you want to trigger an event only when a specific column is updated. [ON table_name] - This clause identifies the name of the table or view to which the trigger is associated. [REFERENCING OLD AS o NEW AS n] - This clause is used to reference the old and new values of the data being changed. By default, you reference the values as :old.column_name or :new.column_name. The reference names can also be changed from old (or new) to any other
user-defined name. You cannot reference old values when inserting a record, or new values when deleting a record, because they do not exist. [FOR EACH ROW] - This clause is used to determine whether a trigger must fire when each row gets affected ( i.e. a Row Level Trigger) or just once when the entire sql statement is executed(i.e.statement level Trigger). WHEN (condition) - This clause is valid only for row level triggers. The trigger is fired only for rows that satisfy the condition specified.
<trigger_body> is a PL/SQL block, rather than sequence of SQL statements. Oracle has placed certain restrictions on what you can do in <trigger_body>, in order to avoid situations where
one trigger performs an action that triggers a second trigger, which then triggers a third, and so on, which could potentially create an infinite loop. The restrictions on <trigger_body> include: o You cannot modify the same relation whose modification is the event triggering the trigger. o You cannot modify a relation connected to the triggering relation by another constraint such as a foreign-key constraint.
DROP TABLE SALARY; CREATE TABLE SALARY (JOB VARCHAR2(9) primary key, MINSAL NUMBER(7,2), MAXSAL NUMBER(7,2) ); INSERT INSERT INSERT INSERT INSERT INTO INTO INTO INTO INTO SALARY SALARY SALARY SALARY SALARY VALUES VALUES VALUES VALUES VALUES ('CLERK', 800, 1300); ('ANALYST', 3000, 3500); ('SALESMAN', 1250, 1600); ('MANAGER', 2450, 2975); ('PRESIDENT', 5000, 5500);
create or replace trigger check_salary_EMP before insert or update of SAL, JOB on EMP for each row when (new.JOB != 'PRESIDENT') declare minsal number; maxsal number; begin select MINSAL, MAXSAL into minsal, maxsal from SALARY where JOB = :new.JOB; if :new.SAL < minsal or :new.SAL > maxsal then raise_application_error(-20225, 'Salary range exceeded'); elsif :new.SAL < :old.SAL then dbms_output.put_line(Salary has been decreased); elsif :new.SAL > 1.1*:old.SAL then dbms_output.put_line(Salary has been increased by 10 %); increase'); end if; end; /
update emp set sal=1600 where empno=7369; update emp set sal=1300 where empno=7369; update emp set sal=4000 where empno=7369;
Before & After Triggers: Before Triggers execute the trigger action before the triggering statement.
By using BEFORE trigger, user can eliminate unnecessary processing of the triggering statement. Are used to derive specific column values before completing a triggering INSERT or UPDATE statement.
After Triggers execute the trigger action after the triggering statement. If a before trigger already exists an after trigger can perform different actions on the same triggering statement.
CREATE TRIGGER trig1 AFTER INSERT ON T4 REFERENCING NEW AS newRow FOR EACH ROW WHEN (newRow.a <= 10) BEGIN INSERT INTO T5 VALUES(:newRow.b, :newRow.a); END;
Displaying Trigger Definition Errors
-- A database trigger that allows changes to employee table only during the business hours(i.e. from 8 a.m to 5.00 p.m.) from monday to saturday. There is no restriction on viewing data from the table
CREATE OR REPLACE TRIGGER Time_Check BEFORE INSERT OR UPDATE OR DELETE ON EMP BEGIN IF TO_NUMBER(TO_CHAR(SYSDATE,'hh24')) < 10 OR TO_NUMBER(TO_CHAR(SYSDATE,'hh24')) >= 17 OR TO_CHAR(SYSDATE,'DAY') = 'SAT' OR TO_CHAR(SYSDATE,'DAY') = 'SAT' THEN RAISE_APPLICATION_ERROR (-20004,'YOU CAN ACCESS ONLY BETWEEN 10 AM TO 5 PM ON MONDAY TO FRIDAY ONLY.'); END IF; END;
ActiveX ActiveX is the set of technologies that allow separately compiled components to communicate with one another. It allows you to develop components in many different languages such as VC++, Java, Excel, and Visual Basic and have all of the components work together.
1. Select a new project as Active X DLL 2. Add functions/procedures to the class provided. Give name for procedure, functions, attributes, events etc. 3. Make File as DLL File -> Make -> <projectname>.DLL 4. Save File/project in System32 folder 5. Register the DLL RUN-> regsvr32<projectname>
DLL to Add two numbers. Public Function AddTwoNumbers(ByVal a As Integer, ByVal b As Integer) AddTwoNumbers = a + b End Function
Steps to Include the ActiveX DLL component created in the project. 1. Go to Project-> References 2. Select the DLL created which would be used in our application. 3. Make use of the class -> function to use the component features.
Private Sub Command1_Click() Dim a As New SUM.Class1 Dim sum1 As Integer sum1 = a.AddTwoNumbers(9, 10) MsgBox (sum1) End Sub