2016-10-31 4 views
2

Ich möchte einen Artikel auswählen, bei dem das Datum in einer bestimmten Woche im Jahr liegt.Datum in einer bestimmten Woche suchen

Zum Beispiel:

SELECT item 
FROM table 
WHERE my_date in week 44 

Wo Woche 44 von Montag ist 31/10 bis Sonntag 11.06.

Ich weiß, dass die Wochennummer mit

Wie kann ich das tun bekommen? Danke.

+2

Wenn 'my_date' eine' DATE'-Spalte ist, dann ist der Ausdruck 'to_date (my_date, 'MM/DD/YYYY') 'überhaupt nicht sinnvoll. Es konvertiert das 'DATE' in ein varchar, um es wieder in' DATE' umzuwandeln, mit dem es beginnen sollte. Niemals 'to_date()' für Werte aufrufen, die bereits ein 'date' sind –

+1

Betreffs des @ a_horse_with_no_name-Kommentars: Welcher Datentyp ist die 'my_date'-Spalte? Ihre zusammengesetzte Funktion sieht korrekt aus, wenn es ein varchar2 ist (was es nicht sein sollte, es sollte DATUM-Datentyp sein, aber diese Art von schlechtem Tabellenentwurf ist sehr üblich, und oft müssen Sie die Hand spielen, die Sie ausgeteilt bekommen haben). – mathguy

+0

my_date ist ein DATE, ich kann einfach to_char (my_date, 'IW') – iAmoric

Antwort

1

mit ISO Wochen zu arbeiten, ist nicht trivial, weil Woche 1 in Vorjahr und ersten Tagen im Januar als Woche gezählt beginnen kann 52 oder 53.

Also, ohne ein Jahr nur Woche Nummer angeben kann mehrdeutig (für die Wochennummer 52, 53, 1).

Die beste Funktion, die ich, um den ersten Tag einer ISO-Woche zu bekommen gefunden ist

NEXT_DAY(TO_DATE(yearNo || '0104', 'YYYYMMDD') - INTERVAL '7' DAY, 'MONDAY') + (weekNo - 1) * 7 

Also, für Ihren Bedarf wäre es

SELECT item 
FROM table 
WHERE my_date 
    between NEXT_DAY(TO_DATE(yearNo || '0104', 'YYYYMMDD') - INTERVAL '7' DAY, 'MONDAY') + (weekNo - 1) * 7 
     AND 6 + (NEXT_DAY(TO_DATE(yearNo || '0104', 'YYYYMMDD') - INTERVAL '7' DAY, 'MONDAY') + (weekNo - 1) * 7) 

Tatsächlich ist die „vollen Fehler nachgewiesen werden "Weg wäre diese:

FUNCTION ISOWeekDate(weekNo INTEGER, yearNo INTEGER) RETURN DATE DETERMINISTIC IS 
    res DATE; 
BEGIN 
    IF weekNo > 53 OR weekNo < 1 THEN 
     RAISE VALUE_ERROR;  
    END IF; 
    res := NEXT_DAY(TO_DATE(yearNo || '0104', 'YYYYMMDD') - INTERVAL '7' DAY, 'MONDAY') + (weekNo - 1) * 7; 
    IF TO_CHAR(res, 'fmIYYY') = yearNo THEN 
     RETURN res; 
    ELSE 
     RAISE VALUE_ERROR; 
    END IF; 
END ISOWeekDate; 
+1

Ich würde sagen, die Arbeit mit ISO Wochen ist trivial ('trunc (dt, 'iw')') - es ist Nicht-ISO-Wochen, die nicht sind trivial, aufgrund der unterschiedlichen Definitionen, die sie haben könnten. ISO Wochen sind festgelegt, also ... – Boneist

0

Wenn der Datentyp der my_date Spalte ist in der Tat, VARCHAR 2 (was nicht sein sollte, aber es ist oft), dann müssen Sie es zuerst in Datum und dann zurück in Char (String) in einem anderen Format konvertieren. Wenn 44 nicht unbedingt eine Zahl ist, sondern das Ergebnis einer Berechnung oder einer Unterabfrage oder eines Werts in einer anderen Tabelle (und wenn es vom Datentyp NUMBER ist), müssen Sie genau das tun, was Sie getan haben . Was war das Problem damit?

Vielleicht möchten Sie wissen, ob dies effizienter durchgeführt werden kann So zum Beispiel, können Sie stattdessen schreiben die where Zustand als

my_date between (something) and (something else) 

, die die Verwendung eines Index auf my_date erlauben würde? Die Antwort ist NEIN, wenn my_date im VARCHAR2-Format ist - Sie müssten es immer noch in to_date() umhüllen, so dass Sie den Index verlieren würden.

Aber Sie können eine Indexfunktion auf to_date(my_date) bauen, die Ihnen vielleicht auch in anderen Fragen helfen würde. Also ist die Frage, wie Sie Ihre aktuelle Anfrage effizienter gestalten können, sinnvoll.Nun ist die Schwierigkeit der ISO-Woche nicht klar definiert (Sie sagen auch nicht, welches Jahr), also ist die Annahme, dass das Datum in der ISO-Woche 44 sein soll, egal in welchem ​​Jahr es ist. Wenn das Datum a ist reine Datum (Zeitkomponente gleich 00.00.00), können Sie dies tun:

where to_date(my_date, 'MM/DD/YYYY') between 
      trunc(sysdate, 'iw') + 7 * (44 - to_number(to_char(sysdate, 'iw')))  and 
      trunc(sysdate, 'iw') + 7 * (44 - to_number(to_char(sysdate, 'iw'))) + 6 

Es gibt eine Menge von Berechnung auf der rechten Seite, aber sie sind nur einmal für alle Zeilen erfolgt in dein Tisch; sie werden im Wesentlichen keine Zeit brauchen.

Verwandte Themen