是否有一种简洁的方法从sql server表中检索一个随机记录?
我想要随机化我的单元测试数据,因此正在寻找一种简单的方式从表中选择一个随机id。用英语来说,查询应为“从表中选择一个id,其中id是在表中最低id和最高id之间的随机数。”
我无法想出一种不必运行查询、测试空值,然后重新运行的方法。
有什么好的想法吗?
是否有一种简洁的方法从sql server表中检索一个随机记录?
我想要随机化我的单元测试数据,因此正在寻找一种简单的方式从表中选择一个随机id。用英语来说,查询应为“从表中选择一个id,其中id是在表中最低id和最高id之间的随机数。”
我无法想出一种不必运行查询、测试空值,然后重新运行的方法。
有什么好的想法吗?
有没有一种简洁的方式从SQL Server表中检索随机记录?
是的。
SELECT TOP 1 * FROM table ORDER BY NEWID()
对于每个行,都会生成一个NEWID()
,然后按照它进行排序。返回第一条记录(即具有“最低”GUID的记录)。
从第四版开始,GUID被生成为伪随机数:
第4版UUID用于从真正随机或伪随机数生成UUID。
算法如下:
- 将clock_seq_hi_and_reserved的最高有效位(位6和7)分别设置为零和一。
- 将time_hi_and_version字段的四个最高有效位(位12到15)设置为第4.1.3节中的4位版本号。
- 将所有其他位设置为随机(或伪随机)选择的值。
替代方案SELECT TOP 1 * FROM table ORDER BY RAND()
不能按照人们的想法工作。RAND()
每次查询只返回一个单一值,因此所有行将共享相同的值。
虽然GUID值是伪随机的,但对于更苛刻的应用程序,您需要更好的PRNG。
典型性能为大约1,000,000行少于10秒 - 当然取决于系统。请注意,无法命中索引,因此性能将相对有限。
对于较大的表,您也可以使用 TABLESAMPLE
来避免扫描整个表。
SELECT TOP 1 *
FROM YourTable
TABLESAMPLE (1000 ROWS)
ORDER BY NEWID()
为了避免仅返回出现在数据页上的行,仍需使用ORDER BY NEWID
。
需要仔细选择用于表的大小和定义的数字,并且如果未返回任何行,则可能考虑重试逻辑。该技术背后的数学原理以及为什么不适用于小表在此处进行了讨论。
TOP 1
的情况下,同一页上的行是否相关并不重要。你只需要选择其中一个。 - Martin Smith也尝试使用你的方法获取介于MIN(Id)和MAX(Id)之间的随机Id,然后
SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid
它将始终获取一行数据。
SELECT * FROM Table1
WHERE (ABS(CAST(
(BINARY_CHECKSUM
(keycol1, NEWID())) as int))
% 100) < 10
Source: MSDN
我正在寻找改进我尝试过的方法,并偶然看到了这篇文章。我意识到它很旧,但是这种方法并未列出。我正在创建和应用测试数据;这展示了一个名为 @st (两个字符州)的存储过程中“地址”字段的方法。
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
SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
来源:http://technet.microsoft.com/en-us/library/ms189108(v=sql.105).aspx
这是如何工作的?让我们拆分WHERE子句并解释一下。