如何在 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