MySQL

时间:2017-01-09 19:41:10

标签: mysql outer-join

我完全了解这个问题和答案: https://stackoverflow.com/a/4796911/2307520 但这是一个不同的问题!

是的,我理解他们如何使用union和两个左连接模拟MySQL中的简单FULL OUTER JOIN,但我的情况有点复杂(3个表而不是2个)我很难找到一种方法如何修改该解决方案为了我的需要。

这是简化的数据库架构: enter image description here

 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);

项目可以放在一个框中,独立放在一个书架中,也可以放在两个(未定义)中。盒子可以放在架子上或者没有定义。

理想情况下,我会使用这样的SQL查询:(如果我在MySQL中有完全外部联接)

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 ...

那将列出某些条件的所有条目(比如查看框中的框架是否存在,以及其中的所有项目,或其他任何内容)

1 个答案:

答案 0 :(得分:1)

我认为你可以通过LEFT OUTER JOIN和一些工会来解决这个问题。由于您有一个额外的表格,因此需要考虑更多场景,这只是有点复杂。

在我看来,你可以将其减少到四种情况:

  1. 项目存在,可能存在也可能不存在于可能存在或可能不存在于货架上的盒子中,但不能直接放在架子上。这将考虑所有不在包装盒中且不直接放在货架上的独立商品,以及包装盒中的商品,无论它们是否在货架上。
  2. 项目存在,但不在一个盒子中,而是直接放在架子上。
  3. 存在空盒子,可能在架子上,也可能不在架子上。 (如果它中有一个项目,那么我们会在方案1中介绍它)
  4. 存在空架子。
  5. /*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语句直接用你所追求的东西,比如"给我一个项目所在的每个架子,无论它是否在一个盒子中,或者#34;给我所有少于20件商品的货架#34;相反,这只是吐出物品,盒子和货架的所有可能组合,如果每个下游SQL语句都引用它们将不会有效。