在MySQL中,如何在具有给定ID的记录之后/之前检索记录?

时间:2018-05-05 15:15:47

标签: mysql sql pagination

作为实现GraphQL API的一部分,我试图在分页之前/之后提供。例如,返回具有给定ID的记录之后的LIMIT记录。这必须处理任意SELECT语句,其中包含任意JOIN,WHERE和ORDER BY子句。

这种分页优于仅使用页码的好处是,当底层数据发生变化时,它可以更接近地返回预期的结果页面。

如果我能在 之后使工作,我也可以通过反转ORDER BY子句使其适用于之前的,所以在这里我将只关注< em>在条件之后。

修改给定SELECT语句以实现此目的的最简单或最有效的方法是什么?

我的第一个想法是在WHERE子句中添加一个AND条件,将结果限制为ORDER BY子句中具有列值的那些大于或等于具有给定ID的记录中的值。但这似乎不起作用,因为ORDER BY子句列中没有唯一性的期望,因此无法知道目标记录在结果中的位置,因此无法知道如何设置LIMIT返回正确的记录数。

另一种方法是首先在初始SELECT语句中发现目标记录的偏移量,然后使用发现的偏移量向初始SELECT语句添加LIMIT offset+1, limit子句。

MySQL没有row_count()功能或类似功能,但可以添加行号like this

SELECT @rownum:=@rownum+1 ‘rank’, t.* 
FROM my_table t, (SELECT @rownum:=0) r ORDER BY field2;

然后,上面的内容可以用作子查询来获取目标记录的等级,例如

SELECT rank FROM (SELECT @rownum...) WHERE id = 42

然后使用该等级作为最终查询的偏移量:

SELECT ... LIMIT (rank + 1), 100

可能这可以作为具有多个子查询的单个查询来完成,例如

SELECT ... LIMIT (SELECT rank from (SELECT @rownum...) ...) + 1, 100

但是这三种查询方法似乎是一种复杂且不是非常快速的方法来执行非常常用的操作,从而使我们的数据库服务器上的负载比我们希望的更高。

有更好的方法吗?

编辑:请求了一个具体示例。假设我想从10篇文章的表格中获得2篇文章的页面。我们将对此查询进行分页:

select id, title from articles order by title desc

表格:

id, title
1, "a"
3, "b"
4, "c"
6, "d"
7, "e"
8, "f"
9, "g"
10, "h"
11, "i"
12, "k"

因此,在标识6之后请求页面时,正确的记录将是4, "c"3, "b"。这需要适用于任意WHERE和ORDER BY子句。

2 个答案:

答案 0 :(得分:0)

如果没有任何实际的示例表,以下查询是要使用的排序蓝图。

它从表中选择列值大于子查询中的行的行。 子查询选择表中的目标行,该行是所需行的“起始点”。

在下面的示例中, col1 是排名列。将子查询中的WHERE子句更改为选择起始点行所需的任何内容。

对于分页,请更改LIMIT子句以表示先前的分页查询。

SELECT
    col1,
    col2,
    etc
FROM table a
JOIN (
    SELECT col1
    FROM table c
    WHERE conditions
    LIMIT 20,1
    ) b
    ON a.col1 > b.col1
ORDER BY col1
LIMIT 20;

答案 1 :(得分:0)

您可以根据所排序的内容,在目标行之前或之后选择行。假设你有id的索引,这应该只需要一个相对便宜的子查询:

SELECT id, title
FROM articles
WHERE title < (SELECT title FROM articles WHERE id = '6')
ORDER BY title DESC
LIMIT 0,2;

下一组将是

LIMIT 2,2

上一组需要>=运算符:

SELECT id, title
FROM articles
WHERE title >= (SELECT title FROM articles WHERE id = '6')
ORDER BY title DESC
LIMIT 0,2;

等...

使用更具体的数据和表结构给出更简洁的答案会更容易,但希望这会有所帮助。