简体   繁体   中英

SQL - How to subtract the current row with the next row for each group

I want to find the final yield of each group. My main aim is to get the first yield value and the last yield value for each group

In this table

在此处输入图片说明

the first yield value for Group A is 456 and the last yield value is 448 (ie 456-5-2-1).

the result I want is

在此处输入图片说明

Can I know SQL script to get the result table. Thank you.

You can use window functions:

select t.*,
       (2 * first_value(yield) over (partition by grp order by date) -
        sum(yield) over (partition by grp order by date)
       )
from t;

In effect, this is calculating the first value for the group and subtracting the cumulative sum on the remaining rows.

The funky arithmetic ( 2 * ) is because the first value is included in the cumulative sum.

First: you are missing some example logic. I used this setup to test:

create table #temp(
    id int identity(1,1),
    tgroup varchar(10),
    tdate datetime,
    tyield int
)
go
insert into #temp (tgroup,tdate,tyield)
select 'A','01.02.2020',456 union all
select 'A','02.02.2020',5 union all
select 'A','03.02.2020',2 union all
select 'A','04.02.2020',1 union all
select 'B','01.02.2020',123 union all
select 'B','02.02.2020',3 union all
select 'B','03.02.2020',3 union all
select 'B','04.02.2020',2 union all
select 'C','01.02.2020',345 union all
select 'C','02.02.2020',2 union all
select 'C','03.02.2020',22 union all
select 'C','04.02.2020',12 
go
select * from #temp

My solution is based on sub selects. It does basically the same as Gordons code calculating 2 times the sum of the first element and subtracts all elements with a date less or equal than the current one. Without the 2 times sum you need to add exclusion logic for the first element, so its easier to double it and later subtract it again to get to the right value.

Sub selects are standard sql, afaik. So this should work on most Databases(tested on mssql 2016):

select tgroup as 'Group',tdate as 'Date',tyield as 'Yield',
    (select 2*tyield -- 2 times the first yield of the group
       from #temp Layer2 
      where Layer1.tgroup=Layer2.tgroup --only values of the same grouping 
        and Layer2.tdate=(select min(tdate) -- the first entry in that group based on time
                            from #temp Layer3 
                           where Layer1.tgroup=Layer3.tgroup))
    -(select sum(tyield) -- sum up all yields up to the current entrys time
        from #temp Layer4 
      where  Layer1.tgroup=Layer4.tgroup --only values of the same grouping 
         and Layer4.tdate<=Layer1.tdate) -- since we have 2 times the base yield, we subtract it here('<=' includes it) to get the real value
         as 'Diff_yield'
from #temp Layer1

Tested this on sql server 2019 developer edition.

-- create table
drop table if exists grp_y

create table grp_y
(
 grp varchar(100)
,dt date
,yield int
)

insert into grp_y values ('A','2020-02-01',456)
insert into grp_y values ('A','2020-02-02',5)
insert into grp_y values ('A','2020-02-03',2)
insert into grp_y values ('A','2020-02-04',1)
insert into grp_y values ('B','2020-02-01',123)
insert into grp_y values ('B','2020-02-02',3)
insert into grp_y values ('B','2020-02-03',3)
insert into grp_y values ('B','2020-02-04',2)
insert into grp_y values ('C','2020-02-01',345)
insert into grp_y values ('C','2020-02-02',2)
insert into grp_y values ('C','2020-02-03',22)
insert into grp_y values ('C','2020-02-04',12)

-- query
select
     grp
    ,dt
    ,yield
    ,SUM(yield_upd) OVER(partition by grp ORDER BY dt ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as diff_yield --cumulative sum

from
(
select 
     grp
    ,dt
    ,case when rn = 1 then yield else -1 * yield end as yield_upd --update all but the first yield to be negative
    ,yield
    ,rn
from
(
select 
    *
    ,row_number() over(partition by grp order by dt) as rn --used to identify the first yield within a group, so the other yeilds can be make negative
from
    grp_y
)a
)b

The logic here is to:

  1. One row_number() window function to identify the first yield per group. We can then negate all other yield values to allow for subtraction
  2. One sum(yield) window function to actually compute the sum

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM