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 访问方法),我认为这将是一种最佳方法,无论是效率还是可扩展性.
查看我博客中的条目了解更多详情: