如何使用纯 SQL 选择 N 个随机行?
Posted
技术标签:
【中文标题】如何使用纯 SQL 选择 N 个随机行?【英文标题】:How to select N random rows using pure SQL? 【发布时间】:2010-09-28 15:46:57 【问题描述】:我们如何结合How to request a random row in SQL? 和Multiple random values in SQL Server 2005 使用单个纯SQL 查询选择N 个随机行?理想情况下,如果可能,我想避免使用存储过程。这甚至可能吗?
澄清:
-
纯 SQL 是指尽可能接近 ANSI/ISO 标准。
解决方案应该“足够高效”。授予 ORDER BY RAND() 可能有效,但正如其他人指出的那样,这对于中型表是不可行的。
【问题讨论】:
【参考方案1】:您的问题的答案在第二个链接中:
SELECT * FROM table ORDER BY RAND() LIMIT 1
只需更改限制,和/或重写 SQL Server:
SELECT TOP 1 * FROM table ORDER BY newid()
现在,这个严格回答了你的问题,但你真的不应该使用这个解决方案。只需在一张大桌子上试一试,您就会明白我的意思。
如果您的键空间是连续的,要么没有孔,要么只有很少的孔,并且如果它的孔很少,您不必太担心某些行被选中的机会比其他行略高,那么您可以使用变体计算要随机检索的键,范围从 1 到表中的最高键,然后检索键等于或大于您计算的数字的第一行。如果您的键空间有孔,您只需要“高于”部分。
此 SQL 留给读者作为练习。
编辑:请注意,此处对另一个答案的评论提到,pure SQL 可能意味着 ANSI 标准 SQL。如果是这样,那就没有办法了,因为没有标准化的随机函数,也不是每个数据库引擎都以相同的方式对待随机数函数。我见过的至少一个引擎通过调用一次并为所有行重复计算值来“优化”调用。
【讨论】:
NEWID() 如果您想要真正的随机样本,这是一个坏主意,GUID 有很多结构。如果您不在乎是否真的很随机,请继续。【参考方案2】:我不了解纯 ANSI,这并不简单,但您可以在此处查看我对类似问题的回答: Simple Random Samples from a Sql database
【讨论】:
如果假设 #3 为假(即您的桌子有孔),我不清楚如何实施您的建议。 你必须重写整个表,所以假设 #3 是正确的,所以这是一个非常慢的 O(n) 操作。创建一个与原始表具有相同列的新表,以及一个没有间隙的新主键的标识列。然后将整个原始表插入到新表中。【参考方案3】:这是一个潜在的解决方案,它可以让您在获得少于 N 行的风险与表格“前面”的抽样偏差之间取得平衡。这假设 N 与表的大小相比较小:
select * from table where random() < (N / (select count(1) from table)) limit N;
这通常会对表的大部分进行采样,但可以返回少于 N 行。如果有一些偏差是可以接受的,那么分子可以从 N 更改为 1.5*N 或 2*N 以使返回 N 行的可能性很大。此外,如果需要随机化行顺序,而不仅仅是选择一个随机子集:
select * from (select * from table
where random() < (N / (select count(1) from table)) limit N)
order by mod(tableid,1111);
这个解决方案的缺点是,至少在 PostgreSQL 中,它使用表的顺序扫描。较大的分子会加快查询速度。
【讨论】:
【参考方案4】:这可能对你有帮助:
SELECT TOP 3 * FROM TABLE ORDER BY NEWID()
【讨论】:
-1,已被 ***.com/a/396946/14731 覆盖,并且不是纯 SQL(newid() 是 Microsoft 特有的)。【参考方案5】:使用下面的代码,您可以达到您想要的效果..
select top 1 * from student1 order by newid()
将 N 的值更改为前 1,这样您将收到该数量的随机记录。
【讨论】:
-1,已经被 ***.com/a/396946/14731 覆盖并且不是纯 SQL(newid() 是 Microsoft 特有的)。以上是关于如何使用纯 SQL 选择 N 个随机行?的主要内容,如果未能解决你的问题,请参考以下文章
Hibernate Criteria API:获取 n 个随机行