已经提供的答案都是正确的,但为了丰富一下,这里介绍一种使用'tablefunc'扩展来对结果进行交叉表格化的方法,使其与您的示例完全相同。
在使用之前,您必须创建tablefunc扩展(它在postgresql的contrib包中可用):
CREATE EXTENSION IF NOT EXISTS tablefunc;
以下是查询语句,假设输入数据位于表t的created_at列中:
SELECT * FROM CROSSTAB($$SELECT h.hour AS hour_of_day,
dow.day AS day,
COUNT(t.created_at)::INT
FROM (values('Mon'),('Tue'),('Wed'),('Thu'),('Fri'),('Sat'),('Sun')) AS dow(day)
CROSS JOIN generate_series(0,23) as h(hour)
LEFT JOIN t ON to_char(t.created_at, 'Dy')=dow.day AND extract(hour from t.created_at)=h.hour
GROUP BY dow.day,h.hour
ORDER BY h.hour,dow.day$$) AS d(Hour int, "Mon" int,"Tue" int,"Wed" int,"Thu" int,"Fri" int,"Sat" int,"Sun" int);
需要注意的要点:
- 查询将天数集合与00-23小时集合进行交叉连接,以便所有输出中的单元格都存在,即使对于给定单元格在输入表中没有数据也是如此。
- crosstab函数接受SQL查询作为输入并交叉制表结果,生成记录集。
- 由于某些原因我不完全清楚,我必须将count的返回值转换为类型(我猜它返回BIGINT?)
- 您(不幸的是)必须通过AS子句在结果中拼写列名,如所示。
以下是结果:
hour | Mon | Tue | Wed | Thu | Fri | Sat | Sun
------+-----+-----+-----+-----+-----+-----+-----
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0
3 | 0 | 0 | 0 | 0 | 0 | 0 | 0
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0
5 | 0 | 0 | 0 | 0 | 0 | 0 | 0
6 | 0 | 0 | 0 | 0 | 0 | 0 | 0
7 | 0 | 0 | 0 | 0 | 0 | 0 | 0
8 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 | 0 | 0 | 0 | 0 | 0 | 0 | 1
11 | 0 | 0 | 0 | 0 | 0 | 0 | 0
12 | 0 | 0 | 0 | 0 | 0 | 0 | 0
13 | 0 | 0 | 0 | 1 | 0 | 0 | 0
14 | 0 | 0 | 0 | 0 | 0 | 0 | 0
15 | 0 | 0 | 0 | 0 | 0 | 0 | 0
16 | 0 | 0 | 0 | 0 | 0 | 0 | 0
17 | 0 | 0 | 1 | 0 | 0 | 0 | 0
18 | 0 | 0 | 0 | 0 | 0 | 0 | 0
19 | 0 | 0 | 0 | 0 | 0 | 0 | 0
20 | 0 | 0 | 0 | 0 | 0 | 0 | 0
21 | 0 | 0 | 0 | 0 | 0 | 0 | 0
22 | 0 | 0 | 0 | 0 | 0 | 0 | 0
23 | 0 | 0 | 0 | 0 | 1 | 0 | 0
(24 rows)
这是从样本数据生成的:
created_at
2014-06-12 23:06:03.746884
2014-01-15 10:00:00
2014-05-25 13:00:00
2014-03-01 17:00:00
(4 rows)