Reputation: 1489
Given the following table
id short_name long_name category departure rec_order
1548 AAA AAA AA station 10:00 1
1548 BBB BBB BB station 11:10 2
1548 CCC CCC CC station 12:30 3
1548 DDD DDD DD border 15:30 4
I want to access only last the row (station) before the border. Basically return only
CCC CCC CC station 12:30 3
Because the database is rather big and even this timetable is in the real life a complicated structure and we have in indexed view for putting together all the data (here is a simplification for the sake of example) I'm looking for a higher performance solution (possibly no cross join).
I've tried the selection with lag and/or lead, as well as offset fetch but those solutions were not working as soon as I put in the where clause where category = 'border'
as it only selects the border row.
This query is working, but I'm looking for a more optimised solution:
select top 1 M1.short_name M1.long_name
from V_TIMETABLE M1 WITH ( NOEXPAND )
join
(
select top 1 rec_order, id
from V_TIMETABLE V WITH ( NOEXPAND )
where V.id = 1548
and category = 'border'
order by rec_order desc
) M2 on M1.id = M2.id
where M1.rec_order < M2.rec_order
order by M1.rec_order desc
Upvotes: 0
Views: 40
Reputation: 1269773
I just want to point out an alternative solution:
select t.*
from (select t.*,
lead(category) over (partition by id order by departure) as next_category
from t
) t
where next_category = 'border';
Important note: This will not return id
s that have no border in them. It will also return multiple rows for id
s that have border multiple times. These seem more in line with the question actually asked than always selecting one row -- and is consistent with the sample code provided in the question.
Upvotes: 2
Reputation: 28900
This works for given data
;with cte
as
(
select
id, short_name , long_name, category , departure , rec_order,
row_number() over (partition by id order by departure desc) as rownum
from table where category<>'border'
)
select * from cte where rownum=1
Upvotes: 4