每个工作日按小时分组

时间:2015-07-30 19:20:54

标签: sql database postgresql join

我有一张表orders

  id  |  price  |  items_count  |         created_at
------+---------+---------------+------------------------
   1  |  16.50  |      3        | 2015-07-21 12:52:00.824
   2  |  50.00  |      1        | 2015-07-21 12:54:42.658
   3  |  12.00  |     10        | 2015-07-22 07:21:47.808
   .  |   .     |      .        |             .
   .  |   .     |      .        |             .
   .  |   .     |      .        |             .

依旧......

现在我希望从上个月按工作日获得订单数量价格总和(数字从0到6) )和小时(从0到23的数字)。

我设法做的是:

SELECT EXTRACT('dow' FROM to_timezone(created_at, 'CEST', 0)) AS DAY,
(EXTRACT('hour' FROM to_timezone(created_at, 'CEST', 0)) + 0)::INT % 24 AS HOUR,
COUNT(DISTINCT id) AS orders_count,
SUM(price) AS price_total
FROM orders
WHERE created_at BETWEEN '2015-06-30 22:00:00.000000'
AND '2015-07-31 21:59:59.999999'
GROUP BY extract('dow' from to_timezone(created_at, 'CEST', 0)),
EXTRACT('hour' from to_timezone(created_at, 'CEST', 0))
ORDER BY 1 ASC, EXTRACT('hour' from to_timezone(created_at, 'CEST', 0));

这就是我得到的 - 当前结果

 day | hour | orders_count | price_total
-----+------+--------------+-------------
   0 |    7 |           11 |    298.00
   0 |    9 |            8 |     64.00
   1 |    8 |            1 |     12.50
   1 |   12 |            3 |     69.00 
   2 |   10 |            2 |    112.00
   2 |   13 |            1 |    100.00
   2 |   14 |           13 |   2163.70
   2 |   21 |            4 |    357.00

依旧......

现在我希望在一天内包含所有小时,如果在给定时间内没有订单,则将0放在orders_countprice_total列中。所以期望的结果应该如下所示:

 day | hour | orders_count | price_total
-----+------+--------------+-------------
   0 |    0 |            0 |      0.00
   0 |    1 |            0 |      0.00
   0 |    2 |            0 |      0.00
   0 |    3 |            0 |      0.00
   0 |    4 |            0 |      0.00
   0 |    5 |            0 |      0.00
   0 |    6 |            0 |      0.00
   0 |    7 |           11 |    298.00
   0 |    8 |            0 |      0.00
   0 |    9 |            8 |     64.00
   0 |   10 |            0 |      0.00

依此类推 - 我需要7天[0,6]以及每天24小时[0,23]以及0汇总列。

我想出了一天使用generate_series来获取所有时间的想法:

SELECT EXTRACT(hour from generate_series)
FROM generate_series('2015-07-01 00:00'::timestamp, '2015-07-01 23:00', '1 hour');

我的问题是我不知道如何将当前结果所有时间结合起来。我应该使用什么样的JOIN?如果给定行没有订单,如何在前面提到的列中插入0

1 个答案:

答案 0 :(得分:1)

  1. 使用^形成Cartesian product天和小时。
  2. CROSS JOINLEFT JOIN的汇总总和 - 方便地使用(day, hour)子句将列折叠为一个实例。
  3. Joins in the manual.

    USING

    还清理了一下你的查询 使用标准SQL构造SELECT day, hour , COALESCE(orders_count, 0) AS orders_count , COALESCE(price_total, 0.0) AS price_total FROM generate_series(0,6) day CROSS JOIN generate_series(0,23) hour LEFT JOIN ( SELECT EXTRACT('dow' FROM created_at AT TIME ZONE 'CEST')::int AS day , EXTRACT('hour' FROM created_at AT TIME ZONE 'CEST')::int AS hour , count(DISTINCT id) AS orders_count , sum(price) AS price_total FROM orders WHERE created_at BETWEEN '2015-06-30 22:00:00.000000' AND '2015-07-31 21:59:59.999999' GROUP BY 1, 2 ) o USING (day, hour) ORDER BY 1, 2; 而不是Postgres函数AT TIME ZONE。详细说明:

    删除了多余的模运算符 to_timezone()

    使用COALESCE()% 24替换为NULL0