Oracle11g ORA-00904-“;NORM";:无效标识符-动态sql中的字符串

Oracle11g ORA-00904-“;NORM";:无效标识符-动态sql中的字符串,oracle11g,Oracle11g,我试图执行下面的代码部分,但得到一个ORA-00904错误 Declare i_status varchar2(4) := 'NORM'; vsql varchar2(4000); ... ... Begin ... ...<Part of larger dynamic sql> If i_status is not null Then vSql := vSql || ' And account.astatus = ' ||i_status|| ''; End if;

我试图执行下面的代码部分,但得到一个ORA-00904错误

Declare
i_status varchar2(4) := 'NORM';
vsql varchar2(4000);
...
...
Begin
...
...<Part of larger dynamic sql>
  If i_status is not null Then
  vSql := vSql || ' And account.astatus = ' ||i_status|| '';
  End if;

execute immediate (vSql) into tmp,ssn;

<Do something with tmp, ssn>

End;
声明
i_status varchar2(4):=“正常”;
vsql varchar2(4000);
...
...
开始
...
...
如果i_状态不为空,则
vSql:=vSql | |和account.astatus='| | | i| |';
如果结束;
在tmp、ssn中执行immediate(vSql);
终止
在“立即执行”行引发异常,错误为 ORA-00904-“标准”:无效标识符

列account.astatus的类型为char(4字节)

我假设问题是我试图在where子句中传递字符串变量NORM,而不添加引号“”。你如何回避这个问题


谢谢

简单的答案是使用绑定变量,这意味着您可以避免将变量硬编码到动态sql中时遇到的整个棘手的sql注入问题。您还省去了必须解决如何在动态sql当前缺少的字符串周围包含单引号的麻烦

使用绑定变量,代码将变为:

Declare
  i_status varchar2(4) := 'NORM';
  vsql varchar2(4000);
  ...
  ...
Begin
  ...
  ...<Part of larger dynamic sql>

  If i_status is not null Then
    vSql := vSql || ' And account.astatus = :i_status';
  End if;

  execute immediate (vSql) into tmp,ssn using i_status;

  <Do something with tmp, ssn>

End;
声明
i_status varchar2(4):=“正常”;
vsql varchar2(4000);
...
...
开始
...
...
如果i_状态不为空,则
vSql:=vSql | |'和account.astatus=:i_status';
如果结束;
使用i_状态将立即(vSql)执行到tmp、ssn中;
终止

通过在执行VSQL之前打印VSQL,您可以轻松地深入了解代码并检查问题所在

 Declare
    i_status varchar2(10) := 'NORM';
    vsql varchar2(4000):= 'Select * from dual where 1=3';

    Begin

      If i_status is not null Then
      vSql := vSql || ' And account.astatus = ' ||i_status|| '';
      End if;

      dbms_output.put_line(vSql);

      --execute immediate (vSql) into tmp,ssn;        

    End;
运行此块时,可以看到生成的语句,其中显示:

从dual中选择*,其中1=3,account.astatus=NORM

现在您可以很容易地注意到您的
account.astatus=NORM
不正确,因此您可以将其替换为:

i_status varchar2(10) := '''NORM''';
或使用q引号:

i_status varchar2(10) := q'['NORM']';

不过,Boneist提到的是避免sql注入的最佳实践。

谢谢。工作得很有魅力。