确定记录的页面

时间:2014-01-25 03:04:37

标签: sql sqlite select pagination offset

如何确定某个记录在哪个页面?

假设我使用如下查询显示每页5条记录:

SELECT * FROM posts ORDER BY date DESC LIMIT 0,5
SELECT * FROM posts ORDER BY date DESC LIMIT 5,5
SELECT * FROM posts ORDER BY date DESC LIMIT 10,5

示例数据:

id  | name | date
-----------------------------------------------------
1   | a    | 2013-11-07 08:19               page 1
2   | b    | 2013-12-02 12:32
3   | c    | 2013-12-14 14:11
4   | d    | 2013-12-21 09:26
5   | e    | 2013-12-22 18:52      _________ 
6   | f    | 2014-01-04 11:20               page 2
7   | g    | 2014-01-07 21:09
8   | h    | 2014-01-08 13:39
9   | i    | 2014-01-08 16:41
10  | j    | 2014-01-09 07:45      _________
11  | k    | 2014-01-14 22:05               page 3
12  | l    | 2014-01-21 17:21

有人可以使用id = 7编辑记录,或者插入新记录(id = 13)。如何确定该记录在哪个页面上?原因是我想显示包含刚刚编辑或添加的记录的页面。

好吧我想我可以在编辑记录时显示相同的页面。但问题是当记录被添加时。列表可以按名称排序,新记录可以放在任何地方:(

我是否可以通过某种方式执行SELECT offset WHERE id = 13 ORDER BY date LIMIT 5之类的查询,返回10?

1 个答案:

答案 0 :(得分:1)

为了这个例子,我们假设刚刚添加了条目7(并且可能存在重复的名称) - 您需要做的第一件事就是找到在该条目之前有多少条目(基于name),因此:

SELECT COUNT(*) 
FROM Posts
WHERE name <= 'g'
      AND id < 7

此处,id被用作“决胜局”列,以确保稳定排序。我们也假设我们也知道id的价值 - 鉴于非关键数据可能重复,您需要这种功能。
无论如何,这给了我们前一行(6)之前的行数。通过一些整数除法运算(基于LIMIT),我们现在可以得到相关信息:

(int) ((6 - 1) / 5) = 1

...这是针对0索引的页面(即,条目1 - 5出现在页面“0”);但是,在这种情况下,它对我们有利。请注意,我们必须从初始计数中减去1,因为第一个是1,不是 0 - 否则,条目5将出现在第二页而不是第一页。
我们现在有索引,但我们需要将其转换为条目索引。一些简单的乘法对我们来说是这样的:

(1 * 5) + 1 = 6

(忽略这与计数相同 - 在这种情况下是巧合) 这为我们提供了页面上第一个条目的索引,即OFFSET的值 我们现在可以编写查询:

SELECT id, name, date
FROM Posts
ORDER BY name, id
LIMIT 5 OFFSET 6

(请注意,我们要求 id以保证数据的稳定排序,如果我们假设name可能是重复的!)。
这是两次访问数据库。令人惊讶的是,SQLite允许LIMIT / OFFSET值成为SQL子查询的结果(请记住,并非所有RDBMS都允许它们甚至是主变量,这意味着只能可以使用动态SQL进行更改。虽然至少有一种情况,但db有ROW_NUMBER()来弥补...)。但是,我无法摆脱子查询的重复。

SELECT Posts.id, Posts.name, Posts.date, Pages.pageCount
FROM Posts
CROSS JOIN (SELECT ((COUNT(*) - 1) / 5) + 1 as pageCount 
      FROM Posts
      WHERE name <= 'g'
            AND id < 7) Pages
ORDER BY name
LIMIT 5, (SELECT ((COUNT(*) - 1) / 5) * 5 + 1 as entryCount 
      FROM Posts
      WHERE name <= 'g'
            AND id < 7);

(和工作SQL Fiddle example)。