SQL动态地转动和分组结果

时间:2013-02-22 04:17:30

标签: sql-server-2008 tsql pivot

我的表设置如下:

CLIENTNAME          MONTHANDYEAR     RESOURCE     COST
abc                 JAN2011          res1         1000
abc                 FEB2011          res1         2000
def                 JAN2011          res2         1500
def                 MAR2011          res1         2000 
ghi                 MAR2011          res3         2500

我需要一个如下输出。月份将以3个月的间隔动态生成。在这种情况下,有没有办法按MONTHANDYEAR和group by clientname进行数据透视?

RESOURCE    CLIENTNAME     JAN2011      FEB2011      MAR2011   
res1        abc            1000         1000
res1        def                                      2000
res2        def            1500
res3        ghi                                      2500

3 个答案:

答案 0 :(得分:2)

这就是PIVOT运营商的目的:

SELECT 
  Resource, ClientName,
  [JAN2011], [FEB2011], [MAR2011]
FROM
  (
  SELECT 
    *  
  FROM tblname
  ) AS SourceTable
PIVOT
  (
  SUM(COST)
  FOR MONTHANDYEAR IN ([JAN2011], [FEB2011], [MAR2011])
  ) AS PivotTable;

由于您使用@startDate作为基准月份动态选择月份,因此您可以使用以下动态查询:

DECLARE @startDate datetime
SET @startDate = '2011-01-01'

DECLARE @sql varchar(MAX)
SET @sql = 'SELECT
        Resource, ClientName, [' +
          REPLACE(SUBSTRING(CONVERT(varchar, @startDate, 13), 4, 8), ' ', '') + '], [' +
          REPLACE(SUBSTRING(CONVERT(varchar, DATEADD(MONTH, 1, @startDate), 13), 4, 8), ' ', '') + '], [' +
          REPLACE(SUBSTRING(CONVERT(varchar, DATEADD(MONTH, 2, @startDate), 13), 4, 8), ' ', '') + ']
        FROM
          (
          SELECT
            *
          FROM tblName
          ) AS SourceTable
        PIVOT
          (
          SUM(COST)
          FOR MONTHANDYEAR IN (' +
                  QUOTENAME(REPLACE(SUBSTRING(CONVERT(varchar, @startDate, 13), 4, 8), ' ', '')) + ', ' +
                  QUOTENAME(REPLACE(SUBSTRING(CONVERT(varchar, DATEADD(MONTH, 1, @startDate), 13), 4, 8), ' ', '')) + ', ' +
                  QUOTENAME(REPLACE(SUBSTRING(CONVERT(varchar, DATEADD(MONTH, 2, @startDate), 13), 4, 8), ' ', '')) + ')
          ) AS PivotTable'

execute(@sql)

工作sqlfiddle here

答案 1 :(得分:1)

可以使用PIVOT函数完成此数据转换。

如果您知道这些值,那么您可以对monthandyear日期进行硬编码:

select resource,
  clientname,
  isnull(jan2011, '') Jan2011,
  isnull(feb2011, '') Feb2011,
  isnull(mar2011, '') Mar2011
from
(
  select clientname, monthandyear, resource, cost
  from yourtable
) src
pivot
(
  sum(cost)
  for monthandyear in (Jan2011, Feb2011, Mar2011)
) piv;

请参阅SQL Fiddle with Demo

但如果日期未知,那么您将需要使用动态SQL:

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

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

select @colNames = STUFF((SELECT distinct ', isnull(' + QUOTENAME(monthandyear)+', 0) as '+QUOTENAME(monthandyear)
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT resource, clientname,' + @colNames + ' from 
             (
                select clientname, monthandyear, resource, cost
                from yourtable
            ) x
            pivot 
            (
                sum(cost)
                for monthandyear in (' + @cols + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo

两者的结果是:

| RESOURCE | CLIENTNAME | JAN2011 | FEB2011 | MAR2011 |
-------------------------------------------------------
|     res1 |        abc |    1000 |    2000 |       0 |
|     res1 |        def |       0 |       0 |    2000 |
|     res2 |        def |    1500 |       0 |       0 |
|     res3 |        ghi |       0 |       0 |    2500 |

答案 2 :(得分:0)

SELECT Resource, Clientname
, SUM(CASE WHEN MonthAndYear = 'JAN2011' THEN COST ELSE 0 END) AS JAN2011
, SUM(CASE WHEN MonthAndYear = 'FEB2011' THEN COST ELSE 0 END) AS FEB2011
, SUM(CASE WHEN MonthAndYear = 'MAR2011' THEN COST ELSE 0 END) AS MAR2011
FROM yourtable
GROUP BY Resource, Clientname

您还可以删除ELSE 0,为没有数据的资源/客户名称组合返回NULL