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
我有一辆 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