我必须生成每天和每小时完成的任务量的报告。这样,报告将看起来像一个网格。
我想在水平轴上是一个月中的天数(从 1 到 31),在垂直轴上是小时数(从 8:00 到 18:00)。
如何在 PostgreSQL 中使用 SQL 从数据库中选择此类数据?
我必须生成每天和每小时完成的任务量的报告。这样,报告将看起来像一个网格。
我想在水平轴上是一个月中的天数(从 1 到 31),在垂直轴上是小时数(从 8:00 到 18:00)。
如何在 PostgreSQL 中使用 SQL 从数据库中选择此类数据?
您正在查找的查询是 SQL 聚合查询。它可能看起来有点复杂,但结构很简单。
select extract(hour from date_time_of_task) as thehour,
sum(case when extract(day from date_time_of_task) = 1 then 1 else 0 end) as day_01,
sum(case when extract(day from date_time_of_task) = 2 then 1 else 0 end) as day_02,
sum(case when extract(day from date_time_of_task) = 3 then 1 else 0 end) as day_03,
sum(case when extract(day from date_time_of_task) = 4 then 1 else 0 end) as day_04,
... up to day 31
group by extract(hour from date_time_of_task)
order by 1
这只是按一天中的时间分组。然后,它会为每个月的每一天手动旋转数据。“总和”计算同时满足两个条件的行数——行的小时数和列的天数。
一个优雅的解决方案的关键元素是generate_series()
、date_part()
、CTEGROUP BY
和,最后是:来自附加模块 tablefunc 的count(*)
函数(带有 1 个参数)。要安装它,每个数据库运行一次:LEFT JOIN
crosstab()
CREATE EXTENSION tablefunc;
询问:
SELECT *
FROM crosstab($x$
WITH x AS (
SELECT date_part('day', date_time_of_task)::int AS d
,date_part('hour', date_time_of_task)::int AS h
,count(*)::int AS ct
FROM tasks
GROUP BY 1,2
)
SELECT d, h, ct
FROM (SELECT generate_series(1,31) AS d, generate_series(0,23) AS h) t
LEFT JOIN x USING (d,h)
ORDER BY 1,2
$x$)
AS orders(
day int
,h8 int, h9 int, h10 int, h11 int, h12 int, h13 int, h14 int, h15 int
,h16 int, h17 int, h18 int);
生成一个包含天数和小时数的矩阵,其中包含您描述的每个字段中的任务数。
顺便说一句:我用过这个辅助。生成目标定义列表的函数:
SELECT 'day int, ' || string_agg (x, ', ')
FROM (SELECT ('h' || generate_series(8,18) || ' int') AS x) a