Oracle PLSQL Workbook
Oracle PLSQL Workbook
Oracle PLSQL Workbook
Table Of Contents
Unit Topics Page Numbers
Introduction PL/SQL
1 Introduction PL/SQL Block Advantages of PL/SQL Control Structures Nested Blocks Exception Handling Introduction Overview Advantages Pre-defined Exceptions User-defined Exceptions Propagation of Exceptions Excercises Cursors Introduction Managing Cursors Explicit Cursors Declaring Cursors Parameters With Cursors Cursor variables Cursor Attributes Ref Cursor Excercises 24-41 4-23
38-43
44-57
58-61
62-83
84-91
92-99
100
101-104
105-109
Markup languages Define how to add information into a document that indicates its logical components or that provides layout instructions. Examples: HTML, XML. Structured Query Language is a language based on set theory, so it is all about manipulating sets of data. SQL consists of a relatively small number of main commands such as SELECT, INSERT, CREATE, and GRANT; in fact, each statement accomplishes what might take hundreds of lines of procedural code to accomplish. That's one reason SQL-based databases are so widely used. Learning Oracle PL/SQL PL/SQL, Oracle's programming language for stored procedures, delivers a world of possibilities for your database programs. PL/SQL supplements the standard relational database language, SQL, with a wide range of procedural features, including loops, IF-THEN statements, advanced data structures, and rich transactional control--all closely integrated with the Oracle database server. PL/SQL is a procedural structured Query Language, is an extension to SQL where we can write programs using all the SQL statements and procedural statements. Various procedural statements we can use in PL/SQL are Assignment statements Conditional statements Loops Transactional processing statements Assignment statements In any programming language, we use = as assignment operator and == as comparison operator. Where as in PL/SQL we use = as comparison operator and: = as assignment operator and the statement used with this operator is called as assignment statement. Ex. c: = a + b;
Loops In any programming language, we use tow different types of Loops 1. Iterative Loops 2. Conditional Loops 1. Iterative Loops These loops performs operation for a range of values. For loop is used as iterative loop.
REVERSE Without this keyword, the loop counter increases by one with every trip through the loop, from the lower to the upper bound. With REVERSE, though, the loop will decrease by one instead, going from the upper to the lower bound. FOR n IN REVERSE 1..3 LOOP END LOOP; Also, the low and high values in the FOR loop range do not have to be literals, as you can see in the next example: FOR month_num IN 1 .. TO_NUMBER(TO_CHAR(SYSDATE, MM)) LOOP Statements; END LOOP; As youre working with loops, its important to know that PL/SQL declares the loop counter variable for you automatically, and there can be problems if it has the same name as a variable youve declared in the usual place (the programs declaration section). The scope (the only part of the code in which it can be referenced) of the loop counter is between the LOOP and END LOOP keywords.
Conditional Loops The simple loop is the, well, simplest loop structure. It has the following syntax: LOOP EXIT WHEN <CONDITION>; Statements END LOOP; We can use this exit condition any where within the loop. While Loop While <Condition> LOOP Statements; End Loop; Transactional Processing Statements We can use COOMIT and ROLLBACK as transactional processing statements. Once the transaction is over then you decide whether you save the data or not to save the data. Note: - PL/SQL supports 4GL (object oriented programming language) features. Every language uses some structure in writing programs. PL/SQL also uses two different types of block structures in writing programs.
Mandatory
Optional
Scope of Variables
The scope of a variable is the portion of PL/SQL code in which that variable can be referenced (i.e., its value read or modified). Most of the variables you define will have as their scope the block in which they were defined. Consider the following block: DECLARE book_title VARCHAR2 (100); BEGIN book_title := 'Learning Oracle PL/SQL'; END; /
They include host language variables declared in precompiler programs, screen fields in Forms applications, and SQL*Plus or iSQL*Plus host variables.
VARCHAR2 (max-Len)
LONG
Base type for binary data and byte strings up to 32,760 bytes. Number having precision p and scale s. the precision p can range from 1 to 38. Base type for integers between 2,147,483,647 and 2,147,483,647 BASE type for signed integers between 2,147,483,647 and 2,147,483,647. PLS_INTEGER values require less storage and are faster than NUMBER and BINARY_INTEGER values. Base type that stores one of three possible values Base type for date and time
A variable declared by referring column of a table. We can also use %TYPE attribute to declare a variable according to another previously declared variable. Example 1. V_empno EMP.empno%type; 2. v_salary NUMBER(8,2); 3. v_comm. V_salary%type;
Example V_s1 := 5000; V_S2 := 5500; The following expression yields true: V_s1 < v_s2
Composite Data Types A scalar type has no internal components. A composite type has internal components that can be manipulated individually. Composite data types ( Also known as collections) are of TABLE,RECORD, NESTED <variable> <Tablename>%rowtype; rec emp%rowtype; LOB Data Type Variables With LOB (large object) data types you can store blocks of unstructured data ( such as text, graphic, images, video clips and sound wave forms) up to 4GB in size. LOB data types allow efficient, random, piecewise access to the data and can be attributes of an object type. LOBs also support random access to data. CLOB (Character large object) data type is used to store large blocks of single-byte character data in the database. The BLOB (binary large object) data type is used to store large binary objects in the database
Use of variables Variables can be used for: Temporary storage of data Data can be temporarily stored in one or more variables for use when validating data input and for processing later in the data flow process. Manipulation of stored values Variables can be used for calculation and other data manipulations without accessing the database. Reusability After they declared, they can be used repeatedly in an application simply by referencing them in other statements, including other statements, including other declaratie statements. Ease of maintenance When we declare variables using %TYPE and %ROWTYPE, if any underlying definition changes, the variable definition changes accordingly at run time. This provides data independence, reduces maintenance costs.
DECLARE Stu STUDENT%rowtype; BEGIN -- generate rollno automatically SELECT nvl(max(rollno),0) + 1 into stu.rollno from student; -- input name and marks in two subjects stu.sname := &name; stu.sub1 := &marks1; stu.sub2 := &marks2; Stu.total := stu.sub1 + stu.sub2; Stu.average:= stu.total/2; INSERT INTO STUDENT VALUES stu; COMMIT; END; / To run PL/SQL program From SQL*Plus Environment SQL> start student Or SQL> @student From iSQL*Plus Environment Use Execute button
Note The DEFINE command specifies a user variable and assigns it a CHAR value. Even though you enter the number 50000, iSQL*Plus assigns a CHAR value to p_annual_sal consisting of the characters, 5,0,0,0 and 0.
Literal There s no business like show business INSTITUTE FOR TECHNOLOGY NLS LANGUAGE= ENGLISH HELLO
Actual Value Theres no business like show business INSTITUTE FOR TECHNOLOGY NLS LANGUAGE = ENGLISH HELLO
Code Conventions The following table provides guidelines for writing code in uppercase or lowercase to help you distinguish keywords from named objects. Category SQL statements PL/SQL keywords Data types Identifiers and parameters Database tables and columns Exercise 1) Evaluate each of the following declarations. Determine which of them are not legal and explain why. a) DECLARE v_id b) DECLARE Case Convention Uppercase Uppercase Uppercase Lowercase Lowercase Examples SELECT, INSERT DECLARE,BEGIN,IF VARCHAR2, BOOLEAN V_sal_emp_cursor, g_sal Emp, empno
NUMBER(4);
v_x,v_y,v_z
c) DECLARE V_birthdate d) DECLARE v_in_stock
VARCHAR2(10);
DATE NOT NULL; BOOLEAN :=1;
4) Create and execute a PL/SQL block that accepts two numbers through iSQL*Plus substitution variables a. Use the DEFINE command to provide the two values DEFINE p_num1 := 2; DEFINE p_num2 := 4 Pass the two values defined in step a above, to the PL/SQL block through iSQL*Plus substitution variables. The first number should be divided by the second number and have the second number added to the result. The result should be stored in a PL/SQL variable and printed on the screen
b.
EXCEPTION
Trapping an Exception If the exception is raised in the executable section of the block, processing branches to the corresponding exception handler in the exception section of the block. If PL/SQL successfully handles the exception, then the exception does not propagates to the enclosing block or environment. The PL/SQL block terminates successfully. Propagating an Exception If the exception is raised in the executable section of the block and there is no corresponding exception handler, the PL/SQL block terminates with failure and the exception is propagated to the calling environment.
Implicitly raised
Explicitly raised
You can program for exceptions to avoid disruption at run time. There are three types of exceptions. Exception Predefined Oracle Server error No predefined Oracle Server error Description One of approximately 20 errors that occur most often in PL/SQL code Any other standard Oracle Server error Directions for Handling Do not declare and allow the Oracle server to raise them implicitly Declare within the declarative section and allow the Oracle Server to raise them implicitly. Declare within the declarative section, and raise explicitly.
User-defined error
The following PL/SQL block attempts to select information from the employee and includes an exception handler for the case in which no data is found: DECLARE vempno NUMBER; BEGIN SELECT empno INTO vempno FROM EMP WHERE ename = 'RAM'; EXCEPTION WHEN NO_DATA_FOUND THEN INSERT INTO emp (empno, ename, job, deptno) VALUES (101,'RAM', 'EXECUTIVE', 10); END; In other words, if I am not already an employee in the company, the SELECT statement fails and control is transferred to the exception section (which starts with the keyword EXCEPTION). PL/SQL matches up the exception raised with the exception in the WHEN clause (NO_DATA_FOUND is a named, internal exception that represents ORA-01403-no data found). It then executes the statements in that exception handler, so I am promptly inserted into the employee table.
EXCEPTION WHEN OTHERS THEN ... Use the WHEN OTHERS clause in the exception handler as a catch all to trap any exceptions that are not handled by specific WHEN clauses in the exception section. If present, this clause must be the last exception handler in the exception section. The OTHERS handler traps all exceptions not already trapped. Some Oracle tools have their own predefined exceptions that you can raise to cause events in the application. The OTHERS handler also traps these exceptions.
Declare
Associate
Reference
Exception-handling section Handle the raised exception
declare deptno_in number; still_have_employees EXCEPTION; PRAGMA EXCEPTION_INIT(still_have_employees, -2292); BEGIN deptno_in := &deptno; DELETE FROM d1 WHERE deptno = deptno_in; EXCEPTION WHEN still_have_employees THEN DBMS_OUTPUT.PUT_LINE ('Please delete employees in dept first'); ROLLBACK; -- RAISE; /* Re-raise the current exception. */ END; You trap a nonpredefined Oracle server error by declaring it first, or by using the OTHERS handler. The declared exception is raised implicitly. In PL/SQL, the PRAGMA_EXCEPTION_INIT tells the compiler to associate an exception name with an Oracle error number. That allows you to refer to any internal exception by name and to write a specific handler for it. Note: PRAGMA (also called pseudoinstructions) is the keyword that signifies that the statement is a compiler directive, which is not processed when the PL/SQL block is executed. Rather, it directs the Pl/SQL compiler to
Declare
Declarative section
Name the Exception
Raise
Executable Section
Explicitly raise the exception by using the RAISE statement.
Reference
Exception-handling Section
Handle the raised Exception.
PL/SQL allows you to define your own exceptions. User-defined PL/SQL exceptions must be:
Declared in the declare section of a PL/SQL block Raised explicitly with RAISE statements
Example: DEFINE p_department_desc = Accounts DEFINE p_department_number = 50 DECLARE E_invalid_department EXCEPTION; BEGIN UPDATE dept SET dname = &p_department_desc WHERE deptno = &p_department_number; IF SQL%NOTFOUND THEN RAISE e_invalid_department; END IF; COMMIT; EXCEPTION WHEN e_invalid_department THEN DBMS_OUTPUT.PUT_LINE(No such department id); END;
Handle required exceptions 2) Write a PL/SQL block to select the name of the employee with a given salary value. a) Use the DEFINE command to provide salary b) Pass the value in the PL/SQL block through a iSQL*Plus substitution variable. If the salary entered returns more than one row, handle the exception with an appropriate exception handler and insert into the MESSAGES table the message More than one employee with a salary of <salary> c) If the salary entered does not return any rows, handle the exception with an appropriate exception handler and insert into the MESSAGES table the message No Employee with a salary of <salary>. d) If the salary entered returns only one row, insert into the MESSAGES table the employees name and the salary amount. e) Handle any other exception with an appropriate exception handler and insert into the MESSAGES table the message Some other error occurred. f) Test the block for a variety of text cases, Display the rows from the MESSAGES table to check whether the PL/SQL block has executed successfully.
generate sno automatically get the opening balance for each transaction Input (D)eposit / (W)ithdraw for trntype Input amount and calculate the balance Amount is always a +ve number Withdrawal amount is always within the balance Handle suitable exceptions
1) Solution begin dbms_output.new_line; for i in 1 .. 8 loop for j in 1 .. 8 loop dbms_output.put(j||' '); end loop; dbms_output.new_line; end loop; end;
Implicit cursor PL/SQL declares a cursor implicitly for all SQL data manipulation statements, including queries that return only one row. However, for queries that return more than one row, you must declare an explicit cursor or use a cursor FOR loop. The name of the implicit cursor is SQL. You can directly use the cursor without any declaration. Explicit Cursor The set of rows returned by a query can consist of zero, one or multiple rows, depending on how many rows meet your search criteria. When a query returns multiple rows, you can explicitly declare a cursor to process the rows. The set of rows returned by a multiple-row query is called the active set. It is manipulated just like a file in programming languages.
Note: The fetch for an implicit cursor is an array fetch, and the existence of a second row still raises the TOO_MANY_ROWS exception. Furthermore, you can use explicit cursors to perform multiple fetches and to re-execute parsed queries in the work area.
When you put SELECT statements into your PL/SQL, there are two ways to deal with the data. You can use the SELECT INTO, as seen in the previous section, in which case you are using an implicit cursor ("implicit" because you don't refer to it specifically in your code; Oracle manages implicit cursors automatically). The second way gives you more direct control over the creation, naming, and use of cursors associated with your SELECTs. These cursors are called explicit cursors.
1. Declare the cursor in declare section 2. Open the cursor using OPEN 3. Fetch rows from the cursor using FETCH 4. Close the cursor after the process is over using CLOSE.
Declare a Cursor A cursor is declared in DECLARE section using CURSOR statement. Syntax
Note:
No data is actually retrieved at the time of cursor declaration. Data is placed in the cursor when cursor is opened.
SET SERVEROUTPUT ON DECLARE Cursor emp_cur is Select empno, ename, job, sal from EMP where empno >= 7521; Emp_rec emp_cur%rowtype; BEGIN /* open the cursor */ Open emp_cur; /* fetch all the records of the cursor one by one */ LOOP FETCH emp_cur into emp_rec; /* Exit loop if reached end of cursor NOTFOUND is the cursor attribute */ exit when emp_cur%NOTFOUND; DBMS_OUTPUT.PUT_LINE (emp_rec.empno || emp_rec.ename|| emp_rec.sal); END LOOP; -- closing the cursor CLOSE emp_cur; END; /
Attribute
FOUND
Significance TRUE if most recent fetch found a row in the table; otherwise FALSE
NOTFOUND ROWCOUNT
BOOLEAN NUMBER
This the just logical inverse of FOUND Number of Rows fetched so far
Recommended time to use After opening and fetching from the cursor but before closing it (will be NULL before first fetch) Same as above Same as above (except it will be zero before the first fetch)
In addition to those cursor attributes, there are some less-commonly used cursor attributes that you might see from time to time. They include: ISOPEN Returns TRUE or FALSE depending on whether cursor_name is open. For the implicit cursor SQL it always produces FALSE.
Example SET SERVEROUTPUT ON declare cursor c1 is select empno,ename from emp; begin for c in c1 loop dbms_output.put_line(c.empno || c.ename); end loop; end; /
But C is available only inside the cursor for loop. It contains the same columns as the cursor. In order to access a column of the current row of the cursor, in the cursor for loop, use the format: Rowtype_variable.columnname Statements in the cursor for loop are executed once for each row of the cursor. And for each row of the cursor, row is copied into rowtype_variable. Loop is terminated once end of cursor is reached. And cursor is closed.
Note : If parameters are to be passed to cursor, give the values after the name of the cursor. declare cursor c1 (n number) is Select empno, ename from EMP where empno >= n; begin for c in c1(7521) loop dbms_output.put_line (c.empno || c.ename); end loop; end; /
PASSBOOK SNO 1 2 3 4 5 6 TRNDATE TRNTYPE SYSDATE D SYSDATE W SYSDATE W SYSDATE D SYSDATE W SYSDATE D AMOUNT 30000 10000 2000 5000 3000 8000 BALANCE 30000 20000 18000 23000 20000 28000
In the above table, if we modify the amount in one particular transaction, Write a program to modify the corresponding balances. Handle suitable exceptions, to accept only a positive amount and in no case, balance should become negative.
List the benefits of using subprograms List the different environments from which
subprograms can be invoked
Improved performance After a subprogram is compiled, the parsed code is available in the shared SQL area of the server and subsequent calls to the subprogram use this parsed code. This avoids reparsing for multiple users. Avoids PL/SQL parsing at run time by parsing at compile time Reduces the number of calls to the database and decreases network traffic by bundling commands. Improves code clarity: Using appropriate identifier names to describe the action of the routines reduces the need for comments and enhances the clarity of the code.
<header> Subprogram Specification IS | AS Declaration Section BEGIN Executable Section EXCEPTION (optional) Exception Section END;
Subprogram Specification The header is relevant for named blocks only and determines the way that the program unit is called or invoked. The header determines: The PL/SQL subprogram type, that is, either a procedure or a function The name of the subprogram The parameter list, if one exists The RETURN clause, which applies only to functions The IS or AS keyword is mandatory.
Subprogram Body
Mode
Data type
PL/SQL block
Description Name of the procedure Name of PL/SQL variable whose value is passed to or populated by the calling environment, or both, depending on the mode being used Type of argument IN (default) OUT IN OUT Data type of argument can be any SQL/ PLSQL data type. Can be of %TYPE, %ROWTYPE, or any scalar or composite data type. You can not restrict the size of the data type in the parameters. Procedural body that defines the action performed by the procedure.
parameters: variables declared in the parameter list of a subprogram specification. Example: CREATE PROCEDURE raise_sal(p_id NUMBER, p_amount NUMBER) ... END raise_sal;
Actual parameters: variables or expressions referenced in the parameter list of a subprogram call.
OUT Parameters: Example (continued) Run the script file shown in the slide to create the QUERY_EMP procedure. This procedure has four formal parameters. Three of them are OUT parameters that return values to the calling environment. The procedure accepts an EMPNO value for the parameter P_ID. The name, salary, and commission values corresponding to the employee ID are retrieved into the three OUT parameters whose values are returned to the calling environment. Viewing OUT Parameters VARIABLE g_name VARCHAR2(25) VARIABLE g_sal NUMBER VARIABLE g_comm NUMBER EXECUTE query_emp(171, :g_name, :g_sal, :g_comm) PRINT g_name
1. Run the SQL script file to generate and compile the source code. 2. Create host variables in iSQL*Plus, using the VARIABLE command. 3. Invoke the QUERY_EMP procedure, supplying these host variables as the OUT parameters. Note the use of the colon (:) to reference the host variables in the EXECUTE command 4. Variables which are used with : are called as binded variables. The meaning of binded is, getting the value that we are getting from Pl/SQL environment to SQL environment. . 5. To view the values passed from the procedure to the calling environment, use the PRINT command. The example shows the value of the G_NAME variable passed back to the calling environment. The other variables can be viewed, either individually, as above, or with a single PRINT command.
Do not specify a size for a host variable of data type NUMBER when using the VARIABLE command. A host variable of data type CHAR or VARCHAR2 defaults to a length of one, unless a value is supplied in parentheses.
Viewing IN OUT Parameters VARIABLE g_phone_no VARCHAR2(15) BEGIN :g_phone_no := 8006330575; END; / PRINT g_phone_no EXECUTE format_phone (:g_phone_no) PRINT g_phone_no
Example
CREATE OR REPLACE PROCEDURE add_dept (p_name IN departments.department_name%TYPE DEFAULT unknown, p_loc IN departments.location_id%TYPE DEFAULT 1700) IS BEGIN INSERT INTO departments(department_id, department_name, location_id) VALUES (departments_seq.NEXTVAL, p_name, p_loc); END add_dept;
Examples of Passing Parameters BEGIN add_dept; add_dept (TRAINING, 2500); add_dept ( p_loc => 2400, p_name =>EDUCATION); add_dept ( p_loc => 1200) ; END; /
After completing this lesson, you should be able to do the following: Describe the uses of functions Create stored functions Invoke a function Remove a function Differentiate between a procedure and a function
Lesson Aim In this lesson, you will learn how to create and invoke functions.
CREATE [OR REPLACE] FUNCTION function_name [(parameter1 [mode1] datatype1, parameter2 [mode2] datatype2,. . .)] RETURN datatype IS|AS PL/SQL Block; The PL/SQL block must have at least one RETURN statement.
How Procedures and Functions Differ 1. You create a procedure to store a series of actions for later execution. A procedure can contain zero or more parameters that can be transferred to and from the calling environment, but a procedure does not have to return a value. 2. You create a function when you want to compute a value, which must be returned to the calling environment. A function can contain zero or more parameters that are transferred from the calling environment. Functions should return only a single value, and the value is returned through a RETURN statement. 3. Functions used in SQL statements cannot have OUT or IN OUT mode parameters.
create or replace procedure decry(u1 varchar2) is nm varchar2(20); x varchar2(20); begin select p into nm from logram where u=u1; for i in 1 .. length(nm) loop x := x || chr(ascii(substr(nm,i,1))+42); end loop; dbms_output.put_line(x); end; /
Each package contains the following parts: Package specification Package body
Package Specification
Contains all declarations for variable, cursor, procedures and functions that are to be made public. All public objects of package are visible outside the package.
Syntax CREATE OR REPLACE PACKAGE package_name IS /* declare public objects of package */ END;
Syntax
In the body you can declare other variables, but you do not repeat the declarations in the specification. The body contains the full implementation of cursors and modules. In the case of a cursor, the package body contains both specification and SQL statement for the cursor. In the case of a module the package body contains both the specification and body of the module. The BEGIN keyword indicates the presence of an execution or initialization section for the package. This section can also optionally include an exception section. As with a procedure or function, you can add the name of the package, as a label, after the END keyword in both the specification and package
Program
CREATE OR REPLACE PACKAGE SAMPLEPAK IS PROCEDURE PROC1( N NUMBER, N1 OUT NUMBER); FUNCTION FUN1(N NUMBER) RETURN NUMBER; END; / CREATE OR REPLACE PACKAGE BODY SAMPLEPAK IS PROCEDURE PROC1(N NUMBER, N1 OUT NUMBER) IS BEGIN N1 := N * 5; END PROC1; FUNCTION FUN1(N NUMBER) RETURN NUMBER IS N1 NUMBER; BEGIN N1 := N * 2; RETURN N1; END FUN1; END SAMPLEPAK; /
Execution
VARIABLE N NUMBER EXECUTE SAMPLEPAK.PROC1(5,:N) PRINT N EXECUTE :N := SAMPLEPAK.FUN1(4) PRINT N
Execution
VARIABLE N NUMBER EXECUTE SAMPLEPAK.PROC1(5,:N) PRINT N EXECUTE :N := SAMPLEPAK.FUN1(4) PRINT N Note :- A private member can not be accessed by referring package object. They are called only through public members of the package object.
Program
CREATE OR REPLACE PACKAGE POLYPACK IS PROCEDURE PROC1( N NUMBER, N1 OUT NUMBER); PROCEDURE PROC1 (X VARCHAR2,Y VARCHAR2,Z OUT VARCHAR2); END; / CREATE OR REPLACE PACKAGE BODY POLYPACK IS PROCEDURE PROC1(N NUMBER, N1 OUT NUMBER) IS BEGIN N1 := N * 5; END PROC1; PROCEDURE PROC1(X VARCHAR2,Y VARCHAR2, Z OUT VARCHAR2) IS BEGIN Z := CONCAT(X,Y); END PROC1; END POLYPACK; /
Execution
VARIABLE N NUMBER VARIABLE ST VARCHAR2(100)
EXECUTE POLYPACK.PROC1(5,:N)
PRINT N
CREATE OR REPLACE PACKAGE BODY Employee_RefCur_pkg AS function empsearch(i_ename varchar2) return empcur IS o_empcursor empcur; BEGIN OPEN o_EmpCursor FOR SELECT empno, ename, job, sal FROM emp WHERE ename LIKE '%' || i_EName || '%' ORDER BY UPPER(emp.ename); return o_empcursor; END EmpSearch; END Employee_RefCur_pkg; /
select Employee_RefCur_pkg.empsearch('E') from dual
Oracle PL/SQL Work Book Page No: 89
A Schema level trigger is a trigger which is written at database level or user level.. These triggers can be written by DBA only. Any user can write table and ROW level triggers. Table level triggers are ment for providing security at object (Table) level. Row level triggers are ment for validations
Row Triggers : A row trigger is fired each time the table is affected by triggering statement. For example, if an UPDATE statement updates multiple rows of a table, a row trigger is fired once for each row affected by the UPDATE statement. If a triggering statement affects no rows, a row trigger is not executed at all. A Row trigger is fired once for each row affected by the command. These triggers are used to check for the validity of the data in the triggering statements and rows affected.
Statement Triggers A statement trigger is fired once on behalf of the triggering statement, regardless of the number of rows in the table that the triggering statement affects (even no rows are affected). For example, if a DELETE statement deletes several rows from a table, a statement level DELETE trigger is fired only once, regardless of how many rows are deleted from the table.
BEFORE and AFTER Triggers When defining a trigger, you can specify the trigger timing- whether the trigger action is to be executed before or after the triggering statement. BEFORE and AFTER apply to both statement and row triggers.
BEFORE and AFTER triggers fired by DML statements can be defined only on tables, not on views. However, triggers on the on the base table(s) of a view fired if an INSERT, UPDATE, or DELETE statement is issued against the view. BEFORE and AFTER triggers fired by DDL statements can be defined only on the database or a schema, not on particular tables.
Other uses of triggers are to Prevent invalid transaction Enforce complex security authorizations Enforce complex business rules Gather statistics on table access Modify table data when DML statements are issued against views
END;
Note:- RAISE_APPLICATION_ERROR is a server-side built-in procedure that returns an error to the user and causes the PL/SQL block to fail. When a database trigger fails, the Oracle server automatically rolls the triggering statement back.
Testing secure_emp
INSERT INTO EMP (empno, ename) VALUES (101,ravi); ERROR at line 1 ORA-20001 You may insert into EMP table only during business hours ORA-06512 at PLSQL SECURE_emp, LINE 4 Ora-04088 error during execution of trigger PLSQL SECURE_EMP Note : The row might be inserted if you are in a different time zone from the database server. The trigger fires even if your system clock is within these business hours.
CREATE OR REPLACE TRIGGER secure_emp BEFORE INSERT OR UPDATE OR DELETE ON emp BEGIN IF TO_CHAR(SYSDATE,DY) IN(SAT,SUN) OR TO_CHAR(SYSDATE,HH24:MI) NOT BETWEEN 08:00 AND 18:00 THEN IF INSERTING THEN RAISE_APPLICATION_ERROR(-20001,You may Insert into EMP table only during business hours..); ELSIF UPDATING THEN RAISE_APPLICATION_ERROR(-20001,You may UPDATE EMP table only during business hours..); ELSIF DELETING THEN RAISE_APPLICATION_ERROR(-20001,You may DELETE from EMP table only during business hours..); END IF; END IF; END; /
CREATE OR REPLACE TRIGGER restrict_salary BEFORE INSERT OR UPDATE OF sal ON emp FOR EACH ROW BEGIN IF (:NEW.job NOT IN (CLERK, SALESMAN) AND :NEW sal > 15000 THEN RAISE_APPLICATION_ERROR(-20002,Employees cannot earn this amount); END IF: END; /
The OLD and NEW qualifiers are available only in ROW triggers Prefix these qualifiers a colon ( : ) in every SQL and PL/SQL statement There is no colon ( : ) prefix if the qualifiers are referenced in the WHEN restricting condition
Note :- Row triggers can decrease the performance if you do a lot of updates on larger tables.
PL/SQL Records
Records in PL/SQL programs are very similar in concept and structure to the rows of a database table. A record is a composite data structure, which means that it is composed of more than one element or component, each with its own value. The record as a whole does not have value of its own; instead, each individual component or field has a value. The record gives you a way to store and access these values as a group. If you are not familiar with using records in your programs, you might initially find them complicated. When used properly, however, records will greatly simplify
Cursor-based
Programmerdefined
A record whose structure you, the programmer, get to define with a declaration statement.
Each field is defined explicitly (its name and data type) in the TYPE statement for that record; a field in a programmer-defined record can even be another record.
Data abstraction
When you abstract something, you generalize it. You distance yourself from the nitty-gritty details and concentrate on the big picture. When you create modules, you abstract the individual actions of the module into a name. The name (and program specification) represents those actions. When you create a record, you abstract all the different attributes or fields of the subject of that record. You establish a relationship between all those different attributes and you give that relationship a name by defining a record.
Aggregate operations
Once you have stored information in records, you can perform operations on whole blocks of data at a time, rather than on each individual attribute. This kind of aggregate operation reinforces the abstraction of the record. Very often you are not really interested in making changes to individual components of a record, but instead to the object which represents all of those different components. Suppose that in my job I need to work with companies, but I don't really care about whether a company has two lines of address information or three. I want to work at the level of the company itself, making changes to, deleting, or analyzing the status of a company. In all these cases I am talking about a whole row in the database, not any specific column. The company record hides all that information from me, yet makes it accessible when and if I need it. This orientation brings you closer to viewing your data as a collection of objects with rules applied to those objects.
PL/SQL tables are available only in releases of PL/SQL Version 2. PL/SQL tables reside in the private PL/SQL area of the Oracle Server database instance; they are not available as client-side structures at this time. As a result, you cannot declare and manipulate PL/SQL tables in your Oracle Developer/2000 environment. You can, on the other hand, build stored procedures and packages which work with PL/SQL tables, but hide these structures behind their interface. You can then call this
stored code from within Oracle Developer/2000 to take advantage of Version 2 features like PL/SQL tables.
This is a two-dimensional structure and not currently supported. Unbounded or Unconstrained There is no predefined limit to the number of rows in a PL/SQL table. The PL/SQL table grows dynamically as you add more rows to the table. The PL/SQL table is, in this way, very different from an array. Related to this definition, no rows for PL/SQL tables are allocated for this structure when it is defined Sparse In a PL/SQL table, a row exists in the table only when a value is assigned to that row. Rows do not have to be defined sequentially. Instead you can assign a value to any row in the table. So row 15 could have a value of `Fox' and row 15446 a value of `Red', with no other rows defined in between. In contrast, an array is a dense data structure. When you declare an array, all cells in the array are allocated in memory and are ready to use. Homogeneous elements Because a PL/SQL table can have only a single column, all rows in a PL/SQL table contain values of the same data type. It is, therefore, homogeneous. Indexed by integers PL/SQL tables currently support a single indexing mode: by BINARY_INTEGER. This number acts as the "primary key" of the PL/SQL table. The range of a
The datatype of the table type's column can be any of the following: Scalar datatype Any PL/SQL-supported scalar data type, such as VARCHAR2, POSITIVE, DATE, or BOOLEAN. Anchored data type A data type inferred from a column, previously defined variable, or cursor expression using the %TYPE attribute. Here are some examples of table type declarations:
TYPE company_keys_tabtype IS TABLE OF company.company_id%TYPE NOT NULL INDEX BY BINARY_INTEGER;
Where <table_name> is the name of the table and <table_type> is the name of a previously declared table type. In the following example I create a general table type for primary keys in PACKAGE and then use that table type to create two tables of primary keys:
PACKAGE company_pkg IS /* Create a generic table type for primary keys */ TYPE primary_keys_tabtype IS TABLE OF NUMBER NOT NULL INDEX BY BINARY_INTEGER; /* declare two tables based on this table type */ company_keys_tab primary_keys_tabtype; emp_keys_tab primary_keys_tabtype; END company_pkg;
where <table_name> is the name of the table and <primary_key_value> is a literal, variable, or expression whose datatype is compatible with the BINARY_INTEGER
Iterative Assignment
In order to fill up multiple rows of a table, I recommend taking advantage of a PL/SQL loop. Within the loop you will still perform direct assignments to set the values of each row, but the primary key value will be set by the loop rather than hardcoded into the assignment itself. Example
CREATE OR REPLACE PROCEDURE show_bizdays (start_date_in IN DATE := SYSDATE, ndays_in IN INTEGER := 30) IS TYPE date_tabtype IS TABLE OF DATE INDEX BY BINARY_INTEGER; bizdays date_tabtype; nth_day BINARY_INTEGER := 1; v_date DATE := start_date_in; BEGIN /* Loop through the calendar until enough biz days are found */ WHILE nth_day <= ndays_in LOOP /* If the day is not on the weekend, add to the table. */ IF TO_CHAR (v_date, 'DY') NOT IN ('SAT', 'SUN') THEN bizdays (nth_day) := v_date; DBMS_OUTPUT.PUT_LINE (v_date); nth_day := nth_day + 1; END IF; v_date := v_date + 1; END LOOP; END show_bizdays; /
Aggregate Assignment
Just as you can assign one entire record to another record of the same type and structure, you can perform aggregate assignments with tables as well. In order to transfer the values of one table to another, the datatype of the two tables must be compatible. Beyond that you simply use the assignment operator (:=) to transfer the values of one table to the other. The following example contains an example of an aggregate table assignment:
DECLARE TYPE name_table IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER; old_names name_table; new_names name_table; BEGIN /* Assign values to old_names table */ old_names(1) := 'Smith'; old_names(2) := 'Harrison'; /* Assign values to new_names table */ new_names(111) := 'Hanrahan'; new_names(342) := 'Blimey'; /* Transfer values from new to old */ old_names := new_names; /* This assignment will raise NO_DATA_FOUND */ DBMS_OUTPUT.PUT_LINE (old_names (1)); END;
A table-level assignment completely replaces the previously defined rows in the table. In the preceding example, rows 1 and 2 in old_names are defined before the last, aggregate assignment. After the assignment, only rows 111 and 342 in the old_names table have values.
But this assignment doesn't actually remove the row or make it undefined; it just sets the value of the row to NULL. The only way to actually empty a PL/SQL table of all rows is to perform an aggregate assignment with a table that is empty -- a table, that is, with no rows defined. With this approach, for every PL/SQL table you want to be able to empty, you declare a parallel, empty table of the same table type. When you are finished working with your table, simply assign the empty table to the actual table. This will unassign all the rows you have used. The following example demonstrates this technique:
DECLARE TYPE company_names_tabtype IS TABLE OF company.name%TYPE INDEX BY BINARY_INTEGER; company_names_tab company_names_tabtype; /* Here is the empty table declaration */ empty_company_names_tab company_names_tabtype; BEGIN ... set values in company names table ... /* The closest you can come to "dropping" a PL/SQL table */ company_names_tab := empty_company_names_tab; END;
We can use LONG data type to store character data up to 2GB in length per row. In place of LONG and LONG RAW , you can also use the LOB data types(BLOB, CLOB, NCLOB and BFILE) for storage of long data up to 4GB in length. Oracle recommends
What are CLOBs? Basically, LOBs (Large Objects) are designed to support large unstructured data such as text, graphic images, still video clips, full motion video, and sound waveforms. A typical employee record may be a few hundred bytes, but even small amounts of multimedia data can be thousands of times larger. Oracle supports the following two types of LOBs: Those stored in the database either in-line in the table or in a separate segment or tablespace, such as BLOB(Binary LOB), CLOB (Character LOB) and, NCLOB (National Character LOB). As the name signifies, BLOB holds binary data while the CLOB holds textual data and the NCLOB holds, character data that corresponds to the national character set defined for the Oracle database. Those stored as operating system files, such as BFILEs CLOBs can store large amounts of character data and are useful for storing unstructured XML documents. Also useful for storing multimedia data, BFILEs which are external file references can also be used. In this case the XML is stored and managed outside the RDBMS, but can be used in queries on the server.
While LOBs provide the infrastructure in the database to store multimedia data, Oracle8i and Oracle9i also provide developers with additional functionality for the most
Internal LOBs
Internal LOBs, as their name suggests, are stored inside database tablespaces in a way that optimizes space and provides efficient access. Internal LOBs use copy semantics and participate in the transactional model of the server. You can recover internal LOBs in the event of transaction or media failure, and any changes to a internal LOB value can be committed or rolled back. In other words, all the ACID properties that pertain to using database objects pertain to using internal LOBs Number of LOB columns in a table: An Oracle8, Oracle8i, or Oracle9i table can have multiple LOB columns. Each LOB column in the same table can be of a different type. In Oracle7 Release 7.3 and higher, tables are limited to a single LONG or LONG RAW column. Random piece-wise access: LOBs support random access to data, but LONGs support only sequential access.
Internal LOBs Use Copy Semantics, External LOBs Use Reference Semantics
Copy semantics: Both LOB locator and value are copied Reference semantics: Only LOB locator is copied
Example 2 dbms_lob.append( dest_lob IN OUT NOCOPY CLOB CHARACTER SET ANY_CS, src_lob IN CLOB CHARACTER SET dest_lob%CHARSET); CREATE OR REPLACE PROCEDURE Example_1b IS dest_lob, src_lob BLOB; BEGIN -- get the LOB locators SELECT b_lob INTO dest_lob FROM lob_table WHERE key_value = 12 FOR UPDATE; SELECT b_lob INTO src_lob FROM lob_table WHERE key_value = 12; dbms_lob.append(dest_lob, src_lob); COMMIT; END; /
Datatype BLOB
Description Used to store unstructured binary data up to 4G. This datatype stores the full binary object in the database. CLOB/NCLOB Used to store up to 4G of character data. This datatype stores the full character data in the database. BFILE Used to point at large objects that are external to the database and in operating system files. The BFILE column also contains binary data and cannot be selected.
Benefits of LOBs
It use to be that the largest object you could store in the database was of the datatype LONG. Oracle has for the last few releases kept telling us to convert our LONG datatypes to a LOB datatype (maybe they will too). The reason for converting our LONGs to LOBs can be seen in this short list of benefits. 1. 2. 3. 4. 5. LOB columns can reach the size of 4G. You can store LOB data internally within a table or externally. You can perform random access to the LOB data. It is easier to do transformations on LOB columns. You can replicate the tables that contain LOB columns.
SUBSTR
The method DBMS_LOB.SUBSTR can return only 4000 characters which is the limit of a varchar in Oracle. Is there any other way to fetch more than 4000 characters in a single stroke? One way , we can read 4000 characters at a time and store them into a varchar2 variable and finally combine them together. This results in improper output because of the carriage returns and other non printable characters in the script.
DBMS_LOB.READ
declare v_amount number:=1000 v_offset number:=10; v_buffer clob; clobvalue1 clob; begin select t1 into clobvalue1 from test where s = 1; dbms_lob.read(clobvalue1,v_amount,v_offset,v_buffer); dbms_output.put_line(v_buffer); end; COPY declare v_amount number:=3000; v_offset number:=1; v_buffer clob; clobvalue1 clob; clobvalue2 clob; begin select t1 into clobvalue1 from test where s = 3 for update; select t2 into clobvalue2 from test where s = 3; dbms_lob.read(clobvalue1,v_amount,v_offset,v_buffer); dbms_output.put_line(v_buffer); DBMS_LOB.COPY (clobValue1, clobValue2,2000,dbms_lob.getlength(clobvalue1)+2,1); dbms_output.put_line(clobvalue2); end; /
ERASE Procedure
This procedure erases an entire internal LOB or part of an internal LOB. When data is erased from the middle of a for BLOBs or CLOBs respectively.
LOB,
The actual number of bytes or characters erased can differ from the number you specified in the amount parameter if the end of the LOB value is reached before erasing the specified number. The actual number of characters or bytes erased is returned in the amount parameter.
Syntax
DBMS_LOB.ERASE ( lob_loc amount offset lob_loc amount offset IN OUT NOCOPY BLOB, IN OUT NOCOPY INTEGER, IN INTEGER := 1);
DBMS_LOB.ERASE ( IN OUT NOCOPY CLOB CHARACTER SET ANY_CS, IN OUT NOCOPY INTEGER, IN INTEGER := 1);
Parameters
Parameter Description
lob_loc amount
Locator for the LOB to be erased. Number of bytes (for BLOBs or BFILES) or characters (for CLOBs or
NCLOBs)
to be erased.
offset
Absolute offset (origin: 1) from the beginning of the LOB in bytes (for
BLOBs)
or characters (CLOBs).
Description Any input parameter is NULL. Either: - amount < 1 or amount > LOBMAXSIZE - offset < 1 or offset > LOBMAXSIZE
Usage Notes
It is not mandatory that you wrap the LOB operation inside the Open/Close APIs. If you did not open the LOB before performing the operation, the functional and domain indexes on the LOB column are updated during the call. However, if you opened the LOB before performing the operation, you must close it before you commit or rollback the transaction. When an internal LOB is closed, it updates the functional and domain indexes on the LOB column. If you do not wrap the LOB operation inside the Open/Close API, the functional and domain indexes are updated each time you write to the LOB. This can adversely affect performance. Therefore, it is recommended that you enclose write operations to the LOB within the OPEN or CLOSE statement.
Example
CREATE OR REPLACE PROCEDURE Example_4 IS lobd amt BEGIN SELECT b_col INTO lobd FROM lob_table WHERE key_value = 12 FOR UPDATE; dbms_lob.erase(dest_lob, amt, 2000); COMMIT; END; BLOB; INTEGER := 3000;
TRIM Procedure
This procedure trims the value of the internal LOB to the length you specify in the newlen parameter. Specify the length in bytes for BLOBs, and specify the length in characters for CLOBs.
If you attempt to TRIM an empty LOB, then nothing occurs, and TRIM returns no error. If the new length that you specify in newlen is greater than the size of the LOB, then an exception is raised.
Syntax
DBMS_LOB.TRIM ( lob_loc newlen IN OUT NOCOPY BLOB, IN INTEGER);
DBMS_LOB.TRIM ( lob_loc newlen IN OUT NOCOPY CLOB CHARACTER SET ANY_CS, IN INTEGER);
Parameters
Parameter Description
lob_loc newlen
Locator for the internal LOB whose length is to be trimmed. New, trimmed length of the LOB value in bytes for BLOBs or characters for CLOBs.
Description
lob_loc
is NULL.
Usage Notes
It is not mandatory that you wrap the LOB operation inside the Open/Close APIs. If you did not open the LOB before performing the operation, the functional and domain indexes on the LOB column are updated during the call. However, if you opened the LOB before performing the operation, you must close it before you commit or rollback the transaction. When an internal LOB is closed, it updates the functional and domain indexes on the LOB column. If you do not wrap the LOB operation inside the Open/Close API, the functional and domain indexes are updated each time you write to the LOB. This can adversely affect performance. Therefore, it is recommended that you enclose write operations to the LOB within the OPEN or CLOSE statement.
Example
CREATE OR REPLACE PROCEDURE Example_15 IS lob_loc BEGIN -- get the LOB locator SELECT b_col INTO lob_loc FROM lob_table WHERE key_value = 42 FOR UPDATE; dbms_lob.trim(lob_loc, 4000); COMMIT; END; BLOB;
WRITEAPPEND Procedure
This procedure writes a specified amount of data to the end of an internal LOB. The data is written from the buffer parameter. There is an error if the input amount is more than the data in the buffer. If the input amount is less than the data in the buffer, then only amount bytes or characters from the buffer are written to the end of the LOB.
Syntax
DBMS_LOB.WRITEAPPEND ( lob_loc IN OUT NOCOPY BLOB, amount IN buffer IN BINARY_INTEGER, RAW);
DBMS_LOB.WRITEAPPEND ( lob_loc IN OUT NOCOPY CLOB CHARACTER SET ANY_CS, amount IN buffer IN BINARY_INTEGER, VARCHAR2 CHARACTER SET lob_loc%CHARSET);
Parameters
Parameter Description
lob_loc amount
Locator for the internal LOB to be written to. Number of bytes (for BLOBs) or characters (for CLOBs) to write, or number that were written.
buffer
Description Any of lob_loc, amount, or offset parameters are NULL, out of range, or INVALID.
INVALID_ARGVAL
Usage Notes
The form of the VARCHAR2 buffer must match the form of the CLOB parameter. In other words, if the input LOB parameter is of type NCLOB, then the buffer must contain NCHAR data. Conversely, if the input LOB parameter is of type CLOB, then the buffer must contain CHAR data. When calling DBMS_LOB.WRITEAPPEND from the client (for example, in a BEGIN/END block from within SQL*Plus), the buffer must contain data in the client's character set. Oracle converts the client-side buffer to the server's character set before it writes the buffer data to the LOB. It is not mandatory that you wrap the LOB operation inside the Open/Close APIs. If you did not open the LOB before performing the operation, the functional and domain indexes on the LOB column are updated during the call. However, if you opened the LOB before performing the operation, you must close it before you commit or rollback the transaction. When an internal LOB is closed, it updates the functional and domain indexes on the LOB column.
Each table and nonjoined view has a pseudocolumn called ROWID. For example:
CREATE TABLE T_tab (col1 Rowid); INSERT INTO T_tab SELECT Rowid FROM Emp_tab WHERE Empno = 7499;
This command returns the ROWID pseudocolumn of the row of the EMP_TAB table that satisfies the query, and inserts it into the T1 table.
External Character ROWID
The extended ROWID pseudo column is returned to the client in the form of an 18character string (for example, "AAAA8mAALAAAAQkAAA"), which represents a base 64 encoding of the components of the extended ROWID in a four-piece format, OOOOOOFFFBBBBBBRRR: OOOOOO: The data object number identifies the database segment (AAAA8m in the example). Schema objects in the same segment, such as a cluster of tables, have the same data object number. FFF: The datafile that contains the row (file AAL in the example). File numbers are unique within a database. BBBBBB: The data block that contains the row (block AAAAQk in the example). Block numbers are relative to their datafile, not tablespace. Therefore, two rows with identical block numbers could reside in two different datafiles of the same tablespace. RRR: The row in the block (row AAA in the example). There is no need to decode the external ROWID; you can use the functions in the DBMS_ROWID package to obtain the individual components of the extended ROWID.
EXECUTE IMMEDIATE dynamic string [INTO {define_variable [, define_variable]... | record}] [USING [IN | OUT | IN OUT] bind_argument [, [IN | OUT | IN OUT] bind_argument]...] [{RETURNING | RETURN} INTO bind_argument[, bind_argument]...];
Where Dynamic string is a string expression that represents a SQL statement or PL/SQL block define_variable is a variable that stores a selected column value record is a user-defined or %ROWTYPE record that stores a selected row. input bind_argument is an expression whose value is passed to the dynamic SQL statement or PL/SQL block.
Execution
Step1 : SQL> variable p_rows number Step2 : SQL> execute del_all_rows(EMP,:p_rows); Step3 : SQL> print p_rows Example 2 Procedure to update a column value in a table create or replace procedure UPDATE_rows( p_tab_name in varchar2, COL1 IN VARCHAR2, VAL1 IN NUMBER,COL2 IN VARCHAR2,VAL2 IN NUMBER) is begin execute immediate 'UPDATE ' || P_TAB_NAME || ' SET ' || COL1 || ' = ' || VAL1 || ' WHERE ' || COL2 || ' = ' || VAL2 ; END;
Execute
Set serveroutput on DECLARE sql_stmt VARCHAR2(200); my_empno NUMBER(4) := 7902; my_ename VARCHAR2(10); my_job VARCHAR2(9); my_sal NUMBER(7,2) := 3250.00; BEGIN sql_stmt := 'UPDATE emp SET sal = :1 WHERE empno = :2 RETURNING ename, job INTO :3, :4'; /* Bind returned values through USING clause. */ EXECUTE IMMEDIATE sql_stmt USING my_sal, my_empno, OUT my_ename, OUT my_job; /* Bind returned values through RETURNING INTO clause. */ EXECUTE IMMEDIATE sql_stmt USING my_sal, my_empno RETURNING INTO my_ename, my_job; dbms_output.put_line(my_ename); dbms_output.put_line(my_job); END; OUTPUT SQL> set serveroutput on SQL> / FORD ANALYST Test the above code by writing a procedure with empno,sal as IN parameters And my_ename and my_job as OUT parameters
When appropriate, you must specify the OUT or IN OUT mode for bind arguments passed as parameters. For example, suppose you want to call the following standalone procedure:
CREATE PROCEDURE create_dept ( deptno IN OUT NUMBER, dname IN VARCHAR2, loc BEGIN SELECT deptno_seq.NEXTVAL INTO deptno FROM dual; INSERT INTO dept VALUES (deptno, dname, loc); END; IN VARCHAR2) AS
To call the procedure from a dynamic PL/SQL block, you must specify the IN OUT mode for the bind argument associated with formal parameter deptno, as follows:
Execute Immediate statement can also perform DDL operations CREATE OR REPLACE PROCEDURE ddl_add_table(TNAME VARCHAR2) is BEGIN EXECUTE IMMEDIATE 'CREATE TABLE ' || TNAME || '(EMPNO NUMBER(3) PRIMARY KEY, ENAME VARCHAR2(30), SAL NUMBER(8,2) )' ; END; /
Dynamic Insert Statement CREATE OR REPLACE PROCEDURE INSERT_INTO_TABLE( table_name VARCHAR2, empno NUMBER, Name VARCHAR2, saL number) IS str VARCHAR2(200); BEGIN str := INSERT INTO || table_name || values (:empno, :ename,:sal); EXECUTE IMMEDIATE str USING empno,ename,sal; END; /