【问题标题】:How can I create a cumulative report of data with SQL?如何使用 SQL 创建数据的累积报告?
【发布时间】:2017-07-30 16:27:06
【问题描述】:

我有这张表 DDL:

CREATE TABLE [dbo].[Audit] (
    [AuditId] INT              IDENTITY (1, 1) NOT NULL,
    [Entity]  INT              NOT NULL,
    [Action]  INT              NOT NULL,
    [Id]      UNIQUEIDENTIFIER NULL,
    CONSTRAINT [PK_Audit] PRIMARY KEY CLUSTERED ([AuditId] ASC)
);

更新 - 我在这里添加了缺失的 SQL。对此感到抱歉

我所做的是使用此 SQL 创建一个 SQL 报告,该报告将显示每天有多少活动:

select [col1] = CONVERT(VARCHAR(10), DATEADD(HOUR, 8, a.date), 101) ,
       [Col2] = convert(varchar, count(*))
from Audit a
group by CONVERT(VARCHAR(10), DATEADD(HOUR, 8, a.date), 101)
order by CONVERT(VARCHAR(10), DATEADD(HOUR, 8, a.date), 101) desc

输出如下:

col1        Col2
03/05/2017  1
03/04/2017  20
03/03/2017  10
03/02/2017  5
03/01/2017  10

我现在需要做的是创建一个 SQL 选择,它向我显示累积值而不是计数。所以我需要 SQL 来创建一个报告来显示这个

col1        Col2
03/05/2017  46
03/04/2017  45
03/03/2017  25
03/02/2017  15
03/01/2017  10

有人知道如何修改我的 SQL 来创建这种类型的报告吗?

请注意,我真的在寻找一个命令解决方案,因为它是从 .net 框架执行的,如果解决方案中有多个命令,我想我需要弄清楚如何以某种方式将其放入存储过程中。

【问题讨论】:

  • 输出来自选择 * 或??您是如何从第一行开始的累积总和中得到 46 的?
  • 这是一个运行总计。解决方案取决于您使用的 sql server 版本。这个网站上有几十个运行总计的例子。
  • 您好@Anne,我们很乐意帮助您修改 SQL 以获得正确的结果。很遗憾,您尚未提供 SQL 代码,因此我们不知道建议进行哪些修改。
  • @EdwardRusu 很抱歉没有包含用于创建报告的 SQL。我现在添加它。
  • 想知道为什么我的问题有 -2 票。有人有什么想法吗?

标签: sql sql-server


【解决方案1】:

你可以试试下面的方法。

IF OBJECT_ID('tempdb..#CumulativeSum') IS NOT NULL
    DROP TABLE #CumulativeSum

SELECT t1.col1, t1.col2 AS col2Actual, SUM(t2.col2) AS col2
INTO #CumulativeSum
FROM Audit t1
INNER JOIN Audit t2 on t1.col1 >= t2.col1
GROUP BY t1.col1, t1.col2
ORDER BY t1.col1

SELECT col1, col2 FROM #CumulativeSum ORDER BY col2 DESC

答案是按照 FiReTiTi 的建议从下面的链接复制的。

how to get cumulative sum

编辑 - 用于对单个命令进行查询。

SELECT col1, col2 FROM(
    SELECT TOP 100 PERCENT t1.col1, t1.col2 AS col2Actual, SUM(t2.col2) AS col2
    FROM Audit t1
    INNER JOIN Audit t2 on t1.col1 >= t2.col1
    GROUP BY t1.col1, t1.col2
    ORDER BY t1.col1)x
ORDER BY col2 DESC

希望这将有助于实现您的确切要求。

【讨论】:

  • 有没有办法让我只用一个命令就能做到这一点。原因是我使用 exec 命令从 .net 执行它。通过您的实现,我需要以某种方式将其放入存储过程中。谢谢
  • 创建一个存储脚本过程......如果你想把它作为一行来调用。
  • 答案已被编辑,因为 Anne 要求查询仅包含在单个语句中。
【解决方案2】:

您可以使用窗口函数Sum() Over

Select col1 = convert(varchar(10),cast(dateadd(HOUR, 8, a.date) as date),101)
      ,col2 = sum(count(*))  over (Order by cast(dateadd(HOUR, 8, a.date) as date))
 From  Audit a
 Group by cast(dateadd(HOUR, 8, a.date) as date)
 Order By cast(dateadd(HOUR, 8, a.date) as date) Desc

返回

col1        Col2
03/05/2017  46
03/04/2017  45
03/03/2017  25
03/02/2017  15
03/01/2017  10

