2009-05-07 17 views
3

die folgenden Tabellenstruktur Angenommen:Finden der Tage der Woche in einem bestimmten Zeitraum unter Verwendung von Oracle SQL

Event: 
    id: integer 
    start_date: datetime 
    end_date: datetime 

Gibt es eine Möglichkeit alle Ereignisse abzufragen, die an einem bestimmten Tag der Woche fallen? Zum Beispiel möchte ich eine Abfrage finden, die jedes Ereignis findet, das auf einen Montag fällt. Herauszufinden, ob die start_date oder end_date auf einen Montag fällt, aber ich bin mir nicht sicher, wie man für die Daten zwischen herausfinden.

Pure SQL wird bevorzugt, da hier gespeicherte Prozeduren eine Verzerrung aufweisen, und wir rufen dies aus einem Rails-Kontext auf, der nach meinem Verständnis auch gespeicherte Prozeduren nicht verarbeitet.

Antwort

6
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 
     ) 

Die Unterabfrage Iterierten alle Tage von start_date zu end_date, prüft jeden Tag, und wenn es eine Monday ist, kehrt 1.

Sie können diese Abfrage für komplexere Bedingungen verlängern: überprüfen, ob ein Ereignis auf ANY Monday OR Friday 13th fällt, zum Beispiel:

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 
     ) 

Bitte beachte, dass ich MOD(start_date - TO_DATE(1, 'J') + level - 1, 7) statt TO_CHAR('D') verwenden. Dies liegt daran, dass TO_CHAR('D') von NLS_TERRITORY beeinflusst wird und nicht für die Überprüfung eines bestimmten Wochentages verwendet werden sollte.

Diese Abfrage verwendet keine Indizes und führt immer einen vollständigen Tabellenscan durch. Aber das ist in diesem speziellen Fall kein Problem, da es sehr wahrscheinlich ist, dass ein gegebenes Intervall eine Monday enthält.

Auch wenn die Intervalle 1 Tage lang sind, gibt der Index 14% Werte zurück, wenn die Intervalle länger sind, sogar mehr.

Seit würde in diesem Fall ineffizient sein, und die innere Unterabfrage ist sehr schnell (es verwendet in-memory FAST DUAL Zugriffsverfahren), das, denke ich, wird eine optimale Methode, sowohl durch Effizienz und Erweiterbarkeit sein.

Siehe Eintrag in meinem Blog für weitere Informationen:

+0

Absolut richtig. Ich habe CONNECT BY vorher benutzt. – cpm

+0

* nie * benutzt, das ist. – cpm

1

Das es einfach mehr tun soll:

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 
+0

Wenn ich 01.01.2003 (Mittwoch) als START_DATE und 01.01.2004 (Donnerstag) als END_DATE setze, gibt diese Abfrage nichts zurück. Und es gibt viele Montags zwischen diesen Daten. – Quassnoi

+0

Sie haben Recht, danke. Ich habe es jetzt behoben ... – JosephStyons

Verwandte Themen