5

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

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

4 回答 4

3

SQL小提琴

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
于 2012-10-25T13:16:29.373 回答
3

这是一种方法,它使用sum聚合作为具有基于范围的窗口框架的窗口函数的能力 - 查看SUM(...) OVER (PARTITION BY name ORDER BY year ROWS 2 PRECEDING)窗口框架

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

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

于 2012-10-25T13:31:14.107 回答
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
于 2012-10-25T13:09:15.353 回答
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;
于 2012-10-25T14:20:49.227 回答