Postgresql Postgres聚合函数,用于选择组中的最佳/第一个元素

Postgresql Postgres聚合函数,用于选择组中的最佳/第一个元素,postgresql,aggregate-functions,Postgresql,Aggregate Functions,我有一个元素表,其中有许多项需要根据优先级进行重复数据消除。以下是一个非常简单但具有代表性的示例: sophia=> select * from numbers order by value, priority; value | priority | label -------+----------+------- 1 | 1 | One 1 | 2 | Eins 2 | 1 | Two 2 |

我有一个元素表,其中有许多项需要根据优先级进行重复数据消除。以下是一个非常简单但具有代表性的示例:

sophia=> select * from numbers order by value, priority;
 value | priority | label 
-------+----------+-------
     1 |        1 | One
     1 |        2 | Eins
     2 |        1 | Two
     2 |        2 | Zwei
     3 |        2 | Drei
     4 |        1 | Four
     4 |        2 | Vier
(7 rows)
我想将此限制为每个数字只返回一行。非常简单,我可以使用中详细介绍的第一个()聚合函数

问题是顺序没有很好地定义,因此如果以不同的顺序插入DB行,我可能会得到以下结果:

sophia=> select value, first(label) from numbers group by value order by value;
 value | first 
-------+-------
     1 | Eins
     2 | Zwei
     3 | Drei
     4 | Vier
(4 rows)
当然,解决这个问题的方法似乎也很简单,因为我可以通过以下方式进行排序:

sophia=> select value, first(label) from (select * from numbers order by priority) foo group by value order by value;
 value | first 
-------+-------
     1 | One
     2 | Two
     3 | Drei
     4 | Four
(4 rows)

sophia=> 
然而,这里的问题是查询优化器可以自由地丢弃子查询中的order by规则,这意味着这并不总是有效的,并且会在随机的地方中断

我有一个解决方案,我目前正在少数几个地方使用,它依赖于array_agg

sophia=> select value, (array_agg(label order by priority))[1] as best_label from numbers group by value;
 value | best_label 
-------+------------
     1 | One
     2 | Two
     3 | Drei
     4 | Four
(4 rows)

sophia=> 
这提供了健壮的排序,但需要在查询时创建一堆额外的数组,这些数组会被丢弃,因此在更大的数据集上的性能相当糟糕


所以问题是,有没有更好、更干净、更快的方法来处理这个问题?

你上次的尝试包括了你问题的答案,但你没有意识到:

array_agg(label order by priority)
请注意聚合函数中的
orderby
子句。这不是
array\u agg
的特殊功能,而是以下内容的一般部分:

通常,输入行以未指定的顺序馈送到聚合函数。在许多情况下,这并不重要;例如,min无论以何种顺序接收输入,都会产生相同的结果。但是,某些聚合函数(如array_agg和string_agg)生成的结果取决于输入行的顺序。使用这种聚合时,可以使用可选的order_by_子句指定所需的顺序。order_by_子句的语法与查询级order by子句的语法相同,如第7.5节所述,只是其表达式始终只是表达式,不能输出列名或数字

因此,您的问题的解决方案就是在
第一个
聚合表达式中放入一个
order by

select value, first(label order by priority) from numbers group by value order by value;

考虑到这是多么优雅,我很惊讶
first
last
仍然没有作为内置聚合实现。

您上次的尝试包括了您问题的答案,您只是没有意识到:

array_agg(label order by priority)
请注意聚合函数中的
orderby
子句。这不是
array\u agg
的特殊功能,而是以下内容的一般部分:

通常,输入行以未指定的顺序馈送到聚合函数。在许多情况下,这并不重要;例如,min无论以何种顺序接收输入,都会产生相同的结果。但是,某些聚合函数(如array_agg和string_agg)生成的结果取决于输入行的顺序。使用这种聚合时,可以使用可选的order_by_子句指定所需的顺序。order_by_子句的语法与查询级order by子句的语法相同,如第7.5节所述,只是其表达式始终只是表达式,不能输出列名或数字

因此,您的问题的解决方案就是在
第一个
聚合表达式中放入一个
order by

select value, first(label order by priority) from numbers group by value order by value;

考虑到这是多么优雅,我很惊讶
first
last
仍然没有作为内置聚合实现。

Postgres select语句有一个名为DISTINCT ON的子句,当您想要返回组中的一个时,该子句非常有用。在这种情况下,您将使用:

SELECT DISTINCT ON (value) value, label
FROM numbers
ORDER BY value, priority;

使用DISTINCT ON通常比涉及组或窗口函数的其他方法更快。

Postgres select语句有一个名为DISTINCT ON的子句,当您想要返回组中的一个时,该子句非常有用。在这种情况下,您将使用:

SELECT DISTINCT ON (value) value, label
FROM numbers
ORDER BY value, priority;
使用DISTINCT ON通常比涉及组或窗口函数的其他方法更快