如何转动?如何将多行转换为多列的一行?

use*_*856 9 mysql sql sql-server pivot-table

我有两张桌子要结合.第一个表是客户端,另一个是产品.目前我有22个产品,但我希望有一个灵活的数据库设计,所以在产品数据库中没有22列,每个客户每个产品有1行,所以如果我添加或删除1个产品,我不会必须改变数据库结构.

我想要一个select语句,我为每个客户选择所有产品,输出应该在一行中,每个产品都有一列.

我已经看到了一些类似的其他问题,但目标是将所有行连接在一列中 - 这是我不想要的.

假设有2个客户和3个产品.

表客户端:

ClientId | ClientName
---------------------
 1       | Name1
 2       | Name2
Run Code Online (Sandbox Code Playgroud)

表产品

ProductId | ClientId | Product
-------------------------------------
 1        |   1      |  SomeproductA
 2        |   1      |  SomeproductB
 3        |   1      |  SomeproductA
 4        |   2      |  SomeproductC
 5        |   2      |  SomeproductD
 6        |   2      |  SomeproductA
Run Code Online (Sandbox Code Playgroud)

输出应该是这样的:

表输出:

 ClientId | ClientName | Product1     | Product 2    | Product 3
 -------------------------------------------------------------------
     1    | Name1      | SomeproductA | SomeproductB | SomeproductA
     2    | Name2      | SomeproductC | SomeproductD | SomeproductA
Run Code Online (Sandbox Code Playgroud)

完美的解决方案也是灵活的,因为select语句应该计算每个客户端的不同产品的数量(对于所有客户端它们将始终是相同的),这样如果我为所有客户添加或删除1个产品,我不应该更改select语句.

val*_*lex 8

MYSQL版

这是查询.联接查询使用用户定义变量MySQL功能为每个客户端组内的每个产品生成RowNumber(1,2,3,...).外部查询使用GROUP BY来自内部表的CASE和行号来形成PIVOT 表.如果您需要变量产品列数,则考虑创建此查询动态添加MAX(CASE WHEN p.RowNum=X THEN p.Product END) as ProductX到选择列表.

select Clients.ClientName,
       MAX(CASE WHEN p.RowNum=1 THEN p.Product END) as Product1,
       MAX(CASE WHEN p.RowNum=2 THEN p.Product END) as Product2,
       MAX(CASE WHEN p.RowNum=3 THEN p.Product END) as Product3,
       MAX(CASE WHEN p.RowNum=4 THEN p.Product END) as Product4


FROM Clients
JOIN
(
  SELECT Products.*,
       if(@ClientId<>ClientId,@rn:=0,@rn),
       @ClientId:=ClientId,
       @rn:=@rn+1 as RowNum

  FROM Products, (Select @rn:=0,@ClientId:=0) as t
  ORDER BY ClientId,ProductID
 ) as P 
   ON Clients.ClientId=p.ClientId

GROUP BY Clients.ClientId
Run Code Online (Sandbox Code Playgroud)

SQLFiddle demo

SQL Server版:

select Clients.ClientId,
       MAX(Clients.ClientName),
       MAX(CASE WHEN p.RowNum=1 THEN p.Product END) as Product1,
       MAX(CASE WHEN p.RowNum=2 THEN p.Product END) as Product2,
       MAX(CASE WHEN p.RowNum=3 THEN p.Product END) as Product3,
       MAX(CASE WHEN p.RowNum=4 THEN p.Product END) as Product4


FROM Clients
JOIN
(
  SELECT Products.*,
       ROW_NUMBER() OVER (PARTITION BY ClientID ORDER BY ProductID) 
         as RowNum

  FROM Products
 ) as P 
   ON Clients.ClientId=p.ClientId
GROUP BY Clients.ClientId
Run Code Online (Sandbox Code Playgroud)

SQLFiddle demo