2013-08-06 197 views
2

讓我們直接跳到它。這裏的代碼T-SQL數據透視表 - 總行數和動態列數

SELECT [prov], [201304], [201305], [201306], [201307] 
FROM (
SELECT [prov], [arrival], [Amount] 
FROM [tblSource]) up 
PIVOT (SUM([Amount]) FOR [arrival] IN ([201304], [201305], [201306], [201307])) AS pvt 
GO 

它帶給我一個永遠如此可愛的表。我想知道如何獲得每個「日期」列的總數以顯示在附加的最後一行中?

此外,基礎表將添加更多的數據,特別是更多日期。這意味着,將在未來增加,那麼等

這將意味着目前我將不得不修改每個月上面的代碼,以反映增加。有沒有辦法解決?

回答

2

您可以使用動態SQL動態創建列,但是,我真的建議在爲其設計的圖層中處理動態軸,例如SSRS或Excel。

DECLARE @SQL NVARCHAR(MAX) = '', 
     @SQL2 NVARCHAR(MAX) = '', 
     @SQL3 NVARCHAR(MAX) = ''; 

-- COMPILE THE UNIQUE VALUES FOR ARRIVAL THAT NEED TO BE PIVOTED 
SELECT @SQL = @SQL + ',' + QUOTENAME(Arrival), 
     @SQL2 = @SQL2 + '+ISNULL(' + QUOTENAME(Arrival) + ', 0)', 
     @SQL3 = @SQL3 + ',' + QUOTENAME(Arrival) + ' = ISNULL(' + QUOTENAME(Arrival) + ', 0)' 
FROM (SELECT DISTINCT Arrival FROM tblSource) s; 

-- COMBINE THEM INTO A SINGLE QUERY 
SET @SQL = 'SELECT [Prov]' + @SQL3 + ', [Total] = ' + STUFF(@SQL2, 1, 1, '') + ' 
      FROM ( SELECT Arrival, Prov, Amount 
         FROM [tblSource] 
         UNION ALL 
         SELECT Arrival, ''Total'', SUM(Amount) 
         FROM [tblSource] 
         GROUP BY Arrival 
        ) up 
        PIVOT 
        ( SUM(Amount) 
         FOR Arrival IN (' + STUFF(@SQL, 1, 1, '') + ') 
        ) pvt;'; 

-- EXECUTE THE QUERY 
EXECUTE SP_EXECUTESQL @SQL; 

這將創建並執行下面的SQL:

SELECT [Prov], 
     [2013-01-01] = ISNULL([2013-01-01], 0), 
     [2013-02-01] = ISNULL([2013-02-01], 0), 
     [Total] = ISNULL([2013-01-01], 0) + ISNULL([2013-02-01], 0) 
FROM ( SELECT Arrival, Prov, Amount 
      FROM [tblSource] 
      UNION ALL 
      SELECT Arrival, 'Total', SUM(Amount) 
      FROM [tblSource] 
      GROUP BY Arrival 
     ) up 
     PIVOT 
     ( SUM(Amount) 
      FOR Arrival IN ([2013-01-01],[2013-02-01]) 
     ) pvt; 

它是在底部增加了總排子查詢up低於工會查詢,該行總僅通過增加創建該行中的所有列。

Example on SQL Fiddle

我會再次強調,雖然,我真的建議處理數據的操作是這樣的外部SQL的。

編輯

使用UNION得到總行是使用GROUPING SETS如下替代:

DECLARE @SQL NVARCHAR(MAX) = '', 
     @SQL2 NVARCHAR(MAX) = '', 
     @SQL3 NVARCHAR(MAX) = ''; 

-- COMPILE THE UNIQUE VALUES FOR ARRIVAL THAT NEED TO BE PIVOTED 
SELECT @SQL = @SQL + ',' + QUOTENAME(Arrival), 
     @SQL2 = @SQL2 + '+ISNULL(' + QUOTENAME(Arrival) + ', 0)', 
     @SQL3 = @SQL3 + ',' + QUOTENAME(Arrival) + ' = ISNULL(' + QUOTENAME(Arrival) + ', 0)' 
