选择查询在程序包过程之外完美运行,但在程序过程内部完美运行 它会引发“ ORA-01858:在期望数字的位置找到了非数字字符”错误。
这是我的查询:
DECLARE
v_general_number VARCHAR(11);
BEGIN
SELECT 'Q' || TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'Q') || '/' || LPAD(TO_CHAR(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL), '3', '0') || '/' || TO_CHAR(EXTRACT(YEAR FROM TO_DATE(SYSDATE, 'MM/DD/YYYY'))) INTO v_general_number FROM DUAL;
DBMS_OUTPUT.PUT_LINE(v_general_number);
END;
效果很好。
但是在存储过程中,它将引发上面的错误。
这是我的程序:
PROCEDURE save_request(p_name IN requests.suggested_name%TYPE,
p_urgency_type IN requests.urgency_type_id%TYPE)
AS
v_general_number VARCHAR(11);
BEGIN
SELECT 'Q' || TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'Q') || '/' || LPAD(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL, 3, '0') || '/' || TO_CHAR(EXTRACT(YEAR FROM TO_DATE(SYSDATE, 'MM/DD/YYYY'))) INTO v_general_number FROM DUAL;
INSERT INTO requests (suggested_name,
urgency_type_id,
general_number
) VALUES (
p_name ,
p_urgency_type ,
v_general_number );
END save_request;
我看不出是什么问题。任何建议,将不胜感激。
更新:
更改后,我解决了问题:
SELECT 'Q' || TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'Q') || '/' || LPAD(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL, 3, '0') || '/' || TO_CHAR(EXTRACT(YEAR FROM TO_DATE(SYSDATE, 'MM/DD/YYYY'))) INTO v_general_number FROM DUAL;
对此:
SELECT 'Q' || TO_CHAR(SYSDATE, 'Q') || '/' || LPAD(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL, 3, '0') || '/' || TO_CHAR(EXTRACT(YEAR FROM SYSDATE)) INTO v_general_number FROM DUAL;
它奏效了。
但是我仍然不明白为什么相同的查询在过程外仍然起作用,但是在过程内抛出错误。
答案 0 :(得分:6)
SYSDATE
已经是日期,所以
TO_DATE(SYSDATE, 'MM/DD/YYYY')
完全没有道理。您正在将隐式转换为字符串,然后将其显式转换为日期,即有效地:
TO_DATE(TO_CHAR(SYSDATE, <NLS_DATE_FORMAT>), 'MM/DD/YYYY')
是否起作用取决于会话的NLS_DATE_FORMAT设置:
alter session set nls_date_format = 'MM/DD/YYYY';
select TO_DATE(SYSDATE, 'MM/DD/YYYY') from dual;
TO_DATE(SY
----------
07/04/2018
select TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'YYYY-MM-DD') from dual;
TO_CHAR(TO
----------
2018-07-04
alter session set nls_date_format = 'DD/MM/YYYY';
select TO_DATE(SYSDATE, 'MM/DD/YYYY') from dual;
TO_DATE(SY
----------
07/04/2018
select TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'YYYY-MM-DD') from dual;
TO_CHAR(TO
----------
2018-04-07
alter session set nls_date_format = 'DD-MON-YYYY';
select TO_DATE(SYSDATE, 'MM/DD/YYYY') from dual;
ORA-01858: a non-numeric character was found where a numeric was expected
alter session set nls_date_format = 'YYYY-MM-DD';
select TO_DATE(SYSDATE, 'MM/DD/YYYY') from dual;
ORA-01843: not a valid month
请注意,前两个都“起作用”,但实际上给您不同的日期。 (该月晚些时候,第12个之后,第二个也将因无效的月份错误而失败。)
您从中运行匿名块的会话以及从中执行过程的会话仅具有不同的NLS设置。这就是为什么您不应该依赖隐式转换或NLS设置的原因...
无论如何,删除不必要的转换:
SELECT 'Q' || TO_CHAR(SYSDATE, 'Q')
|| '/' || LPAD(TO_CHAR(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL), '3', '0')
|| '/' || TO_CHAR(EXTRACT(YEAR FROM SYSDATE))
INTO v_general_number
FROM DUAL;
或对分配执行相同的操作,而不是从对偶中选择:
v_general_number := 'Q' || TO_CHAR(SYSDATE, 'Q')
|| '/' || LPAD(TO_CHAR(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL), '3', '0')
|| '/' || TO_CHAR(EXTRACT(YEAR FROM SYSDATE));
,甚至,作为替代:
v_general_number := TO_CHAR(SYSDATE, '"Q"Q"/"')
|| TO_CHAR(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL, 'FM000')
|| TO_CHAR(SYSDATE, '"/"YYYY');
在日期格式模型中使用字符文字来替换斜杠的串联,并在序列号中使用格式模型,因此您无需再用零填充。 (并且您实际上并不需要变量,可以在插入的values
子句中进行相同的构造。)