2015-10-11 3 views
0

Привет У меня есть запрос, который получает общее количество инцидентов в месяц и год Я хотел получить результат, который показывает все отчетные годы в столбцах Не могли бы вы объяснить, как сделать этот запрос динамическим?SQL Query для создания динамических столбцов

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) 

Спасибо за вашу помощь!

+0

В чем проблема с вашим запросом? Я имею в виду, что в течение трех лет просто добавьте еще одну колонку. Это намного проще, чем динамический SQL, который необходим для переменного количества столбцов. –

+0

@GordonLinoff Мне нужно получить отличное значение за годы работы: «DateOpened» и поместить его в столбцы, я не хочу писать список лет, мне нужно сделать это динамически – gareching

ответ

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 | 
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())) 

Then сборки в течение нескольких лет

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; 
    ') 
Смежные вопросы