Verwenden von GROUP_CONCAT für eine Unterabfrage in MySQL
-
22-08-2019 - |
Frage
Ich habe eine MySQL-Abfrage, in die ich eine Liste von IDs aus einer anderen Tabelle einschließen möchte.Auf der Website können Benutzer bestimmte Artikel hinzufügen und diese Artikel dann zu ihren Favoriten hinzufügen.Grundsätzlich möchte ich die Liste der IDs der Personen erhalten, die diesen Artikel als Favorit markiert haben (das ist etwas vereinfacht, aber das ist es, worauf es hinausläuft).
Im Grunde mache ich so etwas:
SELECT *,
GROUP_CONCAT((SELECT userid FROM favourites WHERE itemid = items.id) SEPARATOR ',') AS idlist
FROM items
WHERE id = $someid
Auf diese Weise könnte ich zeigen, wer ein Element favorisiert hat, indem ich die Idlist später in einem PHP-Array weiter unten in meinem Code aufteile. Ich erhalte jedoch den folgenden MySQL-Fehler:
1242 – Unterabfrage gibt mehr als eine Zeile zurück
Ich dachte, das wäre irgendwie der Sinn der Verwendung GROUP_CONCAT
statt beispielsweise CONCAT
?Mache ich das falsch?
Ok, danke für die bisherigen Antworten, das scheint zu funktionieren.Allerdings gibt es einen Haken.Elemente gelten auch dann als Favorit, wenn sie von diesem Benutzer hinzugefügt wurden.Daher bräuchte ich eine zusätzliche Prüfung, um zu prüfen, ob Ersteller = Benutzer-ID.Kann mir jemand helfen, eine intelligente (und hoffentlich effiziente) Möglichkeit zu finden, dies zu tun?
Danke schön!
Bearbeiten:Ich habe gerade versucht, Folgendes zu tun:
SELECT [...] LEFT JOIN favourites ON (userid = itemid OR creator = userid)
Und Id-Liste ist leer.Beachten Sie, dass, wenn ich verwende INNER JOIN
anstatt LEFT JOIN
Ich erhalte ein leeres Ergebnis.Auch wenn ich mir sicher bin, dass es Zeilen gibt, die die ON-Anforderung erfüllen.
Lösung
Sie keine Variablen in dem äußeren Umfang in solchen Abfragen zugreifen können (kann dort nicht verwenden items.id
). Sie sollten vielmehr versuchen, so etwas wie
SELECT
items.name,
items.color,
CONCAT(favourites.userid) as idlist
FROM
items
INNER JOIN favourites ON items.id = favourites.itemid
WHERE
items.id = $someid
GROUP BY
items.name,
items.color;
Erweitern Sie die Liste der Felder nach Bedarf (Name, Farbe ...).
Andere Tipps
OP bekam fast es richtig. GROUP_CONCAT
soll die Spalten in der Unterabfrage wurde Verpackung und nicht die komplette Unterabfrage (Ich entlassen den Separator weil Komma ist die Standardeinstellung ):
SELECT i.*,
(SELECT GROUP_CONCAT(userid) FROM favourites f WHERE f.itemid = i.id) AS idlist
FROM items i
WHERE i.id = $someid
Dies wird das gewünschte Ergebnis liefern und bedeutet auch, dass die akzeptierte Antwort teilweise falsch ist, weil Sie äußere Umfang Variablen in einer Unterabfrage zugreifen können.
Ich glaube, Sie haben „userid = itemid“ falsch, es sollte nicht so sein:
SELECT ITEMS.id,GROUP_CONCAT(FAVOURITES.UserId) AS IdList
FROM FAVOURITES
INNER JOIN ITEMS ON (ITEMS.Id = FAVOURITES.ItemId OR FAVOURITES.UserId = ITEMS.Creator)
WHERE ITEMS.Id = $someid
GROUP BY ITEMS.ID
Der Zweck GROUP_CONCAT ist richtig, aber die Unterabfrage ist nicht erforderlich, und das Problem verursacht. Versuchen Sie stattdessen:
SELECT ITEMS.id,GROUP_CONCAT(FAVOURITES.UserId)
FROM FAVOURITES INNER JOIN ITEMS ON ITEMS.Id = FAVOURITES.ItemId
WHERE ITEMS.Id = $someid
GROUP BY ITEMS.ID
Ja, die Lösung von Soulmerge ist in Ordnung.Aber ich brauchte eine Abfrage, bei der ich Daten aus weiteren untergeordneten Tabellen sammeln musste, zum Beispiel:
- Haupttabelle: Sitzungen (Präsentationssitzungen) (UID, Name, ..)
- 1. Kindertisch: Veranstaltungen mit Schlüssel session_id (uid, session_uid, date, time_start, time_end)
- 2. Kindertisch: accessoires_needed (Laptop, Projektor, Mikrofone usw.) mit Schlüssel session_id (uid, session_uid, accessoire_name)
- 3. Kindertisch: session_presenters (Vortragende Personen) mit Schlüssel session_id (uid, session_uid, vortragender_Name, Adresse...)
Jede Sitzung hat mehr Zeilen in untergeordneten Tabellen (mehr Zeitpläne, mehr Zubehör).
Und ich musste für jede Sitzung eine Sammlung sammeln, um sie in der Erzzeile anzuzeigen (einige davon):
session_id | session_name | date | time_start | time_end | accessories | presenters
Meine Lösung (nach vielen Stunden des Experimentierens):
SELECT sessions.uid, sessions.name,
,(SELECT GROUP_CONCAT( `events`.date SEPARATOR '</li><li>')
FROM `events`
WHERE `events`.session_id = sessions.uid ORDER BY `events`.date) AS date
,(SELECT GROUP_CONCAT( `events`.time_start SEPARATOR '</li><li>')
FROM `events`
WHERE `events`.session_id = sessions.uid ORDER BY `events`.date) AS time_start
,(SELECT GROUP_CONCAT( `events`.time_end SEPARATOR '</li><li>')
FROM `events`
WHERE `events`.session_id = sessions.uid ORDER BY `events`.date) AS time_end
,(SELECT GROUP_CONCAT( accessories.name SEPARATOR '</li><li>')
FROM accessories
WHERE accessories.session_id = sessions.uid ORDER BY accessories.name) AS accessories
,(SELECT GROUP_CONCAT( presenters.name SEPARATOR '</li><li>')
FROM presenters
WHERE presenters.session_id = sessions.uid ORDER BY presenters.name) AS presenters
FROM sessions
Es ist also kein JOIN oder GROUP BY erforderlich.Eine weitere nützliche Sache, um Daten benutzerfreundlich anzuzeigen (beim „Echo“):
- Sie können events.date, time_start, time_end usw. in „<UL><LI> ...“ einschließen.</LI></UL>“, sodass das in der Abfrage als Trennzeichen verwendete „<LI></LI>“ die Ergebnisse in Listenelemente trennt.
Ich hoffe, das hilft jemandem.Prost!