ORA-00984: 此处不允许列 - 动态 SQL
ORA-00984: column not allowed here - Dynamic SQL
这是我的包裹代码。
CREATE OR REPLACE PACKAGE BODY FMSSMART.GENERIC_PURGER
AS
PROCEDURE GET_PARTITIONID_JULIAN (i_date IN DATE,
i_number_of_partitions IN NUMBER,
o_partitionID OUT NUMBER)
IS
BEGIN
SELECT MOD (TO_NUMBER (TO_CHAR (TO_DATE (i_date, 'YYYYMMDD'), 'j')),
i_number_of_partitions)
INTO o_partitionID
FROM DUAL;
DBMS_OUTPUT.put_line (o_partitionID);
END GET_PARTITIONID_JULIAN;
PROCEDURE DELETE_TBL_SML
(
i_tablename IN VARCHAR2,
o_retcode OUT NUMBER,
o_errormsg OUT VARCHAR2
)
IS
stmt VARCHAR2(1000);
o_start_time DATE;
o_end_time DATE;
BEGIN
select to_char(sysdate, 'YYYYMMDDHH24MISS') into o_start_time from dual;
stmt := 'DELETE FROM ' ||i_tablename;
EXECUTE IMMEDIATE stmt;
COMMIT;
select to_char(sysdate, 'YYYYMMDDHH24MISS') into o_end_time from dual;
EXCEPTION WHEN OTHERS THEN
o_retcode := SQLCODE;
o_errormsg := substr(SQLERRM, 1, 200);
INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name, procedure_name, start_time, end_time) VALUES (o_retcode, o_errormsg, 'GENERIC_PURGER','DELETE_TBL_SML', o_start_time, o_end_time);
return;
END DELETE_TBL_SML;
PROCEDURE INSERT_AUDIT_PROC_TBL
(
i_retcode IN NUMBER,
i_errormsg IN VARCHAR2,
i_package_name IN VARCHAR2,
i_procedure_name IN VARCHAR2,
i_start_time IN DATE,
i_end_time IN DATE
)
IS
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name, procedure_name, start_time, end_time) VALUES (i_retcode, i_errormsg, i_package_name, i_procedure_name,i_start_time, i_end_time)';
COMMIT;
RETURN;
END INSERT_AUDIT_PROC_TBL;
END GENERIC_PURGER;
/
执行时:
set autocommit off;
set serveroutput on size 1000000;
ALTER SESSION SET NLS_DATE_FORMAT='YYYYMMDD HH24:MI:SS';
EXECUTE INSERT_AUDIT_PROC_TBL(-1, 'NA', 'GENERIC_PURGER','DELETE_TBL_SML', '20150212164527', '20150212164527');
我遇到了一个错误:
Session altered.
BEGIN INSERT_AUDIT_PROC_TBL(-1, 'NA', 'GENERIC_PURGER','DELETE_TBL_SML', '20150212164527', '20150212164527'); END;
*
ERROR at line 1:
ORA-00984: column not allowed here
ORA-06512: at "FMSSMART.INSERT_AUDIT_PROC_TBL", line 12
ORA-06512: at line 1
您遇到的错误不是您如何调用该过程,而是该过程正在做什么。针对 FMSSMART.INSERT_AUDIT_PROC_TBL
过程的第 12 行报告了 ORA-00984 错误,即:
EXECUTE IMMEDIATE 'INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name, procedure_name, start_time, end_time) VALUES (i_retcode, i_errormsg, i_package_name, i_procedure_name,i_start_time, i_end_time)';
您在这里使用动态 SQL 是在您不需要的时候;没有什么动态和静态的 SQL 就好了:
INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name,
procedure_name, start_time, end_time)
VALUES (i_retcode, i_errormsg, i_package_name,
i_procedure_name,i_start_time, i_end_time);
为了将来的参考,当您使用动态 SQL 时,您需要为传入的值使用绑定变量;您在动态 SQL 语句中有一个绑定占位符,该占位符由冒号表示,例如:var1
,然后使用 using
子句提供实际值。目前,在您的原始版本中, i_retcode
被解释为列名,而不是您的变量,这超出了动态上下文的范围。所以你会使用类似的东西:
EXECUTE IMMEDIATE 'INSERT INTO AUDIT_PROC_TBL (error_number, '
|| 'error_message, package_name, procedure_name, start_time, end_time) '
|| 'VALUES (:retcode, :errormsg, :package_name, :procedure_name, '
|| ':start_time, :end_time)'
USING i_retcode, i_errormsg, i_package_name, i_procedure_name,
i_start_time, i_end_time;
为了便于阅读,我将语句分成多行;通过 ||
的连接意味着最后的字符串是一样的,就好像它全部在一行上一样。
我还有一些超出问题范围的其他观察结果:
- 您在会话中设置 NLS_DATE_FORMAT,然后依赖隐式转换;奇怪的是,使用与您的字符串不匹配的格式。最好在您的通话中明确传递日期值,例如
to_date('20150212164527', 'YYYYMMDDHH24MISS')
或 timestamp
文字。
- 在你的
DELETE_TBL_SML
包中更糟,因为你仍然依赖会话 NLS 设置,你不会总是控制它,并且你显式地将日期转换为字符串只是为了隐式转换它们背部。而不是 select to_char(sysdate, 'YYYYMMDDHH24MISS') into o_start_time from dual;
只是为了 o_start_time := sysdate)
.
- 在过程中提交或回滚通常被认为是不好的做法;调用者最好决定是否以及何时提交,因为它可能正在做您的过程不知道的其他事情,应该将其视为同一事务的一部分。
- 捕获您不处理的异常,尤其是
when others
,通常是一个错误。虽然您在这里将代码和消息返回给调用者,但他们随后必须寻找它。让异常传播回调用者几乎总是更好 - 这也可以反馈给 commit/rollback 决定。
删除程序可以简化为:
PROCEDURE DELETE_TBL_SML(i_tablename IN VARCHAR2) IS
o_start_time DATE;
o_end_time DATE;
BEGIN
o_start_time := sysdate;
EXECUTE IMMEDIATE 'DELETE FROM ' ||i_tablename;
o_end_time := sysdate;
INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name,
procedure_name, start_time, end_time)
VALUES (SQLERRCODE, substr(SQLERRM, 1, 200), 'GENERIC_PURGER',
'DELETE_TBL_SML', o_start_time, o_end_time);
END DELETE_TBL_SML;
除非你只想审计错误,在这种情况下你需要将执行包含在它自己的子块中;然后将其命名为 exec FMSSMART.GENERIC_PURGER.DELETE_TBL_SML(<your table name>)
.
这是我的包裹代码。
CREATE OR REPLACE PACKAGE BODY FMSSMART.GENERIC_PURGER
AS
PROCEDURE GET_PARTITIONID_JULIAN (i_date IN DATE,
i_number_of_partitions IN NUMBER,
o_partitionID OUT NUMBER)
IS
BEGIN
SELECT MOD (TO_NUMBER (TO_CHAR (TO_DATE (i_date, 'YYYYMMDD'), 'j')),
i_number_of_partitions)
INTO o_partitionID
FROM DUAL;
DBMS_OUTPUT.put_line (o_partitionID);
END GET_PARTITIONID_JULIAN;
PROCEDURE DELETE_TBL_SML
(
i_tablename IN VARCHAR2,
o_retcode OUT NUMBER,
o_errormsg OUT VARCHAR2
)
IS
stmt VARCHAR2(1000);
o_start_time DATE;
o_end_time DATE;
BEGIN
select to_char(sysdate, 'YYYYMMDDHH24MISS') into o_start_time from dual;
stmt := 'DELETE FROM ' ||i_tablename;
EXECUTE IMMEDIATE stmt;
COMMIT;
select to_char(sysdate, 'YYYYMMDDHH24MISS') into o_end_time from dual;
EXCEPTION WHEN OTHERS THEN
o_retcode := SQLCODE;
o_errormsg := substr(SQLERRM, 1, 200);
INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name, procedure_name, start_time, end_time) VALUES (o_retcode, o_errormsg, 'GENERIC_PURGER','DELETE_TBL_SML', o_start_time, o_end_time);
return;
END DELETE_TBL_SML;
PROCEDURE INSERT_AUDIT_PROC_TBL
(
i_retcode IN NUMBER,
i_errormsg IN VARCHAR2,
i_package_name IN VARCHAR2,
i_procedure_name IN VARCHAR2,
i_start_time IN DATE,
i_end_time IN DATE
)
IS
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name, procedure_name, start_time, end_time) VALUES (i_retcode, i_errormsg, i_package_name, i_procedure_name,i_start_time, i_end_time)';
COMMIT;
RETURN;
END INSERT_AUDIT_PROC_TBL;
END GENERIC_PURGER;
/
执行时:
set autocommit off;
set serveroutput on size 1000000;
ALTER SESSION SET NLS_DATE_FORMAT='YYYYMMDD HH24:MI:SS';
EXECUTE INSERT_AUDIT_PROC_TBL(-1, 'NA', 'GENERIC_PURGER','DELETE_TBL_SML', '20150212164527', '20150212164527');
我遇到了一个错误:
Session altered.
BEGIN INSERT_AUDIT_PROC_TBL(-1, 'NA', 'GENERIC_PURGER','DELETE_TBL_SML', '20150212164527', '20150212164527'); END;
*
ERROR at line 1:
ORA-00984: column not allowed here
ORA-06512: at "FMSSMART.INSERT_AUDIT_PROC_TBL", line 12
ORA-06512: at line 1
您遇到的错误不是您如何调用该过程,而是该过程正在做什么。针对 FMSSMART.INSERT_AUDIT_PROC_TBL
过程的第 12 行报告了 ORA-00984 错误,即:
EXECUTE IMMEDIATE 'INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name, procedure_name, start_time, end_time) VALUES (i_retcode, i_errormsg, i_package_name, i_procedure_name,i_start_time, i_end_time)';
您在这里使用动态 SQL 是在您不需要的时候;没有什么动态和静态的 SQL 就好了:
INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name,
procedure_name, start_time, end_time)
VALUES (i_retcode, i_errormsg, i_package_name,
i_procedure_name,i_start_time, i_end_time);
为了将来的参考,当您使用动态 SQL 时,您需要为传入的值使用绑定变量;您在动态 SQL 语句中有一个绑定占位符,该占位符由冒号表示,例如:var1
,然后使用 using
子句提供实际值。目前,在您的原始版本中, i_retcode
被解释为列名,而不是您的变量,这超出了动态上下文的范围。所以你会使用类似的东西:
EXECUTE IMMEDIATE 'INSERT INTO AUDIT_PROC_TBL (error_number, '
|| 'error_message, package_name, procedure_name, start_time, end_time) '
|| 'VALUES (:retcode, :errormsg, :package_name, :procedure_name, '
|| ':start_time, :end_time)'
USING i_retcode, i_errormsg, i_package_name, i_procedure_name,
i_start_time, i_end_time;
为了便于阅读,我将语句分成多行;通过 ||
的连接意味着最后的字符串是一样的,就好像它全部在一行上一样。
我还有一些超出问题范围的其他观察结果:
- 您在会话中设置 NLS_DATE_FORMAT,然后依赖隐式转换;奇怪的是,使用与您的字符串不匹配的格式。最好在您的通话中明确传递日期值,例如
to_date('20150212164527', 'YYYYMMDDHH24MISS')
或timestamp
文字。 - 在你的
DELETE_TBL_SML
包中更糟,因为你仍然依赖会话 NLS 设置,你不会总是控制它,并且你显式地将日期转换为字符串只是为了隐式转换它们背部。而不是select to_char(sysdate, 'YYYYMMDDHH24MISS') into o_start_time from dual;
只是为了o_start_time := sysdate)
. - 在过程中提交或回滚通常被认为是不好的做法;调用者最好决定是否以及何时提交,因为它可能正在做您的过程不知道的其他事情,应该将其视为同一事务的一部分。
- 捕获您不处理的异常,尤其是
when others
,通常是一个错误。虽然您在这里将代码和消息返回给调用者,但他们随后必须寻找它。让异常传播回调用者几乎总是更好 - 这也可以反馈给 commit/rollback 决定。
删除程序可以简化为:
PROCEDURE DELETE_TBL_SML(i_tablename IN VARCHAR2) IS
o_start_time DATE;
o_end_time DATE;
BEGIN
o_start_time := sysdate;
EXECUTE IMMEDIATE 'DELETE FROM ' ||i_tablename;
o_end_time := sysdate;
INSERT INTO AUDIT_PROC_TBL (error_number, error_message, package_name,
procedure_name, start_time, end_time)
VALUES (SQLERRCODE, substr(SQLERRM, 1, 200), 'GENERIC_PURGER',
'DELETE_TBL_SML', o_start_time, o_end_time);
END DELETE_TBL_SML;
除非你只想审计错误,在这种情况下你需要将执行包含在它自己的子块中;然后将其命名为 exec FMSSMART.GENERIC_PURGER.DELETE_TBL_SML(<your table name>)
.