通过聚合函数中其他列的(第一个值)排序不同的列值

Dol*_*gan 11 sql postgresql distinct sql-order-by aggregate-functions

我正在尝试根据另一列的值来排序某些不同聚合文本的输出顺序,例如:

string_agg(DISTINCT sometext, ' ' ORDER BY numval)
Run Code Online (Sandbox Code Playgroud)

但是,这会导致错误:

错误:在与DISTINCT聚合时,ORDER BY表达式必须出现在参数列表中

我确实理解为什么会这样,因为如果numval两个重复值中的顺序不同,则排序将是"不明确的" ,而另一个重复值之间的排序将是"不明确的" .

理想情况下,我想按照第一次出现/最低顺序排序它们,但是在我的数据中,不明确的情况实际上是非常罕见的(它主要是顺序重复的值,我想用它除去DISTINCT)我最终不要特别关心他们的订购,并且会对像MySQL这样的东西感到满意,GROUP_CONCAT(DISTINCT sometext ORDER BY numval SEPARATOR ' ')尽管它很邋..

我希望Postgres的一些扭曲是必要的,但我真的不知道最有效/简洁的方法是什么.

Erw*_*ter 7

建立在DISTINCT ON

SELECT string_agg(sometext, ' ' ORDER BY numval) AS no_dupe
FROM  (
    SELECT DISTINCT ON (1,2) <whatever>, sometext, numval
    FROM   tbl
    ORDER  BY 1,2,3
    ) sub;
Run Code Online (Sandbox Code Playgroud)

这是@Gordon's query的更简单的等价物。
仅从你的描述来看,我会建议@Clodoaldo's更简单的变体

uniq()对于整数

对于integer值而不是text,附加模块intarray正好适合您:

uniq(int[])     int[]   remove adjacent duplicates
Run Code Online (Sandbox Code Playgroud)

每个数据库安装一次:

CREATE EXTENSION intarray;
Run Code Online (Sandbox Code Playgroud)

那么查询很简单:

SELECT uniq(array_agg(some_int ORDER BY <whatever>, numval)) AS no_dupe
FROM   tbl;
Run Code Online (Sandbox Code Playgroud)

array_to_string()结果是一个数组,如果需要字符串,请将其包装起来。有关的:

事实上,创建一个自定义聚合函数来执行相同的操作并不难text......

适用于任何数据类型的自定义聚合函数

仅当下一个元素与前一个元素不同时才将下一个元素添加到数组中的函数。(NULL值被删除!):

uniq(int[])     int[]   remove adjacent duplicates
Run Code Online (Sandbox Code Playgroud)

使用多态类型使其适用于任何标量数据类型。自定义聚合函数:

CREATE EXTENSION intarray;
Run Code Online (Sandbox Code Playgroud)

称呼:

SELECT uniq(array_agg(some_int ORDER BY <whatever>, numval)) AS no_dupe
FROM   tbl;
Run Code Online (Sandbox Code Playgroud)

请注意,聚合PARALLEL UNSAFE本质上是(默认)的,即使转换函数可以标记为PARALLEL SAFE

相关回答:


Clo*_*eto 5

通过预先汇总来消除进行区分的需要

select string_agg(sometext, ' ' order by numval)
from (
    select sometext, min(numval) as numval
    from t
    group by sometext
) s
Run Code Online (Sandbox Code Playgroud)

@戈登的答案提出了一个很好的观点。那就是如果还有其他需要的列。在这种情况下distinct on,建议使用

select x, string_agg(sometext, ' ' order by numval)
from (
    select distinct on (sometext) *
    from t
    order by sometext, numval
) s
group by x
Run Code Online (Sandbox Code Playgroud)


Gor*_*off 1

select distinct如果这是较大表达式的一部分,则在子查询中执行 a 可能会很不方便。在这种情况下,您可以利用string_agg()忽略NULL输入值的事实并执行以下操作:

select string_agg( (case when seqnum = 1 then sometext end) order by numval)
from (select sometext, row_number() over (partition by <whatever>, sometext order by numval) as seqnum
      from t
     ) t
group by <whatever>
Run Code Online (Sandbox Code Playgroud)

子查询添加一列,但不需要聚合数据。