Ich möchte zwei Tabellen verbinden, bekomme aber nur einen Datensatz von Table2 pro Datensatz in Table1
Zum Beispiel:
SELECT c.id, c.title, p.id AS product_id, p.title
FROM categories AS c
JOIN products AS p ON c.id = p.category_id
Dies würde mir alle Datensätze in products
geben, was ich nicht will. Ich möchte 1 [das erste] Produkt pro Kategorie (Ich habe eine sort
-Spalte im Produktfeld).
Wie mache ich das?
Ich mag mehr einen anderen Ansatz, der in einer ähnlichen Frage beschrieben wird: https://stackoverflow.com/a/11885521/2215679
Diese Vorgehensweise ist besonders für den Fall besser, wenn Sie in SELECT mehr als ein Feld anzeigen müssen. Zur Vermeidung von Error Code: 1241. Operand should contain 1 column(s)
oder doppelter Unterauswahl für jede Spalte.
Für Ihre Situation sollte die Abfrage folgendermaßen aussehen:
SELECT
c.id,
c.title,
p.id AS product_id,
p.title AS product_title
FROM categories AS c
JOIN products AS p ON
p.id = ( --- the PRIMARY KEY
SELECT p1.id FROM products AS p1
WHERE c.id=p1.category_id
ORDER BY p1.id LIMIT 1
)
Die akzeptierte Antwort von @ goggin13 sieht falsch aus. Andere Lösungen, die bisher zur Verfügung gestellt wurden, funktionieren zwar, leiden jedoch unter dem n + 1-Problem und leiden daher unter einem Leistungsabfall.
n + 1 Problem: Wenn es 100 Kategorien gibt, müssen wir 1 auswählen, um die Kategorien zu erhalten. Dann müssen wir für jede der 100 zurückgegebenen Kategorien eine Auswahl treffen, um die Produkte in dieser Kategorie zu erhalten. Es würden also 101 SELECT-Abfragen ausgeführt.
Meine alternative Lösung löst das n + 1-Problem und sollte daher wesentlich leistungsfähiger sein, da nur 2 Auswahlen ausgeführt werden.
SELECT
*
FROM
(SELECT c.id, c.title, p.id AS product_id, p.title
FROM categories AS c
JOIN products AS p ON c.id = p.category_id
ORDER BY c.id ASC) AS a
GROUP BY id;
SELECT c.id, c.title, p.id AS product_id, p.title
FROM categories AS c
JOIN products AS p ON c.id = p.category_id
GROUP BY c.id
Dies gibt die ersten Daten in Produkten zurück (entspricht Limit 1).
Die With-Klausel würde den Trick tun. Etwas wie das:
WITH SELECTION AS (SELECT id FROM products LIMIT 1)
SELECT a.id, c.id, c.title FROM selection a JOIN categories c ON (c.id = a.id);
Was ist damit?
SELECT c.id, c.title, (SELECT id from products AS p
WHERE c.id = p.category_id
ORDER BY ...
LIMIT 1)
FROM categories AS c;
Wenn Sie Postgres verwenden, können Sie mit der Syntax DISTINCT ON
die Anzahl der von beiden Tabellen zurückgegebenen Spalten begrenzen.
Hier ist ein Beispiel für den Code:
SELECT c.id, c.title, p.id AS product_id, p.title
FROM categories AS c
JOIN (
SELECT DISTINCT ON(p1.id) id, p1.title, p1.category_id
FROM products p1
) p ON (c.id = p.category_id)
Der Trick besteht darin, nicht direkt in der Tabelle mit mehreren Vorkommen der ID zu verbinden, sondern erst eine Tabelle mit nur einem Vorkommen für jede ID zu erstellen
Angenommen, Sie möchten ein Produkt mit dem MIN()
imial-Wert in der Spalte sort
, würde es ungefähr so aussehen.
SELECT
c.id, c.title, p.id AS product_id, p.title
FROM
categories AS c
INNER JOIN (
SELECT
p.id, p.category_id, p.title
FROM
products AS p
CROSS JOIN (
SELECT p.category_id, MIN(sort) AS sort
FROM products
GROUP BY category_id
) AS sq USING (category_id)
) AS p ON c.id = p.category_id