Oracle日期错误-ORA-01841

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

我在Oracle11g中有下表

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