SQL Error: ORA-00904: "CNPPARMID": invalid identifier
SQL Error: ORA-00904: "CNPPARMID": invalid identifier
我有一个功能:
在行立即执行'select ' ||模式名|| '.' ||价值1 || '_seq.nextval from dual' into cnpParmId;
出现错误 SQL 错误:ORA-00904:"CNPPARMID":标识符无效。
我试图将 cnpParmId 放在引号内,并尝试以所有可能的方式从 dual 进入 cnpParmId。但它不起作用。
请给我一些解决这个问题的想法。
谢谢!!
使用execute immediate
,你在函数范围之外执行语句,所以它不能使用PLSQL变量。我会通过将其作为普通查询执行并使用 SELECT INTO
或游标来获取查询结果来解决此问题。
但如果您自己简单地将值替换为查询字符串,它也应该有效,如下所示:
改变
'select ''T'' from dual where cnpParmId not in ' ||
进入
'select ''T'' from dual where ' || cnpParmId || ' not in ' ||
您的函数编译成功,但在运行时出现错误:
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
引用它抱怨的那么它会导致编译错误- 将创建该函数,但使用 errors/warnings,并且无法调用它。
所以是第 23 行的第二个 execute immediate
,它在运行时出错(稍微重新格式化):
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
的查询移到循环外;重复调用它没有任何好处。
您这样做似乎是因为您的主键值不是从序列中生成的。如果您仍在像那样添加新记录 - 例如通过仅在传递的键列为空时才使用序列的触发器 - 那么您需要像这样的 hack 或捕获 ORA-01001 的插入循环。但是这种方法仍然存在竞争条件 - 另一个会话可以同时使用您的函数找到的相同值进行手动插入,并且其中一个会话会出错。
通常只使用序列会更好;如果您现在正在这样做,或者可以更改为这样做,那么将所有序列一次性调整为高于当前最大键值会更简单。
我有一个功能:
在行立即执行'select ' ||模式名|| '.' ||价值1 || '_seq.nextval from dual' into cnpParmId;
出现错误 SQL 错误:ORA-00904:"CNPPARMID":标识符无效。 我试图将 cnpParmId 放在引号内,并尝试以所有可能的方式从 dual 进入 cnpParmId。但它不起作用。 请给我一些解决这个问题的想法。 谢谢!!
使用execute immediate
,你在函数范围之外执行语句,所以它不能使用PLSQL变量。我会通过将其作为普通查询执行并使用 SELECT INTO
或游标来获取查询结果来解决此问题。
但如果您自己简单地将值替换为查询字符串,它也应该有效,如下所示:
改变
'select ''T'' from dual where cnpParmId not in ' ||
进入
'select ''T'' from dual where ' || cnpParmId || ' not in ' ||
您的函数编译成功,但在运行时出现错误:
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
引用它抱怨的那么它会导致编译错误- 将创建该函数,但使用 errors/warnings,并且无法调用它。
所以是第 23 行的第二个 execute immediate
,它在运行时出错(稍微重新格式化):
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
的查询移到循环外;重复调用它没有任何好处。
您这样做似乎是因为您的主键值不是从序列中生成的。如果您仍在像那样添加新记录 - 例如通过仅在传递的键列为空时才使用序列的触发器 - 那么您需要像这样的 hack 或捕获 ORA-01001 的插入循环。但是这种方法仍然存在竞争条件 - 另一个会话可以同时使用您的函数找到的相同值进行手动插入,并且其中一个会话会出错。
通常只使用序列会更好;如果您现在正在这样做,或者可以更改为这样做,那么将所有序列一次性调整为高于当前最大键值会更简单。