【问题标题】:Oracle PL/SQL ORA-00904: invalid identifierOracle PL/SQL ORA-00904:标识符无效
【发布时间】:2021-03-17 10:34:38
【问题描述】:

我正在尝试声明一个字符串并在 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.

我在这里遗漏了一些东西,但我不知道是什么。

【问题讨论】:

    标签: sql oracle plsql


    【解决方案1】:

    如果您滥用动态 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 数据类型值存储为字符串是一个糟糕的想法。

    【讨论】:

    • 我这样做是为了绕过引号问题。还有更优雅的方法吗?:WHERE laufi = ]' || '''|| var_laufi ||''' || q'[ AND tdate >= to_char(sysdate, 'YYYYMMDD')
    • 是的,关于日期。我们已经多次向 DBA 强调这一点,但他们并不热衷于改变设计:(
    • 单引号...有时我会连接chr(39),因为它清楚地表明了我的意图。没错,打字多一点,但可以防止错误。截至日期:哦,好吧。祝你有这样的同事好运。
    • 动态 SQL 不是“邪恶的”。它只是被不怀好意的人滥用;)
    猜你喜欢
    • 1970-01-01
    • 2014-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多