SQL Server 2012:将固定行数作为列进行透视(?)

时间:2016-03-01 15:32:18

标签: sql-server pivot rows

我有一张名为Car的表:

CREATE TABLE [dbo].[Car](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Brand] [nchar](10) NOT NULL
)

和一个叫Passenger:

CREATE TABLE [dbo].[Passenger](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [CarID] [int] NOT NULL,
    [Name] [nchar](10) NOT NULL
)

包含以下数据:

+----+------------+
| ID |   Brand    |
+----+------------+
|  1 | Ford       |
|  2 | Audi       |
+----+------------+

+----+-------+------------+
| ID | CarID |    Name    |
+----+-------+------------+
|  1 |     1 | Joe        |
|  2 |     1 | Jack       |
|  3 |     1 | Jim        |
|  4 |     2 | Bob        |
|  5 |     2 | Frank      |
+----+-------+------------+

另外,我对车内乘客数量的限制= 5.(业务逻辑)

我想要做的是在View表中显示这些数据,如下例所示:

+----+------------+------------+------------+------------+------------+------------+
| ID |   Brand    | Passenger1 | Passenger2 | Passenger3 | Passenger4 | Passenger5 |
+----+------------+------------+------------+------------+------------+------------+
|  1 | Ford       | Joe        | Jack       | Jim        | NULL       | NULL       |
|  2 | Audi       | Bob        | Frank      | NULL       | NULL       | NULL       |
+----+------------+------------+------------+------------+------------+------------+

因此,如果乘客少于5人,其余列为NULL,我们不需要处理超过5名乘客。

不需要对乘客进行订购,但NULLs必须在最后(例如Frank, Bob, NULL, NULL, NULL is OK for Car ID 2, but Frank, NULL, NULL, Bob, NULL不是。)如果也可以订购乘客,那么我更愿意订购他们的身份证。

如何使用 SQL Server 2012 进行数据转换?

2 个答案:

答案 0 :(得分:3)

使用Pivot运算符来转动数据

使用Row_number窗口功能生成乘客编号,这样没有所有5名乘客的车最终都会有NULL个值

;WITH cte
     AS (SELECT c.id,
                c.Brand,
                'Passenger'+ Cast(Row_number() OVER(partition BY c.id ORDER BY p.id) AS VARCHAR(50)) p_name,
                NAME
         FROM   [Car] c
                JOIN [Passenger] p
                  ON c.ID = p.CarID)
SELECT *
FROM   cte
       PIVOT (Max(NAME)
             FOR p_name IN(Passenger1,
                           Passenger2,
                           Passenger3,
                           Passenger4,
                           Passenger5 ))pv
ORDER  BY id 

Conditional Aggregate方法

;WITH cte
     AS (SELECT c.id,
                c.Brand,
                'Passenger'+ Cast(Row_number() OVER(partition BY c.id ORDER BY p.id) AS VARCHAR(50)) p_name,
                NAME
         FROM   [Car] c
                JOIN Passenger p
                  ON c.ID = p.CarID)
SELECT id,
       Brand,
       [Passenger1]=Max(CASE WHEN p_name = 'Passenger1' THEN NAME END),
       [Passenger2]=Max(CASE WHEN p_name = 'Passenger2' THEN NAME END),
       [Passenger3]=Max(CASE WHEN p_name = 'Passenger3' THEN NAME END),
       [Passenger4]=Max(CASE WHEN p_name = 'Passenger4' THEN NAME END),
       [Passenger5]=Max(CASE WHEN p_name = 'Passenger5' THEN NAME END)
FROM   cte
GROUP  BY id,
          Brand
ORDER  BY id 

<强>结果:

╔════╦════════════╦════════════╦════════════╦════════════╦════════════╦════════════╗
║ id ║   Brand    ║ Passenger1 ║ Passenger2 ║ Passenger3 ║ Passenger4 ║ Passenger5 ║
╠════╬════════════╬════════════╬════════════╬════════════╬════════════╬════════════╣
║  1 ║ Ford       ║ Joe        ║ Jack       ║ Jim        ║ NULL       ║ NULL       ║
║  2 ║ Audi       ║ Bob        ║ Frank      ║ NULL       ║ NULL       ║ NULL       ║
╚════╩════════════╩════════════╩════════════╩════════════╩════════════╩════════════╝

答案 1 :(得分:0)

UNTESTED:

我们在分区上使用row_num()按卡ID来获得5个位置的常数座位号添加P,因为我不确定SQL服务器是否可以有一个带有数字的列星,然后基于它来转动数据这5个派生值。

Select brand, P1, P2, P3, P4, P5
FROM 
  (
  SELECT brand, name, 'P' & row_Number() Over (partition by CarID order by P.name) as PNum
  FROM car C
  INNER JOIN passenger P
    on C.CardID = P.CardID
  ) src
  PIVOT 
  (
    max(src.name)
    FOr pnum in ([P1],[P2],[P3],[P4],[P5])
  ) as PT