2012-02-27 63 views
1

我有以下查詢需要2個參數。SQL Server 2005 - 基於在主要查詢中傳遞的變量的列名稱

  1. YearNumber
  2. MonthNumber

在我的支點查詢,我想基於@Year_Rtl變量來選擇列。我需要選擇去年,去年和去年的數據。由於UI上顯示的數據是表格格式除以@Year_Rtl,因此我決定爲其編寫一個數據透視表,如下所示。

在查詢中,如果我硬編碼[@Year_Rtl], [@Year_Rtl - 1], [@Year_Rtl - 2][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。
錯誤值「@Year_Rtl」在PIVOT運算符中提供。
無效的列名'@Year_Rtl - 1'。
無效的列名'@Year_Rtl - 2'。

+3

參與'PIVOT'的列不能是可變的,使用動態SQL的外部。是的,它很糟糕。這只是它的方式。 – Yuck 2012-02-27 20:07:45

+0

我能夠將整個查詢創建爲動態SQL。想知道它是否會達到性能? – Asdfg 2012-02-27 20:22:42

+1

據我所知,動態列擺動只能通過動態SQL來實現 - 當然,它不會像存儲查詢計劃那樣具有良好的性能,但是它或者不具備查詢功能。 – 2012-02-27 20:25:11

回答

1

由於您可以使用動態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; 
+0

你知道我怎樣才能選擇多個列,並仍然得到一行?像選擇[Yr_No],數量,金額。我試過,但它給了我2行,並在第一行數量爲空,在其他行數量爲空。 – Asdfg 2012-02-27 21:50:06

0

您需要查看Dynamic SQL Pivoting。

我推薦閱讀Itzik Ben-Gan的T-SQL基礎知識,他會回顧如何做到這一點。

或者,如果您不想購買此書,請嘗試this article

1

由於消費代碼必須根據這項計劃,片狀(例如,基於「位置」,而不是名字中選擇列) - 爲什麼不通過執行DATEDIFF(year,Yr_No,@Year_Rtl)歸列,工作距離那裏?這些列將永遠是0-1-2 ...

0

也許這將幫助:

首先獲得列具有計數功能是這樣的:

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'', '[email protected]+' 
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 ('[email protected]+')) 
       ) 
    ) p 
    PIVOT 
    (
     SUM(Qty) 
     FOR [Yr_No] IN ('[email protected]+') 
    ) AS pvt' 

EXECUTE(@query)