2013-08-06 153 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动态旋转的外部查询