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
в памяти), я думаю, что это будет оптимальный метод, как по эффективности, так и по расширяемости .
См. Запись в моем блоге для более подробной информации: