2017-02-03 3 views
1

Ich habe eine plpgsql-Funktion, die TSTZRANGE zwischen zwei Daten nach gespeicherten Regeln in einer Tabelle mit dem Namen timeslots generiert. Es funktioniert gut, aber jetzt habe ich eine neue Anforderung und fügte ein TSTZRANGE-Feld datespan der timeslots-Tabelle hinzu, die ich auch filtern muss, so dass nur Bereiche zurückgegeben werden, die in diesem Feldwert enthalten sind.SQL-Abfrage auf die generierten Ergebnisse filtern

Zeigt Ihnen hier Teil der Funktion, die ich ändern muss. eid, fromdate und todate sind Parameter, die an die Funktion übergeben werden.

SELECT TSTZRANGE(
    (series::DATE + ts1.start)::TIMESTAMPTZ AT TIME ZONE 'UTC', 
    (series::DATE + ts1.end)::TIMESTAMPTZ AT TIME ZONE 'UTC' 
) AS range 
FROM 
    timeslots AS ts1, 
    generate_series(fromdate, todate, '1 day') AS series 
WHERE 
    eid = ts1.event_id AND 
    EXTRACT(DOW FROM series) = ANY(ts1.weekdays) 
ORDER BY 
    range 

Also, was ich tun möchte, ist ein Filter wie WHERE range <@ ts1.datespan hinzufügen, aber ich kann es nicht schaffen, es überall zu setzen, das funktioniert.

Beispiel: diese Informationen in timeslots Tabelle:

id | start | end | weekdays | event_id |   datespan 
----+----------+----------+---------------+---------------------------------------------------------------- 
1 | 12:00:00 | 14:00:00 | {1,2,3,5,6,0} |  1 | ["2017-01-01 00:00:00+00","2017-02-01 00:00:00+00") 
2 | 09:00:00 | 11:00:00 | {1,2,3,5,6,0} |  1 | [null, null) 
3 | 15:00:00 | 17:00:00 | {1,2,3,5,6,0} |  1 | ["2017-02-01 00:00:00+00","2017-03-01 00:00:00+00") 

Das Ergebnis der SELECT oben aufrufen, wenn eid=1, fromdate='2017-02-02' und todate='2017-02-03' sollte wie folgt aussehen:

     range       
----------------------------------------------------- 
["2017-02-02 09:00:00+00","2017-02-02 11:00:00+00") 
["2017-02-02 15:00:00+00","2017-02-02 17:00:00+00") 
["2017-02-03 09:00:00+00","2017-02-03 11:00:00+00") 
["2017-02-03 15:00:00+00","2017-02-03 17:00:00+00") 
+0

Bitte ** [EDIT] ** Ihre Frage und fügen Sie einige Beispieldaten und die erwartete Ausgabe basierend auf diesen Daten. [** Formatierter Text **] (http://stackoverflow.com/help/formatting) bitte, [keine Screenshots] (http://meta.stackoverflow.com/questions/285551/why-may-i-not -upload-images-of-code-auf-so-wenn-eine-Frage/285557 # 285557) –

Antwort

1

Am einfachsten zu ist Verwenden Sie lateral:

Das LATERAL Schlüsselwort kann einem Sub-SELECT FROM Element vorausgehen. Dadurch kann sich das Sub-SELECT auf Spalten von FROM-Elementen beziehen, die davor in der FROM-Liste erscheinen. (Ohne LATERAL jeder Teil SELECT unabhängig ausgewertet und so kann keinen Querverweis andere von Posten.)

select ts1.*, range 
from 
    timeslots as ts1, 
    generate_series('2017-02-02'::date, '2017-02-03', '1 day') as series 
    cross join lateral 
    (
     select tstzrange (
      (series::date + ts1.start)::timestamptz at time zone 'utc', 
      (series::date + ts1.end)::timestamptz at time zone 'utc' 
     ) as range 
    ) range 
where 
    1 = ts1.event_id and 
    extract(dow from series) = any(ts1.weekdays) and 
    range <@ ts1.datespan 
order by range 
; 
id | start | end | weekdays | event_id |      datespan      |      range       
----+----------+----------+---------------+----------+-----------------------------------------------------+----------------------------------------------------- 
    2 | 09:00:00 | 11:00:00 | {1,2,3,5,6,0} |  1 | (,)             | ["2017-02-03 09:00:00+00","2017-02-03 11:00:00+00") 
    3 | 15:00:00 | 17:00:00 | {1,2,3,5,6,0} |  1 | ["2017-02-01 00:00:00+00","2017-03-01 00:00:00+00") | ["2017-02-03 15:00:00+00","2017-02-03 17:00:00+00") 

Die Alternative es in einer äußeren Abfrage zu wickeln wäre. Jetzt müssen Sie entscheiden/informieren, was mit den Nullgrenzen geschehen soll.

+0

Danke, es funktioniert! Leere Werte in Bereichen bedeutet, dass es unbegrenzt ist, so dass der Bereich "[null, null)" alle anderen Bereiche enthält, aber vielleicht ist das nicht die richtige Notation. –

Verwandte Themen