Kombinieren Sie mehrere untergeordnete Zeilen zu einer Zeile MYSQL

74

Vielen Dank im Voraus, ich kann es einfach nicht verstehen!

Ich habe zwei Tische

Ordered_Item

ID | Artikelname
1 | Pizza
2 | Stromboli

Ordered_Options

Ordered_Item_ID | Optionsnummer | Wert
        1 43 ​​Peperoni
        1 44 Extra Käse
        2 44 Extra Käse

Was ich ausgeben möchte, ist eine MySQL-Abfrage, die etwas in diesem Sinne ist

Ausgabe

ID | Item_Name | Option_1 | Option 2
1 Pizza Pepperoni Extra Käse
2 Stromboli NULL Extra Käse

Ich habe zahlreiche Optionen ausprobiert, die meistens mit Syntaxfehlern enden. Ich habe group_concat ausprobiert, aber das ist nicht wirklich das, wonach ich suche. Ich habe unten ein grobes Beispiel dafür, was ich für einen Anfang halte. Ich muss die Optionen jedes Mal in der gleichen Reihenfolge haben. Und in dem Programm, in dem die Informationen gesammelt werden, gibt es keine Möglichkeit, zuverlässig sicherzustellen, dass dies geschieht. Ist es möglich, sie entsprechend der Optionsnummer verketten zu lassen? Ich weiß auch, dass ich nie mehr als 5 Optionen haben werde, damit eine statische Lösung funktioniert

Select Ordered_Items.ID,
    Ordered_Items.Item_Name,
FROM Ordered_Items
    JOIN (SELECT Ordered_Options.Value FROM Ordered_Options Where Option_Number = 43) as Option_1 
        ON Ordered_Options.Ordered_Item_ID = Ordered_Item.ID
    JOIN (SELECT Ordered_Options.Value FROM Ordered_Options Where Option_Number = 44) as Option_2 
        ON Ordered_Options.Ordered_Item_ID = Ordered_Item.ID;

Vielen Dank! Joe

Kermit
quelle

Antworten:

124

Am einfachsten wäre es, hier die Gruppenfunktion GROUP_CONCAT zu verwenden.

select
  ordered_item.id as `Id`,
  ordered_item.Item_Name as `ItemName`,
  GROUP_CONCAT(Ordered_Options.Value) as `Options`
from
  ordered_item,
  ordered_options
where
  ordered_item.id=ordered_options.ordered_item_id
group by
  ordered_item.id

Welches würde ausgeben:

Id              ItemName       Options

1               Pizza          Pepperoni,Extra Cheese

2               Stromboli      Extra Cheese

Auf diese Weise können Sie so viele Optionen haben, wie Sie möchten, ohne Ihre Abfrage ändern zu müssen.

Ah, wenn Sie sehen, dass Ihre Ergebnisse beschnitten werden, können Sie die Größenbeschränkung von GROUP_CONCAT folgendermaßen erhöhen:

SET SESSION group_concat_max_len = 8192;
Wouter van Nifterick
quelle
3
Er sagte: "Ich habe group_concat ausprobiert, aber das ist nicht wirklich das, wonach ich suche."
Haim Evgi
Hallo, danke für die schnelle Antwort, aber ich fürchte, ich habe keine wichtigen Informationen hinzugefügt. Ich muss die Optionen jedes Mal in der gleichen Reihenfolge haben. Und in dem Programm, in dem die Informationen gesammelt werden, gibt es keine Möglichkeit, zuverlässig sicherzustellen, dass dies geschieht. Ist es möglich, sie entsprechend der Optionsnummer verketten zu lassen? Ich weiß auch, dass ich nie mehr als 5 Optionen haben werde, damit eine statische Lösung funktioniert.
4
Um die Artikel innerhalb der Gruppe zu bestellen, können Sie dies beispielsweise tun: GROUP_CONCAT (Ordered_Options.Value ORDER BY Ordered_Options.value),
Wouter van Nifterick
14

Ich schätze die Hilfe, ich glaube, ich habe eine Lösung gefunden, wenn jemand die Wirksamkeit kommentieren würde, würde ich es schätzen. Im Wesentlichen habe ich getan. Mir ist klar, dass es in seiner Implementierung etwas statisch ist, aber ich tue, was ich brauche (verzeihen Sie falsche Syntax)

SELECT
  ordered_item.id as `Id`,
  ordered_item.Item_Name as `ItemName`,
  Options1.Value
  Options2.Value
FROM ORDERED_ITEMS
LEFT JOIN (Ordered_Options as Options1)
    ON (Options1.Ordered_Item.ID = Ordered_Options.Ordered_Item_ID 
        AND Options1.Option_Number = 43)
LEFT JOIN (Ordered_Options as Options2)
    ON (Options2.Ordered_Item.ID = Ordered_Options.Ordered_Item_ID
        AND Options2.Option_Number = 44);
Kermit
quelle
6
Dies wird schwer zu pflegen sein. Früher oder später wird Ihr Kunde eine dritte oder vierte Option haben wollen, und bis dahin müssen Sie alles neu schreiben.
Wouter van Nifterick
Es wurde eine weitere Antwort hinzugefügt, die dieselben Ergebnisse wie die von Ihnen gepostete Abfrage liefert, jedoch etwas flexibler ist. Sie können immer noch eine unbegrenzte Anzahl von Optionen haben, während Sie immer noch mehrere Spalten für die Pizzaoptionen in Ihrem Ergebnis erhalten.
Wouter van Nifterick
5

Wenn Sie in Ihrem Ergebnis wirklich mehrere Spalten benötigen und die Anzahl der Optionen begrenzt ist, können Sie sogar Folgendes tun:

select
  ordered_item.id as `Id`,
  ordered_item.Item_Name as `ItemName`,
  if(ordered_options.id=1,Ordered_Options.Value,null) as `Option1`,
  if(ordered_options.id=2,Ordered_Options.Value,null) as `Option2`,
  if(ordered_options.id=43,Ordered_Options.Value,null) as `Option43`,
  if(ordered_options.id=44,Ordered_Options.Value,null) as `Option44`,
  GROUP_CONCAT(if(ordered_options.id not in (1,2,43,44),Ordered_Options.Value,null)) as `OtherOptions`
from
  ordered_item,
  ordered_options
where
  ordered_item.id=ordered_options.ordered_item_id
group by
  ordered_item.id
Wouter van Nifterick
quelle
3

Wenn Sie wissen, dass Sie eine begrenzte Anzahl von maximalen Optionen haben werden, würde ich dies versuchen (Beispiel für maximal 4 Optionen pro Bestellung):

Wählen Sie OI.ID, OI.Item_Name, OO1.Value, OO2.Value, OO3.Value, OO4.Value

FROM Ordered_Items OI
    LEFT JOIN Ordered_Options OO1 ON OO1.Ordered_Item_ID = OI.ID.
    LEFT JOIN Ordered_Options OO2 ON OO2.Ordered_Item_ID = OI.ID UND OO2.ID! = OO1.ID
    LEFT JOIN Ordered_Options OO3 ON OO3.Ordered_Item_ID = OI.ID UND OO3.ID! = OO1.ID UND OO3.ID! = OO2.ID
    LEFT JOIN Ordered_Options OO4 ON OO4.Ordered_Item_ID = OI.ID UND OO4.ID! = OO1.ID UND OO4.ID! = OO2.ID UND OO4.ID! = OO3.ID

GRUPPE NACH OI.ID, OI.Item_Name

Die Gruppe nach Bedingung entfernt alle Duplikate, die Sie sonst erhalten würden. Ich habe gerade etwas Ähnliches auf einer Site implementiert, an der ich arbeite, wo ich wusste, dass ich immer 1 oder 2 Übereinstimmungen in meiner untergeordneten Tabelle habe, und ich wollte sicherstellen, dass ich nur 1 Zeile für jedes übergeordnete Element hatte.


quelle
1

So würden Sie Ihre Abfrage für diese Art von Anforderung erstellen.

select ID,Item_Name,max(Flavor) as Flavor,max(Extra_Cheese) as Extra_Cheese
    from (select i.*,
                    case when o.Option_Number=43 then o.value else null end as Flavor,
                    case when o.Option_Number=44 then o.value else null end as Extra_Cheese
                from Ordered_Item i,Ordered_Options o) a
    group by ID,Item_Name;

Grundsätzlich "case out" Sie jede Spalte mit case whenund wählen dann die max()für jede dieser Spalten mit group byfür jedes beabsichtigte Element.

ck.tan
quelle
-2

Joe Edels Antwort auf sich selbst ist tatsächlich der richtige Ansatz, um das Pivot-Problem zu lösen.

Grundsätzlich besteht die Idee darin, zuerst die Spalten in der Basistabelle und dann eine beliebige Anzahl von Spalten options.valueaus der gemeinsamen Optionstabelle aufzulisten. Nur left joindieselbe Optionstabelle mehrmals, um alle Optionen zu erhalten.

Was die Programmiersprache tun muss, ist, diese Abfrage dynamisch gemäß einer Liste von Optionen zu erstellen, die abgefragt werden müssen.

hailong
quelle