Lorsque vous utilisez la jointure sur plusieurs à plusieurs, le résultat est divisé sur plusieurs lignes. Ce que j'aimerais faire, c'est convertir le côté droit d'une jointure en un tableau pour que le résultat soit une ligne.
Un exemple l'expliquera mieux que moi.
J'ai donc ces 3 tableaux:
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)
);
Lorsque je sélectionne des éléments avec leurs balises, je peux le faire de cette façon:
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;
Et le résultat se présentera comme:
(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")
Ce que j'aimerais avoir, c'est ceci:
(1, "item n1", ["sport", "soccer"])
(2, "item n2", ["adventure", "mountain climbing", "sport" , "nature"])
Tout d'abord, vous avez une faute de frappe dans votre requête. La troisième colonne serait t.title
. J'ai ajouté des alias pour clarifier:
SELECT i.id, i.title AS item_title, t.title AS tag_title
FROM items i
JOIN items_tags it ON it.item_id = i.id
JOIN tags t ON t.id = it.tag_id;
À part: "id" ou "title" ne sont généralement pas des identifiants très distinctifs et peu utiles. Plus ici:
Lors de l'interrogation de la totalité ou de la plupart des éléments , il est généralement beaucoup plus rapide d'agréger d'abord puis de rejoindre:
SELECT id, i.title AS item_title, t.tag_array
FROM items i
JOIN ( -- or LEFT JOIN ?
SELECT it.item_id AS id, array_agg(t.title) AS tag_array
FROM items_tags it
JOIN tags t ON t.id = it.tag_id
GROUP BY it.item_id
) t USING (id);
Utilisez LEFT JOIN
Dans la requête externe s'il peut y avoir des éléments sans balises, qui sont exclus avec un INNER JOIN
.
Rejoindre avant l'agrégation devient également incontrôlable avec plus d'une table 1: n dans la liste FROM
(pas dans ce cas simple). Comparer:
Pour une petite sélection , je considérerais une jointure LATERAL
avec un constructeur ARRAY:
SELECT id, title AS item_title, t.tag_array
FROM items i, LATERAL ( -- this is an implicit CROSS JOIN
SELECT ARRAY (
SELECT t.title
FROM items_tags it
JOIN tags t ON t.id = it.tag_id
WHERE it.item_id = i.id
) AS tag_array
) t;
Puisque le constructeur ARRAY produit toujours une ligne (avec un tableau vide si la sous-requête est vide), LEFT JOIN LATERAL (...) ON true
n'est d'aucune utilité ici.
En relation:
Vous devez ajouter le group by
clause et utiliser array_agg
.
SELECT i.id, i.title, array_agg(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
GROUP BY i.id, i.title,