Динамически генерировать столбцы на основе диапазона дат

#sql #sql-server

#sql #sql-сервер

Вопрос:

У меня есть данные метрики таблицы

 Metric ID         Metric Date             Metric Result       Metric Calculation Color
--------------------------------------------------------------------------------------
001              2004-04-01                 1                   GREEN
002              2004-04-01                 0                   RED
001              2004-05-01                 1                   GREEN
002              2004-05-01                 5                   YELLOW
003              2004-05-01                 2                   GREEN
  

Я хочу, чтобы результат задавал что-то вроде

 Metric ID        April Result           April Calc Color    May Result   May Calc Color
---------------------------------------------------------------------------------------
001               1                       GREEN                1          RED
002               0                       RED                  5          YELLOW
003                                                            2          GREEN
  

Я использовал концепцию сводной таблицы, но она дает мне повторяющиеся результаты, такие как

 Metric ID        April Result           April Calc Color    May Result   May Calc Color
---------------------------------------------------------------------------------------
001               1                       GREEN                NULL       NULL
001               NULL                    NULL                 1          RED
002               0                       RED                  NULL       NULL
002               NULL                    NULL                 5          YELLOW
003                                                            2          GREEN
  

Это запрос, который я использовал

 ;With CTE AS
( 
SELECT * FROM ( SELECT C.METRIC_ID,RESULT,COLOR FROM METRICDATA ) Q PIVOT (MAX(RESULT) FOR [RESULT] IN ([April],[May]) )Pv ) PIVOT (MAX(COLOR) FOR [RESULT] IN ([April],[May]) )Pv1 )
  

Результат показателя и столбец цвета вычисления должны быть сгенерированы на основе ограничения даты, предоставленного запросом.

Заранее спасибо.

Комментарии:

1. ;С CTE КАК( ВЫБЕРИТЕ * ИЗ ( ВЫБЕРИТЕ C.METRIC_ID, РЕЗУЛЬТАТ, ЦВЕТ ИЗ METRICDATA ) Q СВОДНАЯ (МАКСИМАЛЬНАЯ (РЕЗУЛЬТАТ) ДЛЯ [РЕЗУЛЬТАТА] В ([апрель], [май]) ) Pv) СВОДНАЯ (МАКСИМАЛЬНАЯ (ЦВЕТНАЯ) ДЛЯ [РЕЗУЛЬТАТА] В ([апрель], [май]) )Pv1)

2. Если вы можете получить этот результат, почему бы вам просто не объединить его в последний раз? Например, ВЫБЕРИТЕ Metric_ID, MAX(April_Result) КАК April_Result, MAX(April_Calc_Color) КАК April_Calc_Color, MAX(May_Result) КАК May_Result, MAX(May_Calc_Color) КАК May_Calc_Color ИЗ ГРУППЫ MyPivot ПО Metric_ID

3. Я не знаю точного диапазона месяцев, который он должен быть передан в качестве параметра, и если я использую aggregate, он принимает значение только за последний месяц в результирующем наборе и возвращает NULL в качестве значения для всех остальных месяцев.

Ответ №1:

Попробуйте это вместо pivot

 Select metricId,
Case when datepart(Metric_Date)=4 then Metric_Result else o end 'April Result',
Case when datepart(Metric_Date)=4 then Metric_Color else NULL end 'April Calc Color',
Case when datepart(Metric_Date)=5 then Metric_Result else o end 'MayResult',
Case when datepart(Metric_Date)=5 then Metric_Color else NULL end 'May Calc Color'
from Metric
  

Ответ №2:

Это было весело. SQLFiddle не нравится мой код (похоже, мне не очень нравятся переменные), но это работает в моем локальном окне. Вот схема для тестирования:

 CREATE TABLE METRICDATA
    ([Metric_ID] varchar(3), [Date] date, [Result] int, [Color] varchar(6))
;

INSERT INTO METRICDATA
    ([Metric_ID], [Date], [Result], [Color])
VALUES
    ('001', '2004-04-01', 1, 'GREEN'),
    ('002', '2004-04-01', 0, 'RED'),
    ('001', '2004-05-01', 1, 'GREEN'),
    ('002', '2004-05-01', 5, 'YELLOW'),
    ('003', '2004-05-01', 2, 'GREEN')
;
  

И вот код:

 DECLARE @StartDate AS DATE,
        @EndDate AS DATE,
        @SQL VARCHAR(MAX);

SET @StartDate = '20040401';
SET @EndDate = '20040501';

WITH cteWithMonths
AS
(
    SELECT      Metric_ID,
                DATENAME(MONTH, Date) AS MonthName,
                DATEPART(M, Date) AS Month,
                MAX(DATEPART(M, Date)) OVER () AS MaxMonth,
                Color
    FROM
                METRICDATA
    WHERE
                Date BETWEEN @StartDate AND @EndDate
    GROUP BY
                Metric_ID,
                DATENAME(MONTH, Date),
                DATEPART(M, Date),
                Color
),
cteSQLFieldList
AS
(
    SELECT      0 AS LineNum, 'SELECT DISTINCT m.Metric_ID,' AS SQL
    UNION ALL
    SELECT      DISTINCT
                MONTH,
                CASE 
                    WHEN Month < MaxMonth THEN MonthName   '.'   MonthName   '_Result, '   MonthName   '.'   MonthName   '_Calc_Color,'
                    ELSE MonthName   '.'   MonthName   '_Result, '   MonthName   '.'   MonthName   '_Calc_Color'
                END
    FROM        cteWithMonths
    UNION ALL
    SELECT      13,
                'FROM METRICDATA m'
),
cteSQLJoinList
AS
(
    SELECT      DISTINCT
                MONTH   13 AS LineNum,
                'LEFT JOIN (SELECT Metric_ID, SUM(RESULT) AS '   MonthName   '_Result, Color AS '   MonthName   '_Calc_Color FROM METRICDATA WHERE DATENAME(MONTH, Date) = '''   MonthName   ''' GROUP BY Metric_ID, Color) '   MonthName  ' ON m.Metric_ID = '   MonthName   '.Metric_ID' AS SQL
    FROM        cteWithMonths
),
cteSQLOrderByList
AS
(
    SELECT      26 AS LineNum,
                'ORDER BY m.Metric_ID' AS SQL
),
cteSQL_ALL
AS
(
    SELECT      *
    FROM        cteSQLFieldList
    UNION
    SELECT      *
    FROM        cteSQLJoinList
    UNION
    SELECT      *
    FROM        cteSQLOrderByList
)

SELECT      @SQL = COALESCE(@SQL   ' ', '')   SQL
FROM        cteSQL_ALL
ORDER BY    LineNum;

EXEC(@SQL);
  

Честно говоря, я не хотел играть с вашим сводным решением. Динамическое построение выглядело сложным. Вместо этого я выбрал агрегирование для каждого Metric_ID в выделенных таблицах, а затем ОБЪЕДИНИЛ их все вместе. Я создаю необходимый динамический SQL, а затем выполняю его.