2016-05-09 11 views
0

Ich versuche, eine komplexe Abfrage zu schreiben, und ich bin Anfänger in Postgresql.PostgreSQL Abfrage zu gruppieren aufeinanderfolgenden Tagen der Woche

Hier ist mein Schema mit einigen Beispieldaten und bisherigen Fortschritte getan:

http://sqlfiddle.com/#!15/e8b13/35

In Schema no Spalte ist nur Primärschlüssel.

Meine Funktion übernimmt das Argument course_no, führt die Abfrage aus und gibt ein json zurück.

Meine Abfrage sollte wie folgt vorgehen:

  1. Zeitfenster von isodow gruppiert, und Endzeit beginnen.
  2. aufeinander folgenden Wochentagen gruppiert nur erste letzte Woche Tag (wie Mo-Di oder Mo-Fr)
  3. Json von start_timestamp bestellt so min (start_timestamp) ist in der ersten Gruppe in json zeigt.

Beispiel eines course_no mit 47 Zeitschlitzen all am Montag, 11: 00-11: 45:

"[{"schedule":"Mon 11:00-11:45","count_timeslots":47}]" 

A course_no mit 15 Zeitschlitzen am Dienstag, 09: 00-09: 30 und 20 Zeitschlitze am Donnerstag 10: 00-10: 45:

"[{"schedule":"Tue 09:00-09:30","count_timeslots":15},{"schedule":"Thu 10:00-10:45","count_timeslots":20}]" 

A course_no mit 46 Zeitschlitzen auf Mo, Di, Mi und 09: 00-09: 30 und 23 Zeitschlitze auf 17 Mi: 00-18: 00.

NOTICE „Mo-Mi ...“

"[{"schedule":"Mon-Wed 09:00-09:45","count_timeslots":46},{"schedule":"Wed 17:00-18:00","count_timeslots":23}]" 

Ich weiß, wie die Zeit von Zeitstempeln und Gruppe von START_TIME und end_time zu extrahieren, aber ich habe keine Ahnung, wie von aufeinander folgenden Tagen zu einer Gruppe?

Update: Fortschritt

Ich schrieb eine Abfrage, die durch min (start_timestamp) nicht von Schlitzen, GROUP BY start_timestamp und end_timestamp und ORDER ZÄHLT.

Ich brauche nur Hilfe, um sie Isodow (Tage der Woche) nur zu gruppieren, wenn sie aufeinander folgen.

SELECT COUNT(*) AS 
count_timeslot, 
(EXTRACT(hour FROM start_timestamp) || ':' || 
EXTRACT(minute FROM start_timestamp)) AS start_time,  
(EXTRACT(hour FROM end_timestamp) || ':' || EXTRACT(minute FROM end_timestamp)) 
AS end_time FROM timeslot GROUP BY start_time, end_time ORDER BY MIN(start_timestamp); 

Update 2: Fortschritt

Fast diese Abfrage mit Hilfe von Fensterfunktionen von Postgresql abgeschlossen.

  1. Zuerst habe ich gruppiert sie auf der Grundlage start_time, end_time, day_of_week.

  2. Dann habe ich grp durch Berechnung day_of_week - ROW NO() over partition of start_time erstellt, die mir einen konstanten Wert gibt, wenn sie aufeinander folgend sind.

  3. Third I SUM von count_timeslot OVER partition of start_time and grp berechnet.

Meine Suche

SELECT *, SUM(count_timeslot) OVER (PARTITION BY start_time, grp) 
AS n_count_time 
FROM (
    SELECT *, day_of_week - ROW_NUMBER() 
    OVER (PARTITION BY start_time ORDER BY day_of_week) AS grp 
    FROM( 
    SELECT COUNT(*) AS count_timeslot, 
    (EXTRACT(hour FROM start_timestamp) || ':' || EXTRACT(minute FROM 
    start_timestamp)) AS start_time, 
    (EXTRACT(hour FROM end_timestamp) || ':' || EXTRACT(minute FROM 
    end_timestamp)) AS end_time, 
    EXTRACT(ISODOW FROM start_timestamp) AS day_of_week FROM 
    timeslot GROUP BY start_time, end_time, day_of_week 
    ORDER BY MIN(start_timestamp) 
    )foo 
    )foo1; 

Antwort

0

Hier ist die Lösung:

WITH temp(k, v) 
AS(VALUES('Mon', 1), ('Tue', 2), ('Wed', 3), ('Thu', 4), ('Fri', 5), ('Sat', 6), ('Sun', 7)) 

SELECT array_to_json(array_agg(row_to_json(foo4))) 
FROM(
    SELECT grouped || ' ' || start_time || '-' || end_time AS schedule 
    , n_count_time AS count_timeslots 
    FROM(
     SELECT * 
     , ROW_NUMBER() OVER (PARTITION BY start_time, grp) AS row_no 
     FROM(
      SELECT * 
      , CASE 
      WHEN COUNT(*) OVER (PARTITION BY start_time, grp) > 1 
      THEN first_value(name_of_day) OVER (PARTITION BY start_time, grp) 
       || '-' || last_value(name_of_day) OVER (PARTITION BY start_time, grp) 
      ELSE first_value(name_of_day) OVER (PARTITION BY start_time, grp) 
      END AS grouped 
      , SUM(count_timeslot) OVER (PARTITION BY start_time, grp) AS n_count_time 
      FROM(
       SELECT * 
       , day_of_week - ROW_NUMBER() OVER (PARTITION BY start_time ORDER BY day_of_week) AS grp 
       , k AS name_of_day FROM(SELECT COUNT(*) AS count_timeslot 
       , to_char(start_timestamp, 'HH24:MI') AS start_time 
       , to_char(end_timestamp, 'HH24:MI') AS end_time 
       , EXTRACT(ISODOW FROM start_timestamp) AS day_of_week 
       FROM timeslot 
       GROUP BY start_time, end_time, day_of_week 
       ORDER BY MIN(start_timestamp) 
       ) foo, temp WHERE v = day_of_week) foo1 
      ) foo2 
     ) foo3 WHERE row_no = 1 
    ) foo4; 

Arbeits Fiddle: http://sqlfiddle.com/#!15/e8b13/47

Verwandte Themen