2016-08-13 3 views
1

Ich versuche, zwei Tabellen zu verbinden, aber ich habe einige Probleme. Dies ist die Haupttabelle, packsMySQL JOINS: Wählen Sie eine Zeile von Kind-Tabelle ist Bedingung erfüllt ist, sonst NULL

This is the main table

Und hier ist die zweite Tabelle, media enter image description here

Die media ist für Bilder von packs speichern. Jedes Paket kann 0 oder mehr Bilder enthalten. Wenn das Paket Bilder enthält, wird das Feld is_default auf 1 gesetzt, um das Hauptbild anzuzeigen.

Ich möchte alle Pack und ein Bild für jeden bekommen. Wenn es keine Bilder gibt, dann einfach eine einfache NULL, sonst erhalten Sie das Bild, das is_default ist.

Hier ist meine Abfrage.

SELECT 
    pack.*, 
    (SELECT media.src FROM packs pack LEFT JOIN packs_media media ON pack.id = media.pack_id WHERE media.is_default = 1 GROUP BY media.id LIMIT 1) AS image 
FROM packs pack 
LEFT JOIN packs_media ON media.pack_id = pack.id 
GROUP BY pack.id 
ORDER BY pack.id DESC 

Ich habe insgesamt drei Packs, und nur eines von ihnen hat einige Bilder. Die Abfrage gibt 3 Ergebnisse zurück. Das Problem ist, dass alle drei Ergebnisse die gleiche image haben, wenn nur eins sollte und die anderen beiden das image Feld null/leer haben sollten.

Gibt es eine Möglichkeit, dies nur mit einer Abfrage zu tun? Ich möchte vermeiden, die Tabelle media in einer Schleife abzufragen.

Danke

Antwort

1

Ich hatte ein ähnliches Problem in letzter Zeit, und es hat eine wirklich, wirklich süße Lösung, um ehrlich zu sein. Auf den ersten Blick wäre ein naheliegender Versuch, die WHERE Bedingung is_default = 1 hinzuzufügen. Wenn wir dies jedoch tun, wo keine Bilder vorhanden sind, wird die Bedingung nicht erfüllt, das heißt, sie sollte NULL zurückgeben, sie überspringt nur diese Zeile.

Allerdings, wenn Sie diese Bedingung zum LEFT JOIN Teil hinzufügen, wie ich es getan habe, funktioniert es wie ein Charme. Wenn die LEFT JOIN Bedingungen erfüllt sind, gibt es das Bild zurück, und wenn nicht, gibt es NULL, nach der Definition von LEFT JOIN zurück.

So sollte das Ergebnis sein:

SELECT pack.*, media.src 
FROM packs pack 
LEFT JOIN media 
ON media.pack_id = pack.id 
AND media.is_default = 1 

Und ich denke, Sie GROUP nicht hinzufügen sollten sie die Dinge einfach vermasselt.

Wenn Sie Ihr Problem lösen wollen, auch wenn es keine is_default ... Nun, das ist eine härtere Nuss zu knacken, aber ich denke, ich habe eine Lösung, die nicht in langen Zeilen von Bedingungen und Unterabfragen verweilen wird. Leider habe ich das Gefühl, dass dieses Problem nicht ohne eine Unterabfrage gelöst werden kann. Meine Idee war nicht, den Artikel zu wählen, dessen media.is_default gleich 1 ist, sondern der den höchsten media.is_default hat. Wie folgt:

SELECT pack.*, media.src 
FROM packs pack 
LEFT JOIN media 
ON media.pack_id = pack.id 
AND media.id = 
    (SELECT m.id FROM media m 
    WHERE m.pack_id = media.pack_id 
    ORDER BY m.is_default DESC 
    LIMIT 1 
    ) 

Erläuterung: Dies ist, wie es funktioniert: wir alle durch is_default in absteigender Reihenfolge zu bestellen, und zurück in der äußeren Abfrage beziehen sie nur verwenden, um die aktuellen pack_id (. Ich hoffe, dass es so funktioniert) Wenn es eine 1 gibt, ist es offensichtlich der erste Gegenstand, ansonsten wird es ein zufälliger Gegenstand sein, höchstwahrscheinlich der erste in der Reihenfolge der ID. Und du nimmst einfach dieses Element und benutzt es. Ich kann nicht garantieren, dass es überhaupt funktioniert. Versuchen Sie es mit IN anstelle von = als möglichen Bugfix.

Allerdings würde ich NICHT diese Lösung empfehlen. Ich würde lieber die vorherige Logik ändern, um dieses Problem zu vermeiden (z. B. wenn der Benutzer ein Medium zu einem leeren Paket hinzufügt, is_default = 1 auf diesem Bild).

+0

Vielen Dank. Es funktioniert super und es sieht sehr sauber aus. Würde es Ihnen etwas ausmachen, mir zu sagen, ob es möglich ist, zum Beispiel das erste Bild auszuwählen, wenn das Feld is_default nicht 1 ist, aber das Paket noch Bilder hat? Wenn es 1 ist, hol das Bild. Ansonsten hol dir den ersten oder nur einen anderen, damit das Paket mindestens ein Bild hat. Wenn das Paket keine hat, dann null. –

+0

Ich habe meine Antwort geändert, um auf Ihren Kommentar zu antworten. Ich hoffe, dass das hilft, aber ich versuche wirklich, den Gedanken zu verschieben, einen anderen Teil des Codes zu ändern, um diesen Teil einfacher zu machen. Glauben Sie mir, Sie wollen lieber zwei kleinere Fragen, die Sie verstehen, und nicht eine lange, an die Sie sich eine Woche später nicht mehr erinnern werden. –

1

Sie eine korrelierte Unterabfrage müssen statt einer beitreten:

SELECT p.*, 
     (SELECT m.src 
     FROM packs_media m 
     WHERE p.id = media.p 
     ORDER BY m.is_default DESC, m.id 
     LIMIT 1 
    ) AS image 
FROM packs p 
ORDER BY p.id DESC; 

In der Tat, aus der Beschreibung des Problems, nicht JOIN ist entweder in der äußeren Abfrage erforderlich. So wird auch die GROUP BY nicht benötigt.

Beachten Sie die Änderung der ORDER BY Klausel. Dies garantiert, dass der Standardwert zuerst gewählt wird.

Und Ihre Abfrage erhält den gleichen Wert für alle Zeilen, weil die Unterabfrage unabhängig von der äußeren Abfrage ist. Daher wird immer derselbe Wert gewählt.

+0

'm.is_default = 1 ORDER BY m.is_default'? –

+0

Danke. Es funktioniert in der Tat. Nur eine kurze Frage. Wenn es Bilder gibt, aber keine das is_default = 1, ist es möglich, noch eins zu bekommen? Wenn jetzt ein Paket Bilder enthält, aber kein Standard ist, wird null zurückgegeben. –

+0

@ C.Ovidiu - entfernen Sie die Bedingung "AND m.is_default = 1" in der Unterabfrage –

Verwandte Themen