Ao usar o relacionamento de muitos para muitos, o resultado é dividido em várias linhas. O que eu gostaria de fazer é converter o lado direito de uma junção em uma matriz para que o resultado seja uma linha.
Exemplo com 3 tabelas:
CREATE TABLE items (
id serial primary key,
title text
);
CREATE TABLE tags (
id serial primary key,
title text
);
CREATE TABLE items_tags (
item_id int references items(id),
tag_id int references tags(id),
primary key (item_id, tag_id)
);
Ao selecionar itens com suas tags, posso fazer assim:
SELECT i.id, i.title, i.title
FROM items i
INNER JOIN items_tags it
ON it.item_id = i.id
INNER JOIN tags t
ON t.id = it.tag_id;
E o resultado será:
(1, "item n1", "sport")
(1, "item n1", "soccer")
(2, "item n2", "adventure")
(2, "item n2", "mountain climbing")
(2, "item n2", "sport")
(2, "item n2", "nature")
O que eu gostaria de ter é isso:
(1, "item n1", ["sport", "soccer"])
(2, "item n2", ["adventure", "mountain climbing", "sport" , "nature"])
Para agregar a maioria das linhas
Ao consultar todos ou a maioria dos itens, normalmente é substancialmente mais rápido agregar linhas da tabela "muitos" primeiro e unir depois:
Use
LEFT [OUTER] JOIN
na consulta externa se houver itens sem tags - que seriam excluídos com[INNER] JOIN
.Como isso não multiplica as linhas na junção, não precisamos
GROUP BY
no exteriorSELECT
.A junção antes da agregação também fica fora de controle com mais de uma tabela 1:n na
FROM
lista (não neste caso simples). Ver:Para agregar algumas linhas
Para uma pequena porcentagem de linhas, use uma
LATERAL
junção com um construtor ARRAY :Como um construtor ARRAY sempre produz uma linha (com array vazio se a subconsulta estiver vazia - diferença sutil no resultado!),
LEFT JOIN LATERAL (...) ON true
não é necessário aqui. Ver:Aparte
Você teve um erro de digitação na sua consulta. A 3ª coluna seria
t.title
. Adicionei aliases à sua consulta original (não agregada) para esclarecer:"id" ou "title" normalmente não são identificadores muito distintivos e não muito úteis. Ver:
Você precisa adicionar a
group by
cláusula e usararray_agg
.