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
)
Les sous-requêtes itère tous les jours de start_date
à end_date
, vérifie chaque jour, et si elle est un Monday
, retourne 1
.
Vous pouvez facilement étendre cette requête pour des conditions plus complexes: vérifier si un événement tombe sur ANY Monday OR Friday 13th
, par exemple:
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
)
Notez que j'utilise MOD(start_date - TO_DATE(1, 'J') + level - 1, 7)
au lieu de TO_CHAR('D')
. En effet, TO_CHAR('D')
est affecté par NLS_TERRITORY
et ne doit pas être utilisé pour vérifier un certain jour de la semaine.
Cette requête n'utilise aucun index et effectue toujours une analyse de table complète. Mais ce n'est pas un problème dans ce cas particulier, car il est hautement probable qu'un intervalle donné contiendra un Monday
.
Même si les intervalles sont 1
jour, l'index renverra 14%
des valeurs, si les intervalles sont plus longs, même plus.
Depuis serait inefficace dans ce cas, et la sous-requête intérieure est très rapide (il utilise FAST DUAL
méthode d'accès en mémoire), cela, je pense, sera une méthode optimale, à la fois par l'efficacité et l'extensibilité.
Voir l'entrée dans mon blog pour plus de détails:
Absolument correct. J'ai utilisé CONNECT BY avant. – cpm
* jamais * utilisé, c'est-à-dire. – cpm