2016-11-29 77 views
2

例如,如果我有球和盒子,球可以放在很多盒子里,盒子可以锁定,我怎样才能选择不在锁盒里的球?排除列值上的连接记录?

balls 
    id name 
    == ==== 
    1 in neither 
    2 in unlocked 
    3 in locked 
    4 in both 

boxes 
    id locked 
    == ====== 
    1 0 
    2 1 

boxings 
    ball_id box_id 
    ======= ====== 
    2  1 
    3  2 
    4  1 
    4  2 

我想出这个使用左连接,但它返回“在两个”球 我想排除。

SELECT balls.* 
FROM balls 
LEFT OUTER JOIN boxings ON boxings.ball_id = balls.id 
LEFT OUTER JOIN boxes ON boxes.id = boxings.box_id 
WHERE (boxings.box_id IS NULL or boxes.locked = 0) 
    AND boxes.id NOT IN (
    SELECT id FROM boxes WHERE locked = 1 
    ) 

期望的结果:

id name 
== ==== 
1 in neither 
2 in unlocked 

SQL小提琴: http://sqlfiddle.com/#!9/c26ab/4

回答

2

我假设你的意思是:选择那些从来没有在一个上锁的箱子球。

如果是这样,一个not exists查询想到:

select b.* 
from balls b 
where not exists (select 1 
        from boxings bxb join 
         boxes bo 
         on bxb.box_id = bo.id 
        where bxb.ball_id = b.id and bo.locked = 1 
       ); 
+0

就是这样,谢谢! – jemminger

0

最straightforwad方式做到这一点是可能与NOT EXISTS

select id, name 
from balls 
where not exists (
    select NULL 
    from boxings 
    inner join boxes on boxes.id = boxings.box_id 
    where boxes.locked = 1 
    and boxings.ball_id = balls.id 
) 
0

我觉得很有意思,这两个答案已经发布两采用与WHERE子句中的某些加入条件相同的稍微奇怪的方法:

inner join boxes on boxes.id = boxings.box_id 
where boxes.locked = 1 

最奇怪的是我确定the same people advise elsewhere to not put join conditions in WHERE clauses

总之,这里的上反连接方式的不同变化:

SELECT * 
    FROM balls 
WHERE id NOT IN (SELECT ball_id 
        FROM boxings 
          NATURAL JOIN 
          (SELECT id AS box_id FROM boxes WHERE locked = 1) 
          NATURAL JOIN 
          (SELECT id AS ball_id FROM boxings));