Oracle SQL 存储过程缺少表达式错误

Posted

技术标签:

【中文标题】Oracle SQL 存储过程缺少表达式错误【英文标题】:Oracle SQL Stored Procedure missing expression error 【发布时间】:2018-08-16 13:56:53 【问题描述】:

我正在编写一个存储过程,它是从一个中间表写入另一个表的动态后续语句。我特别擅长编写 sql 和存储过程。我尝试在我的语句中添加参数,但一直收到此错误: ORA-00936: 缺少表达式 ORA-06512:在“ECH_ETL_BATCH_ID.LOOKUP_TABLE_INSERT”,第 26 行 ORA-06512: 在第 14 行 进程退出。 我取出参数并在值中硬编码只是试图让它工作,但我仍然收到相同的错误。 有什么建议吗?

create or replace PROCEDURE                                                     
LOOKUP_TABLE_INSERT 
(
P_SOURCE_DB IN VARCHAR2
, P_SOURCE_TABLE IN VARCHAR2
, P_TARGET_DB IN VARCHAR2
, P_TARGET_TABLE IN VARCHAR2
, P_COLUMN_NAME IN VARCHAR2
) AS 
l_sql_statement VARCHAR2(1000);
BEGIN


l_sql_statement :=
'INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP' || 
'(PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE, SRC_ROWID, 
HUB_STATE_IND, ROLE_TP) ' || 
' SELECT MISSING_VALUES AS PKEY_SRC_OBJECT' ||
', 1 as VERSION_SEQ' ||
', 0 as TIMELINE_ACTION' ||
', INSERT_TS as LAST_UPDATE_DATE' ||
', MISSING_VALUES as "SRC_ROWID"' || 
', 1 as "HUB_STATE_IND"' ||
', MISSING_VALUES as ROLE_TP' || --P_COLUMN_NAME ||              
' FROM ECH_ETL_BATCH_ID.Ref_Intermediate ' || 
WHERE COLUMN_NM =' || ''||ROLE_TP||'' ||
'AND LOOKUP_TBL_NM =' || ''||C_S_LU_PTY_ROLE_TP||'';
dbms_output.put_line(l_sql_statement);
EXECUTE IMMEDIATE l_sql_statement;
COMMIT;
END;

EXECUTE IMMEDIATE l_sql_statement;
COMMIT;
END;

【问题讨论】:

您是否尝试打印出生成的语句并运行它,或者只是仔细查看它?查看', SELECT MISSING_VALUES as "SRC_ROWID"' || --FROM 行和以下行 - SELECT 不应该在那里,它看起来像一个格式错误的子查询,虽然你甚至不会编译得到你描述的错误。 这里是括号P_TARGET_TABLE.P_TARGET_TABLE) AS "SRC_ROWID" .. 它有什么需要?和from为什么被评论了 很抱歉,*** 上代码的显示方式将我的评论放到了下一行。我想我编辑并修复了您所看到的内容。 【参考方案1】:

您的问题在于 where 条件。删除||

如果您执行dbms_output.putline();,您将获得声明

要添加单引号,请检查以下解决方案

错误原因:

INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP
  (PKEY_SRC_OBJECT,
   VERSION_SEQ,
   TIMELINE_ACTION,
   LAST_UPDATE_DATE,
   SRC_ROWID,
   HUB_STATE_IND,
   ROLE_TP)
  SELECT MISSING_VALUES AS PKEY_SRC_OBJECT,
         1              as VERSION_SEQ,
         0              as TIMELINE_ACTION,
         INSERT_TS      as LAST_UPDATE_DATE,
         MISSING_VALUES as "SRC_ROWID",
         1              as "HUB_STATE_IND",
         MISSING_VALUES as ROLE_TP
    FROM ECH_ETL_BATCH_ID.Ref_Intermediate
   WHERE COLUMN_NM = || ROLE_TP ||
     AND LOOKUP_TBL_NM = || C_S_LU_PTY_ROLE_TP ||

解决办法:

create or replace PROCEDURE                                                     
LOOKUP_TABLE_INSERT 
(
P_SOURCE_DB IN VARCHAR2
, P_SOURCE_TABLE IN VARCHAR2
, P_TARGET_DB IN VARCHAR2
, P_TARGET_TABLE IN VARCHAR2
, P_COLUMN_NAME IN VARCHAR2
) AS 
l_sql_statement VARCHAR2(1000);
BEGIN


