【问题标题】:PostgreSQL Crosstab generate_series of weeks for columnsPostgreSQL 交叉表为列生成周数
【发布时间】:2017-11-17 18:28:36
【问题描述】:

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

表格示例:

+-----+---------+-------------------------+--------------+
| 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 |
+-------+---------+------------+

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

类似的东西

+---------+---------------+--------------+--------------+
| 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            |
+---------+---------------+--------------+--------------+

我一直在网上四处寻找,似乎“动态”生成交叉表的列列表是difficult。我宁愿不要对它们进行硬编码,这对于日期来说似乎很奇怪。或者使用类似case with week number的东西。

我是否应该寻找除交叉表之外的其他解决方案?如果我能为每个用户获得包括所有空值在内的一系列星期,我认为这就足够了。看来现在我的加入策略并没有返回。

【问题讨论】:

    标签: postgresql crosstab generate-series


    【解决方案1】:

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

    您最终要做的就是使用日期表作为SELECT cols FROM table 部分的基础,然后加入它,或者可能使用公用表表达式来创建计算。

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

    【讨论】:

      猜你喜欢
      • 2012-10-04
      • 2021-07-23
      • 2013-09-16
      • 2021-11-08
      • 1970-01-01
      • 2016-09-29
      • 1970-01-01
      • 2019-08-16
      • 2011-03-01
      相关资源
      最近更新 更多