views:

80

answers:

2

I have the following SQL Server query and I am trying to get the next and previous row from a given Id. All works great unless there are two/more dates that are the same, then my logic breaks down.

If you set @currentId = 4 then I get back id 7 (it should be id 6) for the prev

If you set @currentId = 6 then I get back id 2 (it should be id 4) for the next

declare @t table (i int, d datetime)
insert into @t (i, d)
select 1, '17-Nov-2009 07:22:13' union
select 2, '18-Nov-2009 07:22:14' union
select 3, '17-Nov-2009 07:23:15' union
select 4, '20-Nov-2009 07:22:18' union
select 5, '17-Nov-2009 07:22:17' union
select 6, '20-Nov-2009 07:22:18' union
select 7, '21-Nov-2009 07:22:19'

--order that I want
select * from @t order by d desc, i

declare @currentId int; set @currentId = 4

--Get Prev
select TOP 1 * from @t where d > (select TOP 1 d from @t where i = @currentId order by d, i desc) order by d, i desc

--Get Next
select TOP 1 * from @t where d < (select TOP 1 d from @t where i = @currentId order by d desc) order by d desc

Can anyone help me work out how to guarantee get the next/prev row based on a given id, Note that it is important that I keep the this order, Date Desc, id ASC

Many thanks

EDIT: It should be noted that this is going to be used for SQL Server 2005.

A: 

Toy can try something like this

    declare @t table (i int, d datetime)
        insert into @t (i, d)
        select 1, '17-Nov-2009 07:22:13' union
        select 2, '18-Nov-2009 07:22:14' union
        select 3, '17-Nov-2009 07:23:15' union
        select 4, '20-Nov-2009 07:22:18' union
        select 5, '17-Nov-2009 07:22:17' union
        select 6, '20-Nov-2009 07:22:18' union
        select 7, '21-Nov-2009 07:22:19'

        --order that I want
        select * from @t order by d desc, i

        declare @currentId int; 
        set @currentId = 4



SELECT  TOP 1 t.*
FROM    @t t INNER JOIN
      (
       SELECT d CurrentDateVal
       FROM @t
       WHERE i = @currentId
      ) currentDate ON t.d <= currentDate.CurrentDateVal AND t.i != @currentId
    ORDER BY t.d DESC

    SELECT t.*
FROM    @t t INNER JOIN
      (
       SELECT d CurrentDateVal
       FROM @t
       WHERE i = @currentId
      ) currentDate ON t.d >= currentDate.CurrentDateVal AND t.i != @currentId
    ORDER BY t.d

You must be carefull, it can seem that 6 should be both prev and next.

astander
Thanks for answer but I have run your answer and get 6 and 4 back from the current Id of 4, I should expect 7(prev) and 6(next) if currentId is 4....
Rippo
Made some changes. Have a look
astander
Looks like this has nailed it. I tried the <= and >= but did not think to exclude the current Id... thanks
Rippo
Actually spoke to soon, try currentId of 6!
Rippo
What do you need for prev and next when useing id 4? and prev next for id 6?
astander
The order of the id's are based on the date desc e.g. 7,4,6,2,3,5,1If I say have an current id of 4 I would want to return 7 (the previous one) and 6 (the next one). This is what I am trying to achieve.
Rippo
+1  A: 

You were nearly there ... try this instead. Effectively changed the date comparison to be "...-or-equals-to" and telling it not to match the current ID so it doesn't return the same row...

declare @currID int
set @currID = 4

select top 1 *
from (
    select * 
        from @t
        where d = (select d from @t where i = @currID)
            and i > @currID
    union ALL
    select * 
        from @t
        where d < (select d from @t where i = @currID)
) as t
order by d desc, i

select top 1 *
from (
    select * 
        from @t
        where d = (select d from @t where i = @currID)
            and i < @currID
    union ALL
    select * 
        from @t
        where d > (select d from @t where i = @currID)
) as t
order by d, i desc
Chris J
Chris thanks for this, I am struggling to make this work as the schema is different. I can see what you are suggesting though.
Rippo
Different to...? This should work with the example table and data you've provided above :-) I assume you need to adapt this to a live schema?
Chris J
My mistake -- had a typo in my SQL (serves me right for editing the SQL in stackoverflow to clean it up after I'd tested it elsewhere). It will work now...!
Chris J
@Rippo -- I think I've nailed this. I've worked down the sequences as provided and it looks like it's coming out correctly as per what you want. Give this version a run.
Chris J
Excellant, thanks for sticking with this....Now I got to turn it into a Linq query :)
Rippo