如何在纯SQL中请求随机行(或尽可能接近真正的随机)?


当前回答

要小心,因为TableSample实际上并不返回随机的行样本。它引导您的查询查看组成行的8KB页面的随机样本。然后,对这些页面中包含的数据执行查询。由于数据在这些页面上的分组方式(插入顺序等),这可能导致数据实际上不是随机样本。

参见:http://www.mssqltips.com/tip.asp?tip=1308

该表的MSDN页面包含了如何生成实际随机数据样本的示例。

http://msdn.microsoft.com/en-us/library/ms189108.aspx

其他回答

您也可以尝试使用new id()函数。

只需编写一个查询并使用order by new id()函数。它是随机的。

你没说你用的是哪台服务器。在旧版本的SQL Server中,你可以使用这个:

select top 1 * from mytable order by newid()

在SQL Server 2005及以上版本中,你可以使用TABLESAMPLE来获取一个可重复的随机样本:

SELECT FirstName, LastName
FROM Contact 
TABLESAMPLE (1 ROWS) ;

晚了,但通过谷歌到达这里,所以为了子孙后代,我将添加一个替代解决方案。

另一种方法是使用TOP两次,顺序交替。我不知道它是否是“纯SQL”,因为它在TOP中使用了一个变量,但它在SQL Server 2008中工作。这里有一个例子,如果我想要一个随机的单词,我使用字典单词表。

SELECT TOP 1
  word
FROM (
  SELECT TOP(@idx)
    word 
  FROM
    dbo.DictionaryAbridged WITH(NOLOCK)
  ORDER BY
    word DESC
) AS D
ORDER BY
  word ASC

当然,@idx是目标表上从1到COUNT(*)的随机生成的整数。如果您的列被索引,您也会从中受益。另一个优点是可以在函数中使用它,因为NEWID()是不允许的。

最后,在同一个表上,上述查询的执行时间大约是NEWID()类型查询的1/10。YYMV。

正如@BillKarwin对@cnu回答的评论所指出的那样…

当与LIMIT结合使用时,我发现随机排序的JOIN比直接对实际行进行排序执行得更好(至少在PostgreSQL 9.1中)。 SELECT * FROM tbl_post AS t 加入…… JOIN (SELECT id, CAST(-2147483648 * RANDOM() AS integer) AS rand 从tbl_post WHERE create_time >= 1349928000 ) r ON r.id = t.d id WHERE create_time >= 1349928000 AND… ORDER BY r.r rand 限制100

只要确保“r”为与它连接的复杂查询中的每个可能的键值生成一个“rand”值,但仍然尽可能限制“r”的行数。

CAST as Integer对于PostgreSQL 9.2特别有用,它对整型和单精度浮点类型有特定的排序优化。

对于SQL Server 2005及以上版本,在num_value没有连续值的情况下扩展@GreyPanther的答案。这也适用于数据集分布不均匀以及num_value不是数字而是唯一标识符的情况。

WITH CTE_Table (SelRow, num_value) 
AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY ID) AS SelRow, num_value FROM table
) 

SELECT * FROM table Where num_value = ( 
    SELECT TOP 1 num_value FROM CTE_Table  WHERE SelRow >= RAND() * (SELECT MAX(SelRow) FROM CTE_Table)
)