Oracle日期错误-ORA-01841
我在Oracle11g中有下表Oracle日期错误-ORA-01841,oracle,substr,to-date,sysdate,Oracle,Substr,To Date,Sysdate,我在Oracle11g中有下表 SQL> DESC tmp_test; Name Type Nullable Default Comments -------------------- ------------- -------- ------- -------- SERNO NUMBER(10) CARDNO VARC
SQL> DESC tmp_test;
Name Type Nullable Default Comments
-------------------- ------------- -------- ------- --------
SERNO NUMBER(10)
CARDNO VARCHAR2(25) Y
COL_A VARCHAR2(255) Y
DATEA DATE Y
DATEB DATE Y
TAG VARCHAR2(255) Y
FEEDBACK CHAR(1) Y
SQL>
SQL> SELECT * FROM (SELECT T.COL_A FROM TEMP_TEST T ORDER BY DBMS_RANDOM.VALUE) WHERE ROWNUM <=10;
COL_A
--------------------------------------------------------------------------------
00 OK.20150301-0000
00 OK.20150301-0000
00 OK.20150301-0000
00 OK.20150205-0000
00 OK.20150301-0000
00 OK.20150301-0000
00 OK.20150213-0000
00 OK.20150301-0000
00 OK.20150129-0000
00 OK.20150301-0000
10 rows selected
SQL>
我试图识别表TEMP_TEST中的所有行,其中COL_A中的日期小于SYSDATE-7
SQL>
SQL> SELECT * FROM TEMP_TEST T WHERE
TO_DATE(SUBSTR(TRIM(T.COL_A),7,8),'YYYYMMDD') < sysdate-7;
**ORA-01841: (full) year must be between -4713 and +9999, and not be 0**
SQL>
该表仅包含200行,因此我已直观地检查了数据是否存在任何问题。所有日期均有效。这个错误的原因可能是什么
谢谢显然,所有日期都无效,因此会出现错误。我会尝试以下未经测试的内容,但我认为这没关系,只是为了确定问题记录
declare
v_date date;
begin
for c in (select col_a from temp_test) loop
begin
v_date := to_date(substr(trim(c.col_a),7,8),'YYYYMMDD');
exception when others then
dbms_output.put_line(c.col_a);
end;
end loop;
end;
请注意,将其他人用作唯一的异常处理程序通常会被视为不良做法。在生产代码中,异常应该单独处理。即使在用于调试时,输出SQL错误也会更好,但对于第一次通过时只会出现一些错误的情况,有时懒散也没关系。使用显式光标调试数字或日期转换错误通常会很快出现有问题的行,我伪造了您的临时测试表:
declare
cursor l_cur is
with temp_test(col_a) as (
select '20150201_abc' col_a from dual union all
select 'x0150201_abc' col_a from dual union all
select '20150201_abc' col_a from dual)
SELECT * FROM TEMP_TEST T;
l_data l_cur%rowtype;
dummy date;
begin
open l_cur;
loop
fetch l_cur
into l_data;
exit when l_cur%notfound;
begin
dummy := TO_DATE(SUBSTR(TRIM(l_data.COL_A), 1, 8), 'YYYYMMDD');
exception
when others then
dbms_output.put_line(sqlerrm || ' for ' || l_data.col_a);
end;
end loop;
end;
编辑:当此处仅出于交互式调试目的使用其他语言时-请不要在生产代码中使用它。是否可以尝试将nls\U date\U语言添加到“截止日期”中?尝试从dual中选择'00 OK.20150301-0000',7,8,'YYYYMMDD','NLS_DATE_LANGUAGE=AMERICAN';如果我是你,我会从temp_测试中选择substritm.COL_A,7,8,'YYYYMMDD',然后检查返回的内容。通常,这足以识别有问题的行。从dual中选择“DATESUBSTRTRIM'00 OK.20150301-0000',7,8,'YYYYMMDD',NLS_DATE_LANGUAGE=AMERICAN”;选择1行。确定从temp_test中选择substritm.COL_A,7,8,'yyyyymmdd',选择所有270行。但是,当其他行将捕获所有错误时,您应该捕获ORA-01841。那么为什么是其他人呢?当别人本身就是一个bug时。修改过的cusor。光标l_cur是从温度测试中选择的颜色;没有获取行。通过使用SQL SELECT从TEMP_TEST T中提取所有行以_datesubstritt.COL_A,7,8,'YYYYMMDD'确认my Data没有问题这是一个仅用于交互式调试目的的脚本。在生产代码中使用WHEN-other几乎总是一个bug,但在某些情况下它是有意义的,例如记录错误并重新提出错误。Lalit,我接受你对我的答案的批评,尽管在这种情况下我不同意。我完全不接受这个答案。在这里使用others是完全有效的,因为它与输出sqlerrm一起用于帮助调试。Frank,首先我希望你没有误解我的意思,我只是添加了那个注释,这样就没有人盲目复制你的代码并使用它,至少通过阅读该注释,然后阅读你的回复会有一些意义。这一切都是建设性的。所以,感谢您的回复,这给了整个评论的事情一个完整的意义。非常感谢!然而,当其他人捕获所有错误时,您应该捕获ORA-01841。那么为什么是其他人呢?当别人本身就是一只虫子的时候,就像我说的,它是懒惰的。我不会在生产代码中这样做。在这种情况下,我们知道我们正在处理一个日期转换错误,我们知道我们最多要检查200个值。如果有什么不同的话,那么在这里单独处理所有可能的异常就太迂腐了。谢谢你添加了这一行,我只是认为盲目复制代码的人应该知道它的用法。我也对另一个答案发表了评论。这是建设性的,我感谢你的回答。谢谢Lalit,你说得很对-我会相应地修改我的答案。现在完整的答案是+1