如何在查询中添加动态数量的列?

时间:2016-06-08 17:06:36

标签: sql sql-server

我有一个查询列出了一些有关文档编写器的统计信息:

select   d.WrittenBy,
         count(1) as NumDocs,
         sum(case when d.Language = 'English' then 1 else 0 end) as English,
         sum(case when d.Published = 1 then 1 else 0 end) as NumPublished
from     #documents d
group by d.WrittenBy

实际上,#documents.Language包含的语言多于英语:

English
French
English;French
German
French;German

等。 <{1}}上的不同内容可能会在一周内返回不同的结果,因为有人插入了新值。

我想在我的统计数据中包含所有语言:

#documents.Language

但是,这需要我不时地手动更新查询。我希望在新语言可用时自动更新查询:

select   d.WrittenBy,
         count(1) as NumDocs,
         sum(case when d.Language = 'English' then 1 else 0 end) as English,
         sum(case when d.Language = 'French' then 1 else 0 end) as French,
         sum(case when d.Language = 'English;French' then 1 else 0 end) as EnglishFrench,
         ...
         ...
         sum(case when d.Published = 1 then 1 else 0 end) as NumPublished
from     #documents d
group by d.WrittenBy

这为我提供了所有可能declare @cols as nvarchar(max); set @cols = stuff ( ( select distinct ',' + quotename(Language) from #documents for xml path(''), type ).value('.', 'nvarchar(max)'), 1, 1, '' ) 的列表。在这里,我被卡住了。我想动态地将这些语言列添加到我的表中:

Languages

我怎样才能做到这一点?非常感谢任何帮助,如果它意味着涉及另一个临时表加入(尽管,出于学习目的,我更喜欢动态sql)。

2 个答案:

答案 0 :(得分:1)

嗯......因为你准备好了一点点动态SQL ......给它一个旋转:

set nocount on
declare 
    @sql nvarchar( max ),
    @expression nvarchar( max ),
    @template nvarchar( 256 ),
    @language nvarchar( 128 )

select @expression = '';

declare c cursor for select distinct language from #documents
open c
    while ( 1 = 1 )
    begin
        fetch next from c into @language
        if ( @@fetch_status != 0 ) break
        select @template = 'sum(case when d.Language = '''+ @language +''' then 1 else 0 end) as ' + replace(@language,';','')
        select @expression += @template + ','
    end
close c
deallocate c

select @sql = 
'select   
    d.WrittenBy,
    count(1) as NumDocs,
    '+ @expression +'
    sum(case when d.Published = 1 then 1 else 0 end) as NumPublished
from     #documents d
group by d.WrittenBy'

execute ( @sql )

我将解释一个小技巧...确保在开始循环之前将@expression初始化为空字符串...否则它将为null ...并且添加到null只会使更多null; - )

答案 1 :(得分:0)

如果您有SQL 2008及更高版本,则可以使用PIVOT或UNPIVOT。在此处查看更多信息:https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx