sql将行合并到列中(多对多的情况)

时间:2016-10-01 07:58:18

标签: mysql sql many-to-many pivot

我遇到了这个SQL问题:

DB:MySQL 5.6.15 存储引擎:MyISAM

我有3张桌子:

1)产品

id product  |  product_name    
----------  |  --------------    
 1          |  alfa    
 2          |  beta    
 3          |  gamma

2)products_materials [这是桥牌表]

id product  |  id material    
----------  |  --------------    
 1          |   1    
 1          |   2    
 1          |   3   
 2          |   1   
 3          |   1

3)材料

 id material|   material_name   
----------  |  --------------
 1          |   steel   
 2          |   gold    
 3          |   silver  

我需要获得这个结果:

id product  |   material_name_1  |  material_name_2  |    material_name_3    
------------|--------------------|-------------------|--------------------    
product 1     steel                   gold               silver    
product 2     gold                    null                null    
product 3     silver                   null                null    

每件产品的最大材料为10。 我看了一下,但我对它没有足够的信心来创建正确的查询。

非常感谢

2 个答案:

答案 0 :(得分:0)

如果有10个固定产品,那么你可以这样做:

select p.product_name,

(select m.material_name
from products p1
join products_materials pm on pm.id_product=p1.id
join materials m on m.id=pm.id_material
where m.id=1
and p1.id=p.id) as material1,

(select m.material_name
from products p1
join products_materials pm on pm.id_product=p1.id
join materials m on m.id=pm.id_material
where m.id=2
and p1.id=p.id) as material2,

(select m.material_name
from products p1
join products_materials pm on pm.id_product=p1.id
join materials m on m.id=pm.id_material
where m.id=3
and p1.id=p.id) as material3

from products p

(此示例适用于3种可能的产品)

答案 1 :(得分:0)

在子查询中计算行号意味着materia1(例如)将始终具有值(无论是钢,金还是银)

 SELECT S.PRODUCT_NAME,
         MAX(CASE WHEN RN=1 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL1,
         MAX(CASE WHEN RN=2 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL2,
         MAX(CASE WHEN RN=3 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL3,
         MAX(CASE WHEN RN=4 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL4,
         MAX(CASE WHEN RN=5 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL5,
         MAX(CASE WHEN RN=6 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL6,
         MAX(CASE WHEN RN=7 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL7,
         MAX(CASE WHEN RN=8 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL8,
         MAX(CASE WHEN RN=9 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL9,
         MAX(CASE WHEN RN=10 THEN S.MATERIAL_NAME ELSE '' END) MATERIAL10
FROM
(
SELECT P.PRODUCT_NAME,.M.MATERIAL_NAME,
        IF(P.ID <> @P,@RN:=1,@RN:=@RN+1) RN,
        @P:=P.ID P
FROM    (SELECT @RN:=0,@P:=0) RN,PRODUCTS P
JOIN  PRODUCTS_MATERIALS PM ON PM.PRODUCT_ID = P.ID
JOIN  MATERIALS M ON M.MATERIAL_ID = PM.MATERIAL_ID
) S
GROUP BY S.PRODUCT_NAME
ORDER BY S.PRODUCT_NAME