2013-05-16 258 views
1

如何從SQL數據庫查詢中隨機選擇一行?我的意思是:如何從SQL查詢選擇中選擇一個隨機行?

從表1中選擇與分類「綠色」所有的事情:

$stmt = $db->query('SELECT * from table1 WHERE Category LIKE "%green%"'); 

然後隨機從這個選擇顯示行(而不是從這個選擇,顯示的每一行,因爲我已經做了下文)

while($rows = $stmt->fetch()){ 
    echo "<tr><td>". $rows['Number'] . "</td><td>" . $rows['Content'] . "</td></tr>"; 
}; 
+0

你想要一個「隨機」行或「任意」行嗎?隨機行通常指的是返回集合中任何給定行的相等概率。 「任意」行意味着你不關心哪一行。 –

+0

@GordonLinoff你的意思是[this](http://xkcd.com/221/)? –

+0

@GeorgeCummins。 。 。對於評論的解釋太長了。請參閱下面的解決方案 –

回答

5

在一個合理尺寸的數據集,隨機排序的行和選擇第一個:

...ORDER BY RAND() LIMIT 1; 

您的發言會變成:

$stmt = $db->query(
    'SELECT * from table1 
    WHERE Category LIKE "%green%" 
    ORDER BY RAND() LIMIT 1;' 
); 

如果您縮小在您的查詢的選擇,你將不再需要使用一個混亂的過程,從結果在你的PHP代碼中設置提取單行。

如果您的數據集非常大,可以考慮執行多個查詢,建議由Tobias Hagenbeek:

  1. COUNT()匹配的行。
  2. 在PHP中,從1到COUNT()的結果中選擇一個隨機數。
  3. 執行新的查詢選擇指定行:

    ...LIMIT <random number>, 1;

最後,如果你只需要一個單一的,亂排和隨機性/獨特性是不是一個問題,可以考慮選擇第​​一行從每一個由戈登·利諾夫建議的時間表:

...LIMIT 1; 
+1

只在小數據集上使用「ORDER BY RAND」;其效率非常低 – 2013-05-16 19:53:50

+0

即使數據集很大,這是否可能比返回和解析整個結果集更快? –

+0

是的,但這不是 – 2013-05-16 20:05:58

0

簡單的方法是這樣的:

$stmt = $db->query('SELECT * from table1 WHERE Category LIKE "%green%" ORDER BY RAND()'); 

ORDER BY RAND()將隨機命令結果,但它作爲一個操作(link)有點貴。

如果您關心這類事情,您可以查詢表中的行數,然後在查詢結束時執行$r = rand(0, $count-1),然後執行LIMIT 1 OFFSET $r

0

你可以使用ORDER BY RAND(),但是你應該很疲倦。特別是如果你正在談論大型系統,並且多於10K行。

這是爲什麼......

當你運行這樣的查詢時會發生什麼?假設您在具有10000行的表上運行此查詢,而不是SQL服務器生成10000個隨機數,則會掃描最小的數字併爲您提供此行。生成隨機數字是相對昂貴的操作,將它們掃描爲最低的一個(如果您有極限10,則需要查找10個最小數字)也不是那麼快(如果引用是文本,則速度較慢,如果它是固定大小的東西速度更快,可能是因爲需要創建臨時表)。

所以,你應該做的是在你行的計數,在0與您的計數1之間的隨機數,然後做FROM表上限$ generated_number SELECT列,1

0

如果希望只有一行從所有行的集合中,最快的方法是:

SELECT * 
from table1 
WHERE Category LIKE "%green%" 
LIMIT 1; 

這會給你在數據中遇到的第一行。近似地說,這是插入到符合條件的表格中的第一行。 (這是不是保證。例如,刪除肯定可以改變這一點。)

這有是fast'ish,因爲索引不會對where子句中受益,這是有用的優勢。在這種情況下,查詢執行全表掃描,但在第一次匹配時停止。

一個真正的隨機行的選擇是使用rand()

SELECT * 
from table1 
WHERE Category LIKE "%green%" 
order by rand() 
limit 1; 

這需要全表掃描,因爲需要的那種所有比賽並不能阻止。然後你有額外的開銷,通過rand()對子集進行排序。有一些替代方案,如果表現真的是一個問題。