Sql 尝试在列上分组,同时按顺序选择所有其他信息

Sql 尝试在列上分组,同时按顺序选择所有其他信息,sql,postgresql,group-by,greatest-n-per-group,Sql,Postgresql,Group By,Greatest N Per Group,我在构造使用以下条件的查询时遇到了一些问题: 与组织匹配 按分数(desc)排序,然后按句柄(asc)排序 按类型分组 所以这个查询是我的出发点: select * from social_media_handles where org = '00000001' order by score desc, handle asc; 这将给我以下数据。。。然后我需要按类型进行分组,这样我只需要拿出最匹配的社交媒体手柄 org | ha

我在构造使用以下条件的查询时遇到了一些问题:

  • 与组织匹配
  • 按分数(desc)排序,然后按句柄(asc)排序
  • 按类型分组
  • 所以这个查询是我的出发点:

    select * from social_media_handles where org = '00000001' order by score desc, handle asc;
    
    这将给我以下数据。。。然后我需要按类型进行分组,这样我只需要拿出最匹配的社交媒体手柄

       org    |                            handle                             |                   url                   |   type   |      score      | dataset_date
    ----------+---------------------------------------------------------------+-----------------------------------------+----------+-----------------+--------------
     00000001 | boathousesw15                                                 | http://www.boathouseputney.co.uk        | twitter  | 500111972000056 | 2013-10-15
     00000001 | aspall                                                        | http://www.boathouseputney.co.uk        | twitter  | 500111972000018 | 2013-10-15
     00000001 | nathansloane                                                  | http://www.boathouseputney.co.uk        | twitter  | 500111972000018 | 2013-10-15
     00000001 | youngspubs                                                    | http://www.boathouseputney.co.uk        | twitter  | 500111972000018 | 2013-10-15
     00000001 | pages/the-boathouse-putney/153429008029137                    | http://www.boathouseputney.co.uk        | facebook | 500111972000011 | 2013-10-15
     00000001 | putneysocial                                                  | http://www.boathouseputney.co.uk        | twitter  | 500111972000009 | 2013-10-15
     00000001 | theexchangesw15                                               | http://www.boathouseputney.co.uk        | twitter  | 500111972000009 | 2013-10-15
     00000001 | youngspubs                                                    | http://www.youngshotels.co.uk           | twitter  | 500111970000016 | 2013-10-15
    
    预期产量

       org    |                            handle                             |                   url                   |   type   |      score      | dataset_date
    ----------+---------------------------------------------------------------+-----------------------------------------+----------+-----------------+--------------
     00000001 | boathousesw15                                                 | http://www.boathouseputney.co.uk        | twitter  | 500111972000056 | 2013-10-15
     00000001 | pages/the-boathouse-putney/153429008029137                    | http://www.boathouseputney.co.uk        | facebook | 500111972000011 | 2013-10-15
    
    我试过按分组、
    不同的
    和子查询,但运气不太好。这个问题有什么规律吗


    我正在使用Postgres,并在上使用distinct解决了这个问题,但我正在寻找一个与不同供应商兼容的版本。

    有几种方法可以做到这一点,所有方法都基于两个想法。第一个想法是为每种类型获取具有最大分数的记录集,然后将原始表连接到此记录集。第二个想法是,如果你有排名函数,你只需在每个
    类型中使用
    行编号()
    ,然后用
    行编号>1
    过滤掉所有记录

    第一个想法可以这样写:

    select *
    from Table1 as T
    where
        exists (
            select 1
            from Table1 as TT
            where TT.type = T.type
            having max(TT.score) = T.score
        )
    

    如果你有排名功能,那么你也可以使用第二个想法:

    with cte as (
       select *, row_number() over(partition by type order by score desc) as rn
       from Table1
    )
    select *
    from cte
    where rn = 1
    
    您可以轻松地用子查询替换公共表表达式:

    select *
    from (
       select *, row_number() over(partition by type order by score desc) as rn
       from Table1
    ) as a
    where rn = 1
    
    更新

    有一件事需要提及——如果您有多条记录,例如,
    score=500111972000056,type=twitter
    ,那么第一个解决方案将为type='twitter'返回多条记录,而第二个解决方案为type='twitter'返回任意一行

    另外,我忘了提到第三个想法(参见nice@Bill Karwin答案)。我只想在这里加上:

    select *
    from Table1 as T
    where
        not exists (
            select *
            from Table1 as TT
            where TT.type = T.type and TT.score > T.score
        );
    

    这个问题在SO上经常出现,并且通常会给它一个标签(在您的例子中,n=1)

    以下是几个在MySQL中可用的常见解决方案:

    SELECT h.*
    FROM social_media_handles AS h
    JOIN (
        SELECT type, MAX(score) AS score 
        FROM social_media_handles WHERE org = '00000001' 
        GROUP BY type) AS maxh USING (type, score)
    WHERE org = '00000001' 
    ORDER BY score DESC, handle ASC;
    
    第二种解决方案不使用子查询或分组依据。它尝试将一行h1与一个假设行h1进行匹配,该假设行h1具有相同的
    类型
    组织
    ,但具有更高的
    分数
    。如果不存在得分较高的行h2,则h1必须是得分最高的行

    SELECT h1.*
    FROM social_media_handles AS h1
    LEFT OUTER JOIN social_media_handles AS h2
     ON h1.type = h2.type AND h1.org = h2.org AND h1.score < h2.score
    WHERE h1.org = '00000001'
     AND h2.score IS NULL
    ORDER BY h1.score DESC, h1.handle DESC;
    
    选择h1*
    来自社交媒体,作为h1处理
    左外联接社交媒体句柄为h2
    在h1.type=h2.type和h1.org=h2.org和h1.score
    哪种解决方案最快?视情况而定。根据数据集的大小、不同类型的数量等,我让这两种方法都能更好地工作。因此,您应该测试这两种解决方案,看看哪些方法更适合您的情况

    @Roman Pekar展示的CTE解决方案也适用于支持CTE语法的RDBMS。这些包括PostgreSQL、Oracle、MicrosoftSQLServer、IBMDB2和其他一些


    MySQL和SQLite是唯一广泛使用的仍然不支持CTE语法的数据库。

    我不明白我们是如何定义顶级匹配的社交媒体句柄的。
    @草莓,每个
    type
    score
    列中得分最高的人。啊哈,好吧,假设Roman Pekar的第二个解决方案对postgres有效(有一个小的修正),那么我猜那将是最快的。@草莓,我想这取决于你有10000条type='facebook'的记录,并且你有一个合适的索引,然后第一个是fasterOK——我不知道postgres,所以我不能对这种答案发表评论。第二个答案是+1,提到没有银弹:),我忘了没有银弹。也许我应该补充我的答案,如果原始版本中存在重复版本,那么解决方案可能会有不同的效果table@RomanPekar,是的,如果您有多个行,每个组都有最大分数,那么结果中会有多行。这就是CTE解决方案的最佳方式。为让我意识到每个组的最大n值而干杯。这件事我得多调查一下。
    SELECT h1.*
    FROM social_media_handles AS h1
    LEFT OUTER JOIN social_media_handles AS h2
     ON h1.type = h2.type AND h1.org = h2.org AND h1.score < h2.score
    WHERE h1.org = '00000001'
     AND h2.score IS NULL
    ORDER BY h1.score DESC, h1.handle DESC;