如何在 SQL 中请求随机行?

Posted

技术标签:

【中文标题】如何在 SQL 中请求随机行?【英文标题】:How to request a random row in SQL? 【发布时间】:2010-09-06 08:56:49 【问题描述】:

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

【问题讨论】:

我以前总是在 php 中从 sql 查询结果后执行此操作...根据解决方案的限制 1 附件进行处理可能要快得多 If SQL Server you can use a CLR aggregate to avoid unnecessary sorts 似乎没有在每个 dbms 上运行的“纯 SQL”解决方案......每个 dbms 都有一个解决方案。 性能版:***.com/questions/4329396/… 【参考方案1】:

看到这个帖子:SQL to Select a random row from a database table。它通过在 mysql、PostgreSQL、Microsoft SQL Server、IBM DB2 和 Oracle 中执行此操作的方法(以下是从该链接复制的):

用 MySQL 随机选择一行:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

使用 PostgreSQL 随机选择一行:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

使用 Microsoft SQL Server 随机选择一行:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

使用 IBM DB2 随机选择一行

SELECT column, RAND() as IDX 
FROM table 
ORDER BY IDX FETCH FIRST 1 ROWS ONLY

用 Oracle 随机选择一条记录:

SELECT column FROM
( SELECT column FROM table
ORDER BY dbms_random.value )
WHERE rownum = 1

【讨论】:

-1 用于依赖order by rand() 或所有数据库中的等效项:|。 also mentioned here. 十年前some guy said 使用ORDER BY RAND() 是错误的... ORDER BY NEWID() 在 SQL Server 上似乎明显变慢。我的查询看起来像:从客户 C 中选择前 1000 个 C.CustomerId、CL.LoginName 内部加入 LinkedAccount LA on C.CustomerId=LA.CustomerId 内部加入 CustomerLogin CL on C.CustomerId=CL.CustomerId group by C.CustomerId, CL。具有 count(*)>1 order by NEWID() 的 LoginName 删除“order by NEWID()”行会更快地返回结果。 对于 SQLite 使用 RANDOM() 函数。 这些解决方案无法扩展。它们是O(n)n 是表中的记录数。想象一下,你有 100 万条记录,你真的要生成 100 万个随机数或唯一 id 吗?我宁愿使用 COUNT() 并将其包含在带有单个随机数的新 LIMIT 表达式中。【参考方案2】:

像 Jeremies 这样的解决方案:

SELECT * FROM table ORDER BY RAND() LIMIT 1

工作,但他们需要对所有表进行顺序扫描(因为需要计算与每一行关联的随机值 - 以便可以确定最小的值),即使对于中等大小的表来说,这也可能非常慢。我的建议是使用某种索引数字列(许多表都将这些作为主键),然后编写如下内容:

SELECT * FROM table WHERE num_value >= RAND() * 
    ( SELECT MAX (num_value ) FROM table ) 
ORDER BY num_value LIMIT 1

如果num_value 被索引,则无论表大小如何,这都以对数时间工作。一个警告:这假设num_value0..MAX(num_value) 范围内均匀分布。如果您的数据集严重偏离此假设,您将得到偏斜的结果(某些行会比其他行更频繁地出现)。

【讨论】:

第二个建议不是随机的。您无法预测将被选中的行,但如果您必须下注,您会下注第二行。而且你永远不会赌最后一行,无论你的 num_value 的分布情况和你的桌子有多大,它都不太可能被选中。 我知道通常 RAND() 函数质量不是很高,但除此之外,您能否详细说明为什么选择不是随机的? 第一个在 SQL Server 中是错误的。每个查询只调用一次 RAND() 函数,而不是每行调用一次。所以它总是选择第一行(试试看)。 第二个也假设所有的行都被考虑在内:它可能会选择一个已经被删除的行。 @Sam.Rueby 实际上,num_value >= RAND() ... limit 1 确保将跳过空行,直到找到现有行。【参考方案3】:

不知道效率如何,但我以前用过:

SELECT TOP 1 * FROM MyTable ORDER BY newid()

