我有一些表,我想使用基于游标的分页查询,但它需要申请多个列。
让我们看一个使用2列的简化示例 - 我像这样获取第一页:
SELECT column_1, column_2
FROM table_name
ORDER BY column_1, column_2
LIMIT 10
获得结果后,我可以根据最后一行获取下一页。我们说最后一行是column_1 = 5, column_2 = 8
。我想做这样的事情:
SELECT column_1, column_2
FROM table_name
WHERE column_1 > 5 AND column_2 > 8
ORDER BY column_1, column_2
LIMIT 10
但这显然是错误的。它会滤出一行column_1 = 5, column_2 = 9
(由于column_1
上的过滤器)或行column_1 = 6, column_2 = 6
(由于column_2
上的过滤器)
我可以做这样的事情来避免这个问题:
SELECT column_1, column_2
FROM table_name
WHERE column_1 > 5
OR (column_1 = 5 AND column_2 > 8)
ORDER BY column_1, column_2
LIMIT 10
但是这对于超过2列来说变得非常麻烦且容易出错......
此外,我的用例包含多种类型的列(INT UNSIGNED
和BINARY
),但都具有可比性
你有什么建议吗?
谢谢!
答案 0 :(得分:8)
如果(不幸名称)列Column_1
是唯一的,您可以这样做:
WHERE Column_1 > :last_retrieved_value
从问题来看,似乎Column_1
不是唯一的,但(Column_1,Column_2)
元组是唯一的。
"下一页的一般表格"查询,按这两列排序,使用这两列的最后检索值,将是......
(Column1,Column2) > (:lrv_col1,:lrv_col2)
(lrv =从上一个查询检索的最后一行保存的值)
要在MySQL中编写该条件,我们可以像您所示的那样:
WHERE t.Column_1 > :lrv_col1
OR ( t.Column_1 = :lrv_col1 AND t.Column_2 > :lrv_col2 )
或者,我们可以这样写,我更喜欢这样,因为MySQL很少有机会被OR条件混淆并使用错误的索引...
WHERE t.Column_1 >= :lrv_col1
AND ( t.Column_1 > :lrv_col1 OR t.Column_2 > :lrv_col2 )
ORDER BY t.Column_1, t.Column_2
LIMIT n
要将其扩展到三个列,以检查条件......
(c1,c2,c3) > (:lrv1,:lrv2,:lrv3)
我们处理它就像在两列的情况下一样,首先处理c1
,将其分解为两列:
WHERE c1 >= :lrv1
AND ( c1 > :lrv1 OR ( ... ) )
ORDER BY c1, c2, c3
LIMIT n
现在,占位符...
(之前只会检查c2
的情况,实际上只是两列的另一个案例。我们需要检查:(c2,c3) > (lrv2,lrv3)
,所以我们可以使用相同的模式扩展它:
WHERE c1 >= :lrv1
AND ( c1 > :lrv1 OR ( c2 >= :lrv2
AND ( c2 > :lrv2 OR c3 > :lrv3 )
)
)
ORDER BY c1,c2,c3
LIMIT n
我同意扩张可能看起来有点混乱。但它确实遵循非常规律的模式。同样,我们可以在四个列上表达条件......
(c1,c2,c3,c4) > (:lrv1,:lrv2,:lrv3,:lrv4)
我们只考虑三列的内容,我们需要扩展 c3 > :lrv3
,将其替换为 ( c3 >= :lrv3 AND ( c3 > :lrv3 OR c4 > :lrv4 ) )
WHERE c1 >= :lrv1
AND ( c1 > :lrv1 OR ( c2 >= :lrv2
AND ( c2 > :lrv2 OR ( c3 >= :lrv3
AND ( c3 > :lrv3 OR c4 > :lrv4 )
)
)
)
)
ORDER BY c1,c2,c3,c4
LIMIT n
作为对未来读者的帮助,我会评论这个块,并表明意图......
-- (c1,c2,c3,c4) > (lr1,lr2,lr3,lr4)
如果MySQL允许我们像这样表达比较,那将是很好的。不幸的是,我们必须将其扩展为MySQL理解的东西。