PostgreSQL查询将连续几天分组

时间:2016-05-09 10:56:23

标签: sql postgresql

我正在尝试编写一个复杂的查询,我是Postgresql的初学者。

以下是我的架构,其中包含一些示例数据,目前已完成进度

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

在架构no列中,只是主键。

我的函数接受参数course_no,执行查询并返回一个json。

我的查询应该执行以下操作:

  1. 时间段按isodow,开始时间和结束时间分组。
  2. 连续工作日分组仅显示第一个上周工作日(如 周一至周五或周一至周五)
  3. Json按start_timestamp排序,因此min(start_timestamp)位于json的第一个组中。
  4. 在星期一11:00-11:45:

    的47个时段的course_no示例
    "[{"schedule":"Mon 11:00-11:45","count_timeslots":47}]"
    

    课程_在星期二09:00-09:30有15个时段,在星期四10:00-10:45有20个时段:

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

    在星期一,星期二和星期三09:00-09:30以及星期三17:00-18:00的23个时段有46个时段的航线_no。

    通知“周一至周三......”

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

    我知道如何通过start_time和end_time从时间戳和分组中提取时间,但我不知道如何连续分组?

    更新:进度

    我写了一个查询,其中没有插槽,GROUP BY start_timestamp和end_timestamp以及ORDER BY min(start_timestamp)。

    我只需要帮助就可以将它们分组为isodow(星期几),只有当它们是连续的时候。

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

    更新2:进度

    在Postgresql的窗口函数的帮助下,几乎完成了这个查询。

    1. 首先,我根据start_timeend_timeday_of_week对其进行分组。

    2. 然后我通过计算grp来创建day_of_week - ROW NO() over partition of start_time,它在连续时给我一个常数值。

    3. 第三,我计算了count_timeslot OVER partition of start_time and grp的总和。
    4. 我的查询

      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;
      

1 个答案:

答案 0 :(得分:0)

以下是解决方案:

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;

工作小提琴:http://sqlfiddle.com/#!15/e8b13/47