利用MySQL中where的特性模仿limit 0,n实现

原文link https://www.t00ls.net/viewthread.php?tid=45590&from=favorites
此篇文章中只讲述了and/or的工作机制, where的机制并没有讲.
感觉挺有意思的,故无聊的时候用此方法实现了模仿limit效果
此处只补充部分知识,tony师傅的文章里补充的更详细

环境准备

  • MySQL 8
  • xsql中有一个idusename
id username
1 loid
2 admin
3 pas

and/or的惰性计算

  • A and B, 如果 A 为真,那么继续判断B是否为真. 但是如果A为假就不再执行B表达式
  • A or B, 如果 A 为假,那么就继续判断B是否为真, 但是如果A为真,就不再执行B表达式

where在使用的时候的特性

  • 语句 select * from xsql where username='11' or sleep(1)
    此处在执行where的时候, 会对每行数据进行验证.过程如下:

    1
    2
    3
    4
    5
    判断`id`为1的数据, `username`是否为'11' 或者 延时一秒 //为假, 因为username 不为`11`, sleep(1)返回的也是0
    判断`id`为2的数据, `username`是否为'11' 或者 延时一秒 //同上
    判断`id`为3的数据, `username`是否为'11' 或者 延时一秒 //同上
    因为这里是`or`根据or表达式的惰性计算原理,
    后面的`sleep(1)` 会被执行3此,此时总共耗费3秒时间
  • 语句 select * from xsql where username='loid' or sleep(1)

    1
    2
    3
    4
    id=1行判断, username = 'loid'为真,所以不执行 sleep(1)
    id=2行判断, username = 'loid'为假,执行sleep(1)
    id=3行判断, username = 'loid'为假,执行sleep(1)
    结果返回id=1, username='loid'行,并耗时2秒
  • select * from xsql where id>1 and sleep(1)

    1
    2
    3
    4
    id=1行判断, id>1为假,所以不执行sleep(1)        // and的惰性运算
    id=2行判断, id>2为真,执行sleep(1)
    id=3行判断, id>3为真,执行sleep(1)
    结果返回id=2与id=3的行,并且延时2秒

实现limit 0,n效果的sql代码

代码: select * from xsql where if(@a is null, (select @a:=2), 0) or if(@a>=1, (select @a:[email protected]), 0)
代码逻辑

1
2
3
4
5
6
if(@a is null, (select @a:=2), 0)    // 如果 @a 为空,给@a赋值4,并返回2, 否则返回0
第一次匹配行的时候,会进行赋值,这时候第一行返2, 第一行会匹配
第二次匹配判断@a不是null,所以第一个表达式返回0,进行后半部分判断
后半部分因为@a第一次赋值了为2,所以@a>=1成立, 对@a进行递减1,并且返回1, 第二行也会被匹配
第三次匹配时,@a>=1为真,执行(select @a:[email protected]), 这里返回的是0为假,所以不返回第三行
就实现了limit 0,2

写在最后

  • 这里用ifnull这个函数,可以减少很多代码量
  • limit n,1 也可实现
  • 官方文档是好东西, 很多方法都能瞧瞧 传送门