web-dev-qa-db-fra.com

Combiner plusieurs lignes enfants en une seule ligne MYSQL

Merci d'avance, je n'arrive pas à comprendre!

J'ai deux tables

Ordered_Item

ID | Item_Name 
 1 | Pizza 
 2 | Stromboli

Ordered_Options

Ordered_Item_ID | Option_Number | Valeur 
 1 43 Pepperoni 
 1 44 Extra Cheese 
 2 44 Extra Cheese

Ce que je cherche à produire est une requête mysql est quelque chose à cet effet

Sortie

ID | Item_Name | Option_1 | Option_2 
 1 Pizza Pepperoni Extra Cheese 
 2 Stromboli NULL Extra Cheese

J'ai essayé de nombreuses options se terminant le plus par une erreur de syntaxe, j'ai essayé group_concat mais ce n'est pas vraiment ce que je recherche. J'ai un exemple grossier ci-dessous de ce que je pense pourrait être un début. J'ai besoin que les options soient dans le même ordre à chaque fois. Et dans le programme où les informations sont collectées, il n'y a aucun moyen de garantir de manière fiable que cela se produira. Est-il possible de les faire concaténer selon le numéro d'option. Je sais aussi que je n'aurai jamais plus de 5 options, donc une solution statique fonctionnerait

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;

Merci! Joe

62
Joe Edel

Le moyen le plus simple serait d'utiliser ici la fonction de groupe GROUP_CONCAT.

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

Ce qui produirait:

Id              ItemName       Options

1               Pizza          Pepperoni,Extra Cheese

2               Stromboli      Extra Cheese

De cette façon, vous pouvez avoir autant d'options que vous le souhaitez sans avoir à modifier votre requête.

Ah, si vous voyez que vos résultats sont rognés, vous pouvez augmenter la taille limite de GROUP_CONCAT comme ceci:

SET SESSION group_concat_max_len = 8192;
106

J'apprécie l'aide, je pense que j'ai trouvé une solution si quelqu'un commentait l'efficacité je l'apprécierais. Ce que j'ai fait, c'est essentiellement. Je me rends compte qu'il est quelque peu statique dans son implémentation mais je fais ce dont j'ai besoin (pardonnez une syntaxe incorrecte)

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);
9
Joe Edel

Si vous avez vraiment besoin de plusieurs colonnes dans votre résultat et que le nombre d'options est limité, vous pouvez même le faire:

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
3

Si vous savez que vous allez avoir un nombre limité d'options max alors j'essaierais ceci (exemple pour max de 4 options par commande):

Sélectionnez 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. ID! = OO1.ID ET OO3.ID! = OO2.ID 
 JOIN GAUCHE Ordered_Options OO4 ON OO4.Ordered_Item_ID = OI.ID AND OO4.ID! = OO1.ID AND OO4.ID! = OO2.ID ET OO4.ID! = OO3.ID 
 
 GROUPE PAR OI.ID, OI.Item_Name

La condition de regroupement supprime tous les doublons que vous obtiendriez autrement. Je viens d'implémenter quelque chose de similaire sur un site sur lequel je travaille, où je savais que j'aurais toujours 1 ou 2 correspondances dans ma table enfant, et je voulais m'assurer que je n'avais qu'une seule ligne pour chaque élément parent.

1
Seb

Voici comment vous construisez votre requête pour ce type d'exigence.

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;

Fondamentalement, vous "cassez" chaque colonne en utilisant case when, Puis sélectionnez la max() pour chacune de ces colonnes en utilisant group by Pour chaque élément prévu.

1
ck.tan

Ce que vous voulez s'appelle un pivot, et ce n'est pas directement pris en charge dans MySQL, consultez cette réponse pour les options que vous avez:

Comment faire pivoter un schéma de valeur d'attribut d'entité MySQL

1
Vinko Vrsalovic