扩展当前查询,计算列

end*_*eka -2 sql sql-server-2008-r2

我的表看起来像这样的例子:

Name       date      result
 A      2012-01-01     1
 A      2012-02-01     2
 B      2013-01-01     1
         ...
Run Code Online (Sandbox Code Playgroud)

有关完整示例:http://sqlfiddle.com/#!3/00222/1

目前我有一个工作查询,按人和年计算行数:http://sqlfiddle.com/#!3/00225/32

这是完美的,但我想要的是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
Run Code Online (Sandbox Code Playgroud)

更好的是我给结果列一个好名字(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
Run Code Online (Sandbox Code Playgroud)

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

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

我有结果:

,[1]
,[2]
,[3]
Run Code Online (Sandbox Code Playgroud)

但如果我运行整个代码我得到一个错误,invallid列名...

Tar*_*ryn 7

由于您有两列现在想要PIVOT,因此首先必须取消这些列的转换,然后将这些值转换为新列.

从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)
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.此查询将为您提供名称列表,其中包含"新列",然后是每个名称的"总计"条目.

|     NAME | NEW_COL | TOTAL |
|----------|---------|-------|
| Person A |    2012 |    11 |
| Person A |       1 |    11 |
| Person A |    2012 |    11 |
| Person A |       2 |    11 |
Run Code Online (Sandbox Code Playgroud)

您会看到日期和结果现在都存储在"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];
Run Code Online (Sandbox Code Playgroud)

请参阅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;
Run Code Online (Sandbox Code Playgroud)

请参阅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 |
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

请参阅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 = '+@currentYear+' 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;
Run Code Online (Sandbox Code Playgroud)

请参阅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 |
Run Code Online (Sandbox Code Playgroud)