根据另一列中其他行的值计算总和

时间:2015-11-20 23:04:09

标签: sql sql-server sql-server-2008

我想知道如何计算天数,客户没有吃任何糖果。 假设客户每天吃1个糖果 如果客户购买更多糖果,它会被添加到以前的库存中 例如

Day Candy Puchased
0         30
40        30
65        30
110       30
125       40
170       30

这里的答案是20.

第0天的意思是,顾客带来了30个糖果,下次购买的时间是第40天,所以他在第30天到第39天之间没有吃任何糖果,也就像他在第100到第109天之间没吃任何糖果一样一天。

任何人都可以帮我编写查询。我想我的查询中有错误的逻辑。

select sum(curr.candy_purchased-(nxt.day-curr.day)) as diff 
from candies as curr 
left join candies as nxt 
on nxt.day=(select min(day) from candies where day > curr.day) 

3 个答案:

答案 0 :(得分:1)

您需要递归CTE

首先我需要创建一个row_id,所以我使用row_number

现在我需要递归的基本情况。

  • Day:意味着过了多少天。 (0来自db)
  • PrevD:是否为Prev day金额,以便您可以计算Day(从0开始)
  • Candy Puchased:购买了多少名学生(30名来自db)
  • Remaining:吃完后剩下多少个糖果(从0开始)
  • NotEat:多少天不能吃糖果(从0开始)
  • Level:递归级别(从0开始)

递归案例

  • DayPrevDCandy Puchased很容易
  • Remaining:如果我吃的比我多,那么0
  • NotEat:在没有糖果的情况下继续添加差异。

SQL Fiddle Demo

WITH Candy as (
     SELECT
        ROW_NUMBER() over (order by [Day]) as rn,
        *
     FROM Table1
   ), EatCandy ([Day], [PrevD], [Candy Puchased], [Remaining], [NotEat], [Level]) as (
      SELECT [Day], 0 as [PrevD], [Candy Puchased], [Candy Puchased] as [Remaining], 0 as [NotEat], 1 as [Level]
      FROM Candy
      WHERE rn = 1
      UNION ALL
      SELECT c.[Day] - ec.[PrevD], 
             c.[Day],
             c.[Candy Puchased], 
             c.[Candy Puchased] + 
             IIF((c.[Day] - ec.[PrevD]) > ec.[Remaining], 0, ec.[Remaining] - (c.[Day] - ec.[PrevD])),
             ec.[NotEat] + 
             IIF((c.[Day] - ec.[PrevD]) > ec.[Remaining], (c.[Day] - ec.[PrevD]) - ec.[Remaining], 0),
             ec.[Level] + 1
      FROM Candy c
      JOIN EatCandy ec
        ON c.rn = ec.[level] + 1
    )
    select * from EatCandy

<强>输出

| Day | PrevD | Candy Puchased | Remaining | NotEat | Level |
|-----|-------|----------------|-----------|--------|-------|
|   0 |     0 |             30 |        30 |      0 |     1 |
|  40 |    40 |             30 |        30 |     10 |     2 |
|  25 |    65 |             30 |        35 |     10 |     3 |
|  45 |   110 |             30 |        30 |     20 |     4 |
|  15 |   125 |             40 |        55 |     20 |     5 |
|  45 |   170 |             30 |        40 |     20 |     6 |

只需在最后一个查询

上添加SELECT MAX(NotEat)即可

答案 1 :(得分:1)

好问题。

检查我的答案,并尝试使用不同的样本数据。 并且,如果有不同的样本数据它不起作用,请告诉我。

declare @t table([Day] int, CandyPuchased int)
insert into @t
values (0, 30),(40,30),(65, 30)
,(110, 30),(125,40),(170,30)
select * from @t

;With CTE as
(
select *,ROW_NUMBER()over(order by [day])rn from @t
)
,CTE1 as
(
select [day],[CandyPuchased],rn from CTE c where rn=1
union all
select a.[Day],case when a.Day-b.Day<b.CandyPuchased 
then a.CandyPuchased+(b.CandyPuchased-(a.Day-b.Day)) 
else a.CandyPuchased end CandyPuchased
,a.rn from cte A 
inner join CTE B on a.rn=b.rn+1

)
--select * from CTE1
select sum(case when a.Day-b.Day>b.CandyPuchased 
then (a.Day-b.Day)-b.CandyPuchased else 0 end)[CandylessDays]  
from CTE1 A
inner join CTE1 b on a.rn=b.rn+1

答案 2 :(得分:0)

如果你只是需要系列结尾处的结果,那么你真的不需要那个连接。

over

如果您需要将此作为一种运行总计,请尝试select *, sum(candies) over (order by days) as TotalCandies from MyTable order by days desc

build/audio/base/%.wav: src-audio/%.wav