前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MYSQL报错语句原理

MYSQL报错语句原理

作者头像
sugarbeet
修改2023-05-04 10:32:03
7970
修改2023-05-04 10:32:03
举报
文章被收录于专栏:小满的技术录小满的技术录

MYSQL报错语句很多,但是了解其原理才是做重要的

让我们先看一段报错语句

代码语言:javascript
复制
select count(*),(floor(rand(0)*2))x from information_schema.tables group by x

这条报错的语句最重要的部分有三个:

  1. rand(0)
  2. floor()
  3. group by

现在我就讲一下这三个部分

一、rand(0)

rand()是用来产生随机数的,他的范围是[0,1]之间

image-20200725173941167
image-20200725173941167

可以看到每一次的数值都是不同的

而且rand()有一个BUG,报错也就是利用了这个BUG,这个后面会细说,暂时就理解产生随机数就好了

二、floor()

floor()是用来取整的,重点:没有四舍五入

image-20200725174546195
image-20200725174546195

这样一来用floor()来包裹着rand()岂不是没有用了吗?因为结果一定会是0。

所以我们要对rand()进行处理,那就是对他乘个2,这样就会出现1。

image-20200725185235658
image-20200725185235658

这样子我们会有个疑问,因为是rand()是随机的所以出现0,1也是随机的,是不可控的,可以看到确实是随机的

image-20200725185520120
image-20200725185520120

所以我们要对rand()做一点点修改,将rand()加个0,变成rand(0)

image-20200725185728527
image-20200725185728527

加一个0以后的我们发现数字的结果就唯一,是01101,这串数字特别的重要,我们的报错就是来自于他重要的事情说三遍:011010110101101

三、group by

为了演示方便我创建了一个test表

image-20200725191514263
image-20200725191514263

接下来我们用一下group by 看看有什么作用

代码语言:javascript
复制
select * from test group by age;
image-20200725191830700
image-20200725191830700

可以看到 group by 创建了一个新的虚空的表,并且以 by 后的字段 age 来查询test表,如果重复了就不再添加,而且新的虚拟表的主键是 by 后面的字段,这就是上图中的 age 。(ps:一个表中主键是不能重复的)

现在就要进入重点了,在此之前我再介绍一下count()

count()函数允许对表中符合特定条件数的所有行进行计数,举个例子

代码语言:javascript
复制
select count(*) from test group by age;
image-20200725202153725
image-20200725202153725
image-20200725202237338
image-20200725202237338

用count(),可以清楚的知道表中,几个15岁,几个18岁,几个19和20岁。

OK,现在我们开始

我们来看这个语句

代码语言:javascript
复制
 select count(*) from test group by floor(rand(0)*2);

会注意到是不是和文章开始的报错语句不太一样,其实文章开始的那个报错语句是这个的变形而已,为了更直观咱们就看这个。

还记得我之前说的 rand() 的一个小BUG吗,那就是

就是查询的时候如果使用rand()的话,该值会被计算多次,这个是MySql官方说的,这个“多次计算”在咱的报错语句中来解读就是,group by floor(rand(0)*2) 在执行是会计算一次 floor(rand(0)*2) ,但是在插入数据时还会执行一次floor(rand(0)*2)
还有一个,我在提醒一次 floor(rand(0)*2) 的前5个计算结果为 01101

语句开始运行

  1. group by 以 floor(rand(0)*2) 为主键,建立一个虚拟的空表

| key | count |

| ---- | ----- |

| | |

  1. 查询第一条记录,计算 floor(rand(0)*2)(这是第一次计算),得到的值是0,查看表发现没有0,所以进行插入操作,但是在插入时又会计算一次floor(rand(0)*2) (这是第二次计算)结果为1,此时的表为 | key | count |

| ---- | ----- |

| 1 | 1 |

  1. 查询第二条记录,计算floor(rand(0)*2)(这是第三次计算),得到值是1,查看表发现已经有了,则不进行插入操作,直接count+1,此时表为 | key | count |

| ---- | ----- |

| 1 | 2 |

  1. 查询滴三条记录,计算floor(rand(0)*2)(这是第四次计算),得到的是0,查看表发现没有,进行插入操作,但是在插入之前会在此计算floor(rand(0)*2)(这是第五次计算),得到的是1。然而表中已经有key为1 ,所以会产生报错。 | key | count |

| -------- | ----- |

| 1 | 2 |

| 1 (出错) | |

总结

出现报错的原因是,因为已经要执行插入数据操作,才发现了主键冲突。

这个报错是利用 rand() 的特殊性,以及floor(rand(0)*2)前5个数字的可预知性,以及可以通过 group by 来创建一个空的虚拟表,这些条件综合在一起产生的报错。

Q.E.D.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MYSQL报错语句很多,但是了解其原理才是做重要的
    • 让我们先看一段报错语句
      • 这条报错的语句最重要的部分有三个:
        • 现在我就讲一下这三个部分
          • 一、rand(0)
          • 二、floor()
          • 三、group by
        • 现在就要进入重点了,在此之前我再介绍一下count()
          • OK,现在我们开始
            • 总结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档