我尝试在表上收集一些简单的统计信息,比如简化的结构如下:
ID | CREATIONDATE | VALUE |
------------------------------------------------
1 | 2007-01-06 13:54:00.000 | 7 |
2 | 2007-03-07 15:03:00.000 | 8 |
3 | 2008-07-02 18:55:00.000 | 12 |
4 | 2008-09-10 19:12:00.000 | 1 |
5 | 2010-01-06 13:54:00.000 | 4 |
6 | 2010-01-07 07:13:00.000 | 5 |
我想根据创建日期的年份对值进行求和,所以目前我执行以下操作:
select extract('year' from i.creationdate) as d1,
sum(i.value)
from items i
group d1
order by d1;
将输出
2007;15
2008;13
2010;9
有没有什么方法可以改进查询,让它自动为缺少的2009年输出0,即使表格中没有行在2009年有日期?
2007;15
2008;13
2009;0
2010;9
答案 0 :(得分:3)
使用生成系列
中的左外连接select year_list.year,
coalesce(item_list.val,0)
from (select generate_series(2007,2010) as year) AS year_list
left outer join
(select date_part('year',creationdate) item_year,sum(value) as val from i group by item_year) AS item_list
on item_year = year_list.year;
为避免硬编码generate_series中的年份,请在年份部分替换select min()和max()。
答案 1 :(得分:3)
在JOIN中使用generate_series:
SELECT
generate_series as d1,
COALESCE(sum(i.value) , 0)
FROM
generate_series(2005, 2010)
LEFT JOIN items i ON generate_series = extract('year' from i.creationdate)
GROUP BY
d1
ORDER BY
d1;
答案 2 :(得分:1)
我会在执行查询的软件中执行此操作,而不是在查询本身中执行此操作。
我已经通过在SQL中使用for循环来完成这些事情(例如在Oracle中)(毫无疑问在Postgres中有类似的东西)然而我得出的结论是错误的方法。与我简单地用应用程序的编程语言编写代码相比,解决方案更难维护。
SQL返回存在的数据,并对存在的数据进行操作,在这种情况下,没有相关年份的数据。这就是为什么尝试让SQL执行此操作不合适的原因。只需向SQL询问您拥有的数据,以及用您的编程语言为用户生成输出(例如HTML表),然后添加for循环以在第一年和最后一年之间迭代,如果没有结果则打印零
答案 3 :(得分:0)
一种简单(但不是很好)的方法是创建一个(临时)表,在一列中保存所有年份。然后,您只需将数据表加入新表。