SQL错误:ORA-00904:" CNPPARMID":无效的标识符

时间:2016-06-14 20:35:07

标签: oracle function stored-procedures plsql plsqldeveloper

我有一个功能:

在线执行立即'选择' || schemaname || '' || value1 || ' _seq.nextval来自双重'进入cnpParmId;

因错误而收到错误:ORA-00904:" CNPPARMID":无效的标识符。 我试图将cnpParmId放在引号内,从所有可能的方式尝试从双重cnpParmId。但它不起作用。 请给我一些解决这个问题的想法。 谢谢!

2 个答案:

答案 0 :(得分: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引用它抱怨那么它会导致编译错误 - 函数将被创建但有错误/警告,并且无法调用它。

所以它是第23行的第二个execute immediate,它在运行时出错(稍微重新格式化):

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

正如GolezTrol所说,动态语句是在一个没有任何PL / SQL变量可见性的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的插入循环。但是这种方法仍然存在竞争条件 - 另一个会话可以同时执行手动插入,并且函数找到相同的值,其中一个会话将出错。

使用序列通常会更好;如果您现在正在这样做,或者可以改变这样做,那么所有序列的一次性调整将高于当前最大键值将更简单。

答案 1 :(得分:1)

使用execute immediate,您可以在函数范围之外执行语句,因此它无法使用PLSQL变量。我通过将其作为普通查询执行并使用SELECT INTO或游标来获取查询结果来解决此问题。

但是如果您只是自己将值替换为查询字符串,它也应该可以工作,如下所示:

更改

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

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