webentwicklung-frage-antwort-db.com.de

MySQL JOIN mit LIMIT 1 auf der verbundenen Tabelle

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?

49
John Davidson

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
 )
46
Kostanos

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;
21
Gravy
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).

8
Jessé Catrinck

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

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;
1
Krab

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

0
Yaki Klein

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
0
Mchl