SQL汇总报告,寻找优雅的解决方案

Uri*_*rik 4 sql t-sql sql-server pivot sql-server-2008

我有一个包含3列的表:ItemCode,Quantity和DocDate.我想以更"优雅"的方式创建以下报告:

SELECT T0.ItemCode, 
       (SELECT SUM(QUANTITY) FROM MyTable T1 WHERE YEAR(T0.DocDate) = 2011 AND T0.ItemCode = T1.ItemCode) AS '2011',
       (SELECT SUM(QUANTITY) FROM MyTable T1 WHERE YEAR(T0.DocDate) = 2012 AND T0.ItemCode = T1.ItemCode) AS '2012'
FROM MyTable T0
GROUP BY T0.ItemCode, YEAR(T0.DocDate)
Run Code Online (Sandbox Code Playgroud)

我很确定有更好,更有效的方法来编写这个,但我无法想出正确的语法.有任何想法吗?

Iva*_*n G 5

你可以试试这个:

SELECT  T0.ItemCode, 
        SUM(CASE WHEN YEAR(T0.DocDate) = 2011 THEN QUANTITY ELSE 0 END) AS '2011',
        SUM(CASE WHEN YEAR(T0.DocDate) = 2012 THEN QUANTITY ELSE 0 END) AS '2012'
FROM    MyTable T0
GROUP BY 
        T0.ItemCode
Run Code Online (Sandbox Code Playgroud)


Tar*_*ryn 5

这种类型的数据转换称为a PIVOT.有几种方法可以执行此操作.您可以使用该PIVOT函数,也可以将聚合函数与CASE语句一起使用:

Static Pivot Version:这是您将所有值硬编码到查询中的位置

select ItemCode, [2011], [2012]
from
(
  SELECT ItemCode,
    QUANTITY,
    YEAR(DocDate) Year
  FROM MyTable 
) src
pivot
(
  sum(quantity)
  for year in ([2011], [2012])
) piv
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo

聚合案例:

SELECT ItemCode, 
  SUM(CASE WHEN YEAR(DocDate) = 2011 THEN QUANTITY ELSE 0 END) AS '2011',
  SUM(CASE WHEN YEAR(DocDate) = 2012 THEN QUANTITY ELSE 0 END) AS '2012'
FROM    MyTable 
GROUP BY ItemCode;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo

Dynamic Pivot:前两个版本的工作效果很好,你有一个已知数量的year值可以转换,但是你有一个未知的数字,那么你可以使用动态的sql:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(YEAR(DocDate)) 
                    from mytable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT itemcode, ' + @cols + ' from 
             (
                select itemcode, quantity, year(docdate) year
                from mytable
            ) x
            pivot 
            (
                sum(quantity)
                for year in (' + @cols + ')
            ) p '

execute(@query)
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo

所有三个版本都会产生相同的结果:

| ITEMCODE | 2011 | 2012 |
--------------------------
|        1 |  200 |   45 |
|        2 |   89 |    0 |
|        3 |    0 |    7 |
Run Code Online (Sandbox Code Playgroud)