2016-06-14 85 views
1

我有一個功能:SQL錯誤:ORA-00904:「CNPPARMID」:無效的標識符

在行立即執行'select'|| schemaname || '' || value1 || '_seq.nextval from dual'into cnpParmId;

我的錯誤是SQL錯誤:ORA-00904:「CNPPARMID」:無效的標識符。 我試圖把cnpParmId放在引號內,以各種可能的方式嘗試從雙重引用到cnpParmId。但它不工作。 請給我一些想法來解決這個問題。 謝謝!

+1

由於答案是間接指出的,你很可能在第二個'execute immediate'語句中出錯,而不是第一個。 – sstan

回答

2

你的函數編譯成功,和你在運行時得到錯誤:

select test(user, 'T42') from dual; 

SQL Error: ORA-00904: "CNPPARMID": invalid identifier 
ORA-06512: at "MYSCHEMA.TEST", line 23 

你說錯誤是在第一個execute immediate,但這是第21行而不是第23行,如果它是cnpParmId引用它抱怨然後它會導致編譯錯誤 - 函數將創建,但錯誤/警告,而且不可能稱之爲警告。

所以這是第二個execute immediate,在第23行,它在運行時示數(略格式化):

execute immediate 
    'select ''T'' from dual where cnpParmId not in ' || 
    '(select value1 from ' || schemaname || '.' || tablename || ')' 
    into good; 

正如GolezTrol說,動態語句是在沒有任何可見性的SQL上下文中執行你的PL/SQL變量。這是與運行生成的語句:

select 'T' from dual where cnpParmId not in (select value1 from myschema.t42); 

...直接在SQL * Plus或SQL Developer中,這也得到:

SQL Error: ORA-00904: "CNPPARMID": invalid identifier 
00904. 00000 - "%s: invalid identifier" 

由於GolezTrol的級聯的變化,你可以使用綁定變量以防止每次循環的硬解析,但是您還需要提供主鍵列名作爲value1也不會被識別;並且必須連接在:

execute immediate 
    'select ''T'' from dual where :cnpParmId not in ' || 
    '(select ' || value1 || ' from ' || schemaname || '.' || tablename || ')' 
    into good using cnpParmId; 

編譯和運行。

你也可以使用not exists而非not in,因爲你正在尋找的(索引)主鍵可能有更好的表現:

execute immediate 
    'select ''T'' from dual where not exists (select null from ' 
    || schemaname || '.' || tablename || ' where ' || value1 || ' = :cnpParmId)' 
    into good using cnpParmId; 

您也可以移動發現value1外循環查詢;重複地調用它沒有任何好處。


它看起來像你這樣做,因爲你有主鍵值不是從序列中產生的。如果您仍然添加新的記錄 - 例如通過一個只使用序列的觸發器,如果​​傳遞的鍵列爲空 - 那麼你需要一個像這樣的黑客攻擊或一個可以捕獲ORA-01001的插入循環。但是這種方法仍然存在競爭條件 - 另一個會話可以同時執行手動插入,而您的函數找到的值相同,並且其中一個會話將出現錯誤。

它通常會更好只有使用序列;如果你現在正在這樣做,或者可以改變這樣做,那麼一次性調整所有序列使其高於當前最大鍵值將會更簡單。

+0

它工作。謝謝!! :) – bin

1

使用execute immediate,您執行該函數範圍之外的語句,因此它不能使用PLSQL變量。我可以通過將其作爲普通查詢執行來解決此問題,並使用SELECT INTO或遊標來獲取查詢結果。

但同時也應該工作,如果你只是自己替換值到查詢字符串,像這樣:

變化

'select ''T'' from dual where cnpParmId not in ' || 

'select ''T'' from dual where ' || cnpParmId || ' not in ' ||