簡體   English   中英

MySQL 中的雙 FULL OUTER JOIN

[英]Double FULL OUTER JOIN in MySQL

我完全了解這個問題和答案: https: //stackoverflow.com/a/4796911/2307520 但這是一個有點不同的問題!

是的,我理解他們如何使用聯合和兩個左連接在 MySQL 中模擬簡單的 FULL OUTER JOIN,但我的情況有點復雜(3 個表而不是 2 個),我很難找到如何根據我的需要修改該解決方案的方法.

這是簡化的數據庫架構: 在此處輸入圖片說明

 CREATE TABLE item (`i_id` int, `i_name` varchar(70), b_id int null , s_id int null , PRIMARY KEY (i_id));
 CREATE TABLE box (`b_id` int, `b_name` varchar(70), s_id int null , PRIMARY KEY (b_id) );
 CREATE TABLE shelf (`s_id` int, `s_name` varchar(70) , PRIMARY KEY (s_id));
 INSERT INTO shelf VALUES(1,'shelf1');
 INSERT INTO shelf VALUES(2,'shelf2');
 INSERT INTO shelf VALUES(3,'empty shelf');
 INSERT INTO box VALUES(1,'box in s1 with item in it',1);
 INSERT INTO box VALUES(2,'box without shelf',NULL);
 INSERT INTO box VALUES(3,'empty box',2);
 INSERT INTO item VALUES(1,'item a',1,NULL);
 INSERT INTO item VALUES(2,'item b',1,NULL);
 INSERT INTO item VALUES(3,'item c',2,NULL);
 INSERT INTO item VALUES(4,'item in a shelf',NULL,1);
 INSERT INTO item VALUES(5,'item without location',NULL,NULL);

item 可以放在盒子里,單獨放在架子里,或者兩者都沒有(未定義)。 盒子可以在架子上或未定義。

理想情況下,我會使用這樣的 SQL 查詢:(如果我在 MySQL 中有 FULL OUTER JOIN)

SELECT *,coalesce(item.b_id,box.b_id) as b_id,coalesce(item.s_id,box.s_id,shelf.s_id) as s_id
FROM item
FULL OUTER JOIN box ON box.b_id=item.i_id
FULL OUTER JOIN shelf ON (shelf.s_id=item.s_id) OR (shelf.s_id=box.s_id)
WHERE ...

這將列出某些標准的所有條目(比如查看一個盒子在哪個架子上,如果有的話,里面的所有物品,或其他任何東西)

我認為您可以將其從 LEFT OUTER JOIN 和一些工會中拉出來,例如您的示例問題。 由於您有一個額外的表,因此會稍微復雜一些,因此需要考慮更多的場景。

在我看來,您可以將其減少到四種情況:

  1. 物品存在,可能在也可能不在一個盒子里,這個盒子可能在也可能不在貨架上,但不直接在貨架上。 這將考慮所有不在盒子中且不直接在貨架上的獨立物品,以及盒子中的物品,無論它們是否在貨架上。
  2. 物品存在,但不在盒子里,而是直接在架子上。
  3. 一個空盒子存在,可能在也可能不在架子上。 (如果它有一個項目,那么我們會在場景 1 中覆蓋它)
  4. 存在一個空架子。

/*item may or may not be in a box which may or may not be on a shelf, but the item is not directly on a shelf*/

SELECT item.i_id item.i_name, item.b_id, box.b_name, box.s_id, s.s_name FROM left outer join box on item.b_id = box.b_id left outer shelf on box.s_id = shelf.s_id and item.s_id is null

UNION ALL

/*item is directly on the shelf, but aren't in a box*/
SELECT item.i_id, item.i_name, NULL, NULL, shelf.s_id, shelf.s_name FROM item INNER JOIN shelf on item.s_id = shelf.s_id AND item.b_id IS NULL;

UNION ALL

/*empty box may or may not be on the shelf*/
SELECT NULL, NULL, box.b_id, box.b_name, shelf.s_id, shelf.s_name FROM box LEFT OUTER JOIN shelf on box.s_id = shelf.s_id WHERE box IS NOT IN (SELECT DISTINCT b_id FROM item)

UNION ALL

/*Shelfs where there are no boxes nor items sitting on them*/
SELECT NULL, NULL, NULL, NULL, shelf.s_id, shelf.s_name FROM shelf WHERE s_id NOT IN (SELECT distinct s_id FROM item) AND s_id NOT IN (SELECT DISTINCT s_id FROM box);

我認為場景 1 和 2 可以與合並相結合,但我喜歡將它們分開的想法,因為它讓我們更清楚地知道我們要做什么。

最終這感覺有點徒勞。 實際上,您應該編寫一條 SQL 語句來直接處理您所追求的內容,例如“給我一個物品所在的每個架子,無論它是否在一個盒子里”,或“給我所有少於 20 個物品的架子”。 相反,這只是吐出 item、box 和shelf 的所有可能組合,如果每個下游 SQL 語句都引用這些組合,則性能不會很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM