溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL 中出現(xiàn)floor()報錯的原因是什么

發(fā)布時間:2021-07-13 15:54:07 來源:億速云 閱讀:211 作者:Leah 欄目:網(wǎng)絡(luò)管理

這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)MySQL 中出現(xiàn)floor()報錯的原因是什么,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

select count(*) from users group by concat(database(),floor(rand(0)*2));
select count(*),concat(database(),floor(rand(0)*2))x from users group by x;

MySQL 中出現(xiàn)floor()報錯的原因是什么它們表達(dá)的意思是一樣的,第二條語句中的as x其實就是concat(database(),floor(rand(0)*2))的代指(別名),這兩個SQL語句表達(dá)的意思并沒什么區(qū)別。來,讓我們瞅瞅它報了什么錯:ERROR 1062 (23000): Duplicate entry 'security1' for key 'group_key'

它說'group_key'的主鍵'security1'重復(fù)了,嗯?‘security1’從哪里來的?哪個表的主鍵重復(fù)了?

MySQL 中出現(xiàn)floor()報錯的原因是什么雖然剛開始,咱們還不知道原理,但是可以看到報錯提示語句中的數(shù)據(jù)庫函數(shù)已經(jīng)被執(zhí)行了。就像我之前說的那樣,我本身有用到sqli-labs的數(shù)據(jù)庫,所以database()執(zhí)行后是’security’很正常吧。

floor(rand(0)*2)

security1中的1便是來自floor(rand(0)*2),它說security1重復(fù),那說明之前的表中已經(jīng)有這個主鍵了。因為database()固定,我們繼續(xù)來看下產(chǎn)生1的這個floor(rand(0)*2)。rand()同樣是一個數(shù)學(xué)函數(shù),它返回一個隨機浮點值[0,1]。

MySQL 中出現(xiàn)floor()報錯的原因是什么MySQL 中出現(xiàn)floor()報錯的原因是什么

若指定一個整數(shù)參數(shù)N,則它被作用種子值(也被叫為隨機因子),(rand()會根據(jù)這個種子值隨機生成)用來產(chǎn)生重復(fù)序列,也就是rand(0)的值重復(fù)計算是固定的。

MySQL 中出現(xiàn)floor()報錯的原因是什么
MySQL 中出現(xiàn)floor()報錯的原因是什么

而它后面的*2,則是選定獲取數(shù)據(jù)的范圍[0,2],其實就是乘以2。

MySQL 中出現(xiàn)floor()報錯的原因是什么

floor()同樣是一個數(shù)學(xué)函數(shù),返回不大于x的最大整數(shù)值,比如floor(3.3)返回3,floor(-3.3)返回-4。 

MySQL 中出現(xiàn)floor()報錯的原因是什么

現(xiàn)在讓我們看下計算users表數(shù)據(jù)的次數(shù),floor(rand(0)*2)的值。

MySQL 中出現(xiàn)floor()報錯的原因是什么MySQL 中出現(xiàn)floor()報錯的原因是什么可以看到rand(0)的值確實是固定的。同時1也出現(xiàn)了。 concat()是字符串拼接函數(shù),拼接多個字符串,如果字符串中含有NULL,則返回結(jié)果為NULL。這樣來看,concat后的結(jié)果為’security0’或’security1’,’security1’出現(xiàn)了。

分析到這,我們后半部分沒什么好說的了,rand()還有一個非常重要的特性我們之后跟group by一起說。

group by 與 count(*)

咱們再來說這個count(*),這是一個聚合函數(shù),返回值的數(shù)目,它與count()的區(qū)別是它不排除NULL。

咱們通過select count(*) from users group by username;這個查詢語句來了解下group by的工作過程。

MySQL 中出現(xiàn)floor()報錯的原因是什么MySQL 中出現(xiàn)floor()報錯的原因是什么
MySQL 中出現(xiàn)floor()報錯的原因是什么

group by在執(zhí)行時,會依次取出查詢表中的記錄并創(chuàng)建一個臨時表,group by的對象便是該臨時表的主鍵。如果臨時表中已經(jīng)存在該主鍵,則將count(*)值加1,如果不存在,則將該主鍵插入到臨時表中,注意是插入!查詢前創(chuàng)建的空臨時表。 MySQL 中出現(xiàn)floor()報錯的原因是什么

取第一條記錄,username是Dumb,發(fā)現(xiàn)臨時表中沒有該主鍵,則將Dumb插入到主鍵,count(*)值計1,取第二條記錄。 MySQL 中出現(xiàn)floor()報錯的原因是什么

