按参数给出的区间范围聚合值

bad*_*era 3 postgresql aggregate

我有一个包含金额列和索引列的表。我希望构建一个查询,它总结了从给定开始索引到结束索引的每个结果间隔的给定间隔范围的数量 - 即“间隔范围”根据索引列对数据进行切片。对于这些组,将构建金额总和。
这是可能的吗?

SELECT sum(amount) from mytable
WHERE index between <startindex> and <endindex>
GROUP BY ...
Run Code Online (Sandbox Code Playgroud)

例子:

amount | index
55        1
88        5
45        6
86        7
87        10
88        11
57        16
58        17
59        20
60        21
Run Code Online (Sandbox Code Playgroud)

间隔范围为 5、起始索引 5 和结束索引 14 的查询应产生两个返回值:

  88+45+86 => 219
  87+88    => 175
Run Code Online (Sandbox Code Playgroud)

间隔范围为 4、起始索引 0 和结束索引 15 的查询应产生四个返回值:

  55       => 55
  88+45+86 => 219
  87+88    => 175
  --       => 0
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助!

McN*_*ets 5

CREATE TABLE T(amount INT, index INT);
INSERT INTO T VALUES
(55, 1),(88, 5),(45, 6),(86, 7),(87, 10),
(88, 11),(57, 16),(58, 17),(59, 20),(60, 21);
Run Code Online (Sandbox Code Playgroud)

您可以利用 Postgres 函数generate_series()

generate_series(start, stop, step)
Run Code Online (Sandbox Code Playgroud)

生成一系列值,从开始到停止,步长为 step

下面的示例使用从 0 到 14 的序列,间隔为 4。

SELECT generate_series(0, 14, 4) Serie;

| serie |
| ----: |
|     0 |
|     4 |
|     8 |
|    12 |


WITH CTS AS
(
    SELECT generate_series(0, 14, 4) Serie
)
SELECT    COALESCE(SUM(T.amount),0) AS amount, CTS.Serie
FROM      CTS
LEFT JOIN T
ON        T.index >= CTS.Serie 
AND       T.index <  CTS.Serie + 4
GROUP BY  CTS.Serie
ORDER BY  CTS.Serie;

amount | serie
-----: | ----:
    55 |     0
   219 |     4
   175 |     8
     0 |    12
Run Code Online (Sandbox Code Playgroud)

您可以使用允许您使用参数的用户定义函数

CREATE OR REPLACE FUNCTION GroupIntervals(low int, high int, step int)
RETURNS TABLE (amount int, interv int) AS
$$
BEGIN
    RETURN QUERY
    WITH CTS AS
    (
        SELECT generate_series(low, high, step) Serie
    )
    SELECT    COALESCE(SUM(T.amount),0)::int AS amount, CTS.Serie as interv
    FROM      CTS
    LEFT JOIN T
    ON        T.index >= CTS.Serie 
    AND       T.index <  CTS.Serie + step
    GROUP BY  CTS.Serie
    ORDER BY  CTS.Serie;
END;    
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
?
SELECT * FROM GroupIntervals(0, 14, 4);
Run Code Online (Sandbox Code Playgroud)
金额 | 采访
-----: | -----:
    55 | 0
   第219话 4
   175 | 8
     0 | 12
SELECT * FROM GroupIntervals(5, 14, 5);
Run Code Online (Sandbox Code Playgroud)
金额 | 采访
-----: | -----:
   第219话 5
   175 | 10

dbfiddle在这里

更新

正如Evan Carrol在评论中指出的那样,您可以避免使用 CTE 并将函数语言从 plpgsql 更改为纯 SQL。

CREATE OR REPLACE FUNCTION GroupIntervals(low int, high int, step int)
RETURNS TABLE (amount int, interv int)
AS $$
    SELECT    COALESCE(SUM(T.amount),0)::int AS amount, CTS.Serie as interv
    FROM      generate_series(low, high, step) AS CTS(Serie)
    LEFT JOIN T
    ON        index >= CTS.Serie 
    AND       index <  CTS.Serie + step
    GROUP BY  CTS.Serie
    ORDER BY  CTS.Serie;
$$ LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)
SELECT * FROM GroupIntervals(0, 14, 4);
Run Code Online (Sandbox Code Playgroud)
金额 | 采访
-----: | -----:
    55 | 0
   第219话 4
   175 | 8
     0 | 12
SELECT * FROM GroupIntervals(5, 14, 5);
Run Code Online (Sandbox Code Playgroud)
金额 | 采访
-----: | -----:
   第219话 5
   175 | 10

dbfiddle在这里