2008-10-10 36 views
57

是否有簡潔的方式從sql server表中檢索隨機記錄?從數據庫表中隨機的記錄(T-SQL)

我想隨機化我的單元測試數據,所以我正在尋找一種簡單的方法從表中選擇一個隨機ID。在英文中,select將是「從表中選擇一個id,其中id是表中最低id和表中最高id之間的隨機數。」

我找不到一個方法來做到這一點,而不必運行查詢,測試一個空值,然後重新運行,如果爲空。

想法?

+2

您確定要採取這種方法嗎?單元測試數據不應該是隨機的 - 事實上,無論您執行單元測試的次數多少,您都應該保證得到相同的結果。擁有隨機數據可能會違反單元測試的基本原則。 – rein 2009-05-08 10:27:56

+0

這裏有幾個方法http://www.brettb.com/SQL_Help_Random_Numbers.asp – Adrian 2008-10-10 13:49:13

回答

103

是否有一種簡潔的方式從sql server表中檢索一個隨機記錄?

SELECT TOP 1 * FROM table ORDER BY NEWID() 

說明

NEWID()爲每行被生成並且該表,然後通過它排序。返回第一條記錄(即具有「最低」GUID的記錄)。

  1. 的GUID作爲僞隨機數,因爲4版本生成:

    版本4 UUID是指用於從真正隨機的或 僞隨機數生成的UUID。

    的算法如下:

    • 設置兩個最顯著位clock_seq_hi_and_reserved分別0和1的 (比特6和7)。
    • 將 time_hi_and_version字段的四個最高有效位(位12至15)設置爲 的4.1位的4位版本號。
    • 將所有其他位隨機(或僞隨機)設置爲 值。

    A Universally Unique IDentifier (UUID) URN Namespace - RFC 4122

  2. 正如人們所認爲的替代SELECT TOP 1 * FROM table ORDER BY RAND()將無法​​正常工作。 RAND()每個查詢返回一個單一值,因此所有行將共享相同的值。

  3. 雖然GUID值是僞隨機的,但對於要求更高的應用程序,您將需要更好的PRNG。

  4. 對於大約1,000,000行,典型性能不到10秒—當然取決於系統。請注意,不可能達到指數,因此表現會相對有限。

+6

這很有效,但是人,它很慢。有一個更快的方法... – 2008-10-10 13:49:01

+1

它不是很慢。我們在談論多少條記錄? – Sklivvz 2008-10-10 13:51:19

+0

正是我在找的東西。我有一種感覺,比我做得更簡單。 – Jeremy 2008-10-10 13:53:08

5

也可以嘗試你的方法來獲取和MIN(ID)和MAX(Id)的之間的隨機ID,然後在

SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid 

它總是讓你一行。

17

在較大的表格上,您也可以使用TABLESAMPLE來避免掃描整個表格。

SELECT TOP 1 * 
FROM YourTable 
TABLESAMPLE (1000 ROWS) 
ORDER BY NEWID() 

ORDER BY NEWID仍然需要避免只返回數據頁上第一個出現的行。

要使用的數字需要仔細選擇表的大小和定義,如果沒有行返回,您可能會考慮重試邏輯。數學背後,爲什麼這種技術不適合小桌子是discussed here

0

我正在尋找改進我嘗試過的方法,並遇到這篇文章。我意識到這是舊的,但這種方法沒有列出。我正在創建和應用測試數據;這顯示了在一個名爲與@st SP「地址」的方法(兩個char狀態)

Create Table ##TmpAddress (id Int Identity(1,1), street VarChar(50), city VarChar(50), st VarChar(2), zip VarChar(5)) 
Insert Into ##TmpAddress(street, city, st, zip) 
Select street, city, st, zip 
From tbl_Address (NOLOCK) 
Where st = @st 


-- unseeded RAND() will return the same number when called in rapid succession so 
-- here, I seed it with a guaranteed different number each time. @@ROWCOUNT is the count from the most recent table operation. 

Set @csr = Ceiling(RAND(convert(varbinary, newid())) * @@ROWCOUNT) 

Select street, city, st, Right(('00000' + ltrim(zip)),5) As zip 
From ##tmpAddress (NOLOCK) 
Where id = @csr 
3

如果要選擇大的數據,我知道是最好的方式:

SELECT * FROM Table1 
WHERE (ABS(CAST(
    (BINARY_CHECKSUM 
    (keycol1, NEWID())) as int)) 
    % 100) < 10 

來源:MSDN

相關問題