SELECT * FROM mehrere Tabellen. MySQL

75

SELECT name, price, photo FROM drinks, drinks_photos WHERE drinks.id = drinks_id

yeilds 5 Zeilen (5 Arrays), photoist das einzige eindeutige Feld in einer Zeile. name, pricewerde wiederholt ( hier fanta- name, price dreimal wiederholen ). Wie entferne ich diese Duplikate?

Edit: Ich will name, priceund alles photofür jedes Getränk.

 id      name      price
  1.    fanta        5
  2.     dew         4


 id      photo                   drinks_id
  1.     ./images/fanta-1.jpg      1
  2.     ./images/fanta-2.jpg      1  
  3.     ./images/fanta-3.jpg      1 
  4.     ./images/dew-1.jpg        2
  5.     ./images/dew-2.jpg        2
NestedWeb
quelle
5
Nun, Sie haben 5 passende Zeilen, da Sie mehrere Zeilen mit derselben Drinks_ID haben. Was würden Sie erwarten ? Welches Foto würden Sie voraussichtlich behalten?
Jon Skeet

Antworten:

107

Was Sie hier tun, wird als a bezeichnet JOIN(obwohl Sie dies implizit tun, weil Sie aus mehreren Tabellen auswählen). Das heißt, wenn Sie keine Bedingungen in Ihre WHERE-Klausel aufgenommen haben, hatten Sie alle Kombinationen dieser Tabellen. Nur mit Ihrer Bedingung beschränken Sie Ihre Verbindung auf die Zeilen, in denen die Getränke-ID übereinstimmt.

Es gibt jedoch immer noch X mehrere Zeilen im Ergebnis für jedes Getränk, wenn X Fotos mit dieser bestimmten Getränke-ID vorhanden sind. Ihre Aussage schränkt nicht ein, welche Fotos Sie haben möchten!

Wenn Sie nur eine Zeile pro Getränk möchten, müssen Sie SQL mitteilen, was Sie tun möchten, wenn mehrere Zeilen mit einer bestimmten Getränke-ID vorhanden sind. Dazu benötigen Sie eine Gruppierung und eine Aggregatfunktion . Sie teilen SQL mit, welche Einträge Sie gruppieren möchten (z. B. alle gleichen Drinks_ids), und in SELECT müssen Sie angeben, welche der unterschiedlichen Einträge für jede gruppierte Ergebniszeile verwendet werden sollen. Bei Zahlen kann dies Durchschnitt, Minimum, Maximum sein (um nur einige zu nennen).

In Ihrem Fall sehe ich keinen Sinn darin, die Fotos nach Getränken abzufragen, wenn Sie nur eine Zeile möchten. Sie dachten wahrscheinlich, Sie könnten für jedes Getränk eine Reihe von Fotos in Ihrem Ergebnis haben, aber SQL kann dies nicht. Wenn Sie nur ein Foto möchten und es Ihnen egal ist, welches Sie erhalten, gruppieren Sie es einfach nach der drink_id (um nur eine Zeile pro Getränk zu erhalten):

SELECT name, price, photo
FROM drinks, drinks_photos
WHERE drinks.id = drinks_id 
GROUP BY drinks_id

name     price   photo
fanta    5       ./images/fanta-1.jpg
dew      4       ./images/dew-1.jpg

In MySQL haben wir auch GROUP_CONCAT , wenn Sie möchten, dass die Dateinamen zu einer einzigen Zeichenfolge verkettet werden:

SELECT name, price, GROUP_CONCAT(photo, ',')
FROM drinks, drinks_photos
WHERE drinks.id = drinks_id 
GROUP BY drinks_id

name     price   photo
fanta    5       ./images/fanta-1.jpg,./images/fanta-2.jpg,./images/fanta-3.jpg
dew      4       ./images/dew-1.jpg,./images/dew-2.jpg

Dies kann jedoch gefährlich werden, wenn Sie ,Werte innerhalb des Feldes haben, da Sie diese höchstwahrscheinlich auf der Clientseite erneut aufteilen möchten. Es ist auch keine Standard-SQL-Aggregatfunktion.

