【问题标题】:SQL statement to get distinct data获取不同数据的 SQL 语句
【发布时间】:2014-02-07 19:35:11
【问题描述】:
ID | user_id | name      | active
1  | 1       | Profile 1 | f
2  | 1       | Profile 2 | t
3  | 2       | Profile 3 | f
4  | 2       | Profile 4 | f
5  | 3       | Profile 5 | f

我正在使用 PostgreSQL。在我的应用程序中,users 可以创建多个profiles,我想选择每个用户创建的最后一个不同的非活动配置文件。此外,如果有一个属于该用户的active 个人资料,它不应该选择该用户的任何个人资料——这对我来说是困难的部分。

为了得到以下结果,我应该使用什么样的 SQL 语句?

4  | 2       | Profile 4 | f
5  | 3       | Profile 5 | f

【问题讨论】:

    标签: sql postgresql greatest-n-per-group


    【解决方案1】:

    我会将DISTINCT ONNOT EXISTS 结合起来。 假设活动的正确boolean 类型:

    SELECT DISTINCT ON (user_id)
           id, user_id, name, active
    FROM   profiles p
    WHERE  NOT EXISTS (
       SELECT 1 FROM profiles
       WHERE  user_id = p.user_id
       AND    active               -- exclude users with any active profiles
       )
    ORDER  BY user_id, id DESC;
    

    可能是最快和最干净的。

    【讨论】:

      【解决方案2】:

      SQL Fiddle

      select distinct on (user_id)
          id, user_id, name, active
      from
          t
          inner join
          (
              select user_id
              from t
              group by user_id
              having not bool_or(active)
          ) s using(user_id)
      order by user_id, id desc
      

      【讨论】:

        【解决方案3】:

        distinct on 语法对此非常有效:

        select distinct on (user_id) id, user_id, name, active
        from t
        where active = 'f'
        order by user_id, id desc;
        

        编辑:

        为避免激活配置文件,使用分析函数可能更容易:

        select id, user_id, name, active
        from (select t.*,
                     row_number() over (partition by user_id, active order by id desc) as seqnum,
                     max(case when active = 'f' then 0 else 1 end) as numActives
              from t
             ) t
        where numActives = 0 and seqnum = 1;
        

        【讨论】:

        • 确实如此,预计它还会选择具有活动个人资料的用户的行。
        • @ErenCAY 。 . .是的,这使得distinct on 很难使用。查看修改后的版本。
        • @GordonLinoff 最好使用bool_or(active) as anyActive 而不是max(case when active = 'f' then 1 else 0 end) as numActives
        • @GordonLinoff 你也不需要partition by user_id, activepartition by user_id 就足够了。
        • @GordonLinoff 可以使用更多标准结构,但您仍然可以在max(case when active = 'f' then 1 else 0 end) as numActives 中保存一个错误。如果任何记录有active = 'f',它将返回1。你需要case when active then 1 else 0 end
        猜你喜欢
        • 2011-09-15
        • 2022-01-26
        • 1970-01-01
        • 2010-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-25
        相关资源
        最近更新 更多