有没有一种简洁的方法可以从sql server表中检索随机记录?
我想将单元测试数据随机化,因此正在寻找一种从表中选择随机ID的简单方法。用英语来说,选择将是“从表中选择一个ID,其中ID是表中最低ID和表中最高ID之间的随机数”。
我无法找到一种方法,而不必运行查询,测试null值,然后如果为null则重新运行。
有想法吗?
有没有一种简洁的方法可以从sql server表中检索随机记录?
我想将单元测试数据随机化,因此正在寻找一种从表中选择随机ID的简单方法。用英语来说,选择将是“从表中选择一个ID,其中ID是表中最低ID和表中最高ID之间的随机数”。
我无法找到一种方法,而不必运行查询,测试null值,然后如果为null则重新运行。
有想法吗?
Answers:
有没有一种简洁的方法可以从sql server表中检索随机记录?
是
SELECT TOP 1 * FROM table ORDER BY NEWID()
NEWID()
为每一行生成一个A ,然后对该表进行排序。返回第一个记录(即具有“最低” 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
同一情况下,同一页面上的行是否相关并不重要。您只选择其中之一。
还尝试使用您的方法来获得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/zh-CN/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