【问题标题】:Get sum of all previous values? - Total so far? [duplicate]获取所有先前值的总和? - 到目前为止的总数? [复制]
【发布时间】:2012-01-03 00:28:34
【问题描述】:

可能重复:
How do I calculate a running total in SQL without using a cursor?

这有点难以解释,所以我会用一个例子来展示我想要的:

假设我们有一个名为 MonthProfit 的表:

[MonthId][Profit]
1, 10 -- January
2, 20 -- February
3, 30
4, 40
5, 50
6, 60
7, 70
8, 80
9, 90
10, 100
11, 110
12, 120 -- December

profit 列代表当月的利润。

但是,如果我们 1 月份有 10 个利润,2 月份有 20 个利润,那么 2 月份我们的总利润是 30。

所以我想创建一个显示以下内容的视图:

[MonthId][Profit][ProfitTotal]
1, 10, 10 -- January
2, 20, 30 -- February
3, 30, 60
4, 40, 100
5, 50, 150
6, 60, 210
7, 70, 280
8, 80, 360
9, 90, 450
10, 100, 550
11, 110, 660
12, 120, 780 -- December

我现在解决它的方法是这样的:

SELECT [MonthId]
       ,[Profit]
       , (SELECT SUM([Profit])
         FROM MonthProfit
         WHERE [MonthId] <= outer.[MonthId]) as ProfitTotal
FROM MonthProfit as outer

但是,我认为这很慢,因为它必须一直重新计算所有内容,而且对我来说似乎不是很优雅。有没有“好”的方法来做到这一点?

【问题讨论】:

标签: sql tsql recursion


【解决方案1】:

这似乎不是一个非常优雅的选择,但它可以正常工作。

如果你想提高,你有几个选择:

  1. 在表中创建第三列(ProfitTotal),该列将在插入/更新值时更新(触发),或者如果您想在选择时进行更新;
  2. 创建索引以使其更快;
  3. 更新表格统计信息。

【讨论】:

    【解决方案2】:

    试试下面这样的方法,乍一看还不错:-)。

    create table #tab ([MonthId] int, [Profit] int)
    
    insert into #tab select 1, 10 -- January
    insert into #tab select 2, 20 -- February
    insert into #tab select 3, 30
    insert into #tab select 4, 40
    insert into #tab select 5, 50
    insert into #tab select 6, 60
    insert into #tab select 7, 70
    insert into #tab select 8, 80
    insert into #tab select 9, 90
    insert into #tab select 10, 100
    insert into #tab select 11, 110
    insert into #tab select 12, 120 -- December
    
    select t.*, t3.total
    from #tab t
    join (
        select t1.monthId, 
            sum(t2.profit) as total
        from #tab t1
        join #tab t2 on t1.monthId >= t2.monthId
        group by t1.monthId
    ) t3 on t.monthId = t3.monthId
    

    【讨论】:

      【解决方案3】:

      我在这里尝试了一个小示例供您参考,这会根据要求生成结果

      CREATE TABLE [dbo].[tbl_TotalPrevious](
      [id] [int] IDENTITY(1,1) NOT NULL,
      [name] [varchar](50) NOT NULL,
      [values] [bigint] NOT NULL) 
      

      向表格中插入数据

      insert into tbl_TotalPrevious values ('A', 10)
      insert into tbl_TotalPrevious values ('B', 20)
      insert into tbl_TotalPrevious values ('C', 10)
      insert into tbl_TotalPrevious values ('D', 10)
      insert into tbl_TotalPrevious values ('E', 10)
      insert into tbl_TotalPrevious values ('F', 10)
      insert into tbl_TotalPrevious values ('G', 10)
      insert into tbl_TotalPrevious values ('H', 10)
      insert into tbl_TotalPrevious values ('I', 10)
      insert into tbl_TotalPrevious values ('J', 10)
      insert into tbl_TotalPrevious values ('K', 10)
      insert into tbl_TotalPrevious values ('L', 10)
      insert into tbl_TotalPrevious values ('M', 10)
      insert into tbl_TotalPrevious values ('N', 10)
      insert into tbl_TotalPrevious values ('O', 10)
      insert into tbl_TotalPrevious values ('P', 10)
      insert into tbl_TotalPrevious values ('Q', 10)
      insert into tbl_TotalPrevious values ('R', 10)
      insert into tbl_TotalPrevious values ('S', 10)
      insert into tbl_TotalPrevious values ('T', 10)
      insert into tbl_TotalPrevious values ('U', 10)
      insert into tbl_TotalPrevious values ('V', 10)
      insert into tbl_TotalPrevious values ('W', 10)
      insert into tbl_TotalPrevious values ('X', 10)
      insert into tbl_TotalPrevious values ('Y', 10)
      

      创建一个函数,例如。

      ALTER FUNCTION testtotal 
      (
          @id int
      )
      RETURNS int
      AS
      BEGIN
          DECLARE @Result int
          SELECT @Result = (SELECT SUM([values])
               FROM tbl_TotalPrevious
               WHERE [id] <= @id)
      
          RETURN @Result
      
      END
      GO
      

      由单个查询生成的结果

      SELECT [id],[values], (dbo.testtotal(id)) as TotalVals FROM tbl_TotalPrevious 
      

      希望以上内容能够解决您的时间问题,并根据需要更快地生成数据。

      【讨论】:

      • 这不和我的子查询完全一样吗?只封装成一个函数?
      • 但是这样做仍然会因为一个函数而减少时间和表扫描。但我认为你应该为你拥有的实时数据实施并测试你的执行计划。
      【解决方案4】:
      declare @MonthProfit table
      (
        [MonthId] int,
        [Profit] int
      )
      
      insert into @MonthProfit values
      (1, 10),(2, 20),(3, 30),(4, 40),
      (5, 50),(6, 60),(7, 70),(8, 80),
      (9, 90),(10, 100),(11, 110),(12, 120)
      
      ;with C as
      (
        select M.MonthId,
               M.Profit
        from @MonthProfit as M
        where M.MonthId = 1
        union all
        select M.MonthId,
               C.Profit + M.Profit
        from @MonthProfit as M
          inner join C 
            on M.MonthId = C.MonthId + 1
      )
      select C.MonthId,
             C.Profit 
      from C
      order by C.MonthId
      

      【讨论】:

        猜你喜欢
        • 2019-12-15
        • 2021-01-21
        • 2021-02-18
        • 1970-01-01
        • 1970-01-01
        • 2014-08-26
        • 2023-04-10
        • 2017-09-25
        • 1970-01-01
        相关资源
        最近更新 更多