SQL 将特定列中的所有数据行转换为列,并将另一列中的值映射到新列
SQL Convert all rows of data in a specific column to columns and mapping values in another column to the new columns
来源TABLE 看起来像这样:
h1_ind = 1 表示包含列名的行。
Source
col1 col2 col3 col4 h1_ind table_sheet y w
Route CNG/Diesel Freq Weekly Miles 1 Summary 2021 Week 1
a 5 B 6 2 Summary 2021 Week 1
b 1 1 1 3 Summary 2021 Week 1
c 5 B 6 4 Summary 2021 Week 1
d 1 1 1 5 Summary 2021 Week 1
Route CNG/Diesel Freq Weekly Miles 1 Summary 2021 Week 2
a 5 B 6 2 Summary 2021 Week 2
b 1 1 1 3 Summary 2021 Week 2
c 5 B 6 4 Summary 2021 Week 2
d 1 1 1 5 Summary 2021 Week 2
然后我转换成这样:
(仅限第 1 周)
Data
IN column table_sheet y w value h1_ind
col1 Route Summary 2021 Week 1 a 2
col2 CNG/Diesel Summary 2021 Week 1 5 3
col3 Freq Summary 2021 Week 1 B 4
col4 Weekly Miles Summary 2021 Week 1 6 5
col1 Route Summary 2021 Week 1 b 2
col2 CNG Summary 2021 Week 1 1 3
col3 Freq Summary 2021 Week 1 1 4
col4 Weekly Miles Summary 2021 Week 1 1 5
col1 Route Summary 2021 Week 1 c 2
col2 CNG/Diesel Summary 2021 Week 1 5 3
col3 Freq Summary 2021 Week 1 B 4
col4 Weekly Miles Summary 2021 Week 1 6 5
col1 Route Summary 2021 Week 1 d 2
col2 CNG Summary 2021 Week 1 1 3
col3 Freq Summary 2021 Week 1 1 4
col4 Weekly Miles Summary 2021 Week 1 1 5
我希望能够按照以下要求呈现。
(仅限第 1 周)
Desired output:
table_sheet y w Route CNG/Diesel Freq Weekly Miles
Summary 2021 Week 1 a 5 B 6
Summary 2021 Week 1 b 1 1 1
Summary 2021 Week 1 c 5 B 6
Summary 2021 Week 1 d 1 1 1
Desired Mapping
我该怎么做? Pivot 只给我一行 (MAX, MIN) 我需要显示所有行。
可以使用PIVOT
,关键是要确保h1_ind
也是分组的一部分,而不是被聚合。
- 我们使用窗口聚合来获取每组值的 header 名称
- 使用
CROSS APPLY
逆轴
- 然后使用
PIVOT
聚合备份。
WITH Headers AS (
SELECT *,
Col1Header = MAX(CASE WHEN h1_ind = '1' THEN col1 END) OVER (PARTITION BY table_sheet, y, w),
Col2Header = MAX(CASE WHEN h1_ind = '1' THEN col2 END) OVER (PARTITION BY table_sheet, y, w),
Col3Header = MAX(CASE WHEN h1_ind = '1' THEN col3 END) OVER (PARTITION BY table_sheet, y, w),
Col4Header = MAX(CASE WHEN h1_ind = '1' THEN col4 END) OVER (PARTITION BY table_sheet, y, w)
FROM YourTable t
),
Unpivoted AS (
SELECT
t.table_sheet,
t.y,
t.w,
t.h1_ind,
v.Header,
v.Value
FROM Headers t
CROSS APPLY (VALUES
(Col1Header, Col1),
(Col2Header, Col2),
(Col3Header, Col3),
(Col4Header, Col4)
) v(Header, Value)
WHERE h1_ind > 1
)
SELECT *
FROM Unpivoted
PIVOT (
MAX(Value) FOR Header IN
(Route, [CNG/Diesel], Freq, [Weekly Miles])
) pvt;
如果需要,您也可以在此处使用 MAX(CASE
条件聚合,而不是 PIVOT
。
WITH ...
SELECT
t.table_sheet,
t.y,
t.w,
Route = MAX(CASE WHEN v.Header = 'Route' THEN v.Value END),
[CNG/Diesel] = MAX(CASE WHEN v.Header = 'CNG/Diesel' THEN v.Value END),
Freq = MAX(CASE WHEN v.Header = 'Freq' THEN v.Value END),
[Weekly Miles] = MAX(CASE WHEN v.Header = 'Weekly Miles' THEN v.Value END)
FROM Unpivoted
GROUP BY
t.table_sheet,
t.y,
t.w
t.h1_ind;
来源TABLE 看起来像这样:
h1_ind = 1 表示包含列名的行。
Source
col1 col2 col3 col4 h1_ind table_sheet y w
Route CNG/Diesel Freq Weekly Miles 1 Summary 2021 Week 1
a 5 B 6 2 Summary 2021 Week 1
b 1 1 1 3 Summary 2021 Week 1
c 5 B 6 4 Summary 2021 Week 1
d 1 1 1 5 Summary 2021 Week 1
Route CNG/Diesel Freq Weekly Miles 1 Summary 2021 Week 2
a 5 B 6 2 Summary 2021 Week 2
b 1 1 1 3 Summary 2021 Week 2
c 5 B 6 4 Summary 2021 Week 2
d 1 1 1 5 Summary 2021 Week 2
然后我转换成这样: (仅限第 1 周)
Data
IN column table_sheet y w value h1_ind
col1 Route Summary 2021 Week 1 a 2
col2 CNG/Diesel Summary 2021 Week 1 5 3
col3 Freq Summary 2021 Week 1 B 4
col4 Weekly Miles Summary 2021 Week 1 6 5
col1 Route Summary 2021 Week 1 b 2
col2 CNG Summary 2021 Week 1 1 3
col3 Freq Summary 2021 Week 1 1 4
col4 Weekly Miles Summary 2021 Week 1 1 5
col1 Route Summary 2021 Week 1 c 2
col2 CNG/Diesel Summary 2021 Week 1 5 3
col3 Freq Summary 2021 Week 1 B 4
col4 Weekly Miles Summary 2021 Week 1 6 5
col1 Route Summary 2021 Week 1 d 2
col2 CNG Summary 2021 Week 1 1 3
col3 Freq Summary 2021 Week 1 1 4
col4 Weekly Miles Summary 2021 Week 1 1 5
我希望能够按照以下要求呈现。
(仅限第 1 周)
Desired output:
table_sheet y w Route CNG/Diesel Freq Weekly Miles
Summary 2021 Week 1 a 5 B 6
Summary 2021 Week 1 b 1 1 1
Summary 2021 Week 1 c 5 B 6
Summary 2021 Week 1 d 1 1 1
Desired Mapping
我该怎么做? Pivot 只给我一行 (MAX, MIN) 我需要显示所有行。
可以使用PIVOT
,关键是要确保h1_ind
也是分组的一部分,而不是被聚合。
- 我们使用窗口聚合来获取每组值的 header 名称
- 使用
CROSS APPLY
逆轴
- 然后使用
PIVOT
聚合备份。
WITH Headers AS (
SELECT *,
Col1Header = MAX(CASE WHEN h1_ind = '1' THEN col1 END) OVER (PARTITION BY table_sheet, y, w),
Col2Header = MAX(CASE WHEN h1_ind = '1' THEN col2 END) OVER (PARTITION BY table_sheet, y, w),
Col3Header = MAX(CASE WHEN h1_ind = '1' THEN col3 END) OVER (PARTITION BY table_sheet, y, w),
Col4Header = MAX(CASE WHEN h1_ind = '1' THEN col4 END) OVER (PARTITION BY table_sheet, y, w)
FROM YourTable t
),
Unpivoted AS (
SELECT
t.table_sheet,
t.y,
t.w,
t.h1_ind,
v.Header,
v.Value
FROM Headers t
CROSS APPLY (VALUES
(Col1Header, Col1),
(Col2Header, Col2),
(Col3Header, Col3),
(Col4Header, Col4)
) v(Header, Value)
WHERE h1_ind > 1
)
SELECT *
FROM Unpivoted
PIVOT (
MAX(Value) FOR Header IN
(Route, [CNG/Diesel], Freq, [Weekly Miles])
) pvt;
如果需要,您也可以在此处使用 MAX(CASE
条件聚合,而不是 PIVOT
。
WITH ...
SELECT
t.table_sheet,
t.y,
t.w,
Route = MAX(CASE WHEN v.Header = 'Route' THEN v.Value END),
[CNG/Diesel] = MAX(CASE WHEN v.Header = 'CNG/Diesel' THEN v.Value END),
Freq = MAX(CASE WHEN v.Header = 'Freq' THEN v.Value END),
[Weekly Miles] = MAX(CASE WHEN v.Header = 'Weekly Miles' THEN v.Value END)
FROM Unpivoted
GROUP BY
t.table_sheet,
t.y,
t.w
t.h1_ind;