【问题标题】:MySQL select all components of a productMySQL选择产品的所有组件
【发布时间】:2015-03-31 19:09:39
【问题描述】:

我在一家汽车公司工作。我们有一个包含产品组件的产品表。

这是我们一个产品的树状视图。产品的零件通过组装操作制造E40。

这是来自我们的 MySQL 数据库的表视图:

我们希望获得产品所有组件的结果。像这样:

'E40-1'、'E40-2'、'E40-3'、'E40-4'、'E40-5'、'E40-6'、'E40-6-1'、 'E40-6-2'

所以结果的长度必须是 8。

我尝试了一些 MySQL 查询,但它们不起作用。

我尝试过的查询:

select alt_bilesen from urunler_seviyeler where parcano in (select parcano from urunler_seviyeler where parcano="E40")

这只给了我们产品的六个部分。没有 E40-6-1 也没有 E40-6-2。 我也试过了:

select alt_bilesen from urunler_seviyeler where parcano in (select alt_bilesen from urunler_seviyeler where parcano="E40")

这只会给我们产品的最低部分。 E40-6-1 和 E40-6-2。不是其他部分。

顺便说一句,我们可以使用 Python。如果我们想使用 Python,我认为我们必须用一些 for 循环、while 循环等来调用它。你能给我一个建议吗?谢谢。

【问题讨论】:

  • 您发布的每个产品的预期输出是一行,还是实际上是 8 行?还有你的树可以有多少层(你帖子中的产品有 2 层,还有比这更多的产品吗?)
  • 子产品可以嵌套多深?只有一层深?
  • BrianDeMilia:对于某些产品,我们有超过 2 个级别。 GordonLinoff:这取决于,我们有 4 级深度产品。如果它有 1 个级别,我们只想看到一个级别的组件。

标签: python mysql sql select mysql-python


【解决方案1】:

MySQL 不支持“分层”查询。可以使用多个查询在有限数量的级别上模拟该功能。查询的结果可以与 UNION ALL 操作相结合。

获取以特定顺序返回的行可能会出现问题,具体取决于您需要返回的行的实际条件。

第一级:

SELECT t1.alt_bilesen
  FROM urunler_seviyeler t1 
 WHERE t1.parcano = 'E40'

二级:

SELECT t2.alt_bilesen
  FROM urunler_seviyeler t1
  JOIN urunler_seviyeler t2
    ON t2.parcano = t1.alt_bilesen
 WHERE t1.parcano = 'E40'

第三级:

SELECT t3.alt_bilesen
  FROM urunler_seviyeler t1
  JOIN urunler_seviyeler t2 ON t2.parcano = t1.alt_bilesen
  JOIN urunler_seviyeler t3 ON t3.parcano = t2.alt_bilesen
 WHERE t1.parcano = 'E40'

第四级:

SELECT t4.alt_bilesen
  FROM urunler_seviyeler t1
  JOIN urunler_seviyeler t2 ON t2.parcano = t1.alt_bilesen
  JOIN urunler_seviyeler t3 ON t3.parcano = t2.alt_bilesen
  JOIN urunler_seviyeler t4 ON t4.parcano = t3.alt_bilesen
 WHERE t1.parcano = 'E40'

可以将查询与UNION ALL 集合运算符结合起来

( SELECT t1.alt_bilesen
    FROM urunler_seviyeler t1 
   WHERE t1.parcano = 'E40'
)
UNION ALL
( SELECT t2.alt_bilesen
    FROM urunler_seviyeler t1
    JOIN urunler_seviyeler t2
      ON t2.parcano = t1.alt_bilesen
   WHERE t1.parcano = 'E40'
)
UNION ALL
( SELECT t3.alt_bilesen
   FROM urunler_seviyeler t1
   JOIN urunler_seviyeler t2 ON t2.parcano = t1.alt_bilesen
   JOIN urunler_seviyeler t3 ON t3.parcano = t2.alt_bilesen
  WHERE t1.parcano = 'E40'
) 
UNION ALL
( SELECT t4.alt_bilesen
    FROM urunler_seviyeler t1
    JOIN urunler_seviyeler t2 ON t2.parcano = t1.alt_bilesen
    JOIN urunler_seviyeler t3 ON t3.parcano = t2.alt_bilesen
    JOIN urunler_seviyeler t4 ON t4.parcano = t3.alt_bilesen
   WHERE t1.parcano = 'E40'
)
ORDER BY 1

