是否有一种简洁的方法从sql server表中检索随机记录?
我想随机化我的单元测试数据,所以我正在寻找一种从表中选择随机id的简单方法。在英语中,select将是“从表中选择一个id,其中id是表中最低id和表中最高id之间的随机数。”
我无法找到一种方法,无需运行查询,测试空值,然后重新运行,如果为null。
想法?
答案 0 :(得分:132)
是否有一种从sql server表中检索随机记录的简洁方法?
是
SELECT TOP 1 * FROM table ORDER BY NEWID()
为每一行生成NEWID()
,然后按表对其进行排序。返回第一个记录(即具有“最低”GUID的记录)。
自第四版以来,GUID生成为伪随机数:
版本4 UUID用于从真正随机或生成UUID生成UUID 伪随机数。
算法如下:
- 设置两个最高有效位(第6位和第7位) clock_seq_hi_and_reserved分别为零和一。
- 设置的四个最高有效位(位12到15) time_hi_and_version字段为4位版本号 第4.1.3节。
- 将所有其他位设置为随机(或伪随机)选择 值。
- A Universally Unique IDentifier (UUID) URN Namespace - RFC 4122
替代SELECT TOP 1 * FROM table ORDER BY RAND()
将无法正常运作。 RAND()
每个查询返回一个值,因此所有行都将共享相同的值。
虽然GUID值是伪随机的,但对于要求更高的应用程序,您需要更好的PRNG。
大约1,000,000行的典型性能不到10秒 - 当然取决于系统。请注意,不可能达到指数,因此性能将相对有限。
答案 1 :(得分:22)
在较大的表格上,您也可以使用TABLESAMPLE
来避免扫描整个表格。
SELECT TOP 1 *
FROM YourTable
TABLESAMPLE (1000 ROWS)
ORDER BY NEWID()
仍然需要ORDER BY NEWID
以避免仅返回首先出现在数据页上的行。
需要根据表的大小和定义仔细选择要使用的数字,如果没有返回行,您可以考虑重试逻辑。这背后的数学以及该技术不适合小表的原因是discussed here
答案 2 :(得分:7)
同时尝试使用您的方法在MIN(Id)和MAX(Id)之间获得随机ID,然后
SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid
总能让你排成一排。
答案 3 :(得分:6)
如果您想选择大数据,我知道的最佳方式是:
SELECT * FROM Table1
WHERE (ABS(CAST(
(BINARY_CHECKSUM
(keycol1, NEWID())) as int))
% 100) < 10
来源:MSDN
答案 4 :(得分:0)
我一直希望改进我尝试过的方法,并且发现了这篇文章。我意识到它已经过时了,但是没有列出这种方法。我正在创建和应用测试数据;这显示了&#34;地址&#34;的方法。在使用@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
答案 5 :(得分:0)
如果您确实想要随机收集单个行的样本,请修改查询以随机过滤掉行,而不是使用TABLESAMPLE。例如,以下查询使用NEWID函数返回Sales.SalesOrderDetail表的大约百分之一的行:
SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
CHECKKSUM表达式中包含SalesOrderID列,以便 NEWID()每行评估一次以实现每行采样。 表达式CAST(CHECKSUM(NEWID(),SalesOrderID)&0x7fffffff AS float / CAST(0x7fffffff AS int)计算为随机float值 在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是要作为样本检索的数据的百分比。