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

时间:2012-10-25 13:02:06

标签: 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

在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);

我想拥有过去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

4 个答案:

答案 0 :(得分:3)

SQL Fiddle

select
    s.name,
    d "year",
    coalesce(act_num, 0) act_num,
    coalesce(act_num, 0)
    + lag(coalesce(act_num, 0), 1, 0) over(partition by s.name order by d)
    + lag(coalesce(act_num, 0), 2, 0) over(partition by s.name order by d)
    total_3_years
from
    entity_year_activity eya
    right join (
        generate_series(
            (select min("year") from entity_year_activity),
            (select max("year") from entity_year_activity)
        ) d cross join (
        select distinct name
        from entity_year_activity
        ) f
    ) s on s.name = eya.name and s.d = eya."year"
order by s.name, d

答案 1 :(得分: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;

请参阅SQLFiddle

生成条目多年没有条目的需要使这个查询复杂化。在生成窗口总和之前,我生成一个包含所有(名称,年份)对的表,然后是left outer join entity_year_activity,因此表示所有名称集的所有年份。这就是为什么这么复杂。然后我过滤聚合结果以排除总和为零的条目。

答案 2 :(得分:2)

SELECT en_key.name, en_key.year, en_key.act_num, SUM(en_sum.act_num) as total_3_years
FROM entity_year_activity en_key
  INNER JOIN entity_year_activity en_sum
     ON en_key.name = en_sum.name
WHERE en_sum.year BETWEEN en_key.year - 2 AND en_key.year
GROUP BY en_key.name, en_key.year

答案 3 :(得分:1)

另一个尝试。但是,这个缺少0行年份:

select t1.name, t1.year, t1.act_num,
      (select sum(t2.act_num) from entity_year_activity t2
                              where t2.year between t1.year - 2 and t1.year
                                    and t2.name = t1.name) total
from entity_year_activity t1;