MySQL RAND()奇怪的行为

Rog*_*vis 1 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
Run Code Online (Sandbox Code Playgroud)

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

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

好吧,所以我想也许这是一个双精度问题,所以我尝试使用>=如下:WHERE num >= FLOOR(1 + (RAND() * @rank)) LIMIT 1.在这种情况下的结果令我感到困惑.使用此代码我总是得到一个结果,但返回的行数始终<100.

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

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

spe*_*593 5

我认为问题是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
Run Code Online (Sandbox Code Playgroud)

- 或者,与您使用单独的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
Run Code Online (Sandbox Code Playgroud)

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

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

除此之外,我对你所看到的行为没有很好的解释.