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数据库.我无法更改兼容级别,因此数据库已关闭.
另一个问题是模块会有所不同,每次添加或删除模块时都不可能重新编写查询.这意味着我无法对模块进行硬编码,因为我事先并不知道将要安装哪些模块.
我怎么能做到这一点?
可以使用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注入攻击.
| 归档时间: |
|
| 查看次数: |
1305 次 |
| 最近记录: |