Leemes
quelle
Ja, ich wollte Name, Preis und eine Reihe von Bildern für jedes Getränk.
NestedWeb
3
In welcher Sprache codieren Sie Ihr Programm, das diese Abfragen ausführt? Weil MySQL keine Arrays als Feldtypen unterstützt. Sie müssen einige String-Tricks wie mit dem machen GROUP_CONCATund es erneut teilen. In relationalen Datenbanken ist dies normalerweise nicht der Fall. Sie sollten die Gruppierung im Programm und nicht in SQL durchführen (erkennen Sie die doppelten IDs und erstellen Sie diese Arrays in Ihrem Programm).
Leemes
@NestedWeb Bitte werfen Sie auch einen Blick auf stackoverflow.com/questions/9024248/…
leemes
@NestedWeb Wenn Sie alle Bilder wollen, wird es besser sein (schneller) nicht zu verwenden GROUP BYund GROUP_CONTACT, aber auch weiterhin , wie Sie taten , aber um durch drinks.id. Auf diese Weise können Sie die Ergebnismenge durchlaufen und Bilder auf der Clientseite in Arrays sammeln.
Bhovhannes
Es entspricht INNER JOIN.
Sławomir Lenart
3

Hier haben Sie die doppelten Werte für Name und Preis. Und IDs sind in der Tabelle drink_photos doppelt vorhanden. Sie können sie auf keinen Fall vermeiden. Auch was genau möchten Sie für die Ausgabe?

AnandPhadke
quelle
2

Um Duplikate zu entfernen, können Sie nach gruppieren drinks.id. Auf diese Weise erhalten Sie jedoch nur ein Foto für jedes Foto drinks.id(welches Foto Sie erhalten, hängt von der datenbankinternen Implementierung ab).

Obwohl es nicht dokumentiert ist, erhalten Sie im Fall von MySQL das Foto mit dem niedrigsten Wert id(meiner Erfahrung nach habe ich noch nie ein anderes Verhalten gesehen).

SELECT name, price, photo 
FROM drinks, drinks_photos 
WHERE drinks.id = drinks_id
GROUP BY drinks.id
Bhovhannes
quelle
1
Sie sollten besser nach der ID gruppieren. Gruppieren Sie immer nach Ihrem eindeutigen Feld, um eindeutige Zeilen einer Quelltabelle zu erhalten. Wenn in Ihrem Fall zwei Getränke denselben Namen haben (aber unterschiedliche Zeilen in der Tabelle sind), würden Sie sie auch zusammenfassen.
Leemes
danke leemes, ich habe nicht bemerkt, dass es ein eindeutiges ID-Feld gibt. Ich habe meine Antwort bearbeitet. Natürlich ist es besser, ID zu verwenden. @ypercube, denkst du wirklich, dass dein Kommentar etwas Übliches zum Posten hinzufügt?
Bhovhannes
@ Bhovhannes: Nein, du hast recht, sorry. Snarky-Kommentare fügen nichts Nützliches hinzu. Eine korrigierte Antwort ist besser - obwohl ich mit dieser Verwendung von GROUP BY(das ist kein SQL-Standard) immer noch nicht einverstanden bin, ohne zu erklären, warum es funktioniert und wie es photofür jedes Getränk einen halbzufälligen Wert zurückgibt. (Das "erste" in der Phrase "Sie erhalten das erste Foto" ist einfach falsch).
Ypercubeᵀᴹ
@ypercube, ja, die Verwendung von GROUP BY zum Filtern von Zeilen (wie in dieser Situation) ist kein SQL-Standard. Aber das funktioniert definitiv für MySQL, ist schnell und kehrt photomit der niedrigsten ID zurück. Ich habe noch nie ein anderes Verhalten in MySQL gesehen (obwohl es nicht dokumentiert ist). Ich habe eine Notiz zu meinem Beitrag hinzugefügt
bhovhannes