l_sql_statement :=
'INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP' || 
'(PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE, SRC_ROWID, 
HUB_STATE_IND, ROLE_TP) ' || 
' SELECT MISSING_VALUES AS PKEY_SRC_OBJECT' ||
', 1 as VERSION_SEQ' ||
', 0 as TIMELINE_ACTION' ||
', INSERT_TS as LAST_UPDATE_DATE' ||
', MISSING_VALUES as "SRC_ROWID"' || 
', 1 as "HUB_STATE_IND"' ||
', MISSING_VALUES as ROLE_TP' || --P_COLUMN_NAME ||              
' FROM ECH_ETL_BATCH_ID.Ref_Intermediate ' || 
' WHERE COLUMN_NM =''' ||ROLE_TP||''     
' AND LOOKUP_TBL_NM =''' ||C_S_LU_PTY_ROLE_TP|''' ';
dbms_output.put_line(l_sql_statement);
EXECUTE IMMEDIATE l_sql_statement;
COMMIT;
END;
/

【讨论】:

非常感谢。这也是正确的。 dbms_output _line 是我在此之前不知道的东西,它本来可以救命。【参考方案2】:

您的(编辑的)代码生成的动态语句是:

INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP(PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE, SRC_ROWID, 
HUB_STATE_IND, ROLE_TP)  SELECT MISSING_VALUES AS PKEY_SRC_OBJECT, 1 as VERSION_SEQ, 0 as TIMELINE_ACTION, INSERT_TS as LAST_UPDATE_DATE, SELECT MISSING_VALUES as "SRC_ROWID", 1 as "HUB_STATE_IND", MISSING_VALUES as ROLE_TP FROM ECH_ETL_BATCH_ID.Ref_Intermediate  WHERE COLUMN_NM =||ROLE_TP|| AND LOOKUP_TBL_NM =||C_S_LU_PTY_ROLE_TP||

或拆分为多行并进行注释以显示其存在的问题:

INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP(PKEY_SRC_OBJECT, VERSION_SEQ,
  TIMELINE_ACTION, LAST_UPDATE_DATE, SRC_ROWID, HUB_STATE_IND, ROLE_TP)
SELECT MISSING_VALUES AS PKEY_SRC_OBJECT
, 1 as VERSION_SEQ
, 0 as TIMELINE_ACTION
, INSERT_TS as LAST_UPDATE_DATE
, SELECT MISSING_VALUES as "SRC_ROWID"
--^^^^^^
, 1 as "HUB_STATE_IND"
, MISSING_VALUES as ROLE_TP
FROM ECH_ETL_BATCH_ID.Ref_Intermediate
WHERE COLUMN_NM =||ROLE_TP|| AND LOOKUP_TBL_NM =||C_S_LU_PTY_ROLE_TP||
--               ^^       ^^                    ^^                  ^^

您对此有一些问题;主要是您在生成的语句中嵌入了一组||,但也有一个额外的SELECT

这可能更接近您想要的,包括嵌入字符串文字的转义单引号:

l_sql_statement :=
'INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP' || 
'(PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE, SRC_ROWID, HUB_STATE_IND, ROLE_TP) ' || 
' SELECT MISSING_VALUES AS PKEY_SRC_OBJECT' ||
', 1 as VERSION_SEQ' ||
', 0 as TIMELINE_ACTION' ||
', INSERT_TS as LAST_UPDATE_DATE' ||
', MISSING_VALUES as "SRC_ROWID"' || 
', 1 as "HUB_STATE_IND"' ||
', MISSING_VALUES as ROLE_TP' ||
' FROM ECH_ETL_BATCH_ID.Ref_Intermediate ' || 
' WHERE COLUMN_NM = ''ROLE_TP''' ||     
' AND LOOKUP_TBL_NM = ''C_S_LU_PTY_ROLE_TP''';

生成(再次拆分):

INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP(PKEY_SRC_OBJECT, VERSION_SEQ,
  TIMELINE_ACTION, LAST_UPDATE_DATE, SRC_ROWID, HUB_STATE_IND, ROLE_TP)
SELECT MISSING_VALUES AS PKEY_SRC_OBJECT
, 1 as VERSION_SEQ
, 0 as TIMELINE_ACTION
, INSERT_TS as LAST_UPDATE_DATE
, MISSING_VALUES as "SRC_ROWID"
, 1 as "HUB_STATE_IND"
, MISSING_VALUES as ROLE_TP
FROM ECH_ETL_BATCH_ID.Ref_Intermediate
WHERE COLUMN_NM = 'ROLE_TP'
AND LOOKUP_TBL_NM = 'C_S_LU_PTY_ROLE_TP'

