【问题标题】:Row and column total in dynamic pivot动态透视中的行和列总计
【发布时间】:2015-01-30 01:41:26
【问题描述】:

在 SQL Server 2008 中,我有一个包含 3 列的表 (tblStock):

  • 零件代码 (NVARCHAR (50))
  • 库存数量 (INT)
  • 位置 (NVARCHAR(50))

下面的一些示例数据:

    PartCode    StockQty    Location
   .........   .........    .........
    A              10        WHs-A
    B              22        WHs-A
    A               1        WHs-B
    C              20        WHs-A
    D              39        WHs-F
    E               3        WHs-D
    F               7        WHs-A
    A               9        WHs-C
    D               2        WHs-A
    F              54        WHs-E

如何创建程序以获得如下结果?

PartCode    WHs-A   WHs-B   WHs-C   WHs-D   WHs-E   WHs-F   Total
........    .....   .....   .....  ......   .....   .....   .....
A            10       1       9       0       0       0      20
B            22       0       0       0       0       0      22
C            20       0       0       0       0       0      20
D             2       0       0       0       0      39      41
E             0       0       0       3       0       0       3
F             7       0       0       0      54       0      61
Total        61       1       9       3      54      39     167

非常感谢您的帮助,谢谢。

【问题讨论】:

    标签: sql-server-2008 pivot cube dynamic-pivot


    【解决方案1】:

    示例表

    SELECT * INTO #tblStock
    FROM
    (
    SELECT 'A' PartCode,  10 StockQty, 'WHs-A' Location
    UNION ALL
    SELECT 'B',   22,  'WHs-A'
    UNION ALL
    SELECT 'A',   1,   'WHs-B'
    UNION ALL
    SELECT 'C',   20,  'WHs-A'
    UNION ALL
    SELECT 'D',   39,  'WHs-F'
    UNION ALL
    SELECT 'E',   3,   'WHs-D'
    UNION ALL
    SELECT 'F',   7,   'WHs-A'
    UNION ALL
    SELECT 'A',   9,   'WHs-C'
    UNION ALL
    SELECT 'D',   2,   'WHs-A'
    UNION ALL
    SELECT 'F',   54,  'WHs-E'
    )TAB
    

    获取动态旋转的列并将NULL替换为zero

    DECLARE @cols NVARCHAR (MAX)
    
    SELECT @cols = COALESCE (@cols + ',[' + Location + ']', '[' + Location + ']')
                   FROM (SELECT DISTINCT Location FROM #tblStock) PV 
                   ORDER BY Location 
    -- Since we need Total in last column, we append it at last
    SELECT @cols += ',[Total]'
    
    
    --Varible to replace NULL with zero
    DECLARE @NulltoZeroCols NVARCHAR (MAX)
    
    SELECT @NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+Location+'],0) AS ['+Location+']' 
    FROM (SELECT DISTINCT Location FROM #tblStock)TAB  
    ORDER BY Location FOR XML PATH('')),2,8000) 
    
    SELECT @NullToZeroCols += ',ISNULL([Total],0) AS [Total]'
    

    您可以使用CUBE 查找行和列总计,并将NULL 替换为Total 以获取从CUBE 生成的行。

    DECLARE @query NVARCHAR(MAX)
    SET @query = 'SELECT PartCode,' + @NulltoZeroCols + ' FROM 
                 (
                     SELECT 
                     ISNULL(CAST(PartCode AS VARCHAR(30)),''Total'')PartCode, 
                     SUM(StockQty)StockQty , 
                     ISNULL(Location,''Total'')Location              
                     FROM #tblStock
                     GROUP BY Location,PartCode
                     WITH CUBE
                 ) x
                 PIVOT 
                 (
                     MIN(StockQty)
                     FOR Location IN (' + @cols + ')
                ) p
                ORDER BY CASE WHEN (PartCode=''Total'') THEN 1 ELSE 0 END,PartCode' 
    
    EXEC SP_EXECUTESQL @query
    

    结果

    注意:如果您想要 NULL 而不是 zero 作为值,请在动态数据透视代码中使用 @cols 而不是 @NulltoZeroCols

    编辑:

    1.仅显示总行

    • 请勿使用代码SELECT @cols += ',[Total]'SELECT @NullToZeroCols += ',ISNULL([Total],0) AS [Total]'
    • 使用ROLLUP 而不是CUBE

    2。仅显示列总计

    • 使用代码SELECT @cols += ',[Total]'SELECT @NullToZeroCols += ',ISNULL([Total],0) AS [Total]'
    • 使用ROLLUP 而不是CUBE
    • GROUP BY Location,PartCode 更改为GROUP BY PartCode,Location
    • 请使用WHERE PartCode<>''TOTAL'' ORDER BY PartCode,而不是ORDER BY CASE WHEN (PartCode=''Total'') THEN 1 ELSE 0 END,PartCode

    更新:为 OP 带来 PartName

    我正在更新以下查询以添加 PartName 和结果。由于PartName 将使用CUBE 添加额外的结果,并且为了避免ANDOR 条件中的混淆,最好将透视结果与源表中的DISTINCT 值连接起来。

    DECLARE @query NVARCHAR(MAX)
    SET @query = 'SELECT P.PartCode,T.PartName,' + @NulltoZeroCols + ' FROM 
                 (                
                     SELECT 
                     ISNULL(CAST(PartCode AS VARCHAR(30)),''Total'')PartCode, 
                     SUM(StockQty)StockQty , 
                     ISNULL(Location,''Total'')Location              
                     FROM #tblStock
                     GROUP BY Location,PartCode
                     WITH CUBE                   
                 ) x
                 PIVOT 
                 (
                     MIN(StockQty)
                     FOR Location IN (' + @cols + ')
                ) p
                LEFT JOIN
                (  
                    SELECT DISTINCT PartCode,PartName
                    FROM #tblStock  
                )T
                ON P.PartCode=T.PartCode
                ORDER BY CASE WHEN (P.PartCode=''Total'') THEN 1 ELSE 0 END,P.PartCode' 
    
    EXEC SP_EXECUTESQL @query
    

    【讨论】:

    • 正是我需要的,感谢@Sarath Avanavu 的解决方案和解释。
    • 还有一件事,如果我想在 PartCode 之后添加更多列(PartName),有什么解决方案吗? [PartCode,PartName,WHs-A,..,Total]
    • 一个零件代码只有一个零件名称,对吗? @Sokea
    • 能否将 PartName 中最后一个 NULL 值替换为空?
    • 是的。可以使用 ISNULL(T.PartName,'') AS PartName 来完成,或者如果您不想要任何字符串,请使用 ISNULL(T.PartName,'Nothing') AS PartName @Sokea
    【解决方案2】:

    您需要使用case based aggregation 来透视数据

    要获取total 行,请使用union

    如果事先不知道Location的值,则需要构造一个dynamic query

    您也可以使用pivot 关键字来做同样的事情。

    select partCode,
     sum( case when Location='WHs-A' then StockQty
          else 0 end
        ) as 'Whs-A',
     sum( case when Location='WHs-B' then StockQty
          else 0 end
        ) as 'Whs-B',
    sum(StockQty) as 'Total'
    from tblStock
    group by partCode
    union all
    select 'Total' as 'partCode',
    sum( case when Location='WHs-A' then StockQty
        else 0 end ) as 'Whs-A',
    sum( case when Location='WHs-B' then StockQty
        else 0 end) as 'Whs-B',
    sum(StockQty) as 'Total'
    from tblStock
    

    【讨论】:

    • 感谢雷达。无论如何位置是未知的列,你能请。提供动态查询?
    猜你喜欢
    • 2017-05-27
    • 2018-12-31
    • 2019-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-24
    • 1970-01-01
    相关资源
    最近更新 更多