可以通过在每个查询中包含文字值来包含额外的“级别”列。要通过返回列以外的其他内容进行排序,您需要在每个查询中包含一些额外的表达式...

【讨论】:

  • 要为所有(或多个)parcano 而不仅仅是一个获得此结果,请在 SELECT 列表中包含 t1.parcano,并删除(或修改)谓词(即条件WHERE 子句)在t1.parcano.
【解决方案2】:

我建议使用零件号本身:

select alt_bilesen
from urunler_seviyeler
where CONCAT(parcano, '-') like 'E40-%'

CONCAT() 防止 E400 与 E40 混淆。

否则,您需要开始使用joins。而且,如果子零件可以嵌套很深,那么您就有问题了。 MySQL 不支持对分层或嵌套数据结构的查询。

【讨论】:

  • 很好,但是我们有一些产品,比如命名为 X,但它的组件不是以 X 开头的。
【解决方案3】:

这将比您的示例多 3 个级别,但也适用于级别较少的产品,例如您的示例。如果需要,您可以添加到查询中(如果任何产品的级别超过 4 个):

小提琴演示: http://sqlfiddle.com/#!2/681368/1/0

select t.parcano,
       trim(both ', ' from
            concat(group_concat(distinct t.alt_bilesen order by
                                t.alt_bilesen separator ', '),
                   ', ',
                   ifnull(concat(group_concat(distinct l1.alt_bilesen order by
                                              l1.alt_bilesen separator ', '),
                                 ', '),
                          ''),
                   ', ',
                   ifnull(concat(group_concat(distinct l2.alt_bilesen order by
                                              l2.alt_bilesen separator ', '),
                                 ', '),
                          ''),
                   ', ',
                   ifnull(concat(group_concat(distinct l3.alt_bilesen order by
                                              l3.alt_bilesen separator ', '),
                                 ', '),
                          ''),
                   ', ',
                   ifnull(concat(group_concat(distinct l4.alt_bilesen order by
                                              l4.alt_bilesen separator ', '),
                                 ', '),
                          '')

                   )) as parts
  from urunler_seviyeler t
  left join urunler_seviyeler x
    on x.alt_bilesen = t.parcano
  left join urunler_seviyeler l1
    on t.alt_bilesen = l1.parcano
  left join urunler_seviyeler l2
    on l1.alt_bilesen = l2.parcano
  left join urunler_seviyeler l3
    on l2.alt_bilesen = l3.parcano
  left join urunler_seviyeler l4
    on l3.alt_bilesen = l4.parcano
 where x.parcano is null
 group by t.parcano

要为每个部分生成一行而不是汇总列表(这是您在问题中作为预期输出放置的内容),您可以创建一个非规范化数据的视图:

create denorm_vw as
select t.parcano,
       t.alt_bilesen as l0,
       l1.alt_bilesen as l1,
       l2.alt_bilesen as l2,
       l3.alt_bilesen as l3,
       l4.alt_bilesen as l4
  from urunler_seviyeler t
  left join urunler_seviyeler x
    on x.alt_bilesen = t.parcano
  left join urunler_seviyeler l1
    on t.alt_bilesen = l1.parcano
  left join urunler_seviyeler l2
    on l1.alt_bilesen = l2.parcano
  left join urunler_seviyeler l3
    on l2.alt_bilesen = l3.parcano
  left join urunler_seviyeler l4
    on l3.alt_bilesen = l4.parcano
 where x.parcano is null;

然后运行:

select parcano, l0 from denorm_vw union 
select parcano, l1 from denorm_vw where l1 is not null union 
select parcano, l2 from denorm_vw where l2 is not null union 
select parcano, l3 from denorm_vw where l3 is not null union 
select parcano, l4 from denorm_vw where l4 is not null

小提琴: http://sqlfiddle.com/#!2/bd5a4/4/0

【讨论】:

  • 太棒了。是否可以看到多行的结果,每个组件都有一行?喜欢 spencer7593 的回答吗?
  • @Rictrunks 这就是为什么我在 cmets 中询问您想要 1 行还是 8 行。是的,您可以使用此方法生成 8 行。往上看。但是如果你创建一个视图是因为 MySQL 中没有 with 子句,那将是最简单的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-16
  • 1970-01-01
  • 2019-07-23
  • 2015-02-19
  • 2013-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多