首页 > 解决方案 > Oracle PL/SQL ORA-00904:标识符无效

问题描述

我正在尝试声明一个字符串并在 select 语句中使用它,但它抛出 ORA-00904: invalid identifier。

DECLARE
    var_laufi VARCHAR2(20) := 'JEIV';
BEGIN
    EXECUTE IMMEDIATE q'[
    WITH aux AS (
        SELECT DISTINCT
            zbuag_id AS ca_dat
        FROM
            vw_penddv2
        WHERE
            category = 'Issue'
    ), aux2 AS (
        SELECT DISTINCT
            vkont AS ca_lock
        FROM
            cdc.uap_dfkklocks@rbip
        WHERE
            laufi = ]'
                      || var_laufi
                      || q'[
            AND tdate >= to_char(sysdate, 'YYYYMMDD')
    )
    SELECT
        *
    FROM
        aux    a
        FULL OUTER JOIN aux2   b ON b.ca_lock = a.ca_dat
    WHERE
        ( a.ca_dat IS NULL
          OR b.ca_lock IS NULL )
    ]'
                      ;
END;

但是,如果我只是尝试显示变量本身,它就可以正常工作。

SET SERVEROUTPUT ON;

DECLARE
    var_laufi VARCHAR2(20) := 'JEIV';
BEGIN
    dbms_output.put_line(var_laufi);
END;

结果:

JEIV


PL/SQL procedure successfully completed.

我在这里遗漏了一些东西,但我无法弄清楚它是什么。

标签: sqloracleplsql

解决方案


如果您滥用动态 SQL,它是邪恶的。经验法则:如果你没有检查你正在执行的内容,就永远不要执行它!如何?显示语句。就是这样:

DECLARE
   var_laufi  VARCHAR2 (20) := 'JEIV';
   var_str    VARCHAR2 (2000);
BEGIN
   var_str := q'[
    WITH aux AS (
        SELECT DISTINCT
            zbuag_id AS ca_dat
        FROM
            vw_penddv2
        WHERE
            category = 'Issue'
    ), aux2 AS (
        SELECT DISTINCT
            vkont AS ca_lock
        FROM
            cdc.uap_dfkklocks@rbip
        WHERE
            laufi = ]' || var_laufi || q'[
            AND tdate >= to_char(sysdate, 'YYYYMMDD')
    )
    SELECT
        *
    FROM
        aux    a
        FULL OUTER JOIN aux2   b ON b.ca_lock = a.ca_dat
    WHERE
        ( a.ca_dat IS NULL
          OR b.ca_lock IS NULL )
    ]';

   DBMS_OUTPUT.put_line (var_str);
END;
/

结果(格式化):

WITH
   aux
   AS
      (SELECT DISTINCT zbuag_id AS ca_dat
         FROM vw_penddv2
        WHERE category = 'Issue'),
   aux2
   AS
      (SELECT DISTINCT vkont AS ca_lock
         FROM cdc.uap_dfkklocks@rbip
        WHERE     laufi = JEIV                                  --> here
              AND tdate >= TO_CHAR (SYSDATE, 'YYYYMMDD'))
SELECT *
  FROM aux a FULL OUTER JOIN aux2 b ON b.ca_lock = a.ca_dat
 WHERE (   a.ca_dat IS NULL
        OR b.ca_lock IS NULL)

看到评论了吗?where laufi = JEIV无效,应该用单引号括起来。

还有,tdate真的是字符串吗?您将其与sysdate以指定格式表示的字符串进行比较。DATE如果是这样,将数据类型值存储为字符串的想法很糟糕。


推荐阅读