2017-08-11 35 views
2

我想我的计划的饭菜:MySQL的加入给不一致的结果

select * from 
    (select floor(rand() * 3) + 1 as rand_id, days1.* from (
      select 'Monday' as dy from dual 
    union select 'Tuesday' from dual 
    union select 'Wednesday' from dual 
    union select 'Thursday' from dual 
    union select 'Friday' from dual 
    ) days1) days 
left join 
    (select id as rand_id, meals1.* from (
      select 1 as id, 'Pizza' as dinner from dual 
    union select 2, 'Hotdogs' from dual 
    union select 3, 'Spaghetti' from dual)meals1) meals 
on days.rand_id = meals.rand_id; 

当我SQL Fiddle it works fine运行此查询,但是当我跟我的本地MySQL实例尝试它,我得到总乱码结果:随机

+---------+-----------+---------+------+---------+ 
| rand_id | dy  | rand_id | id | dinner | 
+---------+-----------+---------+------+---------+ 
|  1 | Wednesday |  2 | 2 | Hotdogs | 
|  1 | Monday | NULL | NULL | NULL | 
|  3 | Tuesday | NULL | NULL | NULL | 
|  3 | Friday | NULL | NULL | NULL | 
+---------+-----------+---------+------+---------+ 

+---------+-----------+---------+------+-----------+ 
| rand_id | dy  | rand_id | id | dinner | 
+---------+-----------+---------+------+-----------+ 
|  3 | Wednesday |  1 | 1 | Pizza  | 
|  1 | Wednesday |  3 | 3 | Spaghetti | 
|  2 | Thursday | NULL | NULL | NULL  | 
|  3 | Friday | NULL | NULL | NULL  | 
+---------+-----------+---------+------+-----------+ 

我希望看到的是:用随机加入的行数5行,每行在rand_id中的随机数在1到3之间,days.rand_id和meals.rand_id都是相同的。我希望每次运行查询时,我都会随机抽取一餐,为每周的每一天提供一行。我的本地mysql(但不是sqlfiddle的mysql)会给我这个输出有什么问题?

(注:最初的目标是随机用假客户数据来生成测试数据链路真正的客户记录,但我已经简化了这个例子)

+1

我看不到汉堡。我认为这是根本缺陷 – Strawberry

+0

我在我的机器上试过了,它看起来是文件,不是吗? https://ibb.co/c82XxF – Ali

+0

@aAli看起来不错,但我在我的办公室尝试了几个MySQL实例,他们都给出了垃圾结果。 –

回答

1

这似乎是一个bug与使用加入rand()。这可能与2017年1月份的Bug #84573 Call to rand() in a [condition] can cause an empty set to be erroneously returned中描述的错误相同,但我不确定它是否得到了正确的关注度,因此可能需要重新报告。你可以使用下面的代码。

减少代码重现bug在MySQL 5.6,5.7和8.0(而不是5.5或更早):

create table a (id int primary key); 
insert into a values (1), (2); 

create table b (id int primary key); 
insert into b values (1); 

select * from a left join b on rand(0) > 0.5; 
+----+------+ 
| id | id | 
+----+------+ 
| 2 | 1 | 
| 1 | NULL | 
+----+------+ 
2 rows in set (0.00 sec)  

select * from a left join b on rand(1) > 0.5; 
+----+------+ 
| id | id | 
+----+------+ 
| 1 | NULL | 
+----+------+ 
1 row in set (0.00 sec) 

select * from a left join b on rand(14) > 0.5; 
Empty set (0.00 sec) 

所有查询预期的结果将始终获得两个(左)行在第二列随机null1

减少的代码也会在SQL Fiddle(它使用MySQL 5.6)上产生bug。你的查询在SQL Fiddle上工作的原因似乎是MySQL 5.6会实现你的子查询(而不是合并它),而5.7会默认合并它。

因此,您的案例中的一种解决方法可能是实现使用rand()的子查询的任何事情(尽管该错误可能与实现无直接关系)。设置/切换该行为的简单方法是使用视图,因此请尝试在MySQL 5.7(否则你不能使用在视图中的子查询):

create algorithm=merge view view_days1 
as select floor(rand() * 3) + 1 as rand_id, days1.* from (
      select 'Monday' as dy from dual 
    union select 'Tuesday' from dual 
    union select 'Wednesday' from dual 
    union select 'Thursday' from dual 
    union select 'Friday' from dual 
    ) days1; 

select * from view_days1 days 
left join 
    (select id as rand_id, meals1.* from (
      select 1 as id, 'Pizza' as dinner from dual 
    union select 2, 'Hotdogs' from dual 
    union select 3, 'Spaghetti' from dual)meals1) meals 
on days.rand_id = meals.rand_id; 

会显示相同的错误行为,而使用

create algorithm=temptable view view_days1 as ... 

应该只是罚款。