MySQL RAND() 奇怪的行为

标签 mysql sql database

我正在尝试从 SQL 查询的结果中获取随机行。

我的查询如下

SET @rank = 0;
SELECT * FROM(
     SELECT (@rank:=@rank+1) AS num, ...
     FROM ...
     WHERE ....) as raw
WHERE raw.num = FLOOR(1 + (RAND() * @rank)) LIMIT 1

一般的想法是来自内部查询结果的表的每一行都被赋予一个唯一的数字(num)。我已经手动检查确实是这种情况,并且每一行都已编号。

最后一行让我很苦恼。就目前而言,WHERE num = FLOOR(1 + (RAND() * @rank)) LIMIT 1 返回我想要的 - 只有一半的时间。它似乎返回正确范围内的随机行(对于我正在测试查询的示例是 0-1299)。然而,每三个查询中就有一个完全没有返回任何结果。

好的,所以我认为这可能是一个 double 问题,所以我尝试使用 >= 如下:WHERE num >= FLOOR(1 + (RAND() * @rank )) 限制 1。这种情况下的结果让我感到困惑。使用这段代码,我总能得到一个结果,但返回的行数总是 < 100。

所以如果我们调用 FLOOR(1 + (RAND() * @rank)) x。当我使用 = 而不是 >= 时,它确认 x 必须(在某些情况下)等于大于 1000 的数字。但是,当使用 >=,满足条件的事实意味着 x 必须始终小于 100?

这是怎么回事?或者我还能如何解决我的问题

最佳答案

我认为问题在于查询中的 RAND() 函数被多次调用,从 raw 返回的每一行调用一次。如果是这种情况,那么它可能找不到满足谓词的任何行,因为它将每一行与不同的目标进行比较。 (第一行是第五行吗?第二行是第三行吗?等等)

我会将对 RAND() 的调用和 @rank 的初始赋值移动到查询的开头,如下所示:

SELECT * FROM(
     SELECT (@rank:=@rank+1) AS num, ...
     FROM (SELECT @rand := RAND(), @rank := 0) r
     CROSS JOIN ...
     WHERE ....) as raw
WHERE raw.num = FLOOR(1 + @rand * @rank) LIMIT 1

-- 或者,与您使用单独 SET 语句的模式保持一致 --

SET @rand = RAND();
SET @rank = 0;
SELECT * FROM(
     SELECT (@rank:=@rank+1) AS num, ...
     FROM ...
     WHERE ....) as raw
WHERE raw.num = FLOOR(1 + @rand * @rank) LIMIT 1

(我碰巧更喜欢前者,因为它作为单个语句运行;它不依赖于在 SELECT 语句之外设置的用户变量。)

但其中任何一个都应确保对 RAND() 函数的调用恰好发生一次(在查询开始时)。

除此之外,对于您所看到的行为,我没有很好的解释。

关于MySQL RAND() 奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11401784/

相关文章:

node.js - 使用 Node 服务器连接到 MongoDB 时的警告

mysql - 在 MySQL 中创建外键时遇到问题

php - 当前分页链接未激活,下一页、上一页不起作用

php - 为什么数据不能正确传递 codeigniter 模型

mysql - 统计单个和多个类别的记录

sql - POSTGRES 最小值/最小值

mysql - Qt Windows libmysql.dll

php - MySQL 查询按 JSON 列中的值排序

sql - mysql查询: it's not fetching first result

php - 通过 mysql 进行 JSON Android 登录验证