The CONTINUE statement jumps out of the current loop interation and starts the next one. It can be used on its own, or as part of a CONTINUE WHEN statement, as shown below.
SET SERVEROUTPUT ON DECLARE l_number NUMBER := 0; BEGIN FOR i IN 1 .. 100 LOOP CONTINUE WHEN MOD(i,2) = 0; -- Do something here! l_number := l_number + 1; END LOOP; DBMS_OUTPUT.put_line('CONTINUE WHEN : ' || l_number); l_number := 0; FOR i IN 1 .. 100 LOOP IF MOD(i,2) = 0 THEN CONTINUE; END IF; -- Do something here! l_number := l_number + 1; END LOOP; DBMS_OUTPUT.put_line('IF .. CONTINUE: ' || l_number); END; / CONTINUE WHEN : 50 IF .. CONTINUE: 50 PL/SQL procedure successfully completed. SQL>
This type of processing has always been possible using IF statements either on their own or with exceptions or GOTO statements, but the CONTINUE statement is neater and brings PL/SQL in line with other langauges. The following examples show the type of code necessary to perform the same task before the CONTINUE statement was added to PL/SQL.
SET SERVEROUTPUT ON DECLARE ex_continue EXCEPTION; l_number NUMBER := 0; BEGIN FOR i IN 1 .. 100 LOOP BEGIN IF MOD(i,2) != 0 THEN RAISE ex_continue; END IF; -- Do something here! l_number := l_number + 1; EXCEPTION WHEN ex_continue THEN NULL; END; END LOOP; DBMS_OUTPUT.put_line('EXCEPTION: ' || l_number); l_number := 0; FOR i IN 1 .. 100 LOOP IF MOD(i,2) != 0 THEN -- Do something here! l_number := l_number + 1; END IF; END LOOP; DBMS_OUTPUT.put_line('IF : ' || l_number); l_number := 0; FOR i IN 1 .. 100 LOOP IF MOD(i,2) = 0 THEN GOTO label_continue; END IF; -- Do something here! l_number := l_number + 1; << label_continue >> NULL; END LOOP; DBMS_OUTPUT.put_line('GOTO : ' || l_number); END; / EXCEPTION: 50 IF : 50 GOTO : 50 PL/SQL procedure successfully completed. SQL>
The NEXTVAL and CURRVAL sequence pseudocolumns can now be accessed in PL/SQL expressions as well as queries. This makes the code look simpler, and the documentation suggests it improves performance. The following example compares the speed of the original and new methods of accessing these sequence values.
CREATE SEQUENCE test1_seq START WITH 1000000; SET SERVEROUTPUT ON DECLARE l_start NUMBER; l_loops NUMBER := 100000; l_value NUMBER; BEGIN l_start := DBMS_UTILITY.get_time; FOR i IN 1 .. l_loops LOOP SELECT test1_seq.NEXTVAL INTO l_value FROM dual; END LOOP; DBMS_OUTPUT.put_line('NEXTVAL SELECT=' || (DBMS_UTILITY.get_time - l_start) || ' hsecs'); l_start := DBMS_UTILITY.get_time; FOR i IN 1 .. l_loops LOOP l_value := test1_seq.NEXTVAL; END LOOP; DBMS_OUTPUT.put_line('NEXTVAL Expression=' || (DBMS_UTILITY.get_time - l_start) || ' hsecs'); l_start := DBMS_UTILITY.get_time; FOR i IN 1 .. l_loops LOOP SELECT test1_seq.CURRVAL INTO l_value FROM dual; END LOOP; DBMS_OUTPUT.put_line('CURRVAL SELECT=' || (DBMS_UTILITY.get_time - l_start) || ' hsecs'); l_start := DBMS_UTILITY.get_time; FOR i IN 1 .. l_loops LOOP l_value := test1_seq.CURRVAL; END LOOP; DBMS_OUTPUT.put_line('CURRVAL Expression=' || (DBMS_UTILITY.get_time - l_start) || ' hsecs'); END; / NEXTVAL SELECT=2196 hsecs NEXTVAL Expression=2203 hsecs CURRVAL SELECT=1007 hsecs CURRVAL Expression=1003 hsecs PL/SQL procedure successfully completed. SQL>
You can see that as far as elapsed time is concerned, there is little difference between the two methods.
Native dynamic SQL and the DBMS_SQL package now support dynamic SQL statements larger than 32 KB. The EXECUTE IMMEDIATE statement, OPEN-FOR statement and DBMS_SQL.PARSE procedure all accept SQL statements in the form of CLOBs.
The DBMS_SQL.TO_REFCURSOR function converts a DBMS_SQL cursor ID into a REF CURSOR. SET SERVEROUTPUT ON DECLARE l_cursor NUMBER; l_return NUMBER; l_ref_cursor SYS_REFCURSOR; TYPE t_emp_tab IS TABLE OF emp%ROWTYPE; l_emp_tab t_emp_tab; BEGIN l_cursor := DBMS_SQL.open_cursor; DBMS_SQL.parse(l_cursor, 'SELECT * FROM emp', DBMS_SQL.NATIVE); l_return := DBMS_SQL.EXECUTE(l_cursor); -- Connvert from DBMS_SQL to a REF CURSOR. l_ref_cursor := DBMS_SQL.to_refcursor(l_cursor); FETCH l_ref_cursor BULK COLLECT INTO l_emp_tab; DBMS_OUTPUT.put_line('Employee Count: ' || l_emp_tab.count); CLOSE l_ref_cursor; END; / Employee Count: 14 PL/SQL procedure successfully completed. SQL>
The DBMS_SQL.TO_CURSOR_NUMBER function converts a REF CURSOR into a DBMS_SQL cursor ID.
SET SERVEROUTPUT ON DECLARE l_ref_cursor SYS_REFCURSOR; l_cursor NUMBER; l_count NUMBER := 0; BEGIN OPEN l_ref_cursor FOR 'SELECT * FROM emp'; l_cursor := DBMS_SQL.to_cursor_number(l_ref_cursor); WHILE DBMS_SQL.fetch_rows(l_cursor) > 0 LOOP l_count := l_count + 1; END LOOP; DBMS_OUTPUT.put_line('Employee Count: ' || l_count); DBMS_SQL.close_cursor(l_cursor); END; / Employee Count: 14 PL/SQL procedure successfully completed. SQL>
In addition, the DBMS_SQL package now supports all datatypes supported by native dynamic SQL.
<< pre next >>