您可以跨行拆分字符串分配,这将简化一些事情,因为它会减少(或目前,删除)字符串连接:

l_sql_statement :=
'INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP
(PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE,
  SRC_ROWID, HUB_STATE_IND, ROLE_TP)
SELECT MISSING_VALUES AS PKEY_SRC_OBJECT
, 1 as VERSION_SEQ
, 0 as TIMELINE_ACTION
, INSERT_TS as LAST_UPDATE_DATE
, MISSING_VALUES as "SRC_ROWID"
, 1 as "HUB_STATE_IND"
, MISSING_VALUES as ROLE_TP
FROM ECH_ETL_BATCH_ID.Ref_Intermediate
WHERE COLUMN_NM = ''ROLE_TP''
AND LOOKUP_TBL_NM = ''C_S_LU_PTY_ROLE_TP''';

或者您可以使用the alternative quoting mechanism 来避免转义单引号。

创建动态语句时,从有效的静态语句开始,然后向后工作;并使用dbms_output 显示最终生成的字符串,以便您验证它并在必要时手动运行它。

当然,这根本不需要是动态的,但是从您最初的问题来看,您打算在某个时候在子查询中使用过程参数。


要使用过程参数而不是您必须开始的字符串文字,您可以将它们连接起来:

l_sql_statement :=
'INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP
(PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE,
  SRC_ROWID, HUB_STATE_IND, ROLE_TP)
SELECT MISSING_VALUES AS PKEY_SRC_OBJECT
, 1 as VERSION_SEQ
, 0 as TIMELINE_ACTION
, INSERT_TS as LAST_UPDATE_DATE
, MISSING_VALUES as "SRC_ROWID"
, 1 as "HUB_STATE_IND"
, MISSING_VALUES as ROLE_TP
FROM ECH_ETL_BATCH_ID.Ref_Intermediate
WHERE COLUMN_NM = ' || P_COLUMN_NAME || '
AND LOOKUP_TBL_NM = ' || P_TARGET_TABLE;

或者最好使用绑定变量:

l_sql_statement :=
'INSERT INTO ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP
(PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE,
  SRC_ROWID, HUB_STATE_IND, ROLE_TP)
SELECT MISSING_VALUES AS PKEY_SRC_OBJECT
, 1 as VERSION_SEQ
, 0 as TIMELINE_ACTION
, INSERT_TS as LAST_UPDATE_DATE
, MISSING_VALUES as "SRC_ROWID"
, 1 as "HUB_STATE_IND"
, MISSING_VALUES as ROLE_TP
FROM ECH_ETL_BATCH_ID.Ref_Intermediate
WHERE COLUMN_NM = :COLUMN_NAME
AND LOOKUP_TBL_NM = :TARGET_TABLE';

EXECUTE IMMEDIATE l_sql_statement USING P_COLUMN_NAME, P_TARGET_TABLE;

但这仍然不需要是动态的。

【讨论】:

感谢您指出我的问题。当我添加变量时,它必须是动态的。但是,在我的 WHERE 子句中,我需要它是 'WHERE COLUMN_NM = 'ROLE_TP' AND LOOKUP_TBL_NM = 'C_S_LU_PTY_ROLE_TP' 我不确定如何在那里获得那些额外的单引号。 @TheManC - 我添加了如何在字符串中转义单引号。 这很有帮助,我非常感谢。除了在我的变量中添加一个或两个额外的单引号之外,这是否会发生变化? 您只需要注意表/列参数中的连接方式以及引号的放置位置。 我编辑了它,它应该是这样的吗?它没有出现在 dbms_output 中,但我在 5 分钟前不知道它存在,所以我不确定它是如何工作的。

以上是关于Oracle SQL 存储过程缺少表达式错误的主要内容,如果未能解决你的问题,请参考以下文章

执行存储过程 - Oracle PL SQL

在 Oracle SQL 错误中将日期传递给存储过程:ORA-01858

oracle创建存储过程时,提示错误是:错误(5,18): PL/SQL: ORA-00947: 没有足够的值?代码如下:

将 XML 数据存储在表中的 PL/SQL 过程抛出错误(23,102):PL/SQL:ORA-00907:缺少右括号

oracle创建存储过程时,提示错误是:错误(5,18): PL/SQL: ORA-00947: 没有足够的值?代码如下:

oracle存储过程报937错误