因为 GUID 是非常随机的,所以排序意味着你得到一个随机的行。

【讨论】:

我正在使用 MS SQL 服务器,SELECT TOP 1 * FROM some_table_name ORDER BY NEWID() 对我来说非常有用,感谢大家的建议! 这和ORDER BY RAND() LIMIT 1一模一样 这也是非常特定于数据库的,因为它使用TOP 1newid() 这是个坏主意。此方法不会使用索引,除非每列都单独建立索引。拥有 1 亿条记录的表可能需要很长时间才能获得一条记录。 @Switch 你会提出什么解决方案?【参考方案4】:
ORDER BY NEWID()

接受7.4 milliseconds

WHERE num_value >= RAND() * (SELECT MAX(num_value) FROM table)

接受0.0065 milliseconds

我肯定会选择后一种方法。

【讨论】:

第二个选项不会选择最后一行。我不知道为什么 - 只是指出来。 @Voldemort: rand() 返回一个浮点数 n 其中0 < n < 1。假设num_value 是一个整数,rand() * max(num_value) 的返回值也将被强制转换为一个整数,从而截断小数点后的任何内容。因此,rand() * max(num_value)总是小于max(num_value),这就是为什么永远不会选择最后一行的原因。 如果我的数据经常被删除,我的效率会很低——如果我发现了差距,我将不得不重新运行整个查询。 @IanKemp 愚蠢的问题,那么为什么不简单地使用 SELECT MAX(num_value) + 1 呢?由于 rand(或在大多数情况下为 RANDOM)返回 [0,1),因此您将获得完整的值范围。另外,是的,你是对的,必须修复一个查询。 @IanKemp @Neel rand() 返回0 <= v < 1.0。 dev.mysql.com/doc/refman/8.0/en/… 它还说明了如何正确地从 0..max_val 中选择一个整数:FLOOR(RAND()*max_val)【参考方案5】:

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

select top 1 * from mytable order by newid()

在 SQL Server 2005 及更高版本中,您可以使用 TABLESAMPLE 获取可重复的随机样本:

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

【讨论】:

MSDN 说 newid() 优于 tablesample 以获得真正的随机结果:msdn.microsoft.com/en-us/library/ms189108.aspx @Andrew Hedges : ORDER BY NEWID() 太贵了 不要使用 TABLESAMPLE - 它返回不精确的行数,并且在使用 (1 ROWS) 时不保证非空结果【参考方案6】:

对于 SQL Server

newid()/order by 会起作用,但对于大型结果集来说会非常昂贵,因为它必须为每一行生成一个 id,然后对它们进行排序。

TABLESAMPLE() 从性能的角度来看是好的,但是你会得到结块的结果(将返回页面上的所有行)。

为了获得更好的真实随机样本,最好的方法是随机过滤掉行。我在 SQL Server 联机丛书文章 Limiting Results Sets by Using TABLESAMPLE 中找到了以下代码示例:

如果你真的想要一个随机样本 个别行,将您的查询修改为 随机过滤掉行,而不是 使用 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 浮动 / CAST (0x7fffffff AS int) 计算结果为 0 到 1 之间的随机浮点值。

当针对具有 1,000,000 行的表运行时,我的结果如下:

SET STATISTICS TIME ON
SET STATISTICS IO ON

/* newid()
   rows returned: 10000
   logical reads: 3359
   CPU time: 3312 ms
   elapsed time = 3359 ms
*/
SELECT TOP 1 PERCENT Number
FROM Numbers
ORDER BY newid()

/* TABLESAMPLE
   rows returned: 9269 (varies)
   logical reads: 32
   CPU time: 0 ms
   elapsed time: 5 ms
*/
SELECT Number
FROM Numbers
TABLESAMPLE (1 PERCENT)

/* Filter
   rows returned: 9994 (varies)
   logical reads: 3359
   CPU time: 641 ms
   elapsed time: 627 ms
*/    
SELECT Number
FROM Numbers
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float) 
              / CAST (0x7fffffff AS int)

