SQL:“NOT IN”替代选择基于*不同*行的值的行?

时间:2009-08-17 04:29:39

标签: mysql performance subquery

如何创建一个返回由子查询或连接或其他内容修改的结果的SQL语句来处理您尝试返回的信息?

例如:

CREATE TABLE bowlers (
bowling_id int4 not null primary key auto_increment,
name text,
team text
);

有人可能会错误地访问多个团队:

INSERT INTO `bowlers` (`name`, `team`) VALUES
('homer', 'pin pals'),
('moe', 'pin pals'),
('carl', 'pin pals'),
('lenny', 'pin pals'),
('homer', 'The homer team'),
('bart', 'The homer team'),
('maggie', 'The homer team'),
('lisa', 'The homer team'),
('marge', 'The homer team'),
('that weird french guy', 'The homer team');

所以homer无法决定他的球队,所以他就是两个人。 Do'h!

我想知道所有在the homer team团队中的人pin pals。我能做的最好的就是:

SELECT a.name, a.team 
    FROM bowlers a where a.team = 'The homer team' 
    AND a.name 
    NOT IN (SELECT b.name FROM bowlers b WHERE b.team = 'pin pals');

导致:

+-----------------------+----------------+
| name                  | team           |
+-----------------------+----------------+
| bart                  | The homer team | 
| maggie                | The homer team | 
| lisa                  | The homer team | 
| marge                 | The homer team | 
| that weird french guy | The homer team | 
+-----------------------+----------------+
5 rows in set (0.00 sec)

你知道,这太棒了!

性能将受到影响,因为子查询将针对查询的每个结果运行,这是B到A到D.很好的几行,非常糟糕的数十万行。

什么是更好的方法?我大部分时间都认为自我加入可以解决这个问题,但我无法理解如何做到这一点。

有没有其他方法可以执行此操作,而不使用NOT IN( SELECT ... )

此外,这类问题的名称是什么?

2 个答案:

答案 0 :(得分:15)

像这样:

SELECT a.name, a.team
FROM bowlers a
LEFT OUTER JOIN bowlers b ON a.name = b.name AND b.team = 'pin pals'
WHERE a.team = 'The homer team'
AND b.name IS NULL;

你也可以这样做:

SELECT a.name, a.team
FROM bowlers a
WHERE a.team = 'The homer team'
AND NOT EXISTS (SELECT * FROM bowlers b
    WHERE b.team = 'pin pals'
    AND a.name = b.name
    );

顺便说一下,这被称为“左反半连接”。

答案 1 :(得分:2)

你可以LEFT JOIN并确保连接表中没有数据(一切都为空)。

SELECT a.name, a.team 
    FROM bowlers a
    LEFT JOIN bowlers b
        ON b.name = a.name AND b.team = 'pin pals'
    WHERE a.team = 'The homer team' 
    AND a.name
    -- the join has to fail for this to be null
    AND b.bowling_id IS NULL