2

让我们直接进入它。这是代码

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

它让我想起了一张如此可爱的桌子。我想知道如何让每个“日期”列的总数显示在附加的最后一行中?

此外,基础表将添加更多数据,特别是更多日期。这意味着接下来将添加 201308,然后添加201309

这意味着目前我必须每月修改上面的代码以反映添加。有没有办法解决?

4

2 回答 2

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;

是子查询中 union 下面的查询up在底部添加了总行,而行总只是通过添加行中的所有列来创建。

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;
于 2013-08-06T13:35:47.110 回答
0

SAMPLE TABLE

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

You can use ROLLUP to get the row total. More about 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

Note : If you do not want to replace NULL with zero, just replace @NullToZeroCols with @cols in outer query of dynamic pivot

于 2015-02-16T15:23:04.707 回答