Reputation: 97
I have three tables as follows:
Table A
:
id
--
1
2
Table B
:
id | table_a
-----+------------
100 | 1
101 | 1
102 | 2
103 | 2
Table C
:
id | table_b | item
-----+---------+-------
200 | 100 | Apple
201 | 100 | Apple
202 | 101 | Orange
203 | 102 | Apple
204 | 103 | Banana
205 | 103 | Rice
I want to get one row for every row in table A
, with the contents of table C
aggregated. (I guess with the ARRAY_AGG()
function?)
Obviously, table A
joins with table B
which joins with table C
. The final table will have the following contents:
id_table_a | item
-----------+---------------------
1 | Apple, Orange
2 | Apple, Banana, Rice
Upvotes: 0
Views: 451
Reputation: 656241
You did not specify, but your example also suggests to:
id_table_a
.c.id
- for practical reasons I suppose the lowest c.id
per group of duplicates.Assuming referential integrity, we don't need to involve table a
at all. Cheaper.
To remove duplicates while sorting by the minimum id
per group, use a two-step aggregation:
SELECT id_table_a
, string_agg(c.item, ', ' ORDER BY c_id) AS items
FROM (
SELECT b.table_a AS id_table_a, c.item, min(c.id) AS c_id
FROM b
JOIN c ON c.table_b = b.id
GROUP BY b.table_a, c.item
) c
GROUP BY id_table_a
ORDER BY id_table_a;
It's typically faster to sort in the subquery once instead of the per-group sort in the above query:
SELECT id_table_a
, string_agg(c.item, ', ') AS items
FROM (
SELECT b.table_a AS id_table_a, c.item
FROM b
JOIN c ON c.table_b = b.id
GROUP BY b.table_a, c.item
ORDER BY b.table_a, min(c.id)
) c
GROUP BY id_table_a
ORDER BY id_table_a;
Alternatively, supplying the input values from a sorted subquery will usually work.
Upvotes: 1