it-swarm.com.de

Konvertieren Sie die rechte Seite der Verknüpfung von vielen zu vielen in ein Array

Wenn Sie Join für viele zu viele Beziehungen verwenden, wird das Ergebnis in mehrere Zeilen aufgeteilt. Ich möchte die rechte Seite eines Joins in ein Array konvertieren, sodass das Ergebnis eine Zeile ist.

Ein Beispiel wird es besser erklären als ich.

Also habe ich diese 3 Tabellen:

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)
);

Bei der Auswahl von Elementen mit ihren Tags kann ich dies folgendermaßen tun:

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;

Und das Ergebnis wird folgendermaßen aussehen:

(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")

Was ich gerne hätte, ist Folgendes:

(1, "item n1", ["sport", "soccer"])
(2, "item n2", ["adventure", "mountain climbing", "sport" , "nature"])
13
Ced

Zunächst haben Sie einen Tippfehler in Ihrer Anfrage. Die dritte Spalte wäre t.title. Ich habe Aliase hinzugefügt, um Folgendes zu verdeutlichen:

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;

Abgesehen davon: "id" oder "title" sind normalerweise keine sehr unterscheidenden und nicht sehr nützlichen Bezeichner. Mehr hier:

Beim Abfragen aller oder der meisten Elemente ist es normalerweise wesentlich schneller, zuerst zu aggregieren und dann zu verbinden:

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);

Verwenden Sie LEFT JOIN In der äußeren Abfrage, wenn Elemente ohne Tags vorhanden sein können, die mit einem INNER JOIN Ausgeschlossen sind.

Das Beitreten zu vorher Aggregation gerät auch mit mehr als einer 1: n-Tabelle in der FROM-Liste außer Kontrolle (in diesem einfachen Fall nicht). Vergleichen Sie:

Für eine kleine Auswahl würde ich einen LATERAL Join mit einem ARRAY-Konstruktor in Betracht ziehen:

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;

Da der ARRAY-Konstruktor immer eine Zeile erzeugt (mit leerem Array, wenn die Unterabfrage leer ist), ist LEFT JOIN LATERAL (...) ON true hier nicht von Nutzen.

Verbunden:

15

Sie müssen das group by Klausel und benutze 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,
5
Evan Carroll