如何在 SQL Server 2008 中将行切换为列,反之亦然
How to switch rows to columns and vice versa in SQL Server 2008
我在 SQL Server 2008 中无法将行切换为列,反之亦然,我已尝试对解决方案进行任何查询,但没有得到正确的结果。
我table如下:
declare @tmpTable table
(name varchar(20), date_ date, sales_code char(1), sales smallint, earned int)
insert into @tmpTable
values ('Robert', '2016/8/1', 'A', 2, 30),
('Robert', '2016/8/1', 'B', 3, 45),
('Robert', '2016/8/2', 'B', 1, 15),
('Robert', '2016/8/3', 'B', 2, 30),
('Jhon', '2016/8/1', 'A', 3, 45),
('Jhon', '2016/8/2', 'A', 3, 45),
('Jhon', '2016/8/3', 'B', 2, 30)
select * from @tmpTable;
结果:
Name date_ sales_code sales earned
------ ---------- ---------- ----- ------
Robert 2016-08-01 A 2 30
Robert 2016-08-01 B 3 45
Robert 2016-08-02 B 1 15
Robert 2016-08-03 B 2 30
Jhon 2016-08-01 A 3 45
Jhon 2016-08-02 A 3 45
Jhon 2016-08-03 B 2 30
那么,我有下一个问题:
select * from (
select name, 'sales_code' as category, date_, sales_code from (
select * from (
SELECT name, date_
,STUFF((SELECT ', ' + sales_code [text()]
FROM @tmpTable
WHERE date_ = t.date_
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') sales_code
,STUFF((SELECT ', ' + convert(varchar(max), sales) [text()]
FROM @tmpTable
WHERE date_ = t.date_
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') sales
,STUFF((SELECT ', ' + convert(varchar(max), earned) [text()]
FROM @tmpTable
WHERE date_ = t.date_
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') earned
FROM @tmpTable t
GROUP BY name, date_
) as a
) as a
) as a
pivot (
max(sales_code) FOR date_ IN ([2016/8/1], [2016/8/2], [2016/8/3])
)as pv
union all
select * from (
select name, 'sales' as category, date_, sales from (
select * from (
SELECT name, date_
,STUFF((SELECT ', ' + sales_code [text()]
FROM @tmpTable
WHERE date_ = t.date_
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') sales_code
,STUFF((SELECT ', ' + convert(varchar(max), sales) [text()]
FROM @tmpTable
WHERE date_ = t.date_
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') sales
,STUFF((SELECT ', ' + convert(varchar(max), earned) [text()]
FROM @tmpTable
WHERE date_ = t.date_
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') earned
FROM @tmpTable t
GROUP BY name, date_
) as a
) as a
) as a
pivot (
max(sales) FOR date_ IN ([2016/8/1], [2016/8/2], [2016/8/3])
)as pv
union all
select * from (
select name, 'earned' as category, date_, earned from (
select * from (
SELECT name, date_
,STUFF((SELECT ', ' + sales_code [text()]
FROM @tmpTable
WHERE date_ = t.date_
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') sales_code
,STUFF((SELECT ', ' + convert(varchar(max), sales) [text()]
FROM @tmpTable
WHERE date_ = t.date_
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') sales
,STUFF((SELECT ', ' + convert(varchar(max), earned) [text()]
FROM @tmpTable
WHERE date_ = t.date_
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') earned
FROM @tmpTable t
GROUP BY name, date_
) as a
) as a
) as a
pivot (
max(earned) FOR date_ IN ([2016/8/1], [2016/8/2], [2016/8/3])
)as pv
会显示结果:
name category 2016/8/1 2016/8/2 2016/8/3
------- -------- -------- ------- --------
Jhon sales_code A, B, A B, A B, B
Robert sales_code A, B, A B, A B, B
Jhon sales 2, 3, 3 1, 3 2, 2
Robert sales 2, 3, 3 1, 3 2, 2
Jhon earned 30, 45, 45 15, 45 30, 30
Robert earned 30, 45, 45 15, 45 30, 30
但是,我想得到以下结果:
name category 2016/8/1 2016/8/2 2016/8/3
---- -------- -------- -------- --------
Robert sales_code A, B B B
Robert sales 2, 3 1 2
Robert earned 30, 45 15 30
Jhon sales_code A A B
Jhon sales 3 3 2
Jhon earned 45 45 30
非常感谢您的帮助。
首先您需要对数据进行逆透视。为此,所有数据类型都非常匹配,因此您需要将 2 个数字列转换为 varchars。
在逆透视之前仍然使用东西来获取每个名称 date_ 的组合值,但使用 distinct 仅获取一次名称 date_ 值。
取消旋转后,您只需再次旋转即可。
SELECT *
FROM ( SELECT DISTINCT
Name,
date_,
sales_code = STUFF((SELECT ', ' + sales_code
FROM @tmpTable t2
WHERE t2.Name = t.Name AND t2.date_ = t.date_
FOR XML PATH('')), 1, 2, ''),
sales = STUFF((SELECT ', ' + CONVERT(VARCHAR, sales)
FROM @tmpTable t2
WHERE t2.Name = t.Name AND t2.date_ = t.date_
FOR XML PATH('')), 1, 2, ''),
earned = STUFF((SELECT ', ' + CONVERT(VARCHAR, earned)
FROM @tmpTable t2
WHERE t2.Name = t.Name AND t2.date_ = t.date_
FOR XML PATH('')), 1, 2, '')
FROM @tmpTable t) t
UNPIVOT (
val
FOR category IN (sales_code, sales, earned)
) up
PIVOT (
MAX(val)
FOR date_ IN ([2016-08-01], [2016-08-02], [2016-08-03])
) p
ORDER BY name DESC,
category DESC
我在 SQL Server 2008 中无法将行切换为列,反之亦然,我已尝试对解决方案进行任何查询,但没有得到正确的结果。
我table如下:
declare @tmpTable table (name varchar(20), date_ date, sales_code char(1), sales smallint, earned int) insert into @tmpTable values ('Robert', '2016/8/1', 'A', 2, 30), ('Robert', '2016/8/1', 'B', 3, 45), ('Robert', '2016/8/2', 'B', 1, 15), ('Robert', '2016/8/3', 'B', 2, 30), ('Jhon', '2016/8/1', 'A', 3, 45), ('Jhon', '2016/8/2', 'A', 3, 45), ('Jhon', '2016/8/3', 'B', 2, 30) select * from @tmpTable;
结果:
Name date_ sales_code sales earned ------ ---------- ---------- ----- ------ Robert 2016-08-01 A 2 30 Robert 2016-08-01 B 3 45 Robert 2016-08-02 B 1 15 Robert 2016-08-03 B 2 30 Jhon 2016-08-01 A 3 45 Jhon 2016-08-02 A 3 45 Jhon 2016-08-03 B 2 30
那么,我有下一个问题:
select * from ( select name, 'sales_code' as category, date_, sales_code from ( select * from ( SELECT name, date_ ,STUFF((SELECT ', ' + sales_code [text()] FROM @tmpTable WHERE date_ = t.date_ FOR XML PATH(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') sales_code ,STUFF((SELECT ', ' + convert(varchar(max), sales) [text()] FROM @tmpTable WHERE date_ = t.date_ FOR XML PATH(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') sales ,STUFF((SELECT ', ' + convert(varchar(max), earned) [text()] FROM @tmpTable WHERE date_ = t.date_ FOR XML PATH(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') earned FROM @tmpTable t GROUP BY name, date_ ) as a ) as a ) as a pivot ( max(sales_code) FOR date_ IN ([2016/8/1], [2016/8/2], [2016/8/3]) )as pv union all select * from ( select name, 'sales' as category, date_, sales from ( select * from ( SELECT name, date_ ,STUFF((SELECT ', ' + sales_code [text()] FROM @tmpTable WHERE date_ = t.date_ FOR XML PATH(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') sales_code ,STUFF((SELECT ', ' + convert(varchar(max), sales) [text()] FROM @tmpTable WHERE date_ = t.date_ FOR XML PATH(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') sales ,STUFF((SELECT ', ' + convert(varchar(max), earned) [text()] FROM @tmpTable WHERE date_ = t.date_ FOR XML PATH(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') earned FROM @tmpTable t GROUP BY name, date_ ) as a ) as a ) as a pivot ( max(sales) FOR date_ IN ([2016/8/1], [2016/8/2], [2016/8/3]) )as pv union all select * from ( select name, 'earned' as category, date_, earned from ( select * from ( SELECT name, date_ ,STUFF((SELECT ', ' + sales_code [text()] FROM @tmpTable WHERE date_ = t.date_ FOR XML PATH(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') sales_code ,STUFF((SELECT ', ' + convert(varchar(max), sales) [text()] FROM @tmpTable WHERE date_ = t.date_ FOR XML PATH(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') sales ,STUFF((SELECT ', ' + convert(varchar(max), earned) [text()] FROM @tmpTable WHERE date_ = t.date_ FOR XML PATH(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') earned FROM @tmpTable t GROUP BY name, date_ ) as a ) as a ) as a pivot ( max(earned) FOR date_ IN ([2016/8/1], [2016/8/2], [2016/8/3]) )as pv
会显示结果:
name category 2016/8/1 2016/8/2 2016/8/3 ------- -------- -------- ------- -------- Jhon sales_code A, B, A B, A B, B Robert sales_code A, B, A B, A B, B Jhon sales 2, 3, 3 1, 3 2, 2 Robert sales 2, 3, 3 1, 3 2, 2 Jhon earned 30, 45, 45 15, 45 30, 30 Robert earned 30, 45, 45 15, 45 30, 30
但是,我想得到以下结果:
name category 2016/8/1 2016/8/2 2016/8/3 ---- -------- -------- -------- -------- Robert sales_code A, B B B Robert sales 2, 3 1 2 Robert earned 30, 45 15 30 Jhon sales_code A A B Jhon sales 3 3 2 Jhon earned 45 45 30
非常感谢您的帮助。
首先您需要对数据进行逆透视。为此,所有数据类型都非常匹配,因此您需要将 2 个数字列转换为 varchars。
在逆透视之前仍然使用东西来获取每个名称 date_ 的组合值,但使用 distinct 仅获取一次名称 date_ 值。
取消旋转后,您只需再次旋转即可。
SELECT *
FROM ( SELECT DISTINCT
Name,
date_,
sales_code = STUFF((SELECT ', ' + sales_code
FROM @tmpTable t2
WHERE t2.Name = t.Name AND t2.date_ = t.date_
FOR XML PATH('')), 1, 2, ''),
sales = STUFF((SELECT ', ' + CONVERT(VARCHAR, sales)
FROM @tmpTable t2
WHERE t2.Name = t.Name AND t2.date_ = t.date_
FOR XML PATH('')), 1, 2, ''),
earned = STUFF((SELECT ', ' + CONVERT(VARCHAR, earned)
FROM @tmpTable t2
WHERE t2.Name = t.Name AND t2.date_ = t.date_
FOR XML PATH('')), 1, 2, '')
FROM @tmpTable t) t
UNPIVOT (
val
FOR category IN (sales_code, sales, earned)
) up
PIVOT (
MAX(val)
FOR date_ IN ([2016-08-01], [2016-08-02], [2016-08-03])
) p
ORDER BY name DESC,
category DESC