我有一张表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_count
和price_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
?
答案 0 :(得分:1)
^
形成Cartesian product天和小时。CROSS JOIN
到LEFT JOIN
的汇总总和 - 方便地使用(day, hour)
子句将列折叠为一个实例。
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
替换为NULL
或0
。