SQL Server 2012:旋转(?)固定行数作为列

SQL Server 2012: Pivoting(?) fixed number of rows as columns

我有一辆 table 叫车:

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。(业务逻辑)

我想做的是在视图 table 中显示此数据,如下例所示:

+----+------------+------------+------------+------------+------------+------------+
| 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 不是。)如果也可以对乘客进行排序,那么我更愿意按 ID 排序。

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

使用 Pivot 运算符对数据进行透视

使用 Row_number window 函数生成乘客编号,这样没有所有 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       ║
╚════╩════════════╩════════════╩════════════╩════════════╩════════════╩════════════╝

未测试:

我们使用 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