天天看點

MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的

MYSQL報錯語句很多,但是了解其原理才是做重要的

讓我們先看一段報錯語句

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]之間

MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的

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

而且rand()有一個BUG,報錯也就是利用了這個BUG,這個後面會細說,暫時就了解産生随機數就好了

二、floor()

floor()是用來取整的,重點:沒有四舍五入

MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的

這樣一來用floor()來包裹着rand()豈不是沒有用了嗎?因為結果一定會是0。

是以我們要對rand()進行處理,那就是對他乘個2,這樣就會出現1。

MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的

這樣子我們會有個疑問,因為是rand()是随機的是以出現0,1也是随機的,是不可控的,可以看到确實是随機的

MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的

是以我們要對rand()做一點點修改,将rand()加個0,變成rand(0)

MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的

加一個0以後的我們發現數字的結果就唯一,是01101,這串數字特别的重要,我們的報錯就是來自于他重要的事情說三遍:01101,01101,01101

三、group by

為了示範友善我建立了一個test表

MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的

接下來我們用一下group by 看看有什麼作用

select * from test group by age;           

複制

MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的

可以看到 group by 建立了一個新的虛空的表,并且以 by 後的字段 age 來查詢test表,如果重複了就不再添加,而且新的虛拟表的主鍵是 by 後面的字段,這就是上圖中的 age 。(ps:一個表中主鍵是不能重複的)

現在就要進入重點了,在此之前我再介紹一下count()

count()函數允許對表中符合特定條件數的所有行進行計數,舉個例子

select count(*) from test group by age;           

複制

MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的
MYSQL報錯語句講解MYSQL報錯語句很多,但是了解其原理才是做重要的

用count(),可以清楚的知道表中,幾個15歲,幾個18歲,幾個19和20歲。

OK,現在我們開始

我們來看這個語句

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)

    為主鍵,建立一個虛拟的空表

    keycount

  2. 查詢第一條記錄,計算

    floor(rand(0)*2)

    (這是第一次計算),得到的值是0,檢視表發現沒有0,是以進行插入操作,但是在插入時又會計算一次

    floor(rand(0)*2)

    (這是第二次計算)結果為1,此時的表為

    keycount 11

  3. 查詢第二條記錄,計算

    floor(rand(0)*2)

    (這是第三次計算),得到值是1,檢視表發現已經有了,則不進行插入操作,直接count+1,此時表為

    keycount 12

  4. 查詢滴三條記錄,計算

    floor(rand(0)*2)

    (這是第四次計算),得到的是0,檢視表發現沒有,進行插入操作,但是在插入之前會在此計算

    floor(rand(0)*2)

    (這是第五次計算),得到的是1。然而表中已經有key為1 ,是以會産生報錯。

    keycount 12 1 (出錯)

總結

出現報錯的原因是,因為已經要執行插入資料操作,才發現了主鍵沖突。

這個報錯是利用 rand() 的特殊性,以及

floor(rand(0)*2)

前5個數字的可預知性,以及可以通過 group by 來建立一個空的虛拟表,這些條件綜合在一起産生的報錯。

Q.E.D.