如何在SQL Server 2005中不使用数据透视表将一堆行转换为聚合列?

cde*_*zaq 0 sql sql-server pivot sql-server-2005

这是一个场景:我有一个表记录了user_id,module_id以及查看模块的日期/时间.

例如.

Table: Log
------------------------------
User_ID  Module_ID   Date
------------------------------
1       red         2001-01-01
1       green       2001-01-02
1       blue        2001-01-03
2       green       2001-01-04
2       blue        2001-01-05
1       red         2001-01-06
1       blue        2001-01-07
3       blue        2001-01-08
3       green       2001-01-09
3       red         2001-01-10
3       green       2001-01-11
4       white       2001-01-12
Run Code Online (Sandbox Code Playgroud)

我需要得到一个结果集,其中user_id为第1列,然后是每个模块的列.然后行数据是user_id以及用户查看每个模块的次数.

例如.

---------------------------------
User_ID  red green   blue    white
---------------------------------
1       2   1       2       0
2       0   1       1       0
3       1   2       1       0
4       0   0       0       1
Run Code Online (Sandbox Code Playgroud)

我最初认为我可以用PIVOT做到这一点,但没有骰子; 数据库是在SQL Server 2005中运行的已转换的SQL Server 2000数据库.我无法更改兼容级别,因此数据库已关闭.

另一个问题是模块会有所不同,每次添加或删除模块时都不可能重新编写查询.这意味着我无法对模块进行硬编码,因为我事先并不知道将要安装哪些模块.

我怎么能做到这一点?

Dan*_*haw 7

可以使用CASE和GROUP BY模拟PIVOT

select
    [user_id],
    sum(case when [Module_ID] = 'red' then 1 else 0 end) as red,
    sum(case when [Module_ID] = 'green' then 1 else 0 end) as green,
    sum(case when [Module_ID] = 'blue' then 1 else 0 end) as blue,
    sum(case when [Module_ID] = 'white' then 1 else 0 end) as white
from [log]
group by
    [user_id]
Run Code Online (Sandbox Code Playgroud)

当然,如果模块不同(如问题中所述),这不起作用,但是,PIVOT也有同样的问题.

动态生成一些sql克服了这个问题,但这个解决方案闻起来有点!

declare @sql nvarchar(max)

set @sql = '
select
    [user_id],'

select @sql = @sql + '
    sum(case when [Module_ID] = ''' + replace([Module_ID], '''','''''') + ''' then 1 else 0 end) as [' + replace([Module_ID], '''','') + '],'
from (select distinct [Module_ID] from [log]) as moduleids

set @sql = substring(@sql,1,len(@sql)-1) + '
from [log]
group by
    [user_id]
'
print @sql
exec sp_executesql @sql
Run Code Online (Sandbox Code Playgroud)

请注意,如果模块ID数据不可信,则可能容易受到sql注入攻击.