Mysql隨機查詢一條數據,如何保證一定能查詢到結果,並且保證查詢的結果具有隨機性

從mysql數據庫隨機獲取一條記錄的方法網上有很多,大部分都是採用如下的方法一:

SELECT *
FROM `table` AS t1 
JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 1;

或者使用方法二:

SELECT * FROM `table`
WHERE id >= (SELECT floor( RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`)) + (SELECT MIN(id) FROM `table`))) 
ORDER BY id LIMIT 1;

 方法二再優化一下,得到方法三,如下:

SELECT *
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`))+(SELECT MIN(id) FROM `table`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 1;

但是有的時候,查詢的語句本身就要關聯多張表,同時實際查詢的條件也會複雜許多,這就導致使用上述方法時,多次查詢後的數據整體就不會呈現出太大的隨機性,尤其是當使用多個條件後刷選出來的結果中,每條記錄的主鍵並不一定是規律遞增的,這就可能導致最終返回的是空記錄,顯然這不是我們想要的。比如使用方法一,假設我where子句中多個條件帥選後的最終結果有五條記錄,id分別是18,50,57,67,69。那麼假設此時方法一中的這部分 SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id   執行後的結果t2.id=25,那麼方法一的sql執行後的結果,恐怕不止一半的概率都是id=50吧,此時所謂的隨機性還能體現出來嗎。即便使用方法二、方法三的sql可以減少以上情況的發生,但只是減少,並不是避免,況且以上三種方法還會有一定的概率返回空記錄。

 

下面介紹一種我自己想到的方法,直接上代碼,下面的都是僞代碼,大家自行腦補。首先是代碼段A:
 

select ROUND(1+RAND()*(count(t1.id))) 
from `table` t1
where 條件1 and 條件2 and 條件n

 此時,記代碼段A執行後結果爲countA .

接着請看代碼段B:

select t1.* 
from `table` t1
where 條件1 and 條件2 and 條件n 
limit $(countA),1 

 注意:limit函數後面的${}是mybatis中的字符串替換符,其它框架可以自由改變,不用糾結

分析:首先代碼段A先查詢一遍符合條件的總記錄數,假設爲20,然後對總記錄數進行隨機數取整,得到的一定是1-20之間的整數。然後代碼段B則是直接執行真正的獲取記錄,對原來的那20條記錄進行隨機選取,這樣查詢到的結果便是隨機的。這種方法可能顯得有點笨,因爲需要查詢兩次,但是相比於一次性查詢所有符合條件的記錄並加載進內存,比如封裝到list集合中,然後再使用list.get(隨機數) 隨機抽取符合條件的記錄這種方式,可能要好的多。畢竟,一次性查詢成百上千條記錄後再加載到內存中,最終只是爲了隨機抽取一條記錄,這就顯得有點浪費資源了。當然了,如果不是因爲limit 函數後面只能跟常量,只用一條sql也能達到效果。如果是多表連表並且使用多條件查詢,需要保證代碼段 A 和代碼段B中使用的表和where條件一致即可,這個應該不難理解。

 

如果有更好的方法或者發現了什麼問題,歡迎賜教;但是說歸說,別爆粗口,我沒收誰的錢也沒有要求誰來點贊,甚至沒有要求誰來看,我只是在自己的一畝三分地裏寫點小文章,記錄一些自己曾經走過的路,然後順便給以後可能和我有同樣問題的人提供一些可能的借鑑,同時希望有人提供更好的思路,讓我還能再有所提升。素質不好的人,請遠離我的評論區,這樣你好,我也好,大家都好,謝謝!

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章