GROUP BY下个月超过N年

时间:2015-07-30 08:48:13

标签: sql postgresql group-by aggregation

我需要汇总按"地平线"下个月超过5年的12个月:
假设我们 2015-08-15

SUM amount from  0 to 12 next months (from 2015-08-16 to 2016-08-15)
SUM amount from 12 to 24 next months (from 2016-08-16 to 2017-08-15)
SUM amount from 24 to 36 next months ...
SUM amount from 36 to 48 next months
SUM amount from 48 to 60 next months

这是一个fiddled数据集示例:

+----+------------+--------+
| id | date       | amount |
+----+------------+--------+
|  1 | 2015-09-01 |     10 |
|  2 | 2015-10-01 |     10 |
|  3 | 2016-10-01 |     10 |
|  4 | 2017-06-01 |     10 |
|  5 | 2018-06-01 |     10 |
|  6 | 2019-05-01 |     10 |
|  7 | 2019-04-01 |     10 |
|  8 | 2020-04-01 |     10 |
+----+------------+--------+

以下是预期结果:

+---------+--------+
| horizon | amount |
+---------+--------+
|       1 |     20 |
|       2 |     20 |
|       3 |     10 |
|       4 |     20 |
|       5 |     10 |
+---------+--------+

我怎样才能将这12个月分组和#34;视野" ?

我标记了 PostgreSQL ,但我实际上正在使用ORM,所以它只是为了找到这个想法。 (顺便说一句,我无法访问日期格式化功能)

6 个答案:

答案 0 :(得分:6)

我会将12个月的时间框架和分组分开:

int NathanRoad[80] = {...};
int *address1 = &NathanRoad[11];
int *q;
int s;
q = address1 + 3; /* OK */
s = *(address1 + 3); /* OK */
q = address1 + 75; /* Bad */
q = address1 + 69; /* OK */
s = *(address1 + 69); /* Bad */

SQL Fiddle

灵感来自:Postgresql SQL GROUP BY time interval with arbitrary accuracy (down to milli seconds)

答案 1 :(得分:1)

假设你需要从当前日期到明年这一天的间隔等等,我会这样查询:

SELECT 1 AS horizon, SUM(amount) FROM dataset
WHERE date > now()
AND date < (now() + '12 months'::INTERVAL)
UNION
SELECT 2 AS horizon, SUM(amount) FROM dataset
WHERE date > (now() + '12 months'::INTERVAL)
AND date < (now() + '24 months'::INTERVAL) 
UNION
SELECT 3 AS horizon, SUM(amount) FROM dataset
WHERE date > (now() + '24 months'::INTERVAL)
AND date < (now() + '36 months'::INTERVAL)
UNION
SELECT 4 AS horizon, SUM(amount) FROM dataset
WHERE date > (now() + '36 months'::INTERVAL)
AND date < (now() + '48 months'::INTERVAL)
UNION
SELECT 5 AS horizon, SUM(amount) FROM dataset
WHERE date > (now() + '48 months'::INTERVAL)
AND date < (now() + '60 months'::INTERVAL)
ORDER BY horizon;

您可以使用其他变量对其进行概括并进行类似的操作:

SELECT number AS horizon, SUM(amount) FROM dataset
WHERE date > (now() + ((number - 1) * '12 months'::INTERVAL))
AND date < (now() + (number * '12 months'::INTERVAL));

其中number是范围[1,5]

中的整数

这是我从小提琴那里得到的:

| horizon | sum |
|---------|-----|
|       1 |  20 |
|       2 |  20 |
|       3 |  10 |
|       4 |  20 |
|       5 |  10 |

答案 2 :(得分:1)

也许是CTE?

WITH RECURSIVE grps AS
(
  SELECT 1 AS Horizon, (date '2015-08-15') + interval '1' day AS FromDate, (date '2015-08-15') + interval '1' year AS ToDate
  UNION ALL
  SELECT Horizon + 1, ToDate + interval '1' day AS FromDate, ToDate + interval '1' year
  FROM grps WHERE Horizon < 5
)
SELECT 
  Horizon, 
  (SELECT SUM(amount) FROM dataset WHERE date BETWEEN g.FromDate AND g.ToDate) AS SumOfAmount
FROM 
  grps g

SQL fiddle

答案 3 :(得分:1)

相当简单:

SELECT horizon, sum(amount) AS amount
FROM generate_series(1, 5) AS s(horizon)
JOIN dataset ON "date" >= current_date + (horizon - 1) * interval '1 year'
             AND "date" < current_date + horizon * interval '1 year'
GROUP BY horizon
ORDER BY horizon;

答案 4 :(得分:0)

您需要一个联合和一个聚合函数:

select 1 as horizon, 
       sum(amount) amount
from the_table
where date >= current_date 
  and date < current_date + interval '12' month
union all
select 2 as horizon, 
       sum(amount) amount
where date >= current_date + interval '12' month
  and date < current_date + interval '24' month
union all 
select 3 as horizon, 
       sum(amount) amount
where date >= current_date + interval '24' month
  and date < current_date + interval '36' month
... and so on ...

但我不知道,如何使用混淆层(也称为ORM),但我确信它支持(或应该)聚合和联合。

这可以轻松地包含在PL / PgSQL函数中,您可以在其中传递“视野”并动态构建SQL,以便您需要调用的所有内容如下:select * from sum_horizon(5)其中5表示年数。

顺便说一句:date是一个可怕的名字。因为它是一个保留字,但更重要的是因为它不记录列的含义。这是“发布日期”吗? “截止日期”? “订单日期”?

答案 5 :(得分:0)

试试这个

select 
id,
sum(case when date>=current_date and date<current_date+interval 1 year then amount else 0 end) as year1,
sum(case when date>=current_date+interval 1 year and date<current_date+interval 2 year then amount else 0 end) as year2,
sum(case when date>=current_date+interval 2 year and date<current_date+interval 3 year then amount else 0 end) as year3,
sum(case when date>=current_date+interval 3 year and date<current_date+interval 4 year then amount else 0 end) as year4,
sum(case when date>=current_date+interval 4 year and date<current_date+interval 5 year then amount else 0 end) as year5
from table
group by id