【问题标题】:Running total on multiple columns在多列上运行总计
【发布时间】:2016-02-21 02:22:46
【问题描述】:

我有一张这样的桌子。

Date               Item               BuyItem
20150101           Mouse              10
20150101           Keyboard           100
20150202           Mouse              20
20150202           Keyboard           200

我想这样查询。

Date               Item               RunningTotal
20150101           Mouse              10
20150202           Mouse              30
20150101           Keyboard           100
20150202           Keyboard           300

我该怎么做? 递归 CTE 绑定在一个运行列上,比如日期,对吧? 现在我有一个运行列、日期和另一个分组列项目。 请帮帮我!

【问题讨论】:

    标签: sql-server sql-server-2008 tsql cumulative-sum


    【解决方案1】:
    SELECT Date,
           item,
           running_total
    FROM   #yourtable a
           CROSS apply(SELECT Sum(BuyItem) AS running_total
                       FROM   #yourtable b
                       WHERE  a.Item = b.Item
                              AND a.Date >= b.Date) ca
    ORDER  BY BuyItem 
    

    【讨论】:

      【解决方案2】:

      利用窗口功能。在 SQL 2012+ 中

      DECLARE @Items TABLE
      (
      DATE NVARCHAR(MAX),
      Item NVARCHAR(MAX),
      BuyItem int
      )
      
      INSERT INTO @Items(DATE, Item, BuyItem) VALUES('20150101', 'Mouse', 10)
      INSERT INTO @Items(DATE, Item, BuyItem) VALUES('20150101', 'Keyboard', 100)
      INSERT INTO @Items(DATE, Item, BuyItem) VALUES('20150202', 'Mouse', 20)
      INSERT INTO @Items(DATE, Item, BuyItem) VALUES('20150202', 'Keyboard', 200)
      
      SELECT DATE, Item, SUM(BuyItem) OVER (PARTITION BY Item ORDER BY BuyItem) AS RunningTotal FROM @Items ORDER BY Item DESC
      

      这是运行上述查询的输出。

      20150101    Mouse       10
      20150202    Mouse       30
      20150101    Keyboard    100
      20150202    Keyboard    300
      

      【讨论】:

      • 任何小于 2012 的内容都不允许在 Aggregate 中使用 order bywindow 函数
      • @MM93 即使使用 SQL Server 2008,上面的查询也不能完美运行。看看this sql fiddle。
      • @Jenish Rabadiya 谢谢!我在 sql 2014 上进行了测试,它工作正常。但是,它不适用于 sql 2008r2。
      • @JenishRabadiya - 我想现在你相信我说的了
      • @MM93 对不起!它不适用于实际服务器,但适用于 sql fiddle。 sql fiddle一定有问题。
      【解决方案3】:

      在聚合函数中,用运行总计,使用Window函数性能非常好

      在 SQL 2012+ 中:

      SELECT *,
         SUM() OVER(PARTITION BY Item, ORDER BY Date) AS RunningTotal
      FROM
      Your_Table
      ORDER BY Item DESC
      

      比添加窗框时更快:

      SELECT *,
         SUM() OVER(PARTITION BY Item, ORDER BY Date ROWS UNBOUNDED PRECEDING) AS RunningTotal
      FROM
      Your_Table
      ORDER BY Item DESC
      

      【讨论】:

      • 任何小于2012 的东西都不允许在Aggregate 中使用order bywindow 函数
      【解决方案4】:

      尝试使用Cross ApplyCorrelated sub-query

      ;with cte as
      (
      select 
       * from
       (VALUES (20150101,'Mouse',10),
                     (20150101,'Keyboard',100),
                     (20150202,'Mouse',20),
                     (20150202,'Keyboard',200) )tc(Date, Item, BuyItem) 
      )
      SELECT *
      FROM   cte a
             CROSS apply(SELECT Sum(BuyItem) AS running_total
                         FROM   cte b
                         WHERE  a.Item = b.Item
                                AND a.Date >= b.Date) cs 
      

      结果:

      Date        Item        BuyItem running_total
      --------    --------    ------- -------------
      20150101    Mouse       10      10
      20150202    Mouse       20      30
      20150101    Keyboard    100     100
      20150202    Keyboard    200     300
      

      Recursive CTE方法:

      ;WITH cte
           AS (SELECT Row_number()OVER(partition BY Item
                          ORDER BY date ) AS rn,*
               FROM   (VALUES (20150101,'Mouse',10),
                              (20150101,'Keyboard',100),
                              (20150202,'Mouse',20),
                              (20150202,'Keyboard',200) )tc(Date, Item, BuyItem)),
           CTE_RunningTotal
           AS (SELECT Date,Item,BuyItem,BuyItem AS running_total,rn
               FROM   cte
               WHERE  rn = 1
               UNION ALL
               SELECT T.Date,T.Item,t.BuyItem,
                      T.BuyItem + C.running_total AS running_total,
                      t.rn
               FROM   CTE_RunningTotal AS C
                      INNER JOIN cte AS T
                              ON T.Item = c.Item
                                 AND t.rn = C.rn + 1)
      SELECT Date,
             Item,
             BuyItem,
             running_total
      FROM   CTE_RunningTotal AS C
      

      最好将您的服务器更新为2012,它可以使用sum() over(order by) 方法来计算运行总数,这比这些方法快得多

      【讨论】:

      • 它适用于样本数据。在现实世界的数据中,我有日期列、两个分组列(如项目和仓库)和数量列。我的表有大约 20000 条记录。这些方法需要太多时间,我必须在它给出任何结果之前停下来。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      • 1970-01-01
      • 1970-01-01
      • 2020-06-30
      • 1970-01-01
      相关资源
      最近更新 更多