如何为历史表中的每个时间段选择和求和()最近的项目?

时间:2014-02-04 21:27:08

标签: sql postgresql

当另一个表中的条目发生更改时,我有一个包含单个条目的历史表。我需要执行一个查询,为每个时间段生成最近条目的sum()或count()。

这是我的表结构的相关位:

CREATE TABLE opportunity_history (
  "id" BIGSERIAL PRIMARY KEY,
  "opportunity_id" TEXT NOT NULL,
  "employee_external_id" TEXT NOT NULL,
  "item_date" TIMESTAMP NOT NULL,
  "amount" NUMERIC(18,2) NOT NULL DEFAULT 0
);

例如,如果我在1月份创建了一个机会,并在2月份更新了两次,我想在1月份计算一次,而在2月份只计算一次。

我所拥有的其他类似查询(不涉及历史记录 - 只是单个数据点)通过在单个查询中加入generate_series()而正常工作。我希望能够实现类似的东西。以下是使用generate_series的示例:

SELECT Periods.day, sum(amount) as value
FROM (
        SELECT generate_series('2012-01-01', '2013-01-01', '1 month'::interval)::date AS day
    ) as Periods LEFT JOIN opportunity ON (
      employee_external_id='...'
AND   close_date >= Periods.day
AND   close_date <  Periods.day
)
GROUP BY 1
ORDER BY 1

然而,这对于opportunity_history并不起作用,因为如果在同一个月内列出一个项目两次就会出现重复。

我真的很难过这个。我试过通过WITH RECURSIVE来做这件事,似乎没有任何东西适合我。

修改

示例数据(跳过id列并使用日期而不是时间戳):

'foo', 'user1', 2013-01-01, 100
'bar', 'user1', 2013-01-02, 50
'foo', 'user1', 2013-01-12, 100
'bar', 'user1', 2013-01-13, 55
'foo', 'user1', 2013-01-23, 100
'foo', 'user1', 2013-02-04, 100
'foo', 'user1', 2013-02-15, 100
'bar', 'user1', 2013-03-01, 55

总和我想要的:

2013-01   155 (foo on 2013-01-23 and bar on 2013-01-13)
2013-02   100 (foo on 2013-02-15)
2013-03   55  (bar on 2013-03-01)

或计数:

2013-01   2
2013-02   1
2013-03   1

另请注意,我很高兴使用&#34;扩展&#34; SQL,如CTE或WITH RECURSIVE或窗口函数(如果需要)。如果我可以在单个查询中执行此操作,我宁愿避免使用Pg / plsql函数中的循环。

2 个答案:

答案 0 :(得分:1)

select item_month, count(*), sum(amount)
from (
   select opportunity_id, 
          item_date,
          amount,
          to_char(item_date, 'yyyy-mm') as item_month,
          row_number() over (partition by opportunity_id, to_char(item_date, 'yyyy-mm') order by item_date desc) as rn
   from opportunity_history
) t
where rn = 1
group by item_month
order by 1;

SQLFiddle示例:http://sqlfiddle.com/#!15/c4152/1

答案 1 :(得分:0)

这是你需要的吗?

select 
  opportunity_id, 
  extract(year from item_date) as year,
  extract(month from item_date) as month,
  count(*), 
  sum(amount)
from opportunity_history
group by opportunity_id, year, month
order by opportunity_id, year, month

如果没有,请解释您需要的其他内容/为何错误。

See fiddle