SQL Server 2005 - имена столбцов на основе переменных, переданных в сводном запросе - PullRequest
1 голос
/ 28 февраля 2012

У меня следующий запрос, который принимает 2 параметра.

  1. YearNumber
  2. MonthNumber

В своем сводном запросе я пытаюсь выбрать столбцы на основепеременная @Year_Rtl.Мне нужно выбрать данные за прошедший год, прошлый год и последний прошлый год.Поскольку данные, отображаемые в пользовательском интерфейсе, имеют формат таблицы, разделенный на @Year_Rtl, я решил написать сводный запрос для этого, как показано ниже.

В запросе все работает нормально, если я жестко кодирую [@Year_Rtl], [@Year_Rtl - 1], [@Year_Rtl - 2] to [2012], [2011], [2010].Но поскольку прошедший год может быть любым, я хочу, чтобы столбцы назывались динамически.

DECLARE @Month_Rtl int  
DECLARE @Year_Rtl int  

SET @Year_Rtl = 2012
SET @Month_Rtl = 1

SELECT  
    'Data 1', [@Year_Rtl], [@Year_Rtl - 1], [@Year_Rtl - 2]
FROM
   (SELECT [Yr_No], Qty
    FROM dbo.Table1 t
    WHERE (t.Col1 = 10) AND   
    (t.Col2 = '673') AND  
    ((t.Mth_No = @Month_Rtl AND t.Yr_No = @Year_Rtl) OR 
     (t.Mth_No = 12 AND t.Yr_No IN (@Year_Rtl - 1, @Year_Rtl - 2)))  
   ) p PIVOT (SUM(Qty)
              FOR [Yr_No] IN ([@Year_Rtl], [@Year_Rtl-1], [@Year_Rtl-2])
             ) AS pvt

Выше запроса выдает следующие ошибки:

Ошибка преобразования типа данных nvarchar в smallint.
В операторе PIVOT указано неверное значение "@Year_Rtl".
Неверное имя столбца '@Year_Rtl - 1'.
Неверное имя столбца '@Year_Rtl - 2'.

Ответы [ 4 ]

1 голос
/ 28 февраля 2012

Поскольку вы можете использовать динамический SQL, я бы пошел с подходом замены макроса.Вы определяете области запроса, которые должны быть динамически заменены местозаполнителями (например, $$Year_Rtl), а затем вычисляете их значения замены ниже.Я считаю, что это делает SQL-оператор простым для понимания.

DECLARE @SQL NVarChar(2000);
SELECT @SQL = N'
  SELECT  
      ''Data 1'', [$$Year_Rtl], [$$Year_RtlM1], [$$Year_RtlM2]
  FROM
     (SELECT [Yr_No], Qty
      FROM dbo.Table1 t
      WHERE (t.Col1 = 10) AND   
      (t.Col2 = ''673'') AND  
      ((t.Mth_No = $$Month_Rtl AND t.Yr_No = $$Year_Rtl) OR 
       (t.Mth_No = 12 AND t.Yr_No IN ($$Year_RtlM1, $$Year_RtlM2)))  
     ) p PIVOT (SUM(Qty)
                FOR [Yr_No] IN ([$$Year_Rtl], [$$Year_RtlM1], [$$Year_RtlM2])
               ) AS pvt';

SELECT @SQL = REPLACE(@SQL, '$$Year_RtlM2', @Year_Rtl - 2);
SELECT @SQL = REPLACE(@SQL, '$$Year_RtlM1', @Year_Rtl - 1);
SELECT @SQL = REPLACE(@SQL, '$$Year_Rtl', @Year_Rtl);
SELECT @SQL = REPLACE(@SQL, '$$Month_Rtl', @Month_Rtl);

PRINT @SQL;
-- Uncomment the next line to allow the built query to execute...
--EXECUTE sp_ExecuteSQL @SQL;
1 голос
/ 28 февраля 2012

Так как потребляющий код будет , также должны быть нестабильными в этой схеме (например, при выборе столбцов на основе «позиции», а не имени) - почему бы не нормализовать столбцы, выполнив DATEDIFF(year,Yr_No,@Year_Rtl), а работа оттуда?Эти столбцы всегда будут 0, -1 и -2 ...

0 голосов
/ 29 февраля 2012

Может быть, это поможет:

Сначала получите столбцы с функцией подсчета, подобной этой:

DECLARE @Month_Rtl int,  
        @Year_Rtl int,
        @Year_Rtl_Start INT,
        @cols VARCHAR(MAX),
        @values VARCHAR(MAX)

SET @Year_Rtl = 2012
SET @Month_Rtl = 1
SET @Year_Rtl_Start=2009

;WITH Years ( n ) AS (
        SELECT @Year_Rtl_Start UNION ALL
        SELECT 1 + n FROM Years WHERE n < @Year_Rtl )
SELECT
    @cols = COALESCE(@cols + ','+QUOTENAME(n),
                     QUOTENAME(n)),
    @values = COALESCE(@values + ','+CAST(n AS VARCHAR(100)),
                     CAST(n AS VARCHAR(100)))
FROM
    Years
ORDER BY n DESC

Переменная @cols содержит столбцы, находящиеся в сводной области, и переменную@values содержит годы для IN.@Year_Rtl - это конечный год, а @Year_Rtl_Start - начальный диапазон для вас.

Затем объявите и выполните динамический пивот, как показано ниже:

DECLARE @query NVARCHAR(4000)=
N'SELECT  
    ''Data 1'', '+@cols+'
FROM
    (
        SELECT 
            [Yr_No], Qty
        FROM 
            dbo.Table1 t
        WHERE 
            t.Col1 = 10 
            AND t.Col2 = ''673''
            AND 
            (
                (
                    t.Mth_No = '+CAST(@Month_Rtl AS VARCHAR(10))+'
                    AND t.Yr_No = '+CAST(@Year_Rtl AS VARCHAR(10))+'
                ) 
                OR 
                (
                    t.Mth_No = 12 
                    AND t.Yr_No IN ('+@values+'))
                )  
    ) p 
    PIVOT 
    (
        SUM(Qty)
        FOR [Yr_No] IN ('+@cols+')
    ) AS pvt'

EXECUTE(@query)
0 голосов
/ 28 февраля 2012

Вам нужно взглянуть на Dynamic SQL Pivoting.

Я рекомендую прочитать Основы T-SQL Ицик Бен-Гана, где он рассказывает, как это сделать.

Или попробуйте thisстатья , если вы не хотите покупать книгу.

...