【讨论】:

  • 很抱歉我没有提到我已经有一个 SQL 选择,我想修改它以创建总和报告。您的建议很好,但是有没有办法可以将其与我现在已添加到问题中的原始选择联系起来。谢谢
  • @JohnCappelletti 我明白,您已经习惯了这种简写方式,而且效果很好。我也用了很长时间。反对速记的论点只是为了清楚起见,因为一些不太常见的缩写变得非常神秘,有些可能最终不得不去参考缩写表来弄清楚某些东西的作用。诚然,我认为hh 代表hour 是显而易见的。我现在会投票,但在发布上一条评论之前我已经投票了。
  • @JohnCappelletti 作为旁注,即使使用缩写,它也是这里的最佳答案。
  • 来自Itzik Ben-Gan 的另一个坏习惯:“尽可能坚持使用ROWS 表格,并尽量避免在没有框架的情况下指示订购”。你最好明确写SUM(...) OVER (ORDER BY ... ROWS UNBOUNDED PRECEDING),而不是忽略它并默认为RANGE。在这种特定情况下,两种变体将始终产生相同的结果,但ROWS 可能更有效一些。一般来说,结果可能会有所不同,所以最好总是明确地说ROWS或RANGE。
【解决方案3】:

试试下面的查询

select [col1] = CONVERT(VARCHAR(10), DATEADD(HOUR, 8, a.date), 101) ,
       [Col2] = (select count(*) from Audit b where b.date<= DATEADD(HOUR, 8, a.date))
from Audit a
group by DATEADD(HOUR, 8, a.date)
order by CONVERT(VARCHAR(10), DATEADD(HOUR, 8, a.date), 101) desc

【讨论】:

    【解决方案4】:

    使用“with”语句在一个命令中求和。像这样:

    WITH TBL ([col1], [col2])  
    AS  
    (  
    SELECT [col1] = CONVERT(DATE, DATEADD(HOUR, 8, a.date)),
           [Col2] = COUNT(*)
    FROM Audit a
    GROUP BY CONVERT(DATE, DATEADD(HOUR, 8, a.date))
    )  
    SELECT  [col1] = CONVERT(VARCHAR(10), t1.[col1], 101), 
            [col2] = CONVERT(VARCHAR, SUM(t2.[Col2]))
    FROM TBL t1 INNER JOIN TBL t2 on t1.col1 >= t2.col1
    GROUP BY t1.col1
    ORDER BY t1.col1 DESC
    

    祝你好运!

    【讨论】:

    • 这是您获得累积值的答案。要记住两件事。 1- 在 WITH 语句前加一个 ;。 2- SQL 服务器有一个默认的最大递归(我相信 100);您可以使用 MAXRECURSION() 语句来扩展它。
    【解决方案5】:

    如果您提供审计表的数据样本而不是结果集的数据,那么您可能会得到优化和准确的查询。

    使用 Sql 2012,

    DECLARE @Audit TABLE (
        [col1]  datetime  NOT NULL
        ,[col2]  INT  NOT NULL
    )
    
    insert into @audit(col1,Col2)
    VALUES
    ('03/05/2017',  1  )
    ,('03/04/2017',  20 )
    ,('03/03/2017',  10 )
    ,('03/02/2017',  5  )
    ,('03/01/2017',  10 )
    
    ;WITH CTE as
    (
    select col1 ,sum(col2) over(ORDER BY col1 desc  RANGE BETWEEN 
    CURRENT ROW AND UNBOUNDED FOLLOWING) AS col2
    from @Audit
    )
    SELECT * FROM cte   
    order by col1 desc
    

    【讨论】:

    • @Anne,你可以根据你的真实数据使用 Rows 而不是 Range。
    【解决方案6】:

    仅通过以下查询更改您的查询(此查询仅在您使用 SQL SERVER 2012 时有效)

    试试这个:

        DECLARE Audit TABLE (date datetime,
            [col1]  int  NOT NULL
        )
    
        insert into Audit(date,Col1)
        VALUES
        ('03/05/2017',  1  )
        ,('03/04/2017',  20 )
        ,('03/03/2017',  10 )
        ,('03/02/2017',  5  )
        ,('03/01/2017',  10 )
    
    
        select [col1] = CONVERT(VARCHAR(10), DATEADD(HOUR, 8, a.date), 101) ,
               [Col2] = SUM(col1)  over (Order by CONVERT(VARCHAR(10), DATEADD(HOUR, 8, a.date), 101))
        from Audit a
        order by CONVERT(VARCHAR(10), DATEADD(HOUR, 8, a.date), 101) desc
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 2016-05-23
      • 1970-01-01
      • 1970-01-01
      • 2018-10-27
      • 1970-01-01
      相关资源
      最近更新 更多