【问题标题】:How to select N random rows using pure SQL?如何使用纯 SQL 选择 N 个随机行?
【发布时间】:2010-09-28 15:46:57
【问题描述】:

我们如何结合How to request a random row in SQL?Multiple random values in SQL Server 2005 使用单个纯SQL 查询选择N 个随机行?理想情况下,如果可能,我想避免使用存储过程。这甚至可能吗?

澄清

  1. 纯 SQL 是指尽可能接近 ANSI/ISO 标准。
  2. 解决方案应该“足够高效”。授予 ORDER BY RAND() 可能有效,但正如其他人指出的那样,这对于中型表是不可行的。

【问题讨论】:

    标签: sql random


    【解决方案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()
      

      【讨论】:

      【解决方案5】:

      使用下面的代码,您可以达到您想要的效果..

      select top 1 * from student1 order by newid()
      

      将 N 的值更改为前 1,这样您将收到该数量的随机记录。

      【讨论】:

      • -1,已经被 stackoverflow.com/a/396946/14731 覆盖并且不是纯 SQL(newid() 是 Microsoft 特有的)。
      猜你喜欢
      • 2010-10-25
      • 2016-06-17
      • 2017-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-12
      相关资源
      最近更新 更多