Reputation: 5417
I have a large database in SQL Server of over a million lines of data, and 30+ columns (fields). I have run a routine to find 97 specific lines of particular interest to me from a single table. I have not included the various logical steps I took to isolate those 97 lines.
What I now need to do, is to sort my table into order by Date and Time, and retrieve not only the 97 lines I have identified (I have their IDs) but also the 5 data rows above and below each of the 97 in the sorted table.
Does anyone know how this can be achieved?
SELECT *
FROM table
WHERE ID IN (. . list of 97 IDs . . )
ORDER BY Date, Time
/* and get the 5 rows above and below each of the 97 specified lines */
I thought about using a difference between the specified IDs and the IDs other rows, but the Date, Time sort means the IDs are not in order anyway, so that field cannot be used to achieve my objective.
Upvotes: 0
Views: 276
Reputation: 3807
Try this LOGIC, it differs from you table, but you can use same LOGIC & achive what you want.
;With CTE as
(
select *
,ROW_NUMBER() OVER (ORDER BY DateDt) AS RowNumber
from mtT
), CTETop as
(
select top 5 *,'top' as section from CTE
order by RowNumber asc
),CTEBottom as
(
select top 5 *,'bottom' as section from CTE
order by RowNumber desc
)
select * from CTETop
Union All
select * from CTEBottom
Upvotes: 0
Reputation: 95101
Use LAG and LEAD to get previous and following records and their ids:
with wanted_ids as (select list of 97 IDs)
select *
from
(
select
thetable.*,
lag(id,1) over (order by thedate, thetime) as lag1,
lag(id,2) over (order by thedate, thetime) as lag2,
lag(id,3) over (order by thedate, thetime) as lag3,
lag(id,4) over (order by thedate, thetime) as lag4,
lag(id,5) over (order by thedate, thetime) as lag5,
lead(id,1) over (order by thedate, thetime) as lead1,
lead(id,2) over (order by thedate, thetime) as lead2,
lead(id,3) over (order by thedate, thetime) as lead3,
lead(id,4) over (order by thedate, thetime) as lead4,
lead(id,5) over (order by thedate, thetime) as lead5
from thetable
)
where id in wanted_ids
or lag1 in wanted_ids
or lag2 in wanted_ids
or lag3 in wanted_ids
or lag4 in wanted_ids
or lag5 in wanted_ids
or lead1 in wanted_ids
or lead2 in wanted_ids
or lead3 in wanted_ids
or lead4 in wanted_ids
or lead5 in wanted_ids
order by thedate, thetime;
You can do the same with a join. Only be aware not to get a record twice (when ranges overlap). Use distict to avoid this.
select distinct all_records.*
from
(
select
thetable.*,
lag(id,1) over (order by thedate, thetime) as lag1,
lag(id,2) over (order by thedate, thetime) as lag2,
lag(id,3) over (order by thedate, thetime) as lag3,
lag(id,4) over (order by thedate, thetime) as lag4,
lag(id,5) over (order by thedate, thetime) as lag5,
lead(id,1) over (order by thedate, thetime) as lead1,
lead(id,2) over (order by thedate, thetime) as lead2,
lead(id,3) over (order by thedate, thetime) as lead3,
lead(id,4) over (order by thedate, thetime) as lead4,
lead(id,5) over (order by thedate, thetime) as lead5
from thetable
) all_records
inner join (select list of 97 IDs) wanted_ids
on all_records.id = wanted_ids.id
or all_records.lag1 = wanted_ids.id
or all_records.lag2 = wanted_ids.id
or all_records.lag3 = wanted_ids.id
or all_records.lag4 = wanted_ids.id
or all_records.lag5 = wanted_ids.id
or all_records.lead1 = wanted_ids.id
or all_records.lead2 = wanted_ids.id
or all_records.lead3 = wanted_ids.id
or all_records.lead4 = wanted_ids.id
or all_records.lead5 = wanted_ids.id
order by thedate, thetime;
Upvotes: 1