2017-08-11 13 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 ... 

應該只是罰款。