Reference article: https://www.cnblogs.com/huyong/archive/2011/05/04/2036377.html
In PL/SQL programs, cursors are often used to handle transactions with multiple rows of records.
There are four steps to use: define, open, extract, and close.
Example:
09:52:04 SCOTT@std1> DECLARE 09:52:07 2 CURSOR c_cursor 09:52:07 3 IS SELECT ename, sal 09:52:07 4 FROM emp 09:52:07 5 WHERE rownum<11; 09:52:07 6 v_ename emp.ename%TYPE; 09:52:07 7 v_sal emp.ename%TYPE; 09:52:07 8 BEGIN 09:52:07 9 OPEN c_cursor; 09:52:07 10 FETCH c_cursor INTO v_ename, v_sal; 09:52:07 11 WHILE c_cursor%FOUND LOOP 09:52:07 12 DBMS_OUTPUT.PUT_LINE(v_ename||'---'||to_char(v_sal) ); 09:52:07 13 FETCH c_cursor INTO v_ename, v_sal; 09:52:07 14 END LOOP; 09:52:07 15 CLOSE c_cursor; 09:52:08 16 END; 09:52:09 17 / SMITH---800 ALLEN---1600 WARD---1250 JONES---2975 MARTIN---1250 BLAKE---2850 CLARK---2450 SCOTT---3000 TURNER---1500 ADAMS---1100 PL/SQL procedure successfully completed. Elapsed: 00:00:00.00
10:01:43 SCOTT@std1> DECLARE 11:31:04 2 deptrec dept%Rowtype; 11:31:04 3 dept_name dept.dname%TYPE; 11:31:04 4 dept_loc dept.loc%TYPE; 11:31:04 5 CURSOR c1 IS SELECT dname,loc FROM dept WHERE deptno<=30; 11:31:04 6 CURSOR c2(dept_no NUMBER DEFAULT 10) IS SELECT dname,loc FROM dept WHERE deptno <= dept_no; 11:31:04 7 CURSOR c3(dept_no NUMBER DEFAULT 10) IS SELECT * FROM dept WHERE deptno <= dept_no; 11:31:04 8 11:31:04 9 BEGIN 11:31:04 10 OPEN c1; 11:31:04 11 LOOP 11:31:04 12 FETCH c1 INTO dept_name,dept_loc; 11:31:04 13 EXIT WHEN c1%NOTFOUND; 11:31:04 14 dbms_output.put_line(dept_name||'---'||dept_loc); 11:31:04 15 END LOOP; 11:31:04 16 CLOSE c1; 11:31:04 17 11:31:04 18 OPEN c2; 11:31:04 19 LOOP 11:31:04 20 FETCH c2 INTO dept_name,dept_loc; 11:31:04 21 EXIT WHEN c2%NOTFOUND; 11:31:04 22 dbms_output.put_line(dept_name||'---'||dept_loc); 11:31:04 23 END LOOP; 11:31:04 24 CLOSE c2; 11:31:04 25 11:31:04 26 OPEN c3(dept_no => 20); 11:31:04 27 LOOP 11:31:04 28 FETCH c3 INTO deptrec; 11:31:04 29 EXIT WHEN c3%NOTFOUND; 11:31:04 30 dbms_output.put_line(deptrec.deptno||'---'||deptrec.dname||'---'||deptrec.loc); 11:31:04 31 END LOOP; 11:31:04 32 CLOSE c3; 11:31:04 33 END; 11:31:06 34 / ACCOUNTING---NEW YORK RESEARCH---DALLAS SALES---CHICAGO ACCOUNTING---NEW YORK 10---ACCOUNTING---NEW YORK 20---RESEARCH---DALLAS PL/SQL procedure successfully completed. Elapsed: 00:00:00.02 11:31:07 SCOTT@std1>
Cursor properties: Cursor_name%FOUND Boolean property is TRUE when the last cursor extraction operation FETCH succeeds, otherwise FALSE. Cursor_name%NOTFOUND Boolean property, contrary to%FOUND; Cursor_name%ISOPEN Boolean property, returns TRUE when the cursor is open; Cursor_name%ROWCOUNT numeric property that returns the number of records read from the cursor Example
15:04:04 SCOTT@std1> set serverout on 15:04:27 SCOTT@std1> DECLARE 15:04:40 2 v_empno emp.empno%TYPE; 15:04:40 3 v_sal emp.sal%TYPE; 15:04:40 4 CURSOR c_cursor IS SELECT empno,sal FROM emp; 15:04:40 5 BEGIN 15:04:40 6 OPEN c_cursor; 15:04:40 7 LOOP 15:04:40 8 FETCH c_cursor INTO v_empno,v_sal; 15:04:40 9 EXIT WHEN c_cursor%NOTFOUND; 15:04:40 10 IF v_sal<1200 THEN 15:04:40 11 UPDATE emp SET sal=sal+50 WHERE empno=v_empno; 15:04:41 12 dbms_output.put_line('Coded as'||v_empno||'Wages have been updated!'); 15:04:41 13 END IF; 15:04:41 14 END LOOP; 15:04:41 15 CLOSE c_cursor; 15:04:41 16 END; 15:04:42 17 / //Wage code 7369 has been updated! //Wage code 7876 has been updated! //The code 7900 salary has been updated! PL/SQL procedure successfully completed. Elapsed: 00:00:00.00 15:04:43 SCOTT@std1>
15:04:43 SCOTT@std1> DECLARE 15:06:12 2 v_name emp.ename%TYPE; 15:06:12 3 v_job emp.job%TYPE; 15:06:12 4 CURSOR c1 IS SELECT ename,job FROM emp WHERE deptno=20; 15:06:12 5 BEGIN 15:06:12 6 OPEN c1; 15:06:12 7 LOOP 15:06:12 8 FETCH c1 INTO v_name,v_job; 15:06:12 9 IF c1%FOUND THEN 15:06:12 10 dbms_output.put_line(v_name||'The position is'||v_job); 15:06:12 11 ELSE 15:06:12 12 dbms_output.put_line('The results have been processed.'); 15:06:12 13 EXIT; 15:06:12 14 END IF; 15:06:12 15 END LOOP; 15:06:12 16 CLOSE c1; 15:06:12 17 END; 15:06:14 18 / SMITH The position is CLERK JONES The position is MANAGER SCOTT The position is ANALYST ADAMS The position is CLERK FORD The position is ANALYST //The results have been processed. PL/SQL procedure successfully completed. Elapsed: 00:00:00.00 15:06:15 SCOTT@std1>
15:06:15 SCOTT@std1> DECLARE 15:38:26 2 v_ename emp.ename%TYPE; 15:38:26 3 v_hiredate emp.hiredate%TYPE; 15:38:26 4 CURSOR c1(dept_id NUMBER,jobid VARCHAR2) IS SELECT ename,hiredate FROM emp WHERE deptno=dept_id AND job=jobid; 15:38:26 5 BEGIN 15:38:26 6 OPEN c1(30,'SALESMAN'); 15:38:26 7 LOOP 15:38:26 8 FETCH c1 INTO v_ename,v_hiredate; 15:38:26 9 IF c1%FOUND THEN 15:38:26 10 dbms_output.put_line(v_ename||'The date of employment is:'||v_hiredate); 15:38:26 11 ELSE 15:38:26 12 dbms_output.put_line('The result set has been processed.'); 15:38:26 13 EXIT; 15:38:26 14 END IF; 15:38:26 15 END LOOP; 15:38:26 16 CLOSE c1; 15:38:26 17 END; 15:38:27 18 / ALLEN The date of employment is 20:-FEB-81 WARD The date of employment is: 22-FEB-81 MARTIN The date of employment is 28:-SEP-81 TURNER The date of employment is 08.-SEP-81 //The result set has been processed. PL/SQL procedure successfully completed. Elapsed: 00:00:00.00 15:38:28 SCOTT@std1>
15:38:28 SCOTT@std1> DECLARE 16:22:36 2 TYPE emp_record_type IS RECORD( 16:22:36 3 v_ename emp.ename%TYPE, 16:22:36 4 v_hiredate emp.hiredate%TYPE); 16:22:36 5 v_emp_record emp_record_type; 16:22:36 6 16:22:36 7 CURSOR c1(dept_id NUMBER,jobid VARCHAR2) RETURN emp_record_type IS SELECT ename,hiredate FROM emp WHERE deptno=dept_id AND job=jobid; 16:22:36 8 BEGIN 16:22:36 9 OPEN c1(20,'CLERK'); 16:22:36 10 LOOP 16:22:36 11 FETCH c1 INTO v_emp_record; 16:22:36 12 IF c1%FOUND THEN 16:22:36 13 dbms_output.put_line(v_emp_record.v_ename||'The date of employment is:'||v_emp_record.v_hiredate); 16:22:36 14 ELSE 16:22:36 15 dbms_output.put_line('The result set has been processed.'); 16:22:36 16 EXIT; 16:22:36 17 END IF; 16:22:36 18 END LOOP; 16:22:36 19 CLOSE c1; 16:22:36 20 END; 16:22:37 21 / SMITH The date of employment is 17:-DEC-80 ADAMS The date of employment is 23:-MAY-87 //The result set has been processed. PL/SQL procedure successfully completed. Elapsed: 00:00:00.01 16:22:38 SCOTT@std1>
16:22:38 SCOTT@std1> DECLARE 16:31:29 2 CURSOR c1(dept_id NUMBER,jobid VARCHAR2) IS SELECT ename,hiredate FROM emp WHERE deptno=dept_id AND job=jobid; 16:31:29 3 v_emp_record c1%ROWTYPE; 16:31:29 4 BEGIN 16:31:29 5 OPEN c1(20,'CLERK'); 16:31:29 6 LOOP 16:31:29 7 FETCH c1 INTO v_emp_record; 16:31:29 8 IF c1%FOUND THEN 16:31:29 9 dbms_output.put_line(v_emp_record.ename||'The date of employment is:'||v_emp_record.hiredate); 16:31:29 10 ELSE 16:31:29 11 dbms_output.put_line('The result set has been processed.'); 16:31:29 12 EXIT; 16:31:29 13 END IF; 16:31:29 14 END LOOP; 16:31:29 15 CLOSE c1; 16:31:29 16 END; 16:31:30 17 / SMITH The date of employment is 17:-DEC-80 ADAMS The date of employment is 23:-MAY-87 //The result set has been processed. PL/SQL procedure successfully completed. Elapsed: 00:00:00.00 16:31:31 SCOTT@std1>
Cursor FOR loops automatically execute cursor open, fetch, close and loops Example:
16:31:31 SCOTT@std1> DECLARE 16:43:57 2 CURSOR c1 IS SELECT deptno,ename,sal FROM emp; 16:43:57 3 BEGIN 16:43:57 4 FOR v1 IN c1 LOOP 16:43:57 5 dbms_output.put_line(v1.deptno||'---'||v1.ename||'---'||v1.sal); 16:43:57 6 END LOOP; 16:43:57 7 END; 16:43:58 8 / 20---SMITH---850 30---ALLEN---1600 30---WARD---1250 20---JONES---2975 30---MARTIN---1250 30---BLAKE---2850 10---CLARK---2450 20---SCOTT---3000 30---TURNER---1500 20---ADAMS---1150 30---JAMES---1000 20---FORD---3000 10---MILLER---1300 PL/SQL procedure successfully completed. Elapsed: 00:00:00.00 16:43:59 SCOTT@std1>
16:43:59 SCOTT@std1> DECLARE 16:58:03 2 CURSOR c1(dept_no NUMBER DEFAULT 10) IS SELECT deptno,dname,loc FROM dept WHERE deptno=dept_no; 16:58:03 3 BEGIN 16:58:03 4 dbms_output.put_line('When dept_no The parameter value is 30:'); 16:58:03 5 FOR v1 IN c1(30) LOOP dbms_output.put_line(v1.deptno||'---'||v1.dname||'---'||v1.loc); 16:58:03 6 END LOOP; 16:58:03 7 dbms_output.put_line('When dept_no The parameter value is 10:'); 16:58:03 8 FOR v1 IN c1 LOOP dbms_output.put_line(v1.deptno||'---'||v1.dname||'---'||v1.loc); 16:58:04 9 END LOOP; 16:58:04 10 END; 16:58:04 11 / //When dept_no parameter value is 30: 30---SALES---CHICAGO //When the dept_no parameter value is 10: 10---ACCOUNTING---NEW YORK PL/SQL procedure successfully completed. Elapsed: 00:00:00.00 16:58:05 SCOTT@std1>
PL/SQL also allows the use of sub-queries in cursor FOR loop statements to achieve cursor functionality Example
16:58:05 SCOTT@std1> BEGIN 17:03:37 2 FOR v1 IN (SELECT dname,loc FROM dept) LOOP 17:03:37 3 dbms_output.put_line(v1.dname||'---'||v1.loc); 17:03:37 4 END LOOP; 17:03:37 5 END; 17:03:38 6 / ACCOUNTING---NEW YORK RESEARCH---DALLAS SALES---CHICAGO OPERATIONS---BOSTON PL/SQL procedure successfully completed. Elapsed: 00:00:00.00 17:03:38 SCOTT@std1>
Implicit Cursor
Example: Delete all employees of a department in the EMPLOYEES table. If there are no employees in the department, delete the Department in the DEPARTMENT table.
17:36:32 SCOTT@std1> DECLARE 17:36:53 2 v_deptno emp.deptno%TYPE:=&p_deptno; 17:36:53 3 BEGIN 17:36:53 4 DELETE FROM emp WHERE deptno=v_deptno; 17:36:53 5 IF SQL%NOTFOUND THEN 17:36:53 6 DELETE FROM dept WHERE deptno=v_deptno; 17:36:53 7 END IF; 17:36:53 8 END; 17:36:54 9 / Enter value for p_deptno: 10 old 2: v_deptno emp.deptno%TYPE:=&p_deptno; new 2: v_deptno emp.deptno%TYPE:=10; PL/SQL procedure successfully completed. Elapsed: 00:00:00.00 17:36:58 SCOTT@std1>
Get the number of updated rows
08:48:43 SYS@std1> conn scott/tiger; Connected. 08:48:49 SCOTT@std1> DECLARE 08:54:12 2 v_rows NUMBER; 08:54:12 3 BEGIN 08:54:12 4 UPDATE emp SET sal=30000 WHERE deptno=30; 08:54:12 5 v_rows:=SQL%ROWCOUNT; 08:54:12 6 dbms_output.put_line('Updated'||v_rows||'Wages of individual employees'); 08:54:12 7 ROLLBACK; 08:54:12 8 END; 08:54:13 9 / //Updated salaries for six employees PL/SQL procedure successfully completed. Elapsed: 00:00:00.01 08:54:14 SCOTT@std1>
The difference between NO_DATA_FOUND and% NOTFOUND: SELECT... INTO statement triggers NO_DATA_FOUND Trigger% NOTFOUND when an explicit cursor WHERE clause is not found Trigger SQL%NOTFOUND when the WHERE clause of the UPDATE or DELETE statement is not found Use% NOTFOUND or% FOUND to determine the exit condition of the extraction loop, not NO_DATA_FOUND. Update and delete data using cursors Cursor modification and deletion operations refer to the modification or deletion of data rows specified in the table under cursor positioning. At this point, the FOR UPDATE option is required in the cursor query statement to lock all columns and partial columns of the corresponding data rows in the cursor result set in the table when the cursor is opened. In order not to change rows being processed (queried) by other users, ORACLE provides a FOR UPDATE clause to lock the selected rows. This requirement forces ORACLE to lock the rows of the cursor result set, preventing other transaction processes from updating or deleting the same rows until your transaction process commits or falls back. Grammar:
ORA-0054 : resource busy and acquire with nowait specified.
> If you use FOR UPDATE to declare cursors, you can use the WHERE CURRENT OF cursor_name clause in DELETE and UPDATE statements to modify or delete data rows in the database table corresponding to the current row of the cursor result set. Example
08:54:14 SCOTT@std1> DECLARE 09:21:38 2 v_deptno emp.deptno%TYPE:=&p_deptno; 09:21:38 3 CURSOR emp_cursor IS SELECT empno,sal FROM emp WHERE deptno=v_deptno FOR UPDATE NOWAIT; 09:21:38 4 BEGIN 09:21:38 5 FOR emp_record IN emp_cursor LOOP 09:21:38 6 IF emp_record.sal
09:36:06 SCOTT@std1> DECLARE 09:36:11 2 v_emp_record emp%ROWTYPE; 09:36:11 3 CURSOR c1 IS SELECT * FROM emp FOR UPDATE; 09:36:11 4 BEGIN 09:36:11 5 OPEN c1; 09:36:11 6 LOOP 09:36:11 7 FETCH c1 INTO v_emp_record; 09:36:12 8 EXIT WHEN c1%NOTFOUND; 09:36:12 9 IF v_emp_record.deptno=30 AND v_emp_record.job='SALESMAN' THEN 09:36:12 10 UPDATE emp SET sal=20000 WHERE CURRENT OF c1; 09:36:12 11 END IF; 09:36:12 12 END LOOP; 09:36:12 13 CLOSE c1; 09:36:12 14 END; 09:36:12 15 / PL/SQL procedure successfully completed. Elapsed: 00:00:04.39 09:36:17 SCOTT@std1>
Cursor variable Like a cursor, a cursor variable is a pointer to the current data row in a multiline query result set. But unlike cursors, cursor variables are dynamic and cursors are static. A cursor can only be connected to a specified query, that is, it can fixedly point to the memory processing area of a query, while a cursor variable can be connected to different query statements. It can point to the memory processing area of different query statements (but it can not point to multiple memory processing areas at the same time, and can only be connected to one query statement at a certain time). As long as the return types of these queries are compatible The cursor variable is a pointer, which belongs to the reference type, so the cursor variable type must be defined before the cursor variable type is declared. In PL/SQL, cursor variable types can be defined in the declaration areas of blocks, subroutines, and packages
TYPE ref_type_name IS REF CURSOR [ RETURN return_type];
Among them: ref_type_name is the newly defined cursor variable type name; return_type is the return value type of the cursor variable, which must be a record variable. When defining cursor variable type, we can use strong type definition and weak type definition. Strong type definitions must specify the return value type of cursor variables, while weak type definitions do not specify the return value type. Simply put: Strong type dynamic cursors refer to return statements, while weak type dynamic cursors refer to non-return statements (that is, weak type dynamic cursors can match any query statement, but strong type dynamic cursors can only match a specific query statement). Two steps to declare a cursor variable: Step 1: Define a REF CURSOU data type, such as: TYPE ref_cursor_type IS REF CURSOR; Step 2: Declare a cursor variable for the data type, such as: cv_ref REF_CURSOR_TYPE; Example: Create two strongly typed defined cursor variables and one weakly typed cursor variable
DECLARE TYPE deptrecord IS RECORD( deptno dept.deptno%TYPE, dname dept.dname%TYPE, loc dept.loc%TYPE); TYPE depttype1 IS REF CURSOR RETURN dept%ROWTYPE; TYPE depttype2 IS REF CURSOR RETURN deptrecord; TYPE curtype IS REF CURSOR; dept1 depttype1; dept2 depttype2; cr1 curtype;
Cursor variable operations are also open, extract, and close open
OPEN {cursor_variable_name | :host_cursor_variable_name} FOR select_statement;
Among them: cursor_variable_name is a cursor variable, host_cursor_variable_name is a cursor variable declared in PL/SQL host environment (such as OCI: ORACLE Call Interface, Pro*c program, etc.). OPEN... The FOR statement can reopen the cursor variable before closing the current cursor variable without causing CURSOR_ALREAD_OPEN exceptional errors. When a cursor variable is newly opened, the memory processing area of the previous query is released extract
FETCH {cursor_variable_name | :host_cursor_variable_name} INTO {variable [, variable]...| record_variable};
Among them: cursor_variable_name and host_cursor_variable_name are cursor variable and host cursor variable_name respectively; variable and record_variable are common variable and record variable name respectively. Close
CLOSE {cursor_variable_name | :host_cursor_variable_name}
Cursor_variable_name and host_cursor_variable_name are cursor variables and host cursor variable_name respectively. If an application tries to close an open cursor variable, it will cause an INVALID_CURSOR exception error. Example:
09:36:17 SCOTT@std1> DECLARE 10:41:56 2 TYPE emp_job_rec IS RECORD( 10:41:56 3 empno emp.empno%TYPE, 10:41:56 4 ename emp.ename%TYPE, 10:41:56 5 job emp.job%TYPE 10:41:56 6 ); 10:41:57 7 TYPE emp_job_refcur_type IS REF CURSOR RETURN emp_job_rec; 10:41:57 8 emp_refcur emp_job_refcur_type; 10:41:57 9 emp_job emp_job_rec; 10:41:57 10 BEGIN 10:41:57 11 OPEN emp_refcur FOR 10:41:57 12 SELECT empno,ename,job FROM emp ORDER BY deptno; 10:41:57 13 10:41:57 14 FETCH emp_refcur INTO emp_job; 10:41:57 15 WHILE emp_refcur%FOUND LOOP 10:41:57 16 dbms_output.put_line(emp_job.empno||':'||emp_job.ename||'is a '||emp_job.job); 10:41:57 17 FETCH emp_refcur INTO emp_job; 10:41:57 18 END LOOP; 10:41:57 19 10:41:57 20 CLOSE emp_refcur; 10:41:57 21 END; 10:41:58 22 / 7369:SMITHis a CLERK 7876:ADAMSis a CLERK 7566:JONESis a MANAGER 7788:SCOTTis a ANALYST 7902:FORDis a ANALYST 7900:JAMESis a CLERK 7844:TURNERis a SALESMAN 7654:MARTINis a SALESMAN 7521:WARDis a SALESMAN 7499:ALLENis a SALESMAN 7698:BLAKEis a MANAGER PL/SQL procedure successfully completed. Elapsed: 00:00:00.01 10:41:58 SCOTT@std1>
10:41:58 SCOTT@std1> DECLARE 11:38:42 2 Type refcur_t IS REF CURSOR; 11:38:42 3 Refcur refcur_t; 11:38:42 4 TYPE sample_rec_type IS RECORD ( 11:38:42 5 Id number, 11:38:42 6 Description VARCHAR2 (30) 11:38:42 7 ); 11:38:42 8 sample sample_rec_type; 11:38:42 9 selection varchar2(1) := UPPER (SUBSTR ('&tab', 1, 1)); 11:38:42 10 BEGIN 11:38:42 11 IF selection='D' THEN 11:38:42 12 OPEN refcur FOR 11:38:42 13 SELECT deptno,dname FROM dept; 11:38:42 14 dbms_output.put_line('Department Data'); 11:38:42 15 ELSE 11:38:42 16 OPEN refcur FOR 11:38:42 17 SELECT empno,ename FROM emp; 11:38:42 18 dbms_output.put_line('Employee Data'); 11:38:42 19 RETURN; 11:38:42 20 END IF; 11:38:42 21 11:38:42 22 dbms_output.put_line('----------------------------'); 11:38:42 23 FETCH refcur INTO sample; 11:38:42 24 WHILE refcur%FOUND LOOP 11:38:42 25 dbms_output.put_line(sample.id||':'||sample.DESCRIPTION); 11:38:42 26 FETCH refcur INTO sample; 11:38:43 27 END LOOP; 11:38:43 28 CLOSE refcur; 11:38:43 29 END; 11:38:43 30 / Enter value for tab: D old 9: selection varchar2(1) := UPPER (SUBSTR ('&tab', 1, 1)); new 9: selection varchar2(1) := UPPER (SUBSTR ('D', 1, 1)); Department Data ---------------------------- 20:RESEARCH 30:SALES 40:OPERATIONS PL/SQL procedure successfully completed. Elapsed: 00:00:00.00 11:38:46 SCOTT@std1>
11:38:46 SCOTT@std1> DECLARE 12:04:38 2 TYPE emp_cursor_type IS REF CURSOR; 12:04:38 3 c1 emp_cursor_type; 12:04:38 4 v_emp_record emp%ROWTYPE; 12:04:38 5 v_reg_record dept%ROWTYPE; 12:04:38 6 BEGIN 12:04:38 7 OPEN c1 FOR SELECT * FROM emp WHERE deptno=20; 12:04:38 8 LOOP 12:04:38 9 FETCH c1 INTO v_emp_record; 12:04:38 10 EXIT WHEN c1%NOTFOUND; 12:04:38 11 dbms_output.put_line(v_emp_record.ename||'Date of employment:'||v_emp_record.hiredate); 12:04:38 12 END LOOP; 12:04:38 13 OPEN c1 FOR SELECT * FROM dept; 12:04:38 14 LOOP 12:04:38 15 FETCH c1 INTO v_reg_record; 12:04:38 16 EXIT WHEN c1%NOTFOUND; 12:04:38 17 dbms_output.put_line(v_reg_record.deptno||': '||v_reg_record.dname); 12:04:38 18 END LOOP; 12:04:38 19 CLOSE c1; 12:04:38 20 END; 12:04:38 21 / SMITH Date of employment: 17-DEC-80 JONES Date of employment: 02-APR-81 SCOTT Date of employment: 19-APR-87 ADAMS Date of employment: 23-MAY-87 FORD Date of employment: 03-DEC-81 20: RESEARCH 30: SALES 40: OPERATIONS PL/SQL procedure successfully completed. Elapsed: 00:00:00.01 12:04:39 SCOTT@std1>