将计算行插入具有可变行数和列SQL Server的临时表中

时间:2017-04-12 14:55:50

标签: sql-server

我有一个查询只返回在用户指定的时间范围内进行购买的位置,因此行数是可变的。然后,查询找到这些位置已经完成的所有类型的支出,并将其转动以创建动态数量的列。

所以我剩下的就是一张桌子,其中包含所有花费的位置以及他们花费的类别中的花费总和。

我现在想要做的是在顶部插入一个新行,该行是每个列的表中所有位置的平均值,但我不知道如何在可变数量的列中执行此操作行和列。

你们中的任何人都知道怎么做吗?我没有发布任何代码,因为它大约有90行,但如果这样会有所帮助,我可以。

提前致谢!

编辑:这是我的代码。我删除了尽可能多的无关代码(以及匿名表名),以便您可以简洁地看到我到目前为止所拥有的内容。

DECLARE @cols AS NVARCHAR(MAX),
    @query AS NVARCHAR(MAX),
    @RunForText varchar(max), 
    @Periods varchar(max)

Set @RunForText = 
(
SELECT  Distinct Stuff((Select ',' + c.Location
From Table..Table1 c  For Xml Path ('')), 1, 1, ''))  --GET UNIQUE LOCATIONS

Set @Periods = '201703' --SET TIME PERIOD FOR REPORT

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(vw.Description) --GET UNIQUE CATEGORIES OF SPEND AS COLUMNS
                FROM Table..Table vw
            FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')


set @query = 'SELECT p.Number, ' + @cols + ' 
        into ##tmp
        from 
        (
          SELECT 
            vw.Number,
            vw.Name,
            [Total] = vw.Total,
            Description

        FROM Table..Table vw

            ) p
            pivot 
            (
                SUM(p.Total)
                for p.Description in (' + @cols + ')
            ) p '

execute sp_executesql @query;

SELECT * FROM ##tmp

目前,输出看起来像这样:

 NUMBER | Category1 | Category2 | Category3
 01       100.00      125.00      15.00
 02       1.41        23.42       14.89

我想插入一行,以便表格如下所示:

 NUMBER | Category1 | Category2 | Category3
 Average  50.70       74.21       14.94
 01       100.00      125.00      15.00
 02       1.40        23.42       14.88

2 个答案:

答案 0 :(得分:0)

您可以使用与创建数据透视查询的方法类似的方法,但通过调用Avg来围绕列名称。根据您发布的代码,它看起来像:

declare @avgcols AS NVARCHAR(MAX)

select @avgcols = 
    STUFF((SELECT distinct ',avg(' + QUOTENAME(vw.Description) + ')'
    FROM Table..Table vw
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')

set @query = 
    'INSERT into ##tmp (Number,' + @cols + ')
    into ##tmp
    Select ''Average'',' + @avgcols + ' FROM ##tmp'

execute sp_executesql @query;

答案 1 :(得分:0)

您当前方法的一大障碍是枢轴运营商。它一次只支持一个聚合函数(source - Microsoft Docs)。这意味着您无法合并总和,分钟,最大值和平均值。

这是有原因的。每列都有一个目的。但在您的示例中,Col1有两个作业。有时它包含一个总和,有时是平均值。这是anti-pattern,我想避免。您不能在具有不一致内容的列之上构建。

当然,在您的情况下,您只是尝试添加总计/子总计行。不完全是犯罪!尽管如此,这种操作仍然最好在presentation layer中执行。一个很好的理由,往往更容易!

我的示例使用条件聚合(将group by clause与多个case expressions混合),而不是使用数据透视表。但结果是一样的。

在较高的层面上,基本方法是:

  1. 获取您的数据。
  2. 总结一下。
  3. 追加平均值。
  4. 根据需要排序。
  5. 查询

    /* Returns sample data with average sub total row.
     */
    WITH SampleData AS
    (
        -- Conditional aggregation used instead of Pivot.       
        SELECT
            Nu,
            SUM(CASE WHEN Cat = 'C1' THEN Tot ELSE 0 END)   AS C1,
            SUM(CASE WHEN Cat = 'C2' THEN Tot ELSE 0 END)   AS C2,
            SUM(CASE WHEN Cat = 'C3' THEN Tot ELSE 0 END)   AS C3       
        FROM
            (
                VALUES
                (1, 'C1', 100.00),
                (2, 'C1', 1.41),
                (1, 'C2', 125.00),
                (2, 'C2', 23.42),
                (1, 'C3', 15.00),
                (2, 'C3', 14.89)
            ) AS c(Nu, Cat, Tot)
        GROUP BY 
            nu
    )
        -- Returns detail rows.
        SELECT
            *
        FROM
            SampleData
    
    UNION ALL
    
        -- Returns average row.
        SELECT
            '0'     AS Nu,
            AVG(C1) AS C1,
            AVG(C2) AS C2,
            AVG(C3) AS C3
        FROM
            SampleData
        ORDER BY
            Nu
    ;
    

    返回

    Nu  C1      C2      C3
    0   50.71   74.21   14.95
    1   100.00  125.00  15.00
    2   1.41    23.42   14.89
    

    您还可以使用临时表和一些插入语句获得相同的结果。

    如你所见。这是一个丑陋的问题,有很多事情要发生。将其转换为dynamic sql将不会很有趣。这就是为什么我建议你不要使用它。