按不同时间间隔获取聚合结果

Getting aggregated results by different time intervals

我有一个带有 table 的 postgres 数据库,其中包含根据 ID 和时间戳的数据。 table 有几列数据。我想创建一个 pgsql 函数,它允许我根据时间间隔获取数据聚合。

table 看起来像这样:

   user_id  |     created_at      | value_a | value_b | value_c | value_d | unique_key
------------+---------------------+---------+---------+---------+---------+------------
 1          | 2019-12-16 17:37:07 |    1    |    5    |    0    |    5    |  1
 2          | 2019-12-19 15:37:07 |    4    |    7    |    0    |   42    |  2
 3          | 2019-12-16 15:37:07 |   20    |    1    |   20    |  143    |  3
 2          | 2019-12-18 12:01:32 |    0    |    0    |    5    |  987    |  4
 1          | 2019-12-11 14:12:50 |    6    |    0    |    9    |    0    |  5
 2          | 2019-12-10 15:37:07 |    1    |   72    |  100    |   90    |  6
 1          | 2019-12-20 15:37:07 |    5    |    3    |   56    | 1546    |  7
 3          | 2019-12-20 15:37:07 |   30    |    4    |  789    |    3    |  8
 4          | 2019-12-01 15:37:07 |   35    |   90    |    0    |    5    |  9
(9 rows)

我想以一种可以获得时间范围(之前和之后)和时间间隔的方式创建函数,这样它就会根据时间间隔(例如每天)对数据进行分组,分组依据 user_id。 我设法创建了一个 generate_series 的函数,该函数 return 是聚合结果,但它忽略了一些数据。 聚合使用不同的公式来获取数据。

我找到的大多数答案都设法 select 只有一个值而不是多个值的分组总和,即它 return 类似于:

user_id | date | value_a + value_b + value_c + value_c

但就我而言,我想以不同的方式操作数据,例如:

user_id | date | a + b | (a*b)/c | count(a)

等(当然我会处理除以零之类的东西)..

所以我尝试创建的函数类似于:


CREATE OR REPLACE FUNCTION branch_performance_measurements_daily(
    IN after DATE,
    IN before DATE,
    )
RETURNS TABLE (
      date_of_sum DATE,
      func_a INT,
      func_b INT,
      func_c INT
)
AS $$
BEGIN
    RETURN QUERY
    WITH days_series AS (
        SELECT d::date day FROM generate_series(after, before, '1 day') day)
    SELECT days_series.day AS date_of_sum, 
            sum(a + b),
            sum((a*b)/c),
            count(a)

            FROM table b
            WHERE DATE(b.created_at) = DATE(days_series.day)
            GROUP BY days_series.day, b.user_id;
END;
$$ LANGUAGE plpgsql;

遗憾的是,根据所有可用日期,此类查询并未 return table 中的所有可用数据..

有什么方法可以让我知道 generate_series 在我需要的情况下的正确用法吗?

P.S。 我知道 sum 的功能不起作用,它只是为了示例:)

非常感谢!

欢迎来到 Stack Overflow。

您的函数有一些语法错误。您可能正在寻找以下内容:

CREATE OR REPLACE FUNCTION branch_performance_measurements_daily(
  after DATE, before DATE)
RETURNS TABLE (
  date_of_sum DATE, func_a BIGINT,func_b BIGINT, func_c BIGINT) AS $$
BEGIN
RETURN QUERY
  WITH days_series AS (
    SELECT generate_series(after, before, '1 day') AS d)
  SELECT 
    DATE(ds.d) AS date_of_sum, 
    sum(value_a + value_b),
    COALESCE(sum((value_a*value_b)/NULLIF(value_c,0)),0),
    count(value_a) FROM t
  JOIN days_series ds ON ds.d = DATE(t.created_at)
  GROUP BY ds.d, t.user_id
  ORDER BY ds.d;
END;
$$ LANGUAGE plpgsql;

示例数据

CREATE TEMPORARY TABLE t 
(user_id INT, created_at date, 
 value_a int,value_b int,value_c int,value_d int, unique_key int);

INSERT INTO t VALUES
 (1,' 2019-12-16 17:37:07',1,5,0,5,1),
 (2,' 2019-12-19 15:37:07',4,7,0, 42,2),
 (3,' 2019-12-16 15:37:07',20,1,20,143,3),
 (2,' 2019-12-18 12:01:32',0,0,5,987,4),
 (1,' 2019-12-11 14:12:50',6,0,9,0,5),
 (2,' 2019-12-10 15:37:07',1,72,100, 90,6),
 (1,' 2019-12-20 15:37:07',5,3,56,1546,7),
 (3,' 2019-12-20 15:37:07',30,4,789,3,8),
 (4,' 2019-12-01 15:37:07',35, 90,0,5,9);

测试功能

SELECT * FROM branch_performance_measurements_daily('2019-12-01', '2019-12-20');
 date_of_sum | func_a | func_b | func_c 
-------------+--------+--------+--------
 2019-12-01  |    125 |      0 |      1
 2019-12-10  |     73 |      0 |      1
 2019-12-11  |      6 |      0 |      1
 2019-12-16  |      6 |      0 |      1
 2019-12-16  |     21 |      1 |      1
 2019-12-18  |      0 |      0 |      1
 2019-12-19  |     11 |      0 |      1
 2019-12-20  |      8 |      0 |      1
 2019-12-20  |     34 |      0 |      1
(9 rows)

如果您只想按生成日期分组(而不是像您的查询建议的那样与 user_id 一起),只需从 GROUP BY 子句中删除 user_id 即可会得到这样的东西:

 date_of_sum | func_a | func_b | func_c 
-------------+--------+--------+--------
 2019-12-01  |    125 |      0 |      1
 2019-12-10  |     73 |      0 |      1
 2019-12-11  |      6 |      0 |      1
 2019-12-16  |     27 |      1 |      2
 2019-12-18  |      0 |      0 |      1
 2019-12-19  |     11 |      0 |      1
 2019-12-20  |     42 |      0 |      2