Поиск дней недели в диапазоне дат с помощью Oracle Oracle - PullRequest
3 голосов
/ 08 мая 2009

Предположим, следующая структура таблицы:

Event: 
  id: integer
  start_date: datetime
  end_date: datetime

Есть ли способ запросить все события, которые выпадают на определенный день недели? Например, я хотел бы найти запрос, который бы обнаруживал каждое событие, выпадающее в понедельник. Выяснить, выпадет ли start_date или end_date в понедельник, но я не уверен, как узнать даты между.

Чистый SQL предпочтителен, так как здесь есть смещение против хранимых процедур, и мы вызываем это из контекста Rails, который, насколько я понимаю, не обрабатывает и хранимые процедуры.

Ответы [ 2 ]

6 голосов
/ 08 мая 2009
SELECT  *
FROM    event
WHERE   EXISTS
        (
        SELECT  1
        FROM    dual
        WHERE   MOD(start_date - TO_DATE(1, 'J') + level - 1, 7) = 6
        CONNECT BY
                level <= end_date - start_date + 1
        )

Подзапрос повторяет все дни с start_date до end_date, проверяет каждый день, и если это Monday, возвращает 1.

Вы можете легко расширить этот запрос для более сложных условий: проверьте, попадает ли событие на ANY Monday OR Friday 13th, например:

SELECT  *
FROM    event
WHERE   EXISTS  (
        SELECT  1
        FROM    dual
        WHERE   MOD(start_date - TO_DATE(1, 'J') + level - 1, 7) = 6
                OR (MOD(start_date - TO_DATE(1, 'J') + level - 1, 7) = 3 AND TO_CHAR(start_date + level - 1, 'DD') = '13')
        CONNECT BY
                level <= end_date - start_date + 1
        )

Обратите внимание, что я использую MOD(start_date - TO_DATE(1, 'J') + level - 1, 7) вместо TO_CHAR('D'). Это потому, что TO_CHAR('D') зависит от NLS_TERRITORY и не должно использоваться для проверки на определенный день недели.

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

Даже если интервалы 1 дня, индекс вернет 14% значений, если интервалы длиннее, даже больше.

Поскольку INDEX SCAN в этом случае будет неэффективным, а внутренний подзапрос будет очень быстрым (он использует метод доступа FAST DUAL в памяти), я думаю, что это будет оптимальный метод, как по эффективности, так и по расширяемости .

См. Запись в моем блоге для более подробной информации:

1 голос
/ 08 мая 2009

Это должно сделать это проще:

select *
from event
where 2 between to_number(trim(to_char(start_date,'D')))
            and to_number(trim(to_char(end_date,'D')))
   or (end_date - start_date) > 6
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...