在Postgres查询中聚合以前的行

时间:2018-03-29 16:12:21

标签: sql postgresql aggregate-functions

我有一个表格,用于存储应用程序用户的活动信息。

| username | day |
|----------|-----|
|   u1     |   1 |
|   u1     |   2 |
|   u1     |   3 |
|     u2   |   2 |
|       u3 |   1 |
|       u3 |   4 |

我希望能够获取每天唯一和最近用户的历史数据。

  • 第N天的唯一身份用户是在第0天和第N天之间有任何活动的所有不同用户。
  • N天的最近用户是在第N-1天或第N天有任何活动的所有不同用户。在实际应用中,这将是在N-30天和N之间。

我能够获取每个特定日期处于活动状态的用户列表,但我不确定如何汇总这些数据以获得唯一或最近的用户。

SELECT 
day, 
array_agg(username) as day_users
FROM myTable
GROUP BY day
ORDER BY day;

| day | day_users |
|-----|-----------|
|   1 |  u1,   u3 |
|   2 |  u1,u2    |
|   3 |  u1       |
|   4 |        u3 |

对于上面的示例数据,预期输出将是(不需要间距):

| day | unique_users | recent_users 
|-----|--------------|-------------
|   1 |     u1,   u3 |     u1,   u3
|   2 |     u1,u2,u3 |     u1,u2,u3
|   3 |     u1,u2,u3 |     u1,u2
|   4 |     u1,u2,u3 |     u1,   u3

相关SQL小提琴:http://sqlfiddle.com/#!17/b793f/1

1 个答案:

答案 0 :(得分:1)

您需要自定义聚合函数:

create or replace function array_union(anyarray, anyarray)
returns anyarray language sql
as $$
    select 
        array(
            select unnest($1)
            union
            select unnest($2)
            order by unnest
        )
$$;

create aggregate array_union_agg (anyarray)
(
    sfunc = array_union,
    stype = anyarray
);

在查询中使用聚合作为窗口函数,基于你的一个:

select 
    day, 
    day_users, 
    array_union_agg(day_users) over (order by day) as unique_users,
    array_union_agg(day_users) over (order by day rows between 1 preceding and current row) as recent_users
from (
    select day, array_agg(username) as day_users
    from my_table
    group by day
    order by day
    ) s

 day | day_users | unique_users | recent_users 
-----+-----------+--------------+--------------
   1 | {u1,u3}   | {u1,u3}      | {u1,u3}
   2 | {u1,u2}   | {u1,u2,u3}   | {u1,u2,u3}
   3 | {u1}      | {u1,u2,u3}   | {u1,u2}
   4 | {u3}      | {u1,u2,u3}   | {u1,u3}
(4 rows)