来自数据库表的随机记录(T-SQL)

时间:2008-10-10 13:45:45

标签: sql-server tsql random

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

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

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

想法?

6 个答案:

答案 0 :(得分:132)

  

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

SELECT TOP 1 * FROM table ORDER BY NEWID()

说明

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

注释

  1. 自第四版以来,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

  2. 替代SELECT TOP 1 * FROM table ORDER BY RAND()将无法正常运作。 RAND()每个查询返回一个值,因此所有行都将共享相同的值。

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

  4. 大约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是要作为样本检索的数据的百分比。

     

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