2014-09-22 2 views
1

Таблица, на которую я запрашиваю, имеет даты, хранящиеся как varchar2. Мне нужно сравнить даты, хранящиеся как varchar2 с sysdate, с помощью BETWEEN sysdate-1 AND sysdate-30 (чтобы вернуть даты varchar2 с последнего месяца).Varchar2 to date для сравнения sysdate

При указании TO_DATE(varchar2, 'DD-MON-YYYY') Я получаю сообщение об ошибке «literal не соответствует строке формата».

Я застрял, поскольку документация Oracle говорит, что это приемлемый формат для TO_DATE() при преобразовании из varchar2.

ОБНОВЛЕНИЕ: Это корпоративная база данных, я не проектировал БД и не могу работать только с тем, что у меня есть. Набор данных огромен и автоматически обновляется устройствами SCADA, более 10 000 устройств в день.

SELECT device_name, read_date, sysdate 

FROM oracle_database 

------- Data Returned by query -------- 

device_name read_date sysdate 
Device 1 5/14/2013 22-Sep-14 
Device 2 5/14/2013 22-Sep-14 
Device 3 5/14/2013 22-Sep-14 
Device 4 5/14/2013 22-Sep-14 
Device 5 5/14/2013 22-Sep-14 
Device 6 5/14/2013 22-Sep-14 
Device 7 5/14/2013 22-Sep-14 

Результаты использования TO_DATE

ВЫБРАТЬ device_name, TO_DATE (read_date, 'DD-MON-YY'), SYSDATE

------- Данные Возвращается запроса - ---------

ORA-01861: буквальный не соответствует строке формата

+2

Можете привести пример ввода? – paqogomez

+2

Вы должны использовать формат, соответствующий строкам, которые вы фактически сохранили. Вы должны надеяться, что все они в одном формате и действительны ... Возможно, у вас есть функция, которая пробует несколько форматов, но это беспорядок, особенно. если у вас есть сочетание дат DD/MM и MM/DD. Вот почему даты не должны храниться как строки ... В любом случае, если вы показываете некоторые данные образца и даты, которые они представляют (если это не очевидно), то может быть предложена подходящая модель. –

+0

@Alex, надеюсь, вы не возражаете, если я попытаюсь ответить на основе «Почему не хранить дату как строку». Я включил ссылку на статью Эд Стивенса об этом, что довольно удивительно. И везде я использую одну и ту же ссылку для ответа на подобные вопросы. –

ответ

0

Fi во-первых, ваш дизайн испорчен. Вы не должны иметь DATE как VARCHAR2 тип данных.

Во-вторых, при сравнении дат и преобразовании date literal в DATE всегда указывайте ту же самую маску формата с обеих сторон.

Чтобы преобразовать строку в настоящее время, используйте TO_DATE с соответствующей маской формата.

Чтобы преобразовать дату в строку, используйте TO_CHAR с той же маской формата.

Убедитесь, что при сравнении значений в выражении вы преобразуете тип данных по обе стороны от comparison operator во избежание implicit data type conversion.

И вы должны прочитать эту прекрасную статью bybEd Stevens, http://edstevensdba.wordpress.com/2011/04/07/nls_date_format/

1

Учитывая ваши данные, правильный формат очень вероятно MM/DD/YYYY. Он будет соответствовать как одиночным, так и двузначным числам месяцев или дней.

  • MM: месяц от 01 до 12 лет (ведущий 0 не является обязательным по умолчанию)
  • \: любой пунктуации знак
  • DD: день от 01 до 31 (ведущий 0 не является обязательным по умолчанию)
  • \: любой знак препинания
  • YYYY: year

См. Информацию о documentation about datetime Format Models Oracle.

Вот пример:

-- Some test data 
WITH testdata AS (
    SELECT '5/14/2013' as d FROM DUAL 
    UNION SELECT '05/14/2013' FROM DUAL 
    UNION SELECT '5/1/2013' FROM DUAL 
    UNION SELECT '5/01/2013' FROM DUAL 
    UNION SELECT '6-6-2013' FROM DUAL) 

-- Actual query demonstrating the use of the MM/DD/YYYY format 
select d, TO_DATE(d,'MM/DD/YYYY') FROM testdata 

Производство:

D   TO_DATE(D,'MM/DD/YYYY') 
05/14/2013 05/14/2013 
5/01/2013 05/01/2013 
5/1/2013 05/01/2013 
5/14/2013 05/14/2013 
6-6-2013 06/06/2013 

Если вам действительно необходимо для обеспечения того, что ваши компоненты даты разделены / (а не какой-либо другой знак препинания), вы должны использовать вместо этого fxfmMM/DD/YYYY:

  • fx флага принудительного строгое сравнения, как для пунктуации и количества цифр в формате
  • fm флага расслабить, что сравнение, чтобы позволить вверх к числу указанных цифр
+0

Как присоединиться к подзапросу testdata с моей таблицей устройств? Я не могу использовать дату, поскольку она не уникальна.Я прочитал документацию Oracle, относящуюся к WITH, и все еще рисовал пробел. Кроме того, с учетом вышесказанного не представляется возможным возвращать любые данные за пределами диапазона дат в подзапросе. Например: ГДЕ SYSDATE МЕЖДУ (SYSDATE-1) и (SYSDATE-30) –

+0

@tx_query - 'testdata' просто предоставить некоторые данные примера, как ваша, и показать, как он успешно преобразуется в дату в этом формате модель. Вам не нужны 'testdata' или соединение. Просто используйте 'TO_DATE (read_date, 'MM/DD/YYYY')' в вашем исходном запросе. –

+0

@AlexPoole Для чего это стоит, я узнал, что формат был yyyy-mm-dd и пошел с ROUND (avg (valve_pressure) over (PARTITION by unique_id order by to_date (read_date, 'yyyy-mm-dd') диапазон между 30 предшествующими и текущими строками)) MA_30 Большое спасибо вам двоим за ваши быстрые и вежливые ответы. –

1
SELECT device_name, TO_DATE(read_date, 'DD/MM/YYYY'), sysdate 
+0

Ответ может стать более ценным, если вы добавите некоторые пояснения и ссылки на документацию, чтобы исходный плакат и другие пользователи могли на самом деле научиться этому. –

+0

ОК, спасибо .. будет помнить об этом. –

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