选择Distinct On,同时按其他列排序

时间:2013-11-16 05:51:22

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

我来自MySQL背景,其中GROUP BY与Postgres的工作方式截然不同。在Postgres中 - 显然是任何基于标准的SQL数据库 - 你必须按所有选定的列进行分组,而在MySQL中你可以手工挑选哪些列进行分组。

我读到你可以获得与DISTINCT ON相同的效果,而且大多数情况都是如此。问题是你必须ORDER BY所有不同的列,这个排序必须是最左边的排序。当我想主要通过另一个专栏订购时,这是一个问题。

现在我的查询如下:

SELECT
  DISTINCT ON (eventable_id, eventable_type)
           events.eventable_id, events.eventable_type, events.*
  FROM events
  WHERE <query>
  ORDER BY eventable_id, eventable_type, events.created_at DESC

我想换掉订单,看起来像这样:

  ORDER BY events.created_at, eventable_id, eventable_type DESC

有任何关于让它发挥作用的建议吗?

2 个答案:

答案 0 :(得分:4)

由于您选择的是events.*,因此不应将eventable_ideventable_type冗余地添加到输出列。会导致重复的列名称。您知道您不必在目标列表的DISTINCT ON子句中包含列,对吧?

此外,立即使用eventable_type DESC可能会更快,因为您的最终排序顺序是这样的。这也是允许的。

SELECT DISTINCT ON (eventable_id, eventable_type)
       *
FROM   events
WHERE  <condition>
ORDER  BY eventable_id, eventable_type DESC, created_at DESC

@Denis已经涵盖了其余部分:在外部查询中将其作为子查询并按顺序排序。

替代将是GROUP BYmax()的子选择,但是当每个组的最新created_at不唯一时,每个组会产生多个列。 (可能或可能不合适。)并且它可能仍然比DISTINCT ON更慢,但需要额外的ORDER BY步骤。使用EXPLAIN ANALYZE进行测试。

SELECT e.*
FROM   events e
JOIN  (
   SELECT eventable_id, eventable_type, max(created_at) AS created_at
   FROM   events
   WHERE  <condition>
   GROUP   BY 1, 2 DESC
   ) sub USING (eventable_id, eventable_type, created_at) -- maybe not unique
WHERE  <repeat condition if dupes may be eliminated>
ORDER  BY e.created_at, e.eventable_id, e.eventable_type DESC

答案 1 :(得分:1)

如果Postgres抱怨,请使用子选择:

select * from ( ... ) q order by ...

(如果确实如此,我会把它作为查询计划会吮吸的暗示。)