SQL Query生成动态列

时间:2015-10-11 12:16:09

标签: sql sql-server pivot

您好我有一个查询,可以获得每月和每年的事件总数 我想要一个显示列中所有不同年份的结果 您能否建议如何使这个查询动态化?

Expected Result:
Month      2013 2014 2015
January    8    0   12
February   9    6   10
March      12   1   9
April      10   13  27
May        9    22  15
June       27   4   20
July       15   12  22
August     20   2   2
September  22   5   10
October    10   8   12
November    0   7   0
December    0   15  0

查询

select DATENAME(MONTH,DateOpened) as Month,
   sum(case when year(DateOpened)  = '2015' then 1 else 0 end) as [2015],
   sum(case when year(DateOpened)  = '2014' then 1 else 0 end) as [2014]

from Incidents
group by DATENAME(MONTH,DateOpened), MONTH(DateOpened)
order by MONTH(DateOpened)

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

您可以使用PIVOT表运算符,如下所示:

SELECT *
FROM
(
  SELECT
    DATENAME(MONTH,DateOpened) as Month,
    DATENAME(Year,DateOpened) AS Year,
    DateOpened
  FROM Incidents
) AS t
PIVOT
(
  COUNT(DateOpened)
  FOR Year IN([2013], [2014], [2015])
) AS p;

如果您不需要编写年份列表并动态执行任何年份,则必须使用动态SQL动态运行查询,如下所示:

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

SELECT @cols = STUFF((SELECT distinct ',' +
                        QUOTENAME(DATENAME(Year,DateOpened))
                      from Incidents AS t
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                        , 1, 1, '');

SELECT @query = 'SELECT * , '+ @cols + '
FROM
(
  select 
    DATENAME(MONTH,DateOpened) as Month,
    DATENAME(Year,DateOpened) AS Year,
    DateOpened
  FROM Incidents
) AS t
PIVOT
(
  COUNT(DateOpened)
  FOR Year IN(' + @cols + ')' +
                  ') p';

  execute(@query);

这会给你这样的东西:

|     Month | 2014 | 2015 | 2014 | 2015 |
|-----------|------|------|------|------|
|     April |    0 |    3 |    0 |    3 |
|    August |    1 |    1 |    1 |    1 |
|  December |    1 |    0 |    1 |    0 |
|  February |    0 |    1 |    0 |    1 |
|      July |    1 |    1 |    1 |    1 |
| September |    1 |    0 |    1 |    0 |

请注意:两个查询都不会列出原始表上没有日期的任何月份。如果要列出计数为0的表中未列出的任何月份,则必须修改锚点查询,以便列出所有月份,即使未列出:

  SELECT
    m.Name as Month,
    i.Year,
    i.DateOpened 
  FROM
  (
   VALUES ('Janurary'), ('February'), ('March'),
          ('April'),    ('May'),      ('June'),
          ('July'),     ('August'),   ('September'),
          ('October'),  ('November'), ('December')
   ) AS m(Name) 
  LEFT JOIN
  (
    SELECT 
      DATENAME(MONTH,DateOpened) as Month,
      DATENAME(Year,DateOpened) AS Year,
      DateOpened 
    FROM Incidents 
  ) AS i ON i.Month = m.Name

并在动态查询中替换它。

这将为您提供零结果的缺失月份:

|     Month | 2014 | 2015 | 2014 | 2015 |
|-----------|------|------|------|------|
|  Janurary |    0 |    0 |    0 |    0 | <<
|  February |    0 |    1 |    0 |    1 |
|     March |    0 |    0 |    0 |    0 | <<
|     April |    0 |    3 |    0 |    3 |
|       May |    0 |    0 |    0 |    0 | <<
|      June |    0 |    0 |    0 |    0 | <<
|      July |    1 |    1 |    1 |    1 |
|    August |    1 |    1 |    1 |    1 |
| September |    1 |    0 |    1 |    0 |
|   October |    0 |    0 |    0 |    0 | <<
|  November |    0 |    0 |    0 |    0 | <<
|  December |    1 |    0 |    1 |    0 |

答案 1 :(得分:0)

一个像这样的简单创建表..

  CREATE TABLE #tmpIncidents
  (
    IncidentName NVARCHAR(50)
    , DateOpened DATETIME
  )

  INSERT INTO #tmpIncidents (IncidentName,DateOpened) VALUES 
  ('Test1',GETDATE()),
  ('Test1',DATEADD(YEAR,-1,GETDATE())),
  ('Test1',DATEADD(YEAR,-2,GETDATE())),
  ('Test1',DATEADD(YEAR,2,GETDATE())),
  ('Test1',DATEADD(YEAR,1,GETDATE())),
  ('Test1',DATEADD(YEAR,3,GETDATE()))

然后是多年的构建查询

  DECLARE @columnVar NVARCHAR(4000)

  SELECT @columnVar =
      (SELECT DISTINCT
            '[' + CONVERT(NVARCHAR(150),DATEPART(YEAR,DateOpened)) + '],' AS [text()]
      FROM #tmpIncidents
      FOR XML PATH('')
      )
  SET @columnVar = (SELECT LEFT(@columnVar,LEN(@columnVar)-1))
  --SELECT @columnVar --so you can see how it looks..

然后执行您的查询。

  EXEC ('
  SELECT
    pv.*
  FROM 
  (
    SELECT DATENAME(MONTH,DateOpened) AS [DateName], DATEPART(YEAR,DateOpened) AS [YEAR], IncidentName FROM #tmpIncidents
  ) src
  PIVOT
  (
    COUNT(IncidentName)
    FOR [YEAR] IN (' + @columnVar + ')
  ) pv;
  ')