2008-10-10 88 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