Функция Oracle to_date с четвертьформатом - PullRequest
2 голосов
/ 04 августа 2010

Мне нужно найти записи, созданные за несколько кварталов.Например, я ищу все записи, созданные между 4-м кварталом 2008 года и 1-м кварталом 2010 года. У меня есть это в моем предложении WHERE:

...and r.record_create_date between to_date('2008 4','YYYY Q')
                                and to_date('2010 1','YYYY Q')

, но Oracle говорит: ORA-01820: format code cannot appear in date input format.Q является допустимым символом формата даты, поэтому я не уверен, что произошло.Это даже правильный способ найти значения между четвертями календаря, или есть лучший способ?


Также интересно, и, возможно, связано, если я выполню это:

select to_date('2009','YYYY') from dual;

Значение, отображаемое в моей IDE, равно 2009-08-01.Я бы ожидал 2009-08-04, поскольку сегодня - это 2010-08-04.

Это:

select to_date('2009 1','YYYY Q') from dual;

, конечно, не получается.

(Oracle 10g)

Ответы [ 5 ]

4 голосов
/ 04 августа 2010

Оракул говорит: ORA-01820: format code cannot appear in date input format.Q является допустимым символом формата даты, поэтому я не уверен, что произошло.

См. Второй столбец таблицы 2.15 в http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34948. Не все элементы формата разрешены, когдапреобразование в даты, временные метки и т. д.

Я не рекомендую использовать для проверки диапазона дат.Люди часто пропускают значения в течение последнего дня, которые ожидают быть включенными.Поэтому я бы перевел:

and r.record_create_date between to_date('2008 4','YYYY Q')
                             and to_date('2010 1','YYYY Q')

К

and to_date('2008-10-01', 'YYYY-MM-DD') <= r.record_create_date 
and record_create_date < to_date('2010-04-01', 'YYYY-MM-DD') -- < beginning of 2Q2010.
1 голос
/ 05 августа 2010

Поскольку отношение между кварталами к месяцам одно-многим, делать TO_DATE не имеет смысла ('2008 1', 'yyyy q'); какую дату следует вернуть? Первый квартал, конец квартала, ...? (С другой стороны, преобразование даты в квартал - как в TO_CHAR (SYSDATE, 'гггг q') имеет смысл, поскольку конкретная дата существует только в одном квартале.)

Итак, если вам нужен запрос, который ищет дату, которая находится в промежутке между двумя кварталами, вам придется «свернуть свою собственную» (явно указав даты начала / конца квартала).

В качестве примечания: в случае, если кто-то рассматривает возможность использования TO_DATE, не используйте такие вещи, как: WHERE date_value BETWEEN 'date string1' и 'date string2' без функции TO_DATE. Он предполагает формат даты по умолчанию и в определенных ситуациях может вообще избежать потенциально полезных индексов.

Ниже приведен один пример, когда один и тот же запрос может иметь другой результат.

select sysdate from dual where sysdate between '1-Jan-10' and '31-Dec-10';


SYSDATE
---------
04-AUG-10

SQL> alter session set nls_date_format = 'YYYY-MM-DD';

Session altered.

SQL> select * from dual where sysdate between '1-Jan-10' and '31-Dec-10'; 

no rows selected

(Обратите внимание, что во втором случае ошибка не возвращается. Она предполагает только 10 января 0001 и 10 декабря 0031 года.)

1 голос
/ 04 августа 2010

Кто-то задавал тот же вопрос в OTN: http://forums.oracle.com/forums/thread.jspa?threadID=1081398&tstart=255

Суть проблемы в том, что вы можете не указать "Q" в функции TO_DATE,

Если вы уже указали часть даты, почему бы не указать всю дату?Помните также, что to_date('2010 1','YYYY Q') даст вам 1 января 2010 года, когда вы действительно хотите 31 марта 2010 года ... со второй до полуночи.

0 голосов
/ 01 февраля 2018

Чтобы вычислить в Oracle первый день квартала и последний день квартала из года и квартала: я использую факт

start_month = -2 + 3 * квартал

last_month = 3 * квартал

variable v_year    number

variable v_quarter number

exec :v_year     :=2017

exec :v_quarter:=4

select :v_year    as year,
       :v_quarter as quarter,
       to_date(:v_year||to_char(-2+3*:v_quarter,'fm00'),'yyyymm')        as quarter_start,
       last_day(to_date(:v_year||to_char(3*:v_quarter,'fm00')||'01 23:59:59','yyyymmdd hh24:mi:ss')) as quarter_end
from dual a;


YEAR|QUARTER|QUARTER_START      |QUARTER_END        
2017|      4|2017-10-01 00:00:00|2017-12-31 23:59:59
0 голосов
/ 04 августа 2010

Я думаю, что лучший способ - просто ввести дату начала квартала и даты окончания квартала, даже не заботясь о to_date.Я думаю, что если вы, например, используете

between '1-Jan-10' and '31-Dec-10'

, то вам не нужно (в Oracle, я считаю) указывать дату_, и это не намного сложнее, чем вводить номер квартала

...