SET STATISTICS IO OFF
SET STATISTICS TIME OFF

如果您可以不使用 TABLESAMPLE,它将为您提供最佳性能。否则使用 newid()/filter 方法。如果结果集很大,ne​​wid()/order by 应该是最后的手段。

【讨论】:

【参考方案7】:

如果可能,使用存储语句来避免 RND() 上的两个索引效率低下并创建记录号字段。

PREPARE RandomRecord FROM "SELECT * FROM table LIMIT ?,1"; SET @n=FLOOR(RAND()*(SELECT COUNT(*) FROM table)); 使用@n 执行随机记录;

【讨论】:

当上述 where 子句中使用的索引数值分布不均时,此解决方案还负责返回随机行;因此,即使它与使用 where id_value >= RAND() * MAX(id_value) 花费的时间几乎相同(恒定),也更好。 据我所知,这不是在恒定时间内运行,而是在线性时间内运行。在最坏的情况下,@n 等于表中的行数,并且 "SELECT * FROM table LIMIT ?,1" 计算 @n - 1 行直到它到达最后一行。【参考方案8】:

最好的方法是为此目的在一个新列中放置一个随机值,并使用类似这样的东西(伪代码 + SQL):

randomNo = random()
execSql("SELECT TOP 1 * FROM MyTable WHERE MyTable.Randomness > $randomNo")

这是 MediaWiki 代码采用的解决方案。当然,对于较小的值存在一些偏差,但他们发现当没有获取任何行时,将随机值环绕为零就足够了。

newid() 解决方案可能需要进行全表扫描,以便为每一行分配一个新的 guid,这会降低性能。

rand() 解决方案可能根本不起作用(即使用 MSSQL),因为该函数将只被评估一次,并且 每一 行将被分配相同的“随机”数字。

【讨论】:

当你得到 0 个结果时环绕提供一个可证明的随机样本(不仅仅是“足够好”)。这个解决方案几乎可以扩展到多行查询(想想“party shuffle”)。问题是结果往往会在同一组中重复选择。为了解决这个问题,您需要重新分配刚刚使用的随机数。您可以通过跟踪 randomNo 并将其设置为结果中的 max(randomness) 来作弊,但随后 p(查询 1 上的第 i 行和查询 2 上的第 i 行) == 0,这是不公平的。让我做一些数学运算,然后我会用一个真正公平的方案回复你。【参考方案9】:

对于 SQL Server 2005 和 2008,如果我们想要单个行的随机样本(来自 Books Online):

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)

【讨论】:

【参考方案10】:

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

另一种方法是使用 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。

【讨论】:

【参考方案11】:

Insted of using RAND(), as it is not encouraged,您可以简单地获得最大 ID (=Max):

SELECT MAX(ID) FROM TABLE;

获取 1..Max (=My_Generated_Random) 之间的随机数

My_Generated_Random = rand_in_your_programming_lang_function(1..Max);

然后运行这条 SQL:

SELECT ID FROM TABLE WHERE ID >= My_Generated_Random ORDER BY ID LIMIT 1

请注意,它将检查 ID 等于或高于所选值的任何行。 也可以在表中向下寻找行,得到一个等于或小于 My_Generated_Random 的 ID,然后像这样修改查询:

SELECT ID FROM TABLE WHERE ID <= My_Generated_Random ORDER BY ID DESC LIMIT 1

【讨论】:

如果生成的随机ID不再存在于表中会怎样?您不想向用户显示的已删除或被动行会造成麻烦。 没什么。你得到的是最接近的,不准确的,身份证号码。如果你认为 id=1 被移除,则用 minimum 交换 1。【参考方案12】:

正如@BillKarwin 对@cnu 回答的评论中指出的那样......

当与 LIMIT 结合使用时,我发现使用随机排序而不是直接排序实际行,它的性能要好得多(至少在 PostgreSQL 9.1 中):例如

