如何判断某条记录在哪个页面?
假设我使用如下查询每页显示 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 吗?
为了这个例子,我们假设条目
7
刚刚被添加(并且可能有重复的名称) - 您需要做的第一件事是找到在该条目之前有多少条目(基于 name
),因此:
SELECT COUNT(*)
FROM Posts
WHERE name <= 'g'
AND id < 7
这里,
id
被用作“决胜局”列,以确保稳定的排序。它还假设我们也知道 id
的值 - 鉴于非关键数据可以重复,您需要这种功能。LIMIT
),我们现在可以获得相关信息:
(int) ((6 - 1) / 5) = 1
...不过,这是针对 0 索引页面的(即,条目 1 - 5 出现在页面“0”上);然而,在这种情况下,它对我们有利。请注意,我们必须从初始计数中减去 1,因为第一个是 1,而不是 0 - 否则,条目 5 将出现在第二页,而不是第一页。
我们现在有了 page
索引,但我们需要将其转换为 entry 索引。一些简单的乘法就可以为我们做到这一点:
(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 进行更改。尽管在 at至少有一种情况,数据库有
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, id
LIMIT 5, (SELECT ((COUNT(*) - 1) / 5) * 5 + 1 as entryCount
FROM Posts
WHERE name <= 'g'
AND id < 7);
(以及工作中的SQL Fiddle 示例