tags:

views:

319

answers:

5

I want to be able to get the next and previous row using SQLite.

id  statusid  date
168 1   2010-01-28 16:42:27.167
164 1   2010-01-28 08:52:07.207
163 1   2010-01-28 08:51:20.813
161 1   2010-01-28 07:10:35.373
160 1   2010-01-27 16:09:32.550
 46 2   2010-01-30 17:13:45.750
145 2   2010-01-30 17:13:42.607
142 2   2010-01-30 16:11:58.020
140 2   2010-01-30 15:45:00.543

For example:

Given id 46 I would like to return ids 160 (the previous one) and 145 (the next one)

Given id 160 I would like to return ids 161 (the previous one) and 46 (the next one) etc...

Be aware that the data is ordered by statusId then dateCreated DESC and HAS to work using SQLite.

select * from @t order by statusId, dateCreated desc

Test data created in sql server...

set nocount on; set dateformat ymd;
declare @t table(id int, statusId int, dateCreated datetime)
insert into @t
select 168,1,'2010-01-28 16:42:27.167' union
select 164,1,'2010-01-28 08:52:07.207' union
select 163,1,'2010-01-28 08:51:20.813' union
select 161,1,'2010-01-28 07:10:35.373' union
select 160,1,'2010-01-27 16:09:32.550' union
select  46,2,'2010-01-30 17:13:45.750' union
select 145,2,'2010-01-30 17:13:42.607' union
select 142,2,'2010-01-30 16:11:58.020' union
select 140,2,'2010-01-30 15:45:00.543'

Using SQL server 2005+ this would be fairly trivial!

EDIT:

Here's the same test data script but for SQLite which is the focus of the question.

create table t (id int, statusId int, dateCreated datetime);
insert into t
select 168,1,'2010-01-28 16:42:27.167' union
select 164,1,'2010-01-28 08:52:07.207' union
select 163,1,'2010-01-28 08:51:20.813' union
select 161,1,'2010-01-28 07:10:35.373' union
select 160,1,'2010-01-27 16:09:32.550' union
select  46,2,'2010-01-30 17:13:45.750' union
select 145,2,'2010-01-30 17:13:42.607' union
select 142,2,'2010-01-30 16:11:58.020' union
select 140,2,'2010-01-30 15:45:00.543';

EDIT 2 Please note that the data is not a good example so I have change the id 146 to 46

A: 
select id from theTable where id>@id order by id desc limit 1
union
select id from theTable where id<@id order by id desc limit 1
zapping
it's not ordered by id, it's ordered by statusid and date. Rippos didn't say that the id is sequential when ordering like this.
Stefan Steinegger
@zapping, the Id is not sequential, this is my problem. Sorry but this is incorrect.
Rippo
A: 

may be you can add another seq id field with autoincrement and step by this field value

drorhan
I was thinking of this, as it would make it easier to query. However I know that the above is possible I just can't solve it!
Rippo
sqlite provides rowid. you can use it for sequentel moveSelect rowid from t
drorhan
+1  A: 

This problem is a lot more complicated than it first appears. The two order by fields have to be handled separately and then combined with a union and grab the appropriate result. To get both previous and next, we need another union, so we end up with a union with sub-unions.

This works with the supplied data. I tested many inputs and got the right previous/next outputs. When using, make sure you get ALL instances of 146 to replace.

SELECT *
FROM
(
    SELECT  t1.*
    FROM    t t1,
            (
                SELECT  *
                FROM    t
                WHERE   id = 146
            ) t2
    WHERE   t1.statusid = t2.statusid
      AND   t1.dateCreated >= t2.dateCreated
      AND   t1.id <> 146

    UNION

    SELECT  t1.*
    FROM    t t1,
            (
                SELECT  *
                FROM    t
                WHERE   id = 146
            ) t2
    WHERE   t1.statusid < t2.statusid


    ORDER BY             
            t1.statusid DESC,
            t1.dateCreated 

    LIMIT 1
)

UNION

SELECT *
FROM 
(
    SELECT  t1.*
    FROM    t t1,
            (
                SELECT  *
                FROM    t
                WHERE   id = 146
            ) t2
    WHERE   t1.statusid = t2.statusid
      AND   t1.dateCreated <= t2.dateCreated
      AND   t1.id <> 146

    UNION

    SELECT  t1.*
    FROM    t t1,
            (
                SELECT  *
                FROM    t
                WHERE   id = 146
            ) t2
    WHERE   t1.statusid > t2.statusid


    ORDER BY             
            t1.statusid,
            t1.dateCreated DESC

    LIMIT 1
)

ORDER BY             
        statusid,
        dateCreated DESC
;
Sam
Superb, a couple small mods but it works like a charm!
Rippo
A: 

Try this

select    max(id)    from t  where id < 164 union 
select    min(id)    from t  where id > 164
drorhan
Its not ordered by id so this will not work. Your previous answer though is a good alternative answer.
Rippo
do you want find the next id and previes id ?
drorhan
i have tested the code. it gives exactly the same results with Sams code
drorhan
Are you sure you have tested? I don't want just the next/prev id, I want the next/prev id BASED on the order I have presented.
Rippo
Yes it is based on your data.
drorhan
@drorhan, based on the data I have given it seems that you are correct, change the Id of `146` to just `46` then run this `select max(id) from @t where id < 46 union select min(id) from @t where id > 46`
Rippo
@drorhan, you will find that your solution falls over. It just so happens that the data I have given gives you the impression that your solution works. I have edited my question to reflect this, sorry for the confusion!
Rippo
A: 

SQlite does not support variable declaring.(i guess)

CREATE TABLE "tmp" ("ID" INTEGER, "sID" INTEGER)

delete from tmp; // for each iteration clear the table

insert into tmp (ID,sID )SELECT  rowid,id  from t  where ID = 142 order by statusID,dateCreated limit  1;

select * from t where rowid = (select ID from tmp)+1 union
select * from t where rowid = (select ID from tmp)-1

can this help for you ?

drorhan
I will look into this as it may be possible... Will keep you posted. Many thanks
Rippo