计算从x年前开始的运行总和

hei*_*los 5 sql postgresql select sum

我有一个表格,实体名称,年份和活动编号如下.在某些年份,没有任何活动.

name | year | act_num
-----+------+---------
aa   | 2000 |       2
aa   | 2001 |       6
aa   | 2002 |       9
aa   | 2003 |      15
aa   | 2005 |      17
b    | 2000 |       3
b    | 2002 |       4
b    | 2003 |       9
b    | 2005 |      12
b    | 2006 |       2
Run Code Online (Sandbox Code Playgroud)

在postgresql上创建它;

CREATE TABLE entity_year_activity (
name character varying(10),
year integer,
act_num integer
);

INSERT INTO entity_year_activity
VALUES
    ('aa', 2000, 2),
    ('aa', 2001, 6),
    ('aa', 2002, 9),
    ('aa', 2003, 15),
    ('aa', 2005, 17),
    ('b', 2000, 3),
    ('b', 2002, 4),
    ('b', 2003, 9),
    ('b', 2005, 12),
    ('b', 2006, 2);
Run Code Online (Sandbox Code Playgroud)

我希望将过去x年的总数与每年每个实体的今年活动数量相同,如下所示.

作为x =三年的例子.

name | year | act_num | total_3_years
-----+------+---------+---------------
aa   | 2000 |       2 |      2
aa   | 2001 |       6 |      8
aa   | 2002 |       9 |     17
aa   | 2003 |      15 |     30
aa   | 2004 |       0 |     24
aa   | 2005 |      17 |     32
b    | 2000 |       3 |      3
b    | 2001 |       0 |      3
b    | 2002 |       4 |      7
b    | 2003 |       9 |     13
b    | 2005 |      12 |     21
b    | 2006 |       2 |     14
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 3

这是一种使用sum聚合作为窗口函数和基于范围的窗口框架的方法 - 请参阅SUM(...) OVER (PARTITION BY name ORDER BY year ROWS 2 PRECEDING)window framing

WITH name_years(gen_name, gen_year) AS (
  SELECT gen_name, s
  FROM generate_series(
    (SELECT min(year) FROM entity_year_activity),
    (SELECT max(year) FROM entity_year_activity)
  ) s CROSS JOIN (SELECT DISTINCT name FROM entity_year_activity) n(gen_name)
),
windowed_history(name, year,act_num,last3_actnum) AS (
  SELECT
    gen_name, gen_year, coalesce( act_num, 0),
    SUM(coalesce(act_num,0)) OVER (PARTITION BY gen_name ORDER BY gen_year ROWS 2 PRECEDING)
  FROM name_years 
  LEFT OUTER JOIN entity_year_activity ON (gen_name = name AND gen_year = year)
)
SELECT name, year, act_num, sum(last3_actnum) as total_3_years
FROM windowed_history
GROUP BY name, year, act_num
HAVING sum(last3_actnum) <> 0
ORDER BY name, year;
Run Code Online (Sandbox Code Playgroud)

请参阅SQLFiddle

需要生成本身没有条目的年份的条目使该查询变得复杂。我生成一个包含所有(名称、年份)对的表,然后left outer join entity_year_activity在进行窗口求和之前在其上生成,以便表示所有名称集的所有年份。这就是为什么这如此复杂。然后,我过滤聚合结果以排除总和为零的条目。