2015-03-03 2 views
2

У меня есть следующая таблица в Oracle11g.Ошибка даты Oracle - ORA-01841

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 где DATE в 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 строк, поэтому я визуально проверить на любые вопросы с данными. Все даты действительны. Что может быть причиной этой ошибки?

Благодаря

+0

Можете ли вы попробовать добавить 'nls_date_language' в' to_date'? Попробуйте это: SELECT TO_DATE (SUBSTR (TRIM ('00 OK.20150301-0000 '), 7,8),' YYYYMMDD ',' NLS_DATE_LANGUAGE = AMERICAN ') FROM dual; ' –

+0

Если бы я был вами, выполните 'select SUBSTR (TRIM (T.COL_A), 7,8), 'YYYYMMDD' из temp_test', а затем проверим, что возвращается. Обычно этого достаточно, чтобы идентифицировать проблематичные строки. – Boneist

+0

SELECT TO_DATE (SUBSTR (TRIM ('00 OK.20150301-0000 '), 7,8),' YYYYMMDD ',' NLS_DATE_LANGUAGE = AMERICAN ') FROM dual; Выбрана 1 строка. OK выберите SUBSTR (TRIM (T.COL_A), 7,8), 'YYYYMMDD' из temp_test - выбрано всего 270 строк. – MrM

ответ

2

Видимо все даты не являются действительными, следовательно, ошибка вы получаете. Я бы попробовал что-то вроде следующего (непроверенный, но думаю, что все в порядке), просто чтобы определить записи о проблемах.

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; 

Обратите внимание, что такое использование others в качестве единственного обработчика исключений, как правило, считается плохой практикой. В производственном коде исключения должны обрабатываться индивидуально. Даже когда используется для отладки, было бы лучше вывести SQL-ошибку, но для первого прохода, где ожидаются только несколько ошибок, иногда это нормально, чтобы быть ленивым.

+0

Если другие поймают все ошибки, вы должны поймать 'ORA-01841'. Так почему же «другие»? 'когда другие' сам по себе является ошибкой. –

+0

Как я уже сказал, это лениво. Я бы не сделал этого в производственном коде. В этом контексте мы знаем, что имеем дело с ошибкой преобразования даты, и мы знаем, что мы проверяем не более 200 значений. Во всяком случае, было бы педантично относиться ко всем возможным исключениям индивидуально здесь. – Bacs

+0

Спасибо за добавление этой строки, я просто подумал, что кто-то, слепо копируя код, должен знать об использовании этого. Я прокомментировал и другой ответ. Это конструктивно, и я ценю ваш ответ. –

2

Использование явного курсора для отладки цифровой или преобразование даты ошибки, как правило, быстро поворачивает вверх обижая строки (здесь, я подделал свое TEMP_TEST таблицы):

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; 

EDIT: WHEN OTHERS здесь используются исключительно для интерактивных целей отладки - пожалуйста, не используйте его в производственном коде.

+0

Когда другие поймают все ошибки, вы должны поймать 'ORA-01841'. Так почему же «другие»? 'когда другие' сам по себе является ошибкой. –

+0

Модифицированный кузор. курсор l_cur - выберите COL_A из TEMP_TEST; Нет строк. Подтверждено извлечения всех строк с SQL SELECT, TO_DATE (SUBSTR (TRIM (T.COL_A), 7,8), 'YYYYMMDD') FROM TEMP_TEST T Существует не проблема с моими данными – MrM

+0

Это скрипт, который используется только для интерактивной отладки.Использование 'WHEN OTHERS' * в производственном коде * почти всегда является ошибкой (но есть обстоятельства, когда это имеет смысл, например, регистрировать ошибку и повторно поднимать ее). –

Смежные вопросы