【问题标题】:Oracle nvl2 not working in stored procedure PLS-00201: identifier 'NVL2' must be declaredOracle nvl2 在存储过程 PLS-00201 中不起作用:必须声明标识符“NVL2”
【发布时间】:2019-11-29 23:40:34
【问题描述】:

作为标题,我在Oracle上写了一些存储过程,首先我检查了版本

SELECT * FROM v$version;

结果

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE    11.2.0.4.0  Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

...

并且,用常规 SQL 查询尝试了 NVL2

select 'Test: ' || nvl2('...', 'things', 'nothing') from dual;
select 'Test: ' || nvl2('', 'things', 'nothing') from dual;

结果似乎是正确的

Test: things
Test: nothing

...

所以我确认 11g 确实支持 NLV2 功能,我现在可以开始编写我的存储过程,如下所示:

create or replace procedure my_schema.SP_READ_MEMBER(noP in varchar2, nameP in varchar2, idNoP in varchar2, birthdayP in varchar2, resultP out sys_refcursor)
is
v_prg_name varchar2(20) := 'SP_READ_MEMBER';
sys_sql    varchar2(1000);

begin
  Insertlog(SYSDATE, v_prg_name, '1.0 Start');
  sys_sql :=  sys_sql || 'select a.no, a.name, a.id_no, to_char(a.birthday, ''yyyy/MM/dd'') as birthday, ''REGISTERED'' as type, email, mobile from rep where 1=1 ';
  sys_sql :=  sys_sql || nvl2(noP,'and no='''|| noP ||'''', ''); --PLS-00201

  open resultP for sys_sql;
  Insertlog(SYSDATE, v_prg_name, '2.0 Finished w/o error');

  exception
  when others then
    declare
      error_time VARCHAR2(30) := RTRIM(TO_CHAR(SYSDATE, 'YYYY/MM/DD, HH24:MI:SS'));
      error_code NUMBER := SQLCODE;
      error_msg  VARCHAR2(300) := SQLERRM;
    begin
      rollback;
      DBMS_OUTPUT.PUT_LINE(error_time || ',' || TO_CHAR(error_code) || ',' || error_msg);
      Insertlog(SYSDATE, v_prg_name,  error_msg || ', 3.0 ERROR, sql:' || sys_sql);
    end;
end;
/

Oracle 告诉我它编译时出错,这是

PLS-00201:必须声明标识符“NVL2”

为什么函数在常规查询中工作,但在存储过程中未声明?

【问题讨论】:

  • 你有一个有趣的用例。我很确定nvl2 没有被映射为 PL/SQL 函数。试试coalesce。还没有看过 MOS,但我认为缺少该映射是一个错误。但如果它不会被修复,那可能是因为coalesce 是一个比nvl2 更好的名字。
  • NVL2 在 12.2.0.1 中也不起作用(因此您会知道数据库升级不会解决该问题)。
  • PL/SQL 并不支持所有的 SQL 函数。 decode 是另一个。

标签: oracle stored-procedures nvl pls-00201


【解决方案1】:

NVL2 适用于 SQL,但不适用于 PL/SQL。

变化:

sys_sql :=  sys_sql || nvl2(noP,'and no='''|| noP ||'''', '');

收件人:

select sys_sql || nvl2(noP,'and no='''|| noP ||'''', '') into sys_sql from dual;

【讨论】:

    【解决方案2】:

    NVL2 适用于 SQL 但不适用于 PL/SQL。

    并非每个 SQL 关键字都适用于 PL/SQL,这很愚蠢,但以前发生过几次。 Oracle 一直在逐步统一 SQL 和 PL/SQL,他们最终很有可能会实现这个功能。目前,我认为 My Oracle Support 文档Note 359506.1 Pls-00201 Assigning The Result of NVL2() To A Variable In a PLSQL Block 涵盖了这个问题。尽管该文档不可用,即使对于具有支持访问权限的人也是如此。

    目前,我建议使用不同的语法。就个人而言,我发现CASE 版本更清晰,即使它有点冗长。

    变化:

    sys_sql :=  sys_sql || nvl2(noP,'and no='''|| noP ||'''', '');
    

    收件人:

    sys_sql :=  sys_sql || case when nop is not null then 'and no='''|| noP ||'''' else '' end;
    

    【讨论】:

    • 原来是Oracle 11g 的PL/SQL 支持限制……终于明白了。还有解决方案有帮助的情况,谢谢~
    猜你喜欢
    • 1970-01-01
    • 2014-12-09
    • 2014-06-24
    • 1970-01-01
    • 1970-01-01
    • 2019-12-17
    • 2021-12-22
    • 2016-07-25
    • 2018-08-02
    相关资源
    最近更新 更多