arash moeen
arash moeen

Reputation: 4713

android sqlite query with offset doesn't return desired rows

I'm using the following code to get a list of notifications (total rows are 21):

List<Notification> list = new ArrayList<Notification>();
Cursor c = _db.query(TABLE_NAME, COL_ALL, null, null, null, null, order, get_limitStr(offset));
if(c != null && c.moveToFirst())
{
    while(!c.isAfterLast())
    {
        Notification model = cursorToModel(c);
        if(model != null)
        {
            list.add(model);
        }
        c.moveToNext();
    }
    c.close();
}

and the generated query for offset = 0 is

SELECT Id, Token, Title, Read, Message, Image, CreateDate, CreateDateFA FROM Notifications ORDER BY CreateDate DESC LIMIT 20,0

and it works as it's supposed to and returns 20 rows, when I increase offset by 1 (offset = 1) it returns only 1 row which is correct but the problem is when the offset is bigger than 1 then the query will be

SELECT Id, Token, Title, Read, Message, Image, CreateDate, CreateDateFA FROM Notifications ORDER BY CreateDate DESC LIMIT 20,2

and I thought it supposed to skip 20 * 2 rows and then starts taking rows from there, which either my thought or my query is wrong. What am I doing wrong here? Thanks

Upvotes: 5

Views: 7646

Answers (3)

CoDe
CoDe

Reputation: 11146

Here need to understand both LIMIT <offset>, <count> & LIMIT <count> OFFSET <offset> are equivalent.

An example:

A) We have an table with 4 record of id column, values are 1 | 2 | 3 | 4 in respective 4 rows.

B) IF perform select * from TABLE_NAME: it returned all record from table in order 1 | 2 | 3 | 4 .

C) If we need total(e.g. limit) 1 record and it should start from offset index 2, then use

select * from TABLE_NAME limit 1 offset 2

This will return record index | 3 | as request limit = 1 & offset index = 2.

Same can be achieved using select * from company limit 2, 1; similar of what @laalto has mentioned.

Note, here 2 is offset & 1 is limit(order reverse).

Since Android SDK do not provide separate attribute to set offset, in that case last 'limit' attribute of SQLiteDatabase.query(..., limit) can be used as limit 2, 1.

Upvotes: 1

Choletski
Choletski

Reputation: 7525

You can use offset within Cursor as "offset,limit" value:

   Cursor cursor = db.query(
            TABLE_NAME,
            new String[]{COLUMN_NAME_1, COLUMN_NAME_2, COLUMN_NAME_3},
            null,
            null,
            null,
            null,
            null,
            "6,1000");

In this example I selected all rows(I suppose no more than 1000) starting from the 7th one. Here 6 is your offset and 1000 the limit.

Upvotes: 2

laalto
laalto

Reputation: 152867

LIMIT 20,2

and I thought it supposed to skip 20 * 2 rows and then starts taking rows from there, which either my thought or my query is wrong.

LIMIT 20,2 skips first 20 rows and returns at most 2 remaining rows. It's the same as LIMIT 2 OFFSET 20.

Even the documentation says it's counter-intuitive:

Instead of a separate OFFSET clause, the LIMIT clause may specify two scalar expressions separated by a comma. In this case, the first expression is used as the OFFSET expression and the second as the LIMIT expression. This is counter-intuitive, as when using the OFFSET clause the second of the two expressions is the OFFSET and the first the LIMIT. This reversal of the offset and limit is intentional - it maximizes compatibility with other SQL database systems. However, to avoid confusion, programmers are strongly encouraged to use the form of the LIMIT clause that uses the "OFFSET" keyword and avoid using a LIMIT clause with a comma-separated offset.

If you want to achieve sort of result paging with page size of 20, use something like OFFSET k*20 LIMIT 20 where k is your zero-based page number.

Upvotes: 16

Related Questions