是否有一种简洁的方法可以从 sql server 表中检索随机记录?
我想随机化我的单元测试数据,所以我正在寻找一种从表中选择随机 id 的简单方法。在英语中,选择将是“从表中选择一个 id,其中 id 是表中最低 id 和表中最高 id 之间的随机数。”
如果不必运行查询,测试空值,然后如果为空,则重新运行,我无法找到一种方法。
想法?
是否有一种简洁的方法可以从 sql server 表中检索随机记录?
我想随机化我的单元测试数据,所以我正在寻找一种从表中选择随机 id 的简单方法。在英语中,选择将是“从表中选择一个 id,其中 id 是表中最低 id 和表中最高 id 之间的随机数。”
如果不必运行查询,测试空值,然后如果为空,则重新运行,我无法找到一种方法。
想法?
是否有一种简洁的方法可以从 sql server 表中检索随机记录?
是的
SELECT TOP 1 * FROM table ORDER BY NEWID()
为每一行生成A 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
仍然需要避免只返回首先出现在数据页上的行。
需要根据表的大小和定义仔细选择要使用的数字,如果没有返回行,您可能会考虑重试逻辑。这里讨论了这背后的数学以及为什么该技术不适合小表
也尝试你的方法来获得 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
资料来源:MSDN
我正在寻求改进我尝试过的方法并遇到了这篇文章。我意识到它很旧,但没有列出这种方法。我正在创建和应用测试数据;这显示了用@st(两个字符状态)调用的SP中“地址”的方法
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
如果您真的想要单个行的随机样本,请修改您的查询以随机过滤掉行,而不是使用 TABLESAMPLE。例如,以下查询使用 NEWID 函数返回 Sales.SalesOrderDetail 表中大约百分之一的行:
SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
SalesOrderID 列包含在 CHECKSUM 表达式中,以便 NEWID() 每行计算一次,以实现逐行抽样。表达式 CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float / CAST (0x7fffffff AS int) 计算为 0 到 1 之间的随机浮点值。”
来源:http ://technet.microsoft.com/en-us/library/ms189108(v=sql.105).aspx
这在下面进一步解释:
这是如何运作的?让我们拆分 WHERE 子句并解释一下。
CHECKSUM 函数正在计算列表中项目的校验和。是否需要 SalesOrderID 是有争议的,因为 NEWID() 是一个返回新随机 GUID 的函数,因此将随机数字乘以常数在任何情况下都应该是随机的。事实上,排除 SalesOrderID 似乎没有什么区别。如果您是一位敏锐的统计学家并且可以证明将其包含在内,请使用下面的评论部分,让我知道为什么我错了!
CHECKSUM 函数返回一个 VARBINARY。对 0x7fffffff(相当于二进制的 (111111111...))执行按位与运算,会产生一个十进制值,它实际上是 0 和 1 的随机字符串的表示。除以系数 0x7fffffff 有效地将这个十进制数字归一化为 0 和 1 之间的数字。然后为了决定每一行是否值得包含在最终结果集中,使用阈值 1/x(在本例中为 0.01),其中x 是作为样本检索的数据的百分比。