PostgreSQL交叉表为列生成周系列



从一个"时间条目"表中,我试图为每个用户创建一个每周总计的报告。

表格示例:

+-----+---------+-------------------------+--------------+
| id  | user_id | start_time              | hours_worked |
+-----+---------+-------------------------+--------------+
| 997 | 6       | 2018-01-01 03:05:00 UTC | 1.0          |
| 996 | 6       | 2017-12-01 05:05:00 UTC | 1.0          |
| 998 | 6       | 2017-12-01 05:05:00 UTC | 1.5          |
| 999 | 20      | 2017-11-15 19:00:00 UTC | 1.0          |
| 995 | 6       | 2017-11-11 20:47:42 UTC | 0.04         |
+-----+---------+-------------------------+--------------+

现在我可以运行以下程序,基本上得到我需要的

SELECT COALESCE(SUM(time_entries.hours_worked),0) AS total, 
time_entries.user_id, 
week::date
--Using generate_series here to account for weeks with no time entries when
--doing the join
FROM generate_series( (DATE_TRUNC('week', '2017-11-01 00:00:00'::date)),
(DATE_TRUNC('week', '2017-12-31 23:59:59.999999'::date)),
interval '7 day') as week LEFT JOIN time_entries
ON DATE_TRUNC('week', time_entries.start_time) = week
GROUP BY week, time_entries.user_id
ORDER BY week

这将返回

+-------+---------+------------+
| total | user_id | week       |
+-------+---------+------------+
| 14.08 | 5       | 2017-10-30 |
| 21.92 | 6       | 2017-10-30 |
| 10.92 | 7       | 2017-10-30 |
| 14.26 | 8       | 2017-10-30 |
| 14.78 | 10      | 2017-10-30 |
| 14.08 | 13      | 2017-10-30 |
| 15.83 | 15      | 2017-10-30 |
| 8.75  | 5       | 2017-11-06 |
| 10.53 | 6       | 2017-11-06 |
| 13.73 | 7       | 2017-11-06 |
| 14.26 | 8       | 2017-11-06 |
| 19.45 | 10      | 2017-11-06 |
| 15.95 | 13      | 2017-11-06 |
| 14.16 | 15      | 2017-11-06 |
| 1.00  | 20      | 2017-11-13 |
| 0     |         | 2017-11-20 |
| 2.50  | 6       | 2017-11-27 |
| 0     |         | 2017-12-04 |
| 0     |         | 2017-12-11 |
| 0     |         | 2017-12-18 |
| 0     |         | 2017-12-25 |
+-------+---------+------------+

然而,这很难解析,尤其是在一周内没有数据的情况下。我想要的是一个透视表或交叉表,其中周是列,行是用户。并包括每个的null(例如,如果用户在该周或一周内没有条目,而没有任何用户的条目)。

像这样的

+---------+---------------+--------------+--------------+
| user_id | 2017-10-30    | 2017-11-06   | 2017-11-13   |
+---------+---------------+--------------+--------------+
| 6       | 4.0           | 1.0          | 0            |
| 7       | 4.0           | 1.0          | 0            |
| 8       | 4.0           | 0            | 0            |
| 9       | 0             | 1.0          | 0            |
| 10      | 4.0           | 0.04         | 0            |
+---------+---------------+--------------+--------------+

我一直在网上四处寻找,似乎很难"动态"生成交叉表的列列表。我宁愿不硬编码,这似乎很奇怪的日期。或者使用类似于本案例的周数。

除了交叉表之外,我应该寻找其他解决方案吗?如果我能得到每个用户的一系列周,包括所有的null,我认为这就足够了。现在看来,我的加盟策略并没有回报。

就我个人而言,我会使用日期维度表,并将该表用作查询的基础。我发现在这些类型的计算中使用表格数据要容易得多,因为它使SQL更容易读取和维护。有一篇关于在PostgreSQL中创建日期维度表的好文章https://medium.com/@duffin/createing-a-date-dimension-table-in-postgresql-af3f8e2941ac,不过您可以使用该表的一个简单得多的版本。

最终,您要做的是使用Date表作为SELECT cols FROM table部分的基础,然后根据它进行连接,或者可能使用Common table Expression来创建计算。

如果您想演示如何创建这样的查询,我将为此编写一个解决方案。

相关内容

  • 没有找到相关文章

最新更新