Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional preceding values

My sample data is like this

drop 
  table if exists #temp
select 
  * into #temp
from 
  (
    values 
      ('id100', 'status1', 1), 
      ('id100', 'status2', 2), 
      ('id100', 'status1', 3), 
      ('id100', 'status0', 4), 
      ('id100', 'status2', 5), 
      ('id100', 'status2', 6), 
      ('id100', 'status1', 7), 
      ('id100', 'status1', 8), 
      ('id100', 'status2', 9), 
      ('id101', 'status1', 10), 
      ('id101', 'status2', 11)
  ) t(id, status, rowNum) 

I need TSQL to return immediately preceding rowNum for each id with 'status2' where the status='status1'. I hope the code to return this

id status rowNum value
id100 status1 1
id100 status2 2 1
id100 status1 3
id100 status0 4
id100 status2 5 3
id100 status2 6 3
id100 status1 7
id100 status1 8
id100 status2 9 8
id101 status1 10
id101 status2 11 10

I tried this which did not work

SELECT 
  t1.id, 
  t1.status, 
  t1.rowNum, 
  (
    select 
      MIN(t2.rowNum) 
    from 
      #temp t2 
    where 
      t2.id = t1.id 
      and t2.rowNum < t1.rowNum 
      and t1.status = 'status2'
  ) as test 
from 
  #temp t1
like image 729
smpa01 Avatar asked Oct 30 '25 00:10

smpa01


1 Answers

You can use subquery within a case statement to do so:

Query:

  select *, CASE WHEN status='status2' then (select max(rowNum) from #temp tmp 
    where tmp.rowNum<t.rowNum and tmp.status='status1') end value
  from #temp t
order by rowNum

Output:

id status rowNum value
id100 status1 1 null
id100 status2 2 1
id100 status1 3 null
id100 status0 4 null
id100 status2 5 3
id100 status2 6 3
id100 status1 7 null
id100 status1 8 null
id100 status2 9 8
id101 status1 10 null
id101 status2 11 10

fiddle

You can also use last_value() window function or lag() window function instead of subquery:

Query (with last_value()over()):

 select *, CASE WHEN status='status2' then 
    (last_value(case when status='status1' then rowNum else null end) ignore nulls over(order by rowNum)) end value
  from #temp t
order by rowNum

Output:

id status rowNum value
id100 status1 1 null
id100 status2 2 1
id100 status1 3 null
id100 status0 4 null
id100 status2 5 3
id100 status2 6 3
id100 status1 7 null
id100 status1 8 null
id100 status2 9 8
id101 status1 10 null
id101 status2 11 10

Query (with lag()over()):

select *, CASE WHEN status='status2' then 
    (lag(case when status='status1' then rowNum else null end) ignore nulls over(order by rowNum)) end value
  from #temp t
order by rowNum

Output:

id status rowNum value
id100 status1 1 null
id100 status2 2 1
id100 status1 3 null
id100 status0 4 null
id100 status2 5 3
id100 status2 6 3
id100 status1 7 null
id100 status1 8 null
id100 status2 9 8
id101 status1 10 null
id101 status2 11 10

fiddle

like image 195
Kazi Mohammad Ali Nur Avatar answered Nov 01 '25 12:11

Kazi Mohammad Ali Nur



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!