2014-09-11 62 views
-2

我的表看起来例如像这样:扩展当前的查询,计算列

Name  date  result 
A  2012-01-01  1 
A  2012-02-01  2 
B  2013-01-01  1 
     ... 

对于一个完整的例子:http://sqlfiddle.com/#!3/0226b/1

目前,我有一个由人,今年计数行的工作查询:http://sqlfiddle.com/#!3/0226b/3

这是完美的,但我想要的是2014年的一些额外的信息。我需要计算每个结果有多少行。 是这样的:

NAME  1 2 3 2014 2013 2012 TOTAL 
Person B 4 0 2  6  2  2  10 
Person A 2 1 1  4  3  4  11 
Person C 1 1 1  3  1  0  4 

更妙的是,我给的结果,列一个好名字(1 =丢失,2 =平局,3 =韩元):

NAME  lost draw won 2014 2013 2012 TOTAL 
Person B 4  0  2  6  2  2  10 
Person A 2  1  1  4  3  4  11 
Person C 1  1  1  3  1  0  4 

我尝试添加一些额外的代码,如:

select @colsResult 
    = STUFF((SELECT ',' + QUOTENAME(result) 
      from list 
      group by result 
      order by result 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

我的结果是:

,[1] 
,[2] 
,[3] 

但是,如果我跑了整个代码中,我得到一个错误,invallid列名...

+1

最后一列是否需要特定顺序 - 意味着结果值升序和年降序?你只有3个结果值?它总是会被限制在3? – Taryn 2014-09-11 11:48:28

回答

7

既然你有两列,你现在要枢,你首先必须unpivot的那些列,然后将这些值转换为新列。

从SQL Server 2005开始,您可以使用CROSS APPLY来取消转移列。基本语法类似于:

select 
    name, 
    new_col, 
    total 
from 
(
    select name, 
    dt = year(date), 
    result, 
    total = count(*) over(partition by name) 
    from list 
) d 
cross apply 
(
    select 'dt', dt union all 
    select 'result', result 
) c (old_col_name, new_col) 

请参阅SQL Fiddle with Demo。该查询会为您提供一个名称列表,其中包含“新列”,然后是每个名称的Total条目。

|  NAME | NEW_COL | TOTAL | 
|----------|---------|-------| 
| Person A | 2012 | 11 | 
| Person A |  1 | 11 | 
| Person A | 2012 | 11 | 
| Person A |  2 | 11 | 

您会看到日期和结果现在都存储在“new_col”中。这些值现在将用作新的列名称。如果你有列的数量有限,那么只需在硬编码查询:

select name, lost = [1], 
    draw=[2], won = [3], 
    [2014], [2013], [2012], Total 
from 
(
    select 
    name, 
    new_col, 
    total 
    from 
    (
    select name, 
     dt = year(date), 
     result, 
     total = count(*) over(partition by name) 
    from list 
) d 
    cross apply 
    (
    select 'dt', dt union all 
    select 'result', result 
) c (old_col_name, new_col) 
) src 
pivot 
(
    count(new_col) 
    for new_col in([1], [2], [3], [2014], [2013], [2012]) 
) piv 
order by [2014]; 

SQL Fiddle with Demo

现在,因为你的年是动态的,那么你就需要使用动态SQL。但现在看来,你有3个结果,并可能多年 - 所以我会用静态/动态SQL的组合,使它更容易些:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX), 
    @orderby nvarchar(max) 

select @cols 
    = STUFF((SELECT ',' + QUOTENAME(year(date)) 
      from list 
      group by year(date) 
      order by year(date) desc 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

select @orderby = 'ORDER BY ['+cast(year(getdate()) as varchar(4)) + '] desc' 

set @query = 'SELECT name, lost = [1], 
       draw=[2], won = [3],' + @cols + ', Total 
      from 
      (
       select 
       name, 
       new_col, 
       total 
       from 
       (
       select name, 
        dt = year(date), 
        result, 
        total = count(*) over(partition by name) 
       from list 
      ) d 
       cross apply 
       (
       select ''dt'', dt union all 
       select ''result'', result 
      ) c (old_col_name, new_col) 
      ) x 
      pivot 
      (
       count(new_col) 
       for new_col in ([1], [2], [3],' + @cols + ') 
      ) p '+ @orderby 

exec sp_executesql @query; 

SQL Fiddle with Demo。这给出了一个结果:

|  NAME | LOST | DRAW | WON | 2014 | 2013 | 2012 | TOTAL | 
|----------|------|------|-----|------|------|------|-------| 
| Person B | 7 | 1 | 2 | 6 | 2 | 2 | 10 | 
| Person A | 5 | 3 | 3 | 4 | 3 | 4 | 11 | 
| Person C | 2 | 1 | 1 | 3 | 1 | 0 |  4 | 

如果你想只筛选本年度的结果列,然后才能执行此过滤多种方式,但最简单的,你可以包括在逆转置过滤器。硬编码版本将为:

select name, lost = [1], 
    draw=[2], won = [3], 
    [2014], [2013], [2012], Total 
from 
(
    select 
    name, 
    new_col, 
    total 
    from 
    (
    select name, 
     dt = year(date), 
     result, 
     total = count(*) over(partition by name) 
    from list 
) d 
    cross apply 
    (
    select 'dt', dt union all 
    select 'result', case when dt = 2014 then result end 
) c (old_col_name, new_col) 
) src 
pivot 
(
    count(new_col) 
    for new_col in([1], [2], [3], [2014], [2013], [2012]) 
) piv 
order by [2014] desc; 

请参阅SQL Fiddle with Demo。那么动态sql版本将是:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX), 
    @orderby nvarchar(max), 
    @currentYear varchar(4) 

select @currentYear = cast(year(getdate()) as varchar(4)) 

select @cols 
    = STUFF((SELECT ',' + QUOTENAME(year(date)) 
      from list 
      group by year(date) 
      order by year(date) desc 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

select @orderby = 'ORDER BY ['+ @currentYear + '] desc' 

set @query = 'SELECT name, lost = [1], 
       draw=[2], won = [3],' + @cols + ', Total 
      from 
      (
       select 
       name, 
       new_col, 
       total 
       from 
       (
       select name, 
        dt = year(date), 
        result, 
        total = count(*) over(partition by name) 
       from list 
      ) d 
       cross apply 
       (
       select ''dt'', dt union all 
       select ''result'', case when dt = '[email protected]+' then result end 
      ) c (old_col_name, new_col) 
      ) x 
      pivot 
      (
       count(new_col) 
       for new_col in ([1], [2], [3],' + @cols + ') 
      ) p '+ @orderby 

exec sp_executesql @query; 

请参阅SQL Fiddle with Demo。此版本将给出结果:

|  NAME | LOST | DRAW | WON | 2014 | 2013 | 2012 | TOTAL | 
|----------|------|------|-----|------|------|------|-------| 
| Person B | 4 | 0 | 2 | 6 | 2 | 2 | 10 | 
| Person A | 2 | 1 | 1 | 4 | 3 | 4 | 11 | 
| Person C | 1 | 1 | 1 | 3 | 1 | 0 |  4 | 
+0

感谢您的回复!这几乎是我需要的。但是我只需要去年的失利,平局和胜利(现在是2014年......)因此对于B人来说,这将是4 0 2. – endeka 2014-09-11 13:46:28

+0

@endeka看我的编辑。 – Taryn 2014-09-11 14:19:59