为什么手动 运行 SQL 阻止工作但在同一字符串上使用 EXECUTE IMMEDIATE 却不起作用?

Why does manually running SQL block work but using EXECUTE IMMEDIATE on the same string doesn't?

以下过程失败并出现 "ORA-0097: missing equal sign error"。

CREATE PROCEDURE AMEPSA.USP_ETL_BATCH_MASTER_UPDATE
    (ENVIRONMENT in VARCHAR2, BATCH_STATUS in VARCHAR2, BATCH_USER_ID VARCHAR2, BATCH_JOB_NAME VARCHAR2)

AS

BEGIN
    IF (BATCH_STATUS = 'Running') THEN
        EXECUTE IMMEDIATE  'UPDATE AMEPSA.ETL_BATCH_MASTER SET
                            BATCH_STATUS_' || ENVIRONMENT || ' = ' || '''' || BATCH_STATUS || '''' || ',
                            BATCH_JOB_NAME_' || ENVIRONMENT || ' = ' || '''' || BATCH_JOB_NAME || '''' || ',' ||
                            'BATCH_USER_ID_' || ENVIRONMENT || ' = ' || '''' || BATCH_USER_ID || '''' || ',' ||
                            'BATCH_START_DATE_' || ENVIRONMENT || ' = TO_DATE(' || '''' || TO_CHAR(SYSDATE, 'MM/DD/YYYY HH24:MI:SS') || '''' || ', ' || '''' || 'MM/DD/YYYY HH24:MI:SS' || '''' || ') ' || ',' ||
                            'BATCH_END_DATE_' || ENVIRONMENT || ' = ' || 'NULL' || '
                            WHERE BATCH_NBR = (SELECT MAX(BATCH_NBR) FROM AMEPSA.ETL_BATCH_MASTER)';
    ELSE
        EXECUTE IMMEDIATE   'UPDATE AMEPSA.ETL_BATCH_MASTER SET
                            BATCH_STATUS_' || ENVIRONMENT || ' = ' || '''' || BATCH_STATUS || '''' || ',
                            BATCH_JOB_NAME_' || ENVIRONMENT || ' = ' || '''' || BATCH_JOB_NAME || '''' || ',' ||
                            'BATCH_END_DATE_' || ENVIRONMENT || ' = ' || 'TO_DATE(' || '''' || TO_CHAR(SYSDATE, 'MM/DD/YYYY HH24:MI:SS') || '''' || ', ' || '''' || 'MM/DD/YYYY HH24:MI:SS' || '''' || ')
                            WHERE BATCH_NBR = (SELECT MAX(BATCH_NBR) FROM AMEPSA.ETL_BATCH_MASTER)';
    END IF;

    COMMIT;

END;
GO

在调试问题时,我们用 DBMS_OUTPUT.PUT_LINE 语句替换了 EXECUTE IMMEDIATE 语句。这样做之后,该过程返回了一个字符串(如下),该字符串成功执行且没有语法错误。

UPDATE AMEPSA.ETL_BATCH_MASTER 

SET BATCH_STATUS_STAGE = 'Running',
    BATCH_JOB_NAME_STAGE = 'wf_TADM_Stage',
    BATCH_END_DATE_STAGE = TO_DATE('08/14/2017 15:42:00', 'MM/DD/YYYY HH24:MI:SS')
WHERE BATCH_NBR = (SELECT MAX(BATCH_NBR) FROM AMEPSA.ETL_BATCH_MASTER)

当从 DBMS_OUTPUT.PUT_LINE 语句返回的结果字符串在语法上正确时,为什么 EXECUTE IMMEDIATE 语句会认为它缺少等号?

来自 Informatica 的完全异常:

Severity: ERROR Timestamp: 8/15/2017 9:46:10 AM Node: didre2007 Thread: TRANSF_1_1_1 Process ID: 9072 Message Code: CMN_1022 Message: Database driver error... CMN_1022 [ ORA-00927: missing equal sign ORA-06512: at "AMEPSA.USP_ETL_BATCH_MASTER_UPDATE", line 14 ORA-06512: at line 2

Database driver error... Function Name : ExecuteSP

Oracle Fatal Error Database driver error... Function Name : ExecuteSP

Oracle Fatal Error]

看起来传递给过程的参数值有单引号;特别是第一个,但可能是所有的。可以直接调用复制:

exec USP_ETL_BATCH_MASTER_UPDATE('''STAGE''', '''Running''', '''someuser''', '''wf_TADM_Stage''');

得到

Error report -
ORA-00927: missing equal sign
ORA-06512: at "AMEPSA.USP_ETL_BATCH_MASTER_UPDATE", line 14
ORA-06512: at line 1
00927. 00000 -  "missing equal sign"

或者只是

exec USP_ETL_BATCH_MASTER_UPDATE('''STAGE''', 'Running', 'someuser', 'wf_TADM_Stage');

进入另一个分支并得到:

Error report -
ORA-00927: missing equal sign
ORA-06512: at "AMEPSA.USP_ETL_BATCH_MASTER_UPDATE", line 6
ORA-06512: at line 1
00927. 00000 -  "missing equal sign"

通过调试显示代码在执行之前,您可以看到它最终尝试 运行 这个:

UPDATE AMEPSA.ETL_BATCH_MASTER SET
                                        BATCH_STATUS_'STAGE' = 'Running',
                                        BATCH_JOB_NAME_'STAGE' = 'wf_TADM_Stage',BATCH_USER_ID_'STAGE' = 'someuser',BATCH_START_DATE_'STAGE' = TO_DATE('08/15/2017 19:37:00', 'MM/DD/YYYY HH24:MI:SS') ,BATCH_END_DATE_'STAGE' = NULL
                                   WHERE BATCH_NBR = (SELECT MAX(BATCH_NBR) FROM AMEPSA.ETL_BATCH_MASTER)

引用不当; BATCH_STATUS_'STAGE' 构造抛出异常。

如果在没有那些额外的单引号的情况下调用,您所展示的内容在任一分支中都有效。

因此,您需要调查为什么 Informatica 添加这些单引号——可能只是开发人员对如何将字符串作为参数处理感到困惑——并停止这样做。问题不在您显示的代码中,并且在没有看到 Informatica 代码的情况下,我无法更具体地说明应该如何修复它。


顺便说一句,在评论中提到您可以通过 using 子句使用绑定变量,而不是将 sysdate 转换为字符串并返回;这与您收到的错误无关,但可能看起来像:

CREATE PROCEDURE AMEPSA.USP_ETL_BATCH_MASTER_UPDATE
  (ENVIRONMENT in VARCHAR2, BATCH_STATUS in VARCHAR2, BATCH_USER_ID VARCHAR2, BATCH_JOB_NAME VARCHAR2)
AS
BEGIN
    IF (BATCH_STATUS = 'Running') THEN
        EXECUTE IMMEDIATE  'UPDATE AMEPSA.ETL_BATCH_MASTER SET'
                || ' BATCH_STATUS_' || ENVIRONMENT || ' = :BATCH_STATUS,'
                || ' BATCH_JOB_NAME_' || ENVIRONMENT || ' = :BATCH_JOB_NAME,'
                || ' BATCH_USER_ID_' || ENVIRONMENT || ' = :BATCH_USER_ID,'
                || ' BATCH_START_DATE_' || ENVIRONMENT || ' = SYSDATE,'
                || ' BATCH_END_DATE_' || ENVIRONMENT || ' = NULL'
                || ' WHERE BATCH_NBR = (SELECT MAX(BATCH_NBR) FROM AMEPSA.ETL_BATCH_MASTER)'
            USING BATCH_STATUS, BATCH_JOB_NAME, BATCH_USER_ID;
    ELSE
        EXECUTE IMMEDIATE  'UPDATE AMEPSA.ETL_BATCH_MASTER SET'
                || ' BATCH_STATUS_' || ENVIRONMENT || ' = :BATCH_STATUS,'
                || ' BATCH_JOB_NAME_' || ENVIRONMENT || ' = :BATCH_JOB_NAME,'
                || ' BATCH_END_DATE_' || ENVIRONMENT || ' = SYSDATE'
                || ' WHERE BATCH_NBR = (SELECT MAX(BATCH_NBR) FROM AMEPSA.ETL_BATCH_MASTER)'
            USING BATCH_STATUS, BATCH_JOB_NAME;
    END IF;

END;