同樣,取第二條記錄,username為Angelina,同樣沒有該主鍵,則將Angelina插入到主鍵,count(*)值計1。 MySQL 中出現(xiàn)floor()報錯的原因是什么

當(dāng)取到原表中第8條admin時,同樣將admin作為主鍵插入到臨時表中,并將count(*)計1.當(dāng)取第15條數(shù)據(jù)時,發(fā)現(xiàn)臨時表中已經(jīng)有admin作為主鍵了,則直接count(*)加1。最終結(jié)果:

MySQL 中出現(xiàn)floor()報錯的原因是什么MySQL 中出現(xiàn)floor()報錯的原因是什么

雖然在命令行中的顯示結(jié)果跟咱的不太一樣,但是思路是正確的(它貌似對結(jié)果按照字母進行了排序,又或者在插入臨時表前就先進行了排序)。

寫到這里,那按照上面的邏輯,報錯語句應(yīng)該是select count(*) from users group by ‘security0’或’security1’;啊?然后group by時創(chuàng)建臨時表,第一個是security0,發(fā)現(xiàn)沒有這個主鍵,此時將security0插入主鍵的位置,計1,然后取from的表中下一條記錄。 MySQL 中出現(xiàn)floor()報錯的原因是什么

取下一條記錄,group by 后是‘security1‘,臨時表中不存在security1的主鍵,則將security1插入主鍵位置,計1,然后取下一條記錄。 MySQL 中出現(xiàn)floor()報錯的原因是什么

之后group by 只有security0或security1,那應(yīng)該只是計數(shù)上的變化了啊。最終應(yīng)該是: MySQL 中出現(xiàn)floor()報錯的原因是什么

那為什么不是這個結(jié)果,反而報了主鍵重復(fù)的錯誤了呢?

因為還有一個最重要的特性,就是group by與rand()使用時,如果臨時表中沒有該主鍵,則在插入前rand()會再計算一次(也就是兩次,但有些博客寫的是多次,這個多次到底是幾次我并不知道,也沒有找到相關(guān)材料作為支持,但是以兩次來理解下面的實驗都能說的通),就是這個特性導(dǎo)致了主鍵重復(fù)并報錯。我們來看:

當(dāng)group by 取第一條from 的表記錄時,此時group by的是’security0’,發(fā)現(xiàn)臨時表中并沒有’security0‘的主鍵,注意,這個時候rand(0)*2會再計算一次,經(jīng)floor()后,率先插入臨時表的主鍵不是security0,而是security1,并計數(shù)1。 MySQL 中出現(xiàn)floor()報錯的原因是什么

然后取第二條記錄,第二條記錄group by 的key中的01仍由floor(rand(0)*2)繼續(xù)計算獲得,也就是security1。此時臨時表中已經(jīng)有security1的主鍵了,所以count(*)直接加1就可以。 MySQL 中出現(xiàn)floor()報錯的原因是什么

繼續(xù)從from的表中取第三條記錄,再次計算floor(rand(0)*2),結(jié)果為0,與database()拼接為security0,臨時表的主鍵中并不存在,在插入前,floor(rand(0)*2)又計算一次,拼接后與secruity1,但是是直接插入,即使臨時表中已經(jīng)有了主鍵security1也硬要插入,從而導(dǎo)致主鍵重復(fù)報錯,也就是:ERROR 1062 (23000): Duplicate entry 'security1' for key 'group_key'。 

MySQL 中出現(xiàn)floor()報錯的原因是什么

寫到這里報錯的原理已經(jīng)說完了,各位觀眾老爺感覺呼應(yīng)上了嗎?

優(yōu)化

咱們繼續(xù)看,咱們共從from的表中取了三條記錄(這也是floor(rand(0)*2)最少需要表中有三條記錄的原因),因為floor(rand(0)*2)的值為011011...,但其實第三次計算的1可以不要的(變?yōu)?101)。

如果某個floor(rand(x)*2)滿足0101或1010,那么from 的表中兩條數(shù)據(jù)就是可以報錯的。我經(jīng)過多次實驗,發(fā)現(xiàn)floor(rand(14)*2)的值為101000...,那么咱們創(chuàng)建一個有兩條數(shù)據(jù)的表試一下康康。 MySQL 中出現(xiàn)floor()報錯的原因是什么

創(chuàng)建一個test表,里面只有兩條數(shù)據(jù)。 MySQL 中出現(xiàn)floor()報錯的原因是什么

分別用rand(0)*2和rand(14)*2做實驗。 MySQL 中出現(xiàn)floor()報錯的原因是什么

上述就是小編為大家分享的MySQL 中出現(xiàn)floor()報錯的原因是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI