93

是否有一种简洁的方法可以从 sql server 表中检索随机记录?

我想随机化我的单元测试数据,所以我正在寻找一种从表中选择随机 id 的简单方法。在英语中,选择将是“从表中选择一个 id,其中 id 是表中最低 id 和表中最高 id 之间的随机数。”

如果不必运行查询,测试空值,然后如果为空,则重新运行,我无法找到一种方法。

想法?

4

6 回答 6

159

是否有一种简洁的方法可以从 sql server 表中检索随机记录?

是的

SELECT TOP 1 * FROM table ORDER BY NEWID()

解释

为每一行生成A NEWID(),然后按它对表进行排序。返回第一条记录(即具有“最低”GUID 的记录)。

笔记

  1. GUID 从第四版开始生成为伪随机数:

    第 4 版 UUID 用于从真正随机或伪随机数生成 UUID。

    算法如下:

    • 将clock_seq_hi_and_reserved 的两个最高有效位(位6 和7)分别设置为零和一。
    • 将 time_hi_and_version 字段的四个最高有效位(位 12 到 15)设置为 4.1.3 节中的 4 位版本号。
    • 将所有其他位设置为随机(或伪随机)选择的值。

    通用唯一标识符 (UUID) URN 命名空间 - RFC 4122

  2. 替代方案SELECT TOP 1 * FROM table ORDER BY RAND()不会像人们想象的那样起作用。RAND()每个查询返回一个值,因此所有行将共享相同的值。

  3. 虽然 GUID 值是伪随机的,但对于要求更高的应用程序,您将需要更好的 PRNG。

  4. 大约 1,000,000 行的典型性能不到 10 秒——当然取决于系统。请注意,不可能命中索引,因此性能将相对有限。

于 2008-10-10T13:46:58.703 回答
28

在较大的表上,您也可以使用TABLESAMPLE它来避免扫描整个表。

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

ORDER BY NEWID仍然需要避免只返回首先出现在数据页上的行。

需要根据表的大小和定义仔细选择要使用的数字,如果没有返回行,您可能会考虑重试逻辑。这里讨论了这背后的数学以及为什么该技术不适合小表

于 2012-08-26T10:24:27.650 回答
10

也尝试你的方法来获得 MIN(Id) 和 MAX(Id) 之间的随机 Id,然后

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

它总是会让你排一排。

于 2008-10-10T14:13:06.030 回答
7

如果您想选择大数据,我知道的最好方法是:

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

资料来源:MSDN

于 2013-12-16T08:33:56.417 回答
0

我正在寻求改进我尝试过的方法并遇到了这篇文章。我意识到它很旧,但没有列出这种方法。我正在创建和应用测试数据;这显示了用@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
于 2013-09-17T18:58:50.230 回答
0

如果您真的想要单个行的随机样本,请修改您的查询以随机过滤掉行,而不是使用 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 是作为样本检索的数据的百分比。

来源:https ://www.mssqltips.com/sqlservertip/3157/different-ways-to-get-random-data-for-sql-server-data-sampling

于 2019-10-21T14:03:04.597 回答