Modify postgresql “list” aggregate to remove duplicates
-
05-09-2019 - |
Question
One of my favorite postgres aggregates is "list", attributed to "Chris Rohlfs in the idocs" according to the scanty evidence I can find on the web.
CREATE FUNCTION comma_cat (text, text)
RETURNS text AS
'SELECT CASE
WHEN $2 is null or $2 = '''' THEN $1
WHEN $1 is null or $1 = '''' THEN $2
ELSE $1 || '', '' || $2
END'
LANGUAGE sql;
CREATE AGGREGATE list (BASETYPE = text, SFUNC = comma_cat, STYPE = text, INITCOND = '');
I find, sometimes, that I would like it to eliminate duplicates. An old mailing list thread suggests that this approach can't do sorting, which might be a deal-killer for duplication removal. Another post in the same thread suggests a function that does the same thing; maybe it's more modifiable for this purpose?
In the meantime, I'll just massage the output in another language. But it would be cool if we could do this directly in postgres!
Solution
You can use intermediate arrays:
CREATE OR REPLACE FUNCTION comma_cat(text[], text)
RETURNS text[] AS
$BODY$
SELECT
CASE WHEN $1 @> ARRAY[$2] THEN $1
ELSE $1 || $2
END
$BODY$
LANGUAGE 'sql' VOLATILE;
CREATE OR REPLACE FUNCTION comma_finish(text[])
RETURNS text AS
$BODY$
SELECT array_to_string($1, ', ')
$BODY$
LANGUAGE 'sql' VOLATILE
COST 100;
CREATE AGGREGATE list (BASETYPE = text, SFUNC = comma_cat, STYPE = text[], FINALFUNC = comma_finish, INITCOND = '{NULL, NULL}');
value id
-------- --
"puer" 1
"socer" 2
"vesper" 3
"vesper" 4
"gener" 5
"asper" 6
"asper" 7
"miser" 8
"tener" 9
"liber" 10
"puer" 11
SELECT list(value)
FROM t_text
"puer, vesper, gener, asper, miser, tener, liber, socer"
OTHER TIPS
you can just put a "distinct" qualifier inside the aggregate function call to remove duplicates:
select list(distinct <column>)
from...