SELECT * FROM tbl_post AS t
JOIN ...
JOIN ( SELECT id, CAST(-2147483648 * RANDOM() AS integer) AS rand
       FROM tbl_post
       WHERE create_time >= 1349928000
     ) r ON r.id = t.id
WHERE create_time >= 1349928000 AND ...
ORDER BY r.rand
LIMIT 100

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

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

【讨论】:

【参考方案13】:

让 MySQL 获取随机记录

 SELECT name
  FROM random AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(id)
                        FROM random)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1

更多详情http://jan.kneschke.de/projects/mysql/order-by-rand/

【讨论】:

在测试了许多答案后,我相信这是最好的答案。它似乎很快并且每次都选择一个好的随机数。它似乎类似于上面@GreyPanther 的第二个建议,但这个答案选择了更多随机数。【参考方案14】:

使用 SQL Server 2012+,您可以使用 OFFSET FETCH query 对单个随机行执行此操作

select  * from MyTable ORDER BY id OFFSET n ROW FETCH NEXT 1 ROWS ONLY

其中 id 是标识列,n 是您想要的行 - 计算为表的 0 和 count()-1 之间的随机数(偏移量 0 毕竟是第一行)

这适用于表数据中的漏洞,只要您有用于 ORDER BY 子句的索引即可。它对随机性也很有好处——当你自己解决这个问题时,其他方法中的小问题不存在。此外,性能相当不错,在较小的数据集上表现良好,尽管我还没有尝试过对几百万行进行严格的性能测试。

【讨论】:

【参考方案15】:

对于 SQL Server 并且需要“单个随机行”..

如果不需要真正的采样,则生成一个随机值[0, max_rows) 并使用ORDER BY..OFFSET..FETCH from SQL Server 2012+。

如果COUNTORDER BY 超过适当的索引,这非常快 - 这样数据就已经按照查询行“已经排序”了。如果涵盖了这些操作,这是一个快速请求,并且不会受到使用 ORDER BY NEWID() 或类似的可怕的可扩展性的影响。显然,这种方法在非索引 HEAP 表上不能很好地扩展。

declare @rows int
select @rows = count(1) from t

-- Other issues if row counts in the bigint range..
-- This is also not 'true random', although such is likely not required.
declare @skip int = convert(int, @rows * rand())

select t.*
from t
order by t.id -- Make sure this is clustered PK or IX/UCL axis!
offset (@skip) rows
fetch first 1 row only

确保使用适当的事务隔离级别和/或考虑 0 个结果。


对于 SQL Server 并且需要“通用行样本”方法..

注意:这是对on a SQL Server specific question about fetching a sample of rows 的答案的改编。 它是根据上下文量身定制的。

虽然在此处应谨慎使用一般抽样方法,但在其他答案(以及非缩放和/或有问题的实现的重复建议)的上下文中,它仍然可能是有用的信息。这种抽样方法比显示的第一个代码效率低,并且如果目标是找到“单个随机行”,则容易出错。


这是一种更新和改进的对一定百分比的行进行采样的形式。它基于使用 CHECKSUM / BINARY_CHECKSUM 和模数的其他一些答案的相同概念。

在庞大的数据集上相对较快并且可以有效地用于派生查询中/与派生查询一起使用。可以在几秒钟内对数百万个预过滤行进行采样无需使用 tempdb,如果与查询的其余部分保持一致,开销通常是最小的。

不会受到 CHECKSUM(*) / BINARY_CHECKSUM(*) 数据运行问题的影响。 当使用 CHECKSUM(*) 方法时,可以在“块”中选择行,而不是“随意”!这是因为 CHECKSUM 更喜欢速度而不是分布

导致稳定/可重复行选择,并且可以通过简单的更改以在后续查询执行中生成不同的行。使用NEWID() 的方法永远不会稳定/可重复。

不使用整个输入集的ORDER BY NEWID(),因为对于大型输入集,排序可能成为一个重要的瓶颈避免不必要的排序也减少内存和临时数据库的使用

不使用TABLESAMPLE,因此可以使用WHERE 前置过滤器。

这里是要点。 See this answer for additional details and notes.

