简体   繁体   English

将多个子行合并为一行MYSQL

[英]Combine Multiple child rows into one row MYSQL

Thanks in advance, I just can't seem to get it! 在此先感谢,我似乎无法理解!

I have two tables 我有两张桌子

Ordered_Item Ordered_Item

ID | Item_Name
1  | Pizza
2  | Stromboli

Ordered_Options Ordered_Options

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

What I am looking to output is a mysql query is something to this effect 我想要输出的是mysql查询,可以达到这种效果

Output 输出量

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

I have tried numerous options most ending in syntax error, I have tried group_concat but thats not really what I am looking for. 我尝试了很多选项,大多数以语法错误结尾,我尝试了group_concat,但这并不是我真正想要的。 I have a crude example below of what I think might be a start. 下面有一个简单的例子,我认为这可能是一个开始。 I need the options to be in the same order every time. 我需要选项每次都按相同顺序排列。 And in the program where the info is collected there is no way to reliable ensure that will happen. 在收集信息的程序中,没有办法可靠地确保将要发生。 Is it possible to have them concatenate according to option number. 是否可以根据选件号将它们连接在一起。 Also I know that I will never have over 5 options so a static solution would work 我也知道我永远不会有5个以上的选择,因此静态解决方案会起作用

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;

Thanks! 谢谢! Joe

The easiest way would be to make use of the GROUP_CONCAT group function here.. 最简单的方法是在这里使用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

Which would output: 哪个会输出:

Id              ItemName       Options

1               Pizza          Pepperoni,Extra Cheese

2               Stromboli      Extra Cheese

That way you can have as many options as you want without having to modify your query. 这样,您可以根据需要选择多个选项,而无需修改查询。

Ah, if you see your results getting cropped, you can increase the size limit of GROUP_CONCAT like this: 嗯,如果您看到结果被裁剪,可以像下面这样增加GROUP_CONCAT的大小限制:

SET SESSION group_concat_max_len = 8192;

I appreciate the help, I do think I have found a solution if someone would comment on the effectiveness I would appreciate it. 我很感谢您的帮助,如果有人对我的效果表示赞赏,我认为我已经找到了解决方案。 Essentially what I did is. 本质上,我所做的就是。 I realize it is somewhat static in its implementation but I does what I need it to do (forgive incorrect 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);

If you really need multiple columns in your result, and the amount of options is limited, you can even do this: 如果您的结果中确实需要多列,并且选项数量有限,则可以执行以下操作:

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

What you want is called a pivot, and it's not directly supported in MySQL, check this answer out for the options you've got: 您想要的东西称为枢轴,而MySQL并不直接支持它,请查看此答案以了解您拥有的选项:

How to pivot a MySQL entity-attribute-value schema 如何透视MySQL实体-属性-值架构

If you know you're going to have a limited number of max options then I would try this (example for max of 4 options per order): 如果您知道有限数量的最大选项,那么我会尝试一下(例如每个订单最多4个选项):

Select 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 AND OO2.ID != OO1.ID
    LEFT JOIN Ordered_Options OO3 ON OO3.Ordered_Item_ID = OI.ID AND OO3.ID != OO1.ID AND OO3.ID != OO2.ID
    LEFT JOIN Ordered_Options OO4 ON OO4.Ordered_Item_ID = OI.ID AND OO4.ID != OO1.ID AND OO4.ID != OO2.ID AND OO4.ID != OO3.ID

GROUP BY OI.ID, OI.Item_Name

The group by condition gets rid of all of the duplicates that you would otherwise get. 按条件分组将消除您原本可以得到的所有重复项。 I've just implemented something similar on a site I'm working on where I knew I'd always have 1 or 2 matched in my child table, and I wanted to make sure I only had 1 row for each parent item. 我刚刚在我正在工作的网站上实现了类似的操作,我知道我的子表中总是有1或2个匹配项,并且我想确保每个父项只有1行。

Here is how you would construct your query for this type of requirement. 这是您针对此类需求构造查询的方式。

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;

You basically "case out" each column using case when , then select the max() for each of those columns using group by for each intended item. 基本上,您可以在case when使用case when “区分”每一列,然后使用group by为每个预期的项目选择每个列的max()

Joe Edel's answer to himself is actually the right approach to resolve the pivot problem. Joe Edel对自己的回答实际上是解决关键问题的正确方法。

Basically the idea is to list out the columns in the base table firstly, and then any number of options.value from the joint option table. 基本上,这个想法是首先列出基表中的列,然后列出联合选项表中的任意数量的options.value Just left join the same option table multiple times in order to get all the options. left join ,多次联接同一选项表即可获得所有选项。

What needs to be done by the programming language is to build this query dynamically according to a list of options needs to be queried. 编程语言需要做的是根据需要查询的选项列表动态构建此查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM