如何确定某个记录在哪个页面?
假设我使用如下查询显示每页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?
答案 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)。