I have two samples of code below that use the same table and sequence definitions.
The first one inserts using individual insert statements, with the first three inserts giving an override value to the sequenced column and the final insert relying on the sequence. Here, even though 3 rows were previously inserted, the sequence produces a "1" for the sequenced column when the fourth row is inserted.
The second one inserts the same first three rows as above, but does so in a FOR loop. When the fourth row is inserted outside of the FOR LOOP, the sequence produces a "4" for the sequenced column.
So my question is, why does the sequence increase on each insert (with a value provided) when done in a FOR loop and doesn't increase on each insert when not using a FOR loop?
/*************************************************************************/
/*INSERT USING INDIVIDUAL STATEMENTS*/
/*************************************************************************/
CREATE SEQUENCE default_seq;
CREATE TABLE t1 (
col1 NUMBER DEFAULT ON NULL default_seq.NEXTVAL NOT NULL ENABLE,
description VARCHAR2(30)
);
/
DECLARE
BEGIN
INSERT INTO t1 (col1, description) VALUES (1000,'1000,DESCRIPTION');
INSERT INTO t1 (col1, description) VALUES (1001,'1001,DESCRIPTION');
INSERT INTO t1 (col1, description) VALUES (1002,'1002,DESCRIPTION');
INSERT INTO t1 (description) VALUES ('DESCRIPTION only');
END;
/
SELECT * FROM t1;
/
DROP TABLE t1;
DROP SEQUENCE default_seq;
/*************************************************************************/
/*INSERT USING A FOR LOOP*/
/*************************************************************************/
CREATE SEQUENCE default_seq;
CREATE TABLE t1 (
col1 NUMBER DEFAULT ON NULL default_seq.NEXTVAL NOT NULL ENABLE,
description VARCHAR2(30)
);
/
DECLARE
BEGIN
FOR i IN 1..3 LOOP
INSERT INTO t1 (col1, description) VALUES (999 + i,999 + i || ',DESCRIPTION');
END LOOP;
INSERT INTO t1 (description) VALUES ('DESCRIPTION only');
END;
/
SELECT * FROM t1;
/
DROP TABLE t1;
DROP SEQUENCE default_seq;
Thanks,
Hilari
Thanks for the test case!
I've simplified it down to a non-plsql example, because I dont think it is related to FOR loops etc.
SQL> DROP TABLE t1;
Table dropped.
SQL>
SQL> DROP SEQUENCE default_seq;
Sequence dropped.
SQL> CREATE SEQUENCE default_seq;
Sequence created.
SQL>
SQL> CREATE TABLE t1 (
2 col1 NUMBER DEFAULT ON NULL default_seq.NEXTVAL NOT NULL ENABLE,
3 description VARCHAR2(30)
4 );
Table created.
SQL>
SQL> INSERT INTO t1 (col1, description) VALUES (1000,'1000,DESCRIPTION');
1 row created.
SQL> INSERT INTO t1 (col1, description) VALUES (1001,'1001,DESCRIPTION');
1 row created.
SQL> INSERT INTO t1 (col1, description) VALUES (1002,'1002,DESCRIPTION');
1 row created.
SQL> INSERT INTO t1 (description) VALUES ('DESCRIPTION only');
1 row created.
SQL>
SQL> SELECT * FROM t1;
COL1 DESCRIPTION
---------- ------------------------------
1000 1000,DESCRIPTION
1001 1001,DESCRIPTION
1002 1002,DESCRIPTION
1 DESCRIPTION only
SQL>
SQL> DROP TABLE t1;
Table dropped.
SQL> DROP SEQUENCE default_seq;
Sequence dropped.
SQL> CREATE SEQUENCE default_seq;
Sequence created.
SQL>
SQL> CREATE TABLE t1 (
2 col1 NUMBER DEFAULT ON NULL default_seq.NEXTVAL NOT NULL ENABLE,
3 description VARCHAR2(30)
4 );
Table created.
SQL>
SQL> variable i number
SQL> exec :i := 0;
PL/SQL procedure successfully completed.
SQL>
SQL> INSERT INTO t1 (col1, description) VALUES (999 + :i,999 || ',DESCRIPTION');
1 row created.
SQL> INSERT INTO t1 (col1, description) VALUES (999 + :i,999 || ',DESCRIPTION');
1 row created.
SQL> INSERT INTO t1 (col1, description) VALUES (999 + :i,999 || ',DESCRIPTION');
1 row created.
SQL> INSERT INTO t1 (description) VALUES ('DESCRIPTION only');
1 row created.
SQL>
SQL> SELECT * FROM t1;
COL1 DESCRIPTION
---------- ------------------------------
999 999,DESCRIPTION
999 999,DESCRIPTION
999 999,DESCRIPTION
4 DESCRIPTION only
SQL>
SQL>
SQL>
SQL>
When you have an *expression* for the value to get into the column with the default sequence, we don't know *in advance* if that expression might evaluate to null. So we'll pick up a sequence value 'along the way' to use just in case it turns out to be null.
For example, if I repeat the exercise, but the column is DEFAULT not DEFAULT ON NULL, you can see we dont have to do that:
SQL> CREATE TABLE t1 (
2 col1 NUMBER DEFAULT default_seq.NEXTVAL,
3 description VARCHAR2(30)
4 );
Table created.
SQL>
SQL> variable i number
SQL> exec :i := 0;
PL/SQL procedure successfully completed.
SQL>
SQL> INSERT INTO t1 (col1, description) VALUES (999 + :i,999 || ',DESCRIPTION');
1 row created.
SQL> INSERT INTO t1 (col1, description) VALUES (999 + :i,999 || ',DESCRIPTION');
1 row created.
SQL> INSERT INTO t1 (col1, description) VALUES (999 + :i,999 || ',DESCRIPTION');
1 row created.
SQL> INSERT INTO t1 (description) VALUES ('DESCRIPTION only');
1 row created.
SQL>
SQL> SELECT * FROM t1;
COL1 DESCRIPTION
---------- ------------------------------
999 999,DESCRIPTION
999 999,DESCRIPTION
999 999,DESCRIPTION
1 DESCRIPTION only
Hope this helps.