【问题标题】:How to order distinct tuples in a PostgreSQL query如何在 PostgreSQL 查询中对不同的元组进行排序
【发布时间】:2012-04-21 18:09:25
【问题描述】:

我正在尝试在 Postgres 中提交一个只返回不同元组的查询。在我的示例查询中,我不希望一个cluster_id/feed_id 组合存在多次的重复条目。如果我做一个简单的:

select distinct on (cluster_info.cluster_id, feed_id) 
   cluster_info.cluster_id, num_docs, feed_id, url_time 
   from url_info 
   join cluster_info on (cluster_info.cluster_id = url_info.cluster_id) 
   where feed_id in (select pot_seeder from potentials) 
   and num_docs > 5 and url_time > '2012-04-16';

我明白了,但我也想根据num_docs 进行分组。因此,当我执行以下操作时:

select distinct on (cluster_info.cluster_id, feed_id) 
   cluster_info.cluster_id, num_docs, feed_id, url_time 
   from url_info join cluster_info 
   on (cluster_info.cluster_id = url_info.cluster_id) 
   where feed_id in (select pot_seeder from potentials) 
   and num_docs > 5 and url_time > '2012-04-16' 
   order by num_docs desc;

我收到以下错误:

ERROR:  SELECT DISTINCT ON expressions must match initial ORDER BY expressions
LINE 1: select distinct on (cluster_info.cluster_id, feed_id) cluste...

我想我明白为什么会出现错误(除非我以某种方式明确描述该组,否则无法按元组分组)但我该怎么做呢?或者如果我对错误的解释不正确,有没有办法实现我的初始目标?

【问题讨论】:

    标签: sql postgresql distinct-on


    【解决方案1】:

    最左边的ORDER BY 项不能与DISTINCT 子句的项不一致。我引用the manual about DISTINCT

    DISTINCT ON 表达式必须匹配最左边的ORDER BY 表达式。 ORDER BY 子句通常包含额外的 确定所需行优先级的表达式 每个DISTINCT ON 组。

    试试:

    SELECT *
    FROM  (
        SELECT DISTINCT ON (c.cluster_id, feed_id) 
               c.cluster_id, num_docs, feed_id, url_time 
        FROM   url_info u
        JOIN   cluster_info c ON (c.cluster_id = u.cluster_id) 
        WHERE  feed_id IN (SELECT pot_seeder FROM potentials) 
        AND    num_docs > 5
        AND    url_time > '2012-04-16'
        ORDER  BY c.cluster_id, feed_id, num_docs, url_time
               -- first columns match DISTINCT
               -- the rest to pick certain values for dupes
               -- or did you want to pick random values for dupes?
        ) x
    ORDER  BY num_docs DESC;
    

    或者使用GROUP BY:

    SELECT c.cluster_id
         , num_docs
         , feed_id
         , url_time 
    FROM   url_info u
    JOIN   cluster_info c ON (c.cluster_id = u.cluster_id) 
    WHERE  feed_id IN (SELECT pot_seeder FROM potentials) 
    AND    num_docs > 5
    AND    url_time > '2012-04-16'
    GROUP  BY c.cluster_id, feed_id 
    ORDER  BY num_docs DESC;
    

    如果c.cluster_id, feed_id 是您在SELECT 列表中包含列的所有(在这种情况下都是)表的主键列,那么这仅适用于PostgreSQL 9.1 或更高版本。

    否则,您需要GROUP BY 其余列或汇总或提供更多信息。

    【讨论】:

    • 我想我需要你提到的 GROUP BY,因为你的第二个答案出现以下错误:错误:列“c.num_docs”必须出现在 GROUP BY 子句中或用于聚合函数
    • 您的第一个答案给出以下错误:错误:SELECT DISTINCT ON 表达式必须匹配初始 ORDER BY 表达式第 3 行:SELECT DISTINCT ON (c.cluster_id, feed_id)
    • @WildBill:您可能错过了第一次查询的更新。我在第一个版本中修复了一个错误。至于第二个查询:如果您提供了哪些列属于哪个表、哪些主键以及您的 PostgreSQL 版本的缺失信息,我的回答可能会更具体。
    • 感谢您的帮助和参考!
    • 对于一个只有 2800 万行的表来说,这太慢了……有更快的解决方案吗?加入后,列值的变化有很多重复。我们希望按这些列排序并根据主键 (id) 返回不同的行。似乎不是一种性能可以接受的方式......
    猜你喜欢
    • 2014-07-30
    • 1970-01-01
    • 1970-01-01
    • 2020-12-16
    • 1970-01-01
    • 1970-01-01
    • 2021-09-10
    • 1970-01-01
    • 2015-08-31
    相关资源
    最近更新 更多