我用MySQL(8.0版)实现了一个游标分页,只要不涉及null
值,它就能正常工作。
下面是我的示例数据(id
是随机UUID,date
是日期,time
是时间):
id | date | time
--------------------------
68 | 2017-10-28 | 22:00:00
d3 | 2017-11-03 | null
dd | 2017-11-03 | 21:45:00
62 | 2017-11-04 | 14:00:00
a1 | 2017-11-04 | 19:40:00
字符串
我使用的cursor
总是由所有三列组成。
我使用这个查询来获取next结果(在cursor
之后):
SELECT * FROM table
WHERE (date > cursor.date)
OR (date = cursor.date AND time > cursor.time)
OR (date = cursor.date AND time = cursor.time AND id > cursor.id)
ORDER BY date ASC, time ASC, id ASC
型
而这个查询prev的结果(cursor
之前):
SELECT * FROM table
WHERE (date < cursor.date)
OR (date = cursor.date AND time < cursor.time)
OR (date = cursor.date AND time = cursor.time AND id < cursor.id)
ORDER BY date DESC, time DESC, id DESC
型
当对cursor [id = dd, date = 2017-11-03, time = 21:45:00]
使用prev查询时,它不会返回带有id = d3
的行,因为time
是null
,而这不会被time < cursor.time
选中。
尽管我尝试使用time < cursor.time OR time IS NULL
而不是time < cursor.time
来包含具有null
值的行。这似乎解决了这个特定的问题,但随后又产生了一个新问题:当使用cursor [id = d3, date = 2017-11-03, time = null]
的prev查询时,因为现在结果包含所提供游标的行。
我希望有一个简单的解决方案。网络上似乎没有处理光标分页中null
值的示例或教程。
**注意:**对于解决方案,null
是否在non-null
值之前或之后排序并不重要,只要它是一致的。(MySQL的默认排序是null < non-null
)
5条答案
按热度按时间ctzwtxfj1#
我有点迟到了,但给予下面的方法吧。游标逻辑需要针对可为空的列进行调整,以及游标行为time列返回空值时进行调整。
下面列出了两个示例:
字符串
mklgxw1f2#
向表中添加另一列。把它设为
DATETIME
。当不为NULL时,将date
和time
合并到其中;当NULL时,将date
与某个特定时间组合。这样,您的游标就有两列要处理,而且没有空值。如果你有一个合理的最新版本的MySQL,你可以使用一个“生成的存储”列,从而避免任何代码更改。
而且一定要有
INDEX(datetime, id)
。vql8enpb3#
我不打算触及使用光标进行分页的主题。有一些替代方案,例如
limit
/offset
。但我建议您使用
coalesce()
,为比较分配一个假时间。MySQL使这变得有些简单,因为它支持超过24小时的time
值。对于date
/time
组合,这些值将不是有效值。于是:
字符串
更简洁的
WHERE
子句是:型
wztqucjr4#
如果你使用的是MySQL 8.0,那么你可以考虑使用row_number()窗口函数为每一行创建一个唯一的序列ID(rn)。然后只传递当前行的
rn
以获取前一行。Schema和insert语句:
字符串
第一次查询结果:
型
输出量:
| 日期,日期|计时器|rn| rn |
| --|--|--| ------------ |
| 2017-10-28 2017-10-28| 22点|一个| 1 |
| 2017-11-03 2017-11-03|零|二个| 2 |
| 2017-11-03 2017-11-03| 21点45分|三个| 3 |
| 2017-11-04 2017-11-04|下午4点|四个| 4 |
| 2017-11-04 2017-11-04| 19点40分|五个| 5 |
查询以获取仅包含
cursor [rn=3]
的cursor [id = dd, date = 2017-11-03, time = 21:45:00, rn=3]
的前几行:型
输出量:
| 日期,日期|计时器|rn| rn |
| --|--|--| ------------ |
| 2017-10-28 2017-10-28| 22点|一个| 1 |
| 2017-11-03 2017-11-03| * 空 *| 二个| 2 |
如果您不想在代码中引入计算列,请尝试以下解决方案,考虑所有三个列
cursor [id = dd, date = 2017-11-03, time = 21:45:00]
查询:
型
输出量:
| 日期,日期|计时器| time |
| --|--| ------------ |
| 2017-10-28 2017-10-28| 22点| 22:00:00 |
| 2017-11-03 2017-11-03| * 空 *| null |
你的代码应该像下面这样:
型
jq6vz3qz5#
我的解决方案是将我想用作分页游标的可空列转换为具有默认值的NOT NULL列。
对于文本列,我将默认值设置为空字符串,这使得所有这些记录都出现在升序排序的顶部,对于我的日期时间,我将默认值设置为最早的可能值:“1970-01-01 00:00:00”,这使得它们出现在降序排序的末尾。
然后,在TS/JS中检查应用中的日期时间“空”时,它就像这样简单:
字符串
如果您的系统依赖于这些空值,那么这对您来说不是正确的解决方案,但在我的情况下,这是最简单/优雅/减少头痛的解决方案。