В Oracle преобразуйте число (5,10) в дату - PullRequest
1 голос
/ 17 февраля 2012

Когда вы выполняете следующий синтаксис SQL в Oracle, всегда не удается, пожалуйста, помогите.

40284.3878935185 представляет «2010-04-16 09:18:34», с микросекундами.

дата эпохи 01 января 1900 г. (как в Excel).

create table temp1 (date1 number2(5,10));

insert into temp1(date1) values('40284.3878935185');

select to_date(date1, 'yyyy-mm-dd hh24:mi:ssxff') from temp1

Отчет об ошибке: Ошибка SQL: ORA-01861: литерал не соответствует формату строка 01861. 00000 - «литерал не соответствует строке формата» * Причина: литералы во входных данных должны иметь ту же длину, что и литералы в строка формата (за исключением начальных пробелов). Если Модификатор "FX" включен, литерал должен точно совпадать, без лишних пробелов. * Действие: исправьте строку формата в соответствии с литералом.

Благодарю Марка Баннистера

Теперь синтаксис SQL:

select to_char(to_date('1899-12-30','yyyy-mm-dd') + 
date1,'yyyy-mm-dd hh24:mi:ss')  from temp1

но не может получить формат даты, например «гггг-мм-дд чч24: ми: сс.фф». Продолжайте искать помощь.

Ответы [ 4 ]

5 голосов
/ 17 февраля 2012

Используя дату эпохи 30 декабря 1899 г., попробуйте:

select to_date('1899-12-30','yyyy-mm-dd') + date1
1 голос
/ 19 февраля 2012

Простое добавление даты не работает с временными метками, по крайней мере, если вам нужно сохранить доли секунды.Когда вы делаете to_timestamp('1899-12-30','yyyy-mm-dd')+ date1 (в комментарии к ответу Марка), TIMESTAMP неявно преобразуется в DATE до добавления, к общему ответу будет DATE и поэтому не имеет дробных секунд;затем вы используете to_char(..., '... .FF'), он жалуется на ORA-01821.

Вам необходимо преобразовать количество дней, проведенных в столбце date1, в интервал .К счастью, Oracle предоставляет функцию, которая делает именно это: NUMTODSINTERVAL:

select to_timestamp('1899-12-30','YYYY-MM-DD')
    + numtodsinterval(date1, 'DAY') from temp3;

16-APR-10 09.18.33.999998400

Затем вы можете отобразить это в желаемом формате, например (используя CTE для предоставления date1значение):

with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')
    + numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SSXFF') from temp3;

2010-04-16 09:18:33.999998400

Или ограничение тысячными долями секунды:

with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')+
    + numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SS.FF3') from temp3;


2010-04-16 09:18:33.999

Эпоха 1899-12-30 звучит странно и не соответствует Excel, как вы заявили,Кажется более вероятным, что ваш ожидаемый результат неверен, и он должен быть 2010-04-18, поэтому я проверю ваши предположения.Эндрю также делает несколько хороших замечаний, и вы должны сохранить свое значение в таблице в столбце TIMESTAMP.Если вы получаете такие данные, вам все равно нужно что-то в этом духе преобразовать для хранения в какой-то момент.

0 голосов
/ 17 февраля 2012

Я надеюсь, что это не выглядит слишком резко, но вы должны полностью переосмыслить свой подход здесь.

Вы не придерживаетесь типов данных прямо.Каждая строка в вашем примере неправильно использует тип данных.

  • TEMP1.DATE1 - это не дата или varchar2, а НОМЕР
  • , который вставляется не числом 40284.3878935185, а STRING>> '40284.3878935185' << </li>
  • ваш SELECT TO_DATE (...) использует значение NUMBER Temp1.Date1, но обрабатывает его как VARCHAR2 с использованием блока формата

I'mоколо 95% уверены, что, по вашему мнению, Oracle передает эти данные, используя простые блочные копии данных.«Так как каждая дата Oracle хранится как число, в любом случае, почему бы просто не вставить этот номер в таблицу?»Ну, потому что, когда вы определяете столбец как NUMBER, вы говорите Oracle: «Это не дата».Поэтому Oracle не управляет им как датой.

Каждое из этих преобразований типов рассчитывается Oracle на основе ваших текущих переменных сеанса.Если бы вы были во Франции, где "."это разделитель тысяч, а не основание, INSERT полностью потерпит неудачу.

Все эти преобразования со строками изменяются в соответствии с локалью, в которой Oracle считает, что вы работаете.Проверьте представление словаря V $ NLS_PARAMETERS.

Это ухудшается со значениями даты / времени.Значения даты / времени могут распространяться по всей карте - в основном из-за часового пояса.В каком часовом поясе находится ваш сервер баз данных?Из какого часового пояса он бежит?И если это не достаточно круто, проверьте, что произойдет, если вы измените календарь Oracle по умолчанию с Григорианского на Тайский Будду.

Я настоятельно рекомендую вам избавиться от цифр ВСЁ.

Для создания даты или значений даты и времени используйте строки с полностью инвариантными и однозначными форматами.Затем присвойте, сравните и рассчитайте только значения даты, например:

Постоянная GOODFMT VARCHAR2 = 'ГГГГ-ММ-ДД ЧЧ24: MI: SS.FFF ZZZ'

Good_Time DATE = TO_DATE ('2012-02-17 08: 07: 55.000 EST ', GOODFMT);

0 голосов
/ 17 февраля 2012

Точно не знаю дату эпохи, но попробуйте что-то вроде:

select to_date('19700101','YYYYMMDD')+ :secs_since_epoch/86400 from dual;

Или приведение к отметке времени как:

select cast(to_date('19700101', 'YYYYMMDD') + :secs_since_epoch/86400 as timestamp with local time zone) from dual;
...