我在MySQL中查询表时遇到一些不一致的结果。为了演示,我尽可能地删除了代码。
drop table if exists numberfill;
create table numberfill (
id INT not null primary key auto_increment
) Engine=MEMORY;
drop procedure if exists populate;
DELIMITER $$
CREATE PROCEDURE populate(numberRows INT)
BEGIN
DECLARE counter INT;
SET counter = 1;
WHILE counter <= numberRows DO
INSERT INTO
numberfill
SELECT
counter;
SET counter = counter + 1;
END WHILE;
END
$$
DELIMITER ;
start transaction;
call populate(5000);
commit;
select if(a = 1, 5, 0), if(a = 1, 0, 5)
from (select cast(round(rand()) as unsigned) as a from numberfill) k;
似乎如果我不从numberfill中选择,则查询会给出一致的结果。但是,当我从numberfill表中选择时,我得到的结果是混合的。有些行给出0,0,其他行给出5,5,其他行给出5,0或0,5。
有谁能发现为什么会这样?这是一个MySQL问题还是我做了导致未定义行为的事情?我认为它可能与rand()生成一个浮点数有关。
答案 0 :(得分:2)
评论太长了。
你得到5, 0
和0, 5
的混合物是完全合理的。您正在填写一个包含5,000个数字的表格。然后子查询为每个行分配一个随机数 - 0或1。这应该具体化,因此设置值。
因此,不应该使用您的逻辑来获取0, 0
或5, 5
。
最新版本的MySQL可能会发现实现子查询不是必要的 - 他们可能会两次评估rand()
条件。如果您收到0, 0
或5, 5
,那么可能就是这种情况。
答案 1 :(得分:2)
当您多次引用a
时会出现此问题。显然,MySql(v 5.7)决定根据其定义重新评估a
,即它再次执行rand()
以检索a
的值。
它与Memory选项无关,也与if
函数无关。以下查询将在每行中返回两个不同的值:
select a, a
from (select rand() as a from numberfill) k
您可以通过为变量分配rand()
来避免这种情况,并为列别名a
选择该变量:
select a, a
from (select @a:=rand() as a from numberfill) k
该查询将始终返回两个值相同的记录。
强制评估实现的另一种方法是设置内部查询的限制(其值大于numberfill
中的行数):
select a, a
from (select rand() as a from numberfill limit 9999999999) k
另见Bug #86624, Subquery's RAND()
column re-evaluated at every reference。