将多个子行合并为一行MYSQL

Posted

技术标签:

【中文标题】将多个子行合并为一行MYSQL【英文标题】:Combine Multiple child rows into one row MYSQL 【发布时间】:2010-11-07 05:38:11 【问题描述】:

在此先感谢,我似乎无法得到它!

我有两张桌子

Ordered_Item

ID |项目名称
1 |比萨
2 |斯特龙博利

Ordered_Options

Ordered_Item_ID |选项号码 |价值
        1 43​​ 意大利辣香肠
        1 44 额外的奶酪
        2 44 额外的奶酪

我想要输出的是一个 mysql 查询就是这样的结果

输出

ID |物品名称 |选项_1 |选项_2
1 份披萨意大利辣香肠额外奶酪
2 Stromboli NULL 额外奶酪

我尝试了许多以语法错误结尾的选项,我尝试了 group_concat 但这并不是我真正想要的。我在下面有一个粗略的例子,我认为这可能是一个开始。我需要每次都以相同的顺序排列选项。在收集信息的程序中,没有办法可靠地确保会发生这种情况。是否可以根据选项编号将它们连接起来。我也知道我永远不会有超过 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;

谢谢! 乔

【问题讨论】:

【参考方案1】:

Joe Edel 对自己的回答实际上是解决支点问题的正确方法。

基本上这个想法是首先列出基表中的列,然后从联合选项表中列出任意数量的options.value。只需多次left join 同一个选项表即可获得所有选项。

编程语言需要做的是根据需要查询的选项列表动态构建这个查询。

【讨论】:

【参考方案2】:

以下是针对此类需求构建查询的方式。

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;

您基本上使用case when“排除”每一列,然后为每个预期项目使用group by 为每一列选择max()

【讨论】:

【参考方案3】:

如果您的结果确实需要多列,并且选项数量有限,您甚至可以这样做:

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

【讨论】:

【参考方案4】:

感谢您的帮助,我认为我已经找到了解决方案,如果有人评论其有效性,我将不胜感激。基本上我所做的是。我意识到它的实现有些静态,但我做了我需要它做的事情(请原谅不正确的语法)

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);

【讨论】:

这将很难维护。迟早你的客户会想要第 3 或第 4 选项,到那时你需要重写所有内容。 添加了另一个答案,它给出了与您发布的查询相同的结果,但它更灵活一些。您仍然可以拥有无​​限数量的选项,同时仍然会在结果中为披萨选项提供多列。【参考方案5】:

如果您知道您的最大选项数量有限,那么我会试试这个(例如每个订单最多 4 个选项):

选择 OI.ID、OI.Item_Name、OO1.Value、OO2.Value、OO3.Value、OO4.Value

FROM Ordered_Items OI
    左连接 Ordered_Options OO1 ON OO1.Ordered_Item_ID = OI.ID
    左连接 Ordered_Options OO2 ON OO2.Ordered_Item_ID = OI.ID AND OO2.ID != OO1.ID
    左连接 Ordered_Options OO3 ON OO3.Ordered_Item_ID = OI.ID AND OO3.ID != OO1.ID AND OO3.ID != OO2.ID
    左连接 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

按 OI.ID、OI.Item_Name 分组

按条件分组会消除您原本会得到的所有重复项。我刚刚在我正在开发的网站上实现了类似的东西,我知道我的子表中总是有 1 或 2 个匹配项,并且我想确保每个父项只有 1 行。

【讨论】:

【参考方案6】:

最简单的方法是在这里使用 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

哪个会输出:

Id              ItemName       Options

1               Pizza          Pepperoni,Extra Cheese

2               Stromboli      Extra Cheese

这样您就可以拥有任意数量的选项,而无需修改您的查询。

啊,如果你看到你的结果被裁剪了,你可以像这样增加 GROUP_CONCAT 的大小限制:

SET SESSION group_concat_max_len = 8192;

【讨论】:

他说“我已经尝试过 group_concat,但这并不是我真正想要的。” 您好,感谢您的快速回复,但恐怕我没有提供重要信息。我需要每次都以相同的顺序排列选项。在收集信息的程序中,没有办法可靠地确保会发生这种情况。是否可以根据选项编号将它们连接起来。我也知道我永远不会有超过 5 个选项,所以静态解决方案会起作用。 要对组内的项目进行排序,例如:GROUP_CONCAT(Ordered_Options.Value ORDER BY Ordered_Options.value), 如果计数有误,请尝试DISTINCT 计数,即SELECT count(DISTINCT u.id) as totalRecords【参考方案7】:

您想要的称为枢轴,并且 MySQL 不直接支持它,请查看此答案以了解您所拥有的选项:

How to pivot a MySQL entity-attribute-value schema

【讨论】:

以上是关于将多个子行合并为一行MYSQL的主要内容,如果未能解决你的问题,请参考以下文章

使用 PowerShell 将多个 CSV 文件合并为一个

基于子行文件的一行和打印其他行直到它到达下一行

将多个文本文件合并为一个

Python:如何将具有相同变量类型的多个列表合并到一个列表列表中?

怎样将多行数字合并到一行中?

MySql JOIN 3 个表并获取具有相同值的子行