FROM (SELECT DISTINCT Arrival FROM tblSource) s; 

-- COMBINE THEM INTO A SINGLE QUERY 
SET @SQL = 'SELECT [Prov]' + @SQL3 + ', [Total] = ' + STUFF(@SQL2, 1, 1, '') + ' 
      FROM ( SELECT Arrival, Prov = ISNULL(Prov, 'Total'), Amount = SUM(Amount) 
         FROM [tblSource] 
         GROUP BY GROUPING SETS((Prov, arrival), (arrival)) 
        ) up 
        PIVOT 
        ( SUM(Amount) 
         FOR Arrival IN (' + STUFF(@SQL, 1, 1, '') + ') 
        ) pvt;'; 

-- EXECUTE THE QUERY 
EXECUTE SP_EXECUTESQL @SQL; 
+0

我想補充ROLLUP到您的解決方案。 OP要求每行列出總計。 – Taryn

+0

謝謝 - 我把它推到一個網頁上,SSRS對於我們在快速響應和移動友好解決方案中所需要的並不理想,但我確實把它放在了船上。我可能只是建立功能到頁面本身。謝謝。 – pee2pee

+0

@bluefeet不會''ROLLUP'與'PIVOT'一起使用嗎?我通過向查詢添加聯合並重複數據來照顧Total行。我現在使用'GROUPING SETS'添加了一個替代方案。 – GarethD

0

樣品臺

CREATE TABLE #TEMP([prov] VARCHAR(100),[arrival] INT, AMOUNT NUMERIC(12,2)) 

INSERT INTO #TEMP 
SELECT 'A' [prov],'201304' [arrival],100 AMOUNT 
UNION ALL 
SELECT 'A' ,'201305' ,124 
UNION ALL 
SELECT 'A' ,'201306' ,156 
UNION ALL 
SELECT 'B' ,'201304' ,67 
UNION ALL 
SELECT 'B' ,'201305' ,211 
UNION ALL 
SELECT 'B' ,'201306' ,176 
UNION ALL 
SELECT 'C' ,'201304' ,43 
UNION ALL 
SELECT 'C' ,'201305' ,56 
UNION ALL 
SELECT 'C' ,'201306' ,158 

QUERY

您可以使用ROLLUP獲取行總數。更多關於ROLLUP here

-- Get the columns for dynamic pivot 
DECLARE @cols NVARCHAR (MAX) 

SELECT @cols = COALESCE (@cols + ',[' + CAST([arrival] AS VARCHAR(50)) + ']', 
       '[' + CAST([arrival] AS VARCHAR(50)) + ']') 
       FROM (SELECT DISTINCT [arrival] FROM #TEMP) PV 
       ORDER BY [arrival] 

-- Replace NULL value with zero 
DECLARE @NulltoZeroCols NVARCHAR (MAX) 

SELECT @NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+[arrival]+'],0) AS ['+[arrival]+']' 
FROM (SELECT DISTINCT CAST([arrival] AS VARCHAR(50)) [arrival] FROM #TEMP)TAB 
ORDER BY CAST([arrival]AS INT) FOR XML PATH('')),2,8000) 


DECLARE @query NVARCHAR(MAX) 
SET @query = 'SELECT [prov],' + @NullToZeroCols + ' FROM 
      (
       SELECT 
       ISNULL([prov],''Total'')[prov], 
       SUM(AMOUNT)AMOUNT , 
       ISNULL(CAST([arrival] AS VARCHAR(50)),''Total'')[arrival]    
       FROM #TEMP     
       GROUP BY [arrival],[prov] 
       WITH ROLLUP 
      ) x 
      PIVOT 
      (
       MIN(AMOUNT) 
       FOR [arrival] IN (' + @cols + ') 
      ) p 
      ORDER BY CASE WHEN ([prov]=''Total'') THEN 1 ELSE 0 END,[prov]' 

EXEC SP_EXECUTESQL @query 

注意:如果你不想zero更換NULL,只是@cols取代@NullToZeroCols動態旋轉的外部查詢