我正在尝试根据另一列的值来排序某些不同聚合文本的输出顺序,例如:
string_agg(DISTINCT sometext, ' ' ORDER BY numval)
但是,这会导致错误:
错误:在使用DISTINCT的聚合中,ORDER BY表达式必须出现在参数列表
中
我确实理解为什么会这样,因为如果两个重复值的numval
不同,那么排序将是“不明确的”,而另一个的DISTINCT
介于两者之间。
理想情况下,我想按照第一次出现/最低顺序排序它们,但是在我的数据中,定义不明确的情况实际上是非常罕见的(它主要是依次重复的值,我想用{去掉... {1}})我最终并不特别关心他们的排序,并且会对像MySQL GROUP_CONCAT(DISTINCT sometext ORDER BY numval SEPARATOR ' ')
这样的东西感到高兴,尽管它很糟糕,但它仍能正常工作。
我希望有一些Postgres扭曲是必要的,但我真的不知道最有效/简洁的方法是什么。
答案 0 :(得分:4)
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;
这比@Gordon's query更简单 仅从您的描述中我会建议@Clodoaldo's simpler variant。
uniq()
表示整数对于integer
值而不是text
,附加模块intarray
的只是
uniq(int[]) int[] remove adjacent duplicates
每个数据库安装一次:
CREATE EXTENSION intarray;
然后查询就是:
SELECT uniq(array_agg(some_int ORDER BY <whatever>, numval)) AS no_dupe
FROM tbl
结果是一个数组,如果需要字符串,请将其包装在array_to_string()
中。
相关:
事实上,创建一个自定义聚合函数来对text
执行相同操作并不困难...
仅当数组与前一个元素不同时才向数组添加下一个元素的函数。 (NULL
值已删除!):
CREATE OR REPLACE FUNCTION f_array_append_uniq (anyarray, anyelement)
RETURNS anyarray AS
$func$
SELECT CASE WHEN $1[array_upper($1, 1)] <> $2 THEN $1 || $2 ELSE $1 END
$func$ LANGUAGE sql IMMUTABLE;
使用polymorphic types使其适用于任何标量数据类型。 自定义聚合函数:
CREATE AGGREGATE array_agg_uniq(anyelement) (
SFUNC = f_array_append_uniq
, STYPE = anyarray
, INITCOND = '{}'
);
呼叫:
SELECT array_to_string(
array_agg_uniq(sometext ORDER BY <whatever>, numval)
, ' ') AS no_dupe
FROM tbl;
相关答案:
答案 1 :(得分:2)
消除了通过预聚合
进行区分的需要select string_agg(sometext, ' ' order by numval)
from (
select sometext, min(numval) as numval
from t
group by sometext
) s
@Gordon's answer带来了一个好点。那就是有其他需要的列。在这种情况下,建议使用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
答案 2 :(得分:1)
如果这是较大表达式的一部分,则在子查询中执行select distinct
可能不方便。在这种情况下,您可以利用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>
子查询添加了一列,但不需要聚合数据。
答案 3 :(得分:1)
我最终做的是避免完全使用DISTINCT
而是选择使用正则表达式替换来删除顺序重复的条目(这是我的主要目标),如下所示:
regexp_replace(string_agg(sometext, ' ' ORDER BY numval),
'(\y\w+\y)(?:\s+\1)+', '\1', 'g')
如果外部排序导致他们之间有另一个条目,这不会删除重复,但这对我有用,可能更好。它可能比其他选项慢一点,但我发现它足够快,以达到我的目的。