Reputation: 5119
My SQL function:
with recursive locpais as (
select l.id, l.nome, l.tipo tid, lp.pai
from loc l
left join locpai lp on lp.loc = l.id
where l.id = 12554
union
select l.id, l.nome, l.tipo tid, lp.pai
from loc l
left join locpai lp on lp.loc = l.id
join locpais p on (l.id = p.pai)
)
select * from locpais
gives me
12554 | PARNA Pico da Neblina | 9 | 1564
12554 | PARNA Pico da Neblina | 9 | 1547
1547 | São Gabriel da Cachoeira | 8 | 1400
1564 | Santa Isabel do Rio Negro | 8 | 1400
1400 | RIO NEGRO | 7 | 908
908 | NORTE AMAZONENSE | 6 | 234
234 | Amazonas | 5 | 229
229 | Norte | 4 | 30
30 | Brasil | 3 |
which is a hierarchy of places. "PARNA" stands for "National Park", and this one covers two cities: São Gabriel da Cachoeira and Santa Isabel do Rio Negro. Thus it's appearing twice.
If I change the last line for
select string_agg(nome,', ') from locpais
I get
"PARNA Pico da Neblina, PARNA Pico da Neblina, São Gabriel da Cachoeira, Santa Isabel do Rio Negro, RIO NEGRO, NORTE AMAZONENSE, Amazonas, Norte, Brasil"
Which is almost fine, except for the double "PARNA Pico da Neblina". So I tried:
select string_agg(distinct nome, ', ') from locpais
but now I get
"Amazonas, Brasil, Norte, NORTE AMAZONENSE, PARNA Pico da Neblina, RIO NEGRO, Santa Isabel do Rio Negro, São Gabriel da Cachoeira"
Which is out of order. I'm trying to add an order by
inside the string_agg
, but couldn't make it work yet. The definition of the tables were given here.
Upvotes: 5
Views: 6000
Reputation: 643
As you've found out, you cannot combine DISTINCT
and ORDER BY
if you don't order by the distinct expression first:
neither in aggregates:
nor in SELECT:
The DISTINCT ON expression(s) must match the leftmost ORDER BY expression(s).
However could use something like
array_to_string(arry_uniq_stable(array_agg(nome ORDER BY tid DESC)), ', ')
with the help of a function arry_uniq_stable
that removes duplicates in an array w/o altering it's order like I gave an example for in https://stackoverflow.com/a/42399297/5805552
Please take care to use an ORDER BY
expression that actually gives you an deterministic result. With the example you have given, tid
alone would be not enough, as there are duplicate values (8) with different nome
.
Upvotes: 5
Reputation: 125214
select string_agg(nome,', ')
from (
select distinct nome
from locpais
order by tid desc
) s
Upvotes: 2