我正在尝试编写一个复杂的查询,我是Postgresql的初学者。
以下是我的架构,其中包含一些示例数据,目前已完成进度:
http://sqlfiddle.com/#!15/e8b13/35
在架构no
列中,只是主键。
我的函数接受参数course_no
,执行查询并返回一个json。
我的查询应该执行以下操作:
在星期一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的窗口函数的帮助下,几乎完成了这个查询。
首先,我根据start_time
,end_time
,day_of_week
对其进行分组。
然后我通过计算grp
来创建day_of_week - ROW NO() over partition of start_time
,它在连续时给我一个常数值。
count_timeslot OVER partition of start_time and grp
的总和。我的查询
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;
答案 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;