【问题标题】:Postgresql OVER and GROUPPostgresql OVER 和 GROUP
【发布时间】:2017-09-22 12:43:25
【问题描述】:

我遇到了分组问题

我有一张表格(里面有很多东西,但不相关),看起来像:

id user
0 1
1 1
2 1
3 2
4 2
5 2
6 1
7 1

我正在尝试获取以下值:

user start end
1 0 2
2 3 5
1 6 7

基本上,我需要用户的第一次和最后一次出现,而不是弄乱顺序。 我知道我需要使用 OVER (PARTITION BY ...),但我从未使用过它,也不知道如何构建此查询。 如果我“按用户分区”,它会忽略顺序。如果我“按 id 分区,用户”它再次返回错误。

我尝试过的示例(甚至没有尝试获得我需要的东西,但它是一个中点,一旦我弄清楚“结束”部分,我将如何去做):

SELECT user, count(user) over (partition by user):
user count
1 5
1 5
1 5
2 3
2 3
2 3
1 5
1 5

SELECT user, count(user) over (partition by id, user):
user count
1 1
1 1
1 1
2 1
2 1
2 1
1 1
1 1

【问题讨论】:

  • SELECT user, min(id) over (partition by user), max(id) over (partition by user) ?..

标签: sql postgresql window-functions gaps-and-islands


【解决方案1】:

使用行号差异的方法将具有相同用户的连续行归为一组,并在遇到新用户时从新组开始。此后,使用group by 获取每个组的开始和结束。

SELECT USER,MIN(ID) AS START,MAX(ID) AS END
FROM (SELECT user,id, row_number() over(order by id) 
                     - row_number() over (partition by user order by id) as grp
      FROM tablename
      ) T
GROUP BY USER,GRP

【讨论】:

    【解决方案2】:

    开始,结束 id,使用:

    SELECT user, min(id) over (partition by user) "start", max(id) over (partition by user) "end"
    from table_name;
    

    更新 我的回答是基于错误的谓词,所以是错误的。为了提供正确的而不是重复的@vkp,我做了这个可怕的构造:

    create table so74 as
    select * from (values (0, 1), (1, 1), (2, 1), (3, 2), (4, 2), (5, 2), (6, 1), (7, 1)) t(id, u); 
    
    with d as (
        with c as (
            with b as (
                select 
                    *
                    , case when lag(u) over (order by id) <> u or id = min(id) over() then id end min
                    , case when lead(u) over (order by id) <> u or id=max(id) over () then id end max 
                from so74
                )
            select  u, min,max 
            from b 
            where coalesce(min,max) is not null
        ) 
        select u,min,lead(max) over () max  
        from c
    ) 
    select * 
    from d 
    where coalesce(min,max) is not null
    ;
    
     u | min | max
    ---+-----+-----
     1 |   0 |   2
     2 |   3 |   5
     1 |   6 |   7
    (3 rows)
    
    Time: 0.456 ms
    

    【讨论】:

    • 老实说,我不明白你的问题,我只是构建了一个查询,它会产生你想要的结果我正在尝试获得以下值:。如果我失败了,请更新问题
    • 问题是分区会为每个用户返回最小值和最大值。
    • 我现在看到了!你又有用户 1 了! - 只需一分钟
    • @darthzejdr - 我更新了我的答案,至少为您的问题提供了可行的解决方案
    • @vkp 方法要好得多。我只是想证明我的赞成票是合理的
    猜你喜欢
    • 1970-01-01
    • 2012-10-30
    • 1970-01-01
    • 2011-12-10
    • 1970-01-01
    • 2021-01-08
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多