天真的尝试:

declare @sample_percent decimal(7, 4)
-- Looking at this value should be an indicator of why a
-- general sampling approach can be error-prone to select 1 row.
select @sample_percent = 100.0 / count(1) from t

-- BAD!
-- When choosing appropriate sample percent of "approximately 1 row"
-- it is very reasonable to expect 0 rows, which definitely fails the ask!
-- If choosing a larger sample size the distribution is heavily skewed forward,
-- and is very much NOT 'true random'.
select top 1
    t.*
from t
where 1=1
    and ( -- sample
        @sample_percent = 100
        or abs(
            convert(bigint, hashbytes('SHA1', convert(varbinary(32), t.rowguid)))
        ) % (1000 * 100) < (1000 * @sample_percent)
    )

这可以通过混合查询在很大程度上得到解决,方法是混合采样和ORDER BY小得多的样本集中进行选择。这将排序操作限制为样本大小,而不是原始表的大小。

-- Sample "approximately 1000 rows" from the table,
-- dealing with some edge-cases.
declare @rows int
select @rows = count(1) from t

declare @sample_size int = 1000
declare @sample_percent decimal(7, 4) = case
    when @rows <= 1000 then 100                              -- not enough rows
    when (100.0 * @sample_size / @rows) < 0.0001 then 0.0001 -- min sample percent
    else 100.0 * @sample_size / @rows                        -- everything else
    end

-- There is a statistical "guarantee" of having sampled a limited-yet-non-zero number of rows.
-- The limited rows are then sorted randomly before the first is selected.
select top 1
    t.*
from t
where 1=1
    and ( -- sample
        @sample_percent = 100
        or abs(
            convert(bigint, hashbytes('SHA1', convert(varbinary(32), t.rowguid)))
        ) % (1000 * 100) < (1000 * @sample_percent)
    )
-- ONLY the sampled rows are ordered, which improves scalability.
order by newid()

【讨论】:

【参考方案16】:

这里的大多数解决方案旨在避免排序,但它们仍然需要对表进行顺序扫描。

还有一种方法可以通过切换到索引扫描来避免顺序扫描。如果您知道随机行的索引值,您几乎可以立即获得结果。问题是——如何猜测一个索引值。

以下解决方案适用于 PostgreSQL 8.4:

explain analyze select * from cms_refs where rec_id in 
  (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
   from generate_series(1,10))
  limit 1;

我在上面的解决方案中,您猜测 0 .. [id 的最后一个值] 范围内的 10 个不同的随机索引值。

数字 10 是任意的 - 您可以使用 100 或 1000,因为它(令人惊讶地)对响应时间没有太大影响。

还有一个问题 - 如果您的 id 稀疏您可能会错过。解决方案是有一个备份计划 :) 在这种情况下,通过 random() 查询纯旧订单。当组合 id 看起来像这样:

explain analyze select * from cms_refs where rec_id in 
    (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
     from generate_series(1,10))
    union all (select * from cms_refs order by random() limit 1)
    limit 1;

不是 union ALL 子句。在这种情况下,如果第一部分返回任何数据,则第二部分永远不会执行!

【讨论】:

【参考方案17】:

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

只需通过new id() 函数编写您的查询并使用订单。很随意。

【讨论】:

【参考方案18】:

还没有完全看到答案中的这种变化。我有一个额外的约束,我需要一个初始种子,每次都选择相同的行集。

对于 MS SQL:

最小示例:

select top 10 percent *
from table_name
order by rand(checksum(*))

标准化执行时间:1.00

NewId() 示例:

select top 10 percent *
from table_name
order by newid()

标准化执行时间:1.02

NewId()rand(checksum(*)) 慢一点,因此您可能不想将它用于处理大型记录集。

使用初始种子选择:

declare @seed int
set @seed = Year(getdate()) * month(getdate()) /* any other initial seed here */

select top 10 percent *
from table_name
order by rand(checksum(*) % seed) /* any other math function here */

如果您需要在给定种子的情况下选择相同的集合,这似乎可行。

