2013-03-14 63 views
4

在常规的SQL,我的顺序递增每次我打电话.NEXTVAL时间:序列不增加,除非我保存价值

SELECT PDF_DATOS_TITULO_ID_SEQ.CURRVAL FROM DUAL; -- 54 
SELECT PDF_DATOS_TITULO_ID_SEQ.NEXTVAL FROM DUAL; -- 55 
SELECT PDF_DATOS_TITULO_ID_SEQ.NEXTVAL FROM DUAL; -- 56 
SELECT PDF_DATOS_TITULO_ID_SEQ.NEXTVAL FROM DUAL; -- 57 
SELECT PDF_DATOS_TITULO_ID_SEQ.CURRVAL FROM DUAL; -- 57 (54+3, correct) 

然而,在PL/SQL块内的动态SQL不会增加:

SELECT PDF_DATOS_TITULO_ID_SEQ.CURRVAL FROM DUAL; -- 57 
BEGIN 
    EXECUTE IMMEDIATE 'SELECT PDF_DATOS_TITULO_ID_SEQ.NEXTVAL FROM DUAL'; 
    EXECUTE IMMEDIATE 'SELECT PDF_DATOS_TITULO_ID_SEQ.NEXTVAL FROM DUAL'; 
    EXECUTE IMMEDIATE 'SELECT PDF_DATOS_TITULO_ID_SEQ.NEXTVAL FROM DUAL'; 
END; 
/
SELECT PDF_DATOS_TITULO_ID_SEQ.CURRVAL FROM DUAL; -- 57 

......除非我的值存储到一个变量:

SELECT PDF_DATOS_TITULO_ID_SEQ.CURRVAL FROM DUAL; -- 57 (!) 
DECLARE 
    FOO INTEGER; 
BEGIN 
    EXECUTE IMMEDIATE 'SELECT PDF_DATOS_TITULO_ID_SEQ.NEXTVAL FROM DUAL' INTO FOO; 
    EXECUTE IMMEDIATE 'SELECT PDF_DATOS_TITULO_ID_SEQ.NEXTVAL FROM DUAL' INTO FOO; 
    EXECUTE IMMEDIATE 'SELECT PDF_DATOS_TITULO_ID_SEQ.NEXTVAL FROM DUAL' INTO FOO; 
END; 
/
SELECT PDF_DATOS_TITULO_ID_SEQ.CURRVAL FROM DUAL; -- 60 (57+3, correct) 

有什么解释?这是否是EXECUTE IMMEDIATE的记录行为?

在问你之前,SQL需要是动态的,因为序列名是可变的。

+2

我想知道没有'INTO'的'EXECUTE IMMEDIATE'没有获取结果集,所以'SEQ.NEXTVAL'永远不会被增加。 – NPE 2013-03-14 11:15:36

回答

9

当你省略或批量返回到子句时,Oracle只会解析sql,但不会从它发出任何提取。在文档中没有明确说明会发生这种情况,但文档确实指出,如果有一行返回,并且有一行可以返回时,应该使用INTO。

如:

SQL> create sequence testseq; 

Sequence created. 

SQL> alter session set events '10046 trace name context forever'; 

Session altered. 

SQL> exec execute immediate 'select testseq.nextval from dual'; 

PL/SQL procedure successfully completed. 

SQL> alter session set events '10046 trace name context off'; 

Session altered. 

SQL> exit 

我们在跟踪中看到,甲骨文没有与读取级打扰:

===================== 
PARSING IN CURSOR #140341213531640 len=32 dep=1 uid=83 oct=3 lid=83 tim=1363260261727946 hv=956010684 ad='7ac66b58' sqlid='56jwk2hwgr45w' 
select testseq.nextval from dual 
END OF STMT 
PARSE #140341213531640:c=4001,e=50473,p=0,cr=2,cu=0,mis=1,r=0,dep=1,og=1,plh=112670795,tim=1363260261727944 
EXEC#140341213531640:c=0,e=219,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=1,plh=112670795,tim=1363260261728249 
STAT #140341213531640 id=1 cnt=0 pid=0 pos=1 obj=79530 op='SEQUENCE TESTSEQ (cr=0 pr=0 pw=0 time=181 us)' 
STAT #140341213531640 id=2 cnt=0 pid=1 pos=1 obj=0 op='FAST DUAL (cr=0 pr=0 pw=0 time=1 us cost=2 size=0 card=1)' 
CLOSE #140341213531640:c=4001,e=24391,dep=1,type=3,tim=1363260261752736 
EXEC#140341212444728:c=8002,e=75407,p=0,cr=2,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1363260261752783 

*** 2013-03-14 11:24:29.866 
CLOSE #140341212444728:c=0,e=37,dep=0,type=0,tim=1363260269866098 
===================== 

VS:

SQL> alter session set events '10046 trace name context forever'; 

Session altered. 

SQL> var a number 
SQL> exec execute immediate 'select testseq.nextval from dual' into :a; 

PL/SQL procedure successfully completed. 

SQL> alter session set events '10046 trace name context off'; 

Session altered. 

现在:

PARSING IN CURSOR #139830768042232 len=32 dep=1 uid=83 oct=3 lid=83 tim=1363260428931803 hv=956010684 ad='7ac66b58' sqlid='56jwk2hwgr45w' 
select testseq.nextval from dual 
END OF STMT 
PARSE #139830768042232:c=0,e=38,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=1,plh=112670795,tim=1363260428931802 
EXEC#139830768042232:c=0,e=86,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=1,plh=112670795,tim=1363260428931917 
FETCH #139830768042232:c=0,e=22,p=0,cr=0,cu=0,mis=0,r=1,dep=1,og=1,plh=112670795,tim=1363260428931980 
STAT #139830768042232 id=1 cnt=1 pid=0 pos=1 obj=79530 op='SEQUENCE TESTSEQ (cr=0 pr=0 pw=0 time=39 us)' 
STAT #139830768042232 id=2 cnt=1 pid=1 pos=1 obj=0 op='FAST DUAL (cr=0 pr=0 pw=0 time=2 us cost=2 size=0 card=1)' 
CLOSE #139830768042232:c=0,e=0,dep=1,type=3,tim=1363260428931980 
EXEC#139830768045912:c=0,e=294,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1363260428931980 

*** 2013-03-14 11:27:13.138 
CLOSE #139830768045912:c=0,e=45,dep=0,type=0,tim=1363260433138490 
===================== 

FETCH被看到。我认为理想情况下,Oracle应该在用户发出没有定义INTO/BULK INTO的选择的情况下抛出一个错误。

+0

很棒的回答。避免浪费资源来获取你要丢弃的东西可能是有道理的,但我已经遇到了一个边缘案例。 *(现在我想知道在涉及函数或过程调用时会发生什么情况,但如果我想自己测试,此答案包含足够的信息。)* – 2013-03-14 11:36:56