3

我有两张桌子,tempUserstempItems。这两个表具有一对多的关系。

当我在这两个表上使用内部联接时,结果如下所示:

**user | Category**
Jack | Shoes
Jack | Tie
Jack | Glass
Peggy | Shoe
Peggy | Skirt
Peggy | Bat
Peggy | Cat
Bruce | Laptop
Bruce | Beer
Chuck | Cell Phone

相反,我想要一个看起来像这样的结果:

**User | Category1  | Category2 | Category3 | Category4**
Jack   | Shoes      | Tie       | Glass     | .....
Peggy  | Shoe       | Skirt     | Bat       | Cat
Bruce  | Laptop     | Beer      |.....      |......
Chuck  | Cell Phone | .....     |.......    |

类别中不同类别的数量是动态的 - 给定项目可以有任意数量。

我怎样才能产生这个结果?

4

3 回答 3

2

有几种方法可以将数据从行转换为列。

由于您使用的是 SQL Server 2008,因此您可以使用 PIVOT 函数。

我建议使用该row_number()功能来帮助旋转数据。如果您有已知数量的值,则可以对查询进行硬编码:

select user, category1, category2, category3, category4
from
(
  select [user], category,
    'Category'+cast(row_number() over(partition by [user] 
                                      order by [user]) as varchar(3)) rn
  from yt
) d
pivot
(
  max(category)
  for rn in (category1, category2, category3, category4)
) piv;

请参阅SQL Fiddle with Demo

对于您的情况,您声明您将有未知数量的需要作为列的值。在这种情况下,您将需要使用动态 SQL 来生成要执行的查询字符串:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('Category'+cast(row_number() over(partition by [user] 
                                                                      order by [user]) as varchar(3))) 
                    from yt
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT [user],' + @cols + ' 
              from
              (
                select [user], category,
                  ''Category''+cast(row_number() over(partition by [user] 
                                                    order by [user]) as varchar(3)) rn
                from yt
              ) d
              pivot 
              (
                  max(category)
                  for rn in (' + @cols + ')
              ) p '

execute(@query)

请参阅SQL Fiddle with Demo。两者都给出结果:

|  USER |  CATEGORY1 | CATEGORY2 | CATEGORY3 | CATEGORY4 |
----------------------------------------------------------
| Bruce |     Laptop |      Beer |    (null) |    (null) |
| Chuck | Cell Phone |    (null) |    (null) |    (null) |
|  Jack |      Shoes |       Tie |     Glass |    (null) |
| Peggy |       Shoe |     Skirt |       Bat |       Cat |
于 2013-05-24T14:51:51.317 回答
0

Sql Server 确实允许您对数据进行透视。但是,与其他关系数据库一样,它仍然要求您在查询开始时就知道结果将是多少列(以及什么类型),即使使用 PIVOT。您在这里可以期望的最好的方法是使用查询,结合动态 sql(在运行时在代码中构建查询字符串),首先找出谁拥有最多的类别,然后构建一个查询来 PIVOTs 您的数据以查找那个很多项目。

使用未知数量的列进行透视的常规解决方案是从调用服务器的代码执行透视客户端。

于 2013-05-24T14:52:22.707 回答
0

这是使用多个表的解决方案。该方案完全基于bluefeet的方案。我刚刚添加了用户 ID。

create table #tmpUsers
(user_id int, user_name varchar(255));
insert into #tmpUsers values (1,'Jack');
insert into #tmpUsers values (2,'Peggy');
insert into #tmpUsers values (3,'Bruce');
insert into #tmpUsers values (4,'Chuck');


create table #tmpItems
(user_id int, category varchar(255));
insert into #tmpItems values(1,'Shoes');
insert into #tmpItems values(1,'Tie');
insert into #tmpItems values(1,'Glass');

insert into #tmpItems values(2,'Shoe');
insert into #tmpItems values(2,'Skirt');
insert into #tmpItems values(2,'Bat');
insert into #tmpItems values(2,'Cat');

insert into #tmpItems values(3,'Laptop');
insert into #tmpItems values(3,'Beer');

insert into #tmpItems values(4,'Cell Phone');


select TU.user_name,TI.category from #tmpUsers TU inner join #tmpItems TI on TU.user_id=TI.user_id


DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('Category'+cast(row_number() over(partition by TU.[user_id] 
                                                                      order by TU.[user_id]) as varchar(3))) 
                    from #tmpUsers TU inner join #tmpItems TI on TU.user_id=TI.user_id
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')



set @query = 'SELECT [user_name],' + @cols + ' 
              from
              (
                select TU.[user_name], TI.category,
                  ''Category''+cast(row_number() over(partition by TU.[user_id] 
                                                    order by TU.[user_id] ) as varchar(3)) rn
                from #tmpUsers TU inner join #tmpItems TI on TU.user_id=TI.user_id
              ) d
              pivot 
              (
                  max(category)
                  for rn in (' + @cols + ')
              ) p '

execute(@query)


drop table #tmpUsers
drop table #tmpItems
于 2013-05-24T15:34:14.523 回答