【讨论】:

【参考方案19】:

在 MSSQL(在 11.0.5569 上测试)中使用

SELECT TOP 100 * FROM employee ORDER BY CRYPT_GEN_RANDOM(10)

明显快于

SELECT TOP 100 * FROM employee ORDER BY NEWID()

【讨论】:

【参考方案20】:

对于火鸟:

Select FIRST 1 column from table ORDER BY RAND()

【讨论】:

【参考方案21】:

在 SQL Server 中,您可以将 TABLESAMPLE 与 NEWID() 结合使用以获得相当好的随机性并且仍然具有速度。如果您真的只需要 1 行或少量行,这将特别有用。

SELECT TOP 1 * FROM [table] 
TABLESAMPLE (500 ROWS) 
ORDER BY NEWID()

【讨论】:

TABLESAMPLE 的一大缺点是它在任何过滤之前应用。【参考方案22】:
 SELECT * FROM table ORDER BY RAND() LIMIT 1

【讨论】:

十年前 (2005) 有人said 认为使用ORDER BY RAND() 是错误的...【参考方案23】:

我必须同意 CD-MaN:使用“ORDER BY RAND()”对于小桌子或只执行几次 SELECT 时效果很好。

我还使用“num_value >= RAND() * ...”技术,如果我真的想要随机结果,我会在表中设置一个特殊的“随机”列,我每天大约更新一次。单次 UPDATE 运行需要一些时间(尤其是因为您必须在该列上建立索引),但它比每次运行 select 时为每一行创建随机数要快得多。

【讨论】:

【参考方案24】:

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

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

这个 TableSample 的 MSDN 页面包含一个如何生成实际随机数据样本的示例。

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

【讨论】:

【参考方案25】:

似乎列出的许多想法仍然使用排序

但是,如果您使用临时表,则可以分配一个随机索引(就像许多解决方案所建议的那样),然后获取第一个大于 0 到 1 之间任意数字的索引。

例如(对于 DB2):

WITH TEMP AS (
SELECT COMLUMN, RAND() AS IDX FROM TABLE)
SELECT COLUMN FROM TABLE WHERE IDX > .5
FETCH FIRST 1 ROW ONLY

【讨论】:

在考虑了这个解决方案之后,我发现我的逻辑存在根本缺陷。这将始终在表的开头附近返回相同的小设置值,因为我假设如果在 0 和 1 之间存在均匀分布,则第一行有 50% 的机会满足该标准。【参考方案26】:

来自http://akinas.com/pages/en/blog/mysql_random_row/的简单高效的方法

SET @i = (SELECT FLOOR(RAND() * COUNT(*)) FROM table); PREPARE get_stmt FROM 'SELECT * FROM table LIMIT ?, 1'; EXECUTE get_stmt USING @i;

【讨论】:

【参考方案27】:

Oracle 有更好的解决方案,而不是使用 dbms_random.value,但它需要完全扫描才能按 dbms_random.value 对行进行排序,而且对于大型表来说速度很慢。

改用这个:

SELECT *
FROM employee sample(1)
WHERE rownum=1

【讨论】:

【参考方案28】:

对于 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)
)

【讨论】:

【参考方案29】:
select r.id, r.name from table AS r
INNER JOIN(select CEIL(RAND() * (select MAX(id) from table)) as id) as r1
ON r.id >= r1.id ORDER BY r.id ASC LIMIT 1

这将需要更少的计算时间

【讨论】:

【参考方案30】:

来自 sql 的随机函数可能会有所帮助。此外,如果您想限制为一行,只需在最后添加即可。

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

【讨论】:

以上是关于如何在 SQL 中请求随机行?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 SQL 数据库表中选择随机行? [复制]

如何使用纯 SQL 选择 N 个随机行?

SQL - 如何选择随机行,直到该行的总值为某个数字?

从 CockroachDB 中的“SELECT”返回随机行

通过 SQLAlchemy 获取随机行

如何在 Postgres 中从具有非均匀分布的表中选择随机行?