自联接查询

时间:2008-12-05 15:08:41

标签: sql mysql join self-join

考虑下表:

mysql> select * from phone_numbers;
+-------------+------+-----------+
| number      | type | person_id |
+-------------+------+-----------+
| 17182225465 | home |         1 |
| 19172225465 | cell |         1 |
| 12129876543 | home |         2 |
| 13049876543 | cell |         2 |
| 15064223454 | home |         3 |
| 15064223454 | cell |         3 |
| 18724356798 | home |         4 |
| 19174335465 | cell |         5 |
+-------------+------+-----------+

我正试图找到那些拥有家庭电话而不是细胞的人。

此查询有效:

mysql> select h.*
    -> from phone_numbers h
    -> left join phone_numbers c
    -> on h.person_id = c.person_id
    -> and c.type = 'cell'
    -> where h.type = 'home'
    -> and c.number is null;
+-------------+------+-----------+
| number      | type | person_id |
+-------------+------+-----------+
| 18724356798 | home |         4 |
+-------------+------+-----------+

但这个没有:

mysql> select h.*
    -> from phone_numbers h
    -> left join phone_numbers c
    -> on h.person_id = c.person_id
    -> and h.type = 'home'
    -> and c.type = 'cell'
    -> where c.number is null;
+-------------+------+-----------+
| number      | type | person_id |
+-------------+------+-----------+
| 19172225465 | cell |         1 |
| 13049876543 | cell |         2 |
| 15064223454 | cell |         3 |
| 18724356798 | home |         4 |
| 19174335465 | cell |         5 |
+-------------+------+-----------+

两者之间的唯一区别是h.type = 'home'条件的位置 - 在第一个where子句中,第二个是on子句的一部分。

为什么第二个查询不会返回与第一个查询相同的结果?

5 个答案:

答案 0 :(得分:7)

在第二个SQL中,条件h.type ='home'是外连接条件的一部分,并不是结果的过滤器。对于h.type ='cell'的所有记录,条件h.type ='home'为FALSE,因此找不到“匹配”c行 - 所以c.number为null,这是您唯一的过滤(WHERE)条件

在伪代码中,您的第二个SQL的工作方式如下:

for each row in phone_numbers h /* Note this is ALL home AND cell phones */
   select c.number from phone_numbers c
   where h.person_id = c.person_id
   and h.type = 'home'
   and c.type = 'cell';
   if c.number is null (i.e. no row found)
     display h.*
   end if
end loop;

答案 1 :(得分:2)

当做左连接时,我以这种方式处理事物。在连接中,您需要指定实际将两个表链接在一起的anny字段以及来自连接的右侧(连接中的第二个表)的任何过滤条件(有一个例外,我将很快得到)。从连接左侧(第一个表)的过滤条件应该在where子句中,否则它们会在你看到的时候错误地影响连接(并且Tony很好地解释了)。连接的右侧应该在where子句中的唯一时间是,如果要在该表中查找空值(即,第一个表中的记录而不是第二个表中的记录)。

答案 2 :(得分:0)

SEL * 
FROM phone_numbers T1
WHERE typeS='home' AND person_id NOT IN
(SELECT person_id FROM phone_numbers  T2 WHERE T1.person_id=T2.person_id AND  typeS='cell')

答案 3 :(得分:0)

您可以尝试此查询,我希望它对您有用。

select * from phone_numbers
where person_id not in (select person_id from phone_numbers where type='cell')

答案 4 :(得分:-2)

我不知道这是否会解决问题,但是......

以“and”开头的语句应该是WHERE子句的一部分,而不是ON子句的一部分。 ON子句应具有涉及使用哪些列来连接表的语句。