【问题标题】:self join query自连接查询
【发布时间】:2010-09-25 12:55:08
【问题描述】:

考虑下表:

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 子句的一部分。

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

【问题讨论】:

  • 第二种情况,你真的是在做左连接吗?
  • 差点想把这个仅仅为了艺术和奉献来充分说明情况。

标签: sql mysql join self-join


【解决方案1】:

你可以试试这个查询,希望对你有用。

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

【讨论】:

    【解决方案2】:
    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】:

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

      【讨论】:

        【解决方案4】:

        在进行左连接时,我会以这种方式处理事情。在连接中,您需要指定将两个表实际链接在一起的 anny 字段以及来自连接右侧(连接中的第二个表)的任何过滤条件(有一个例外,我将很快介绍)。连接左侧(第一个表)的过滤条件应该在 where 子句中,否则它们会错误地影响连接,如您所见(正如 Tony 很好地解释的那样)。连接右侧应该出现在 where 子句中的唯一情况是,如果您要在该表中查找空值(即在第一个表中但不在第二个表中的记录)。

        【讨论】:

          【解决方案5】:

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

          以“and”开头的语句应该是 WHERE 子句的一部分,而不是 ON 子句的一部分。 ON 子句应包含涉及用于连接表的列的语句。

          【讨论】:

          • 您可以在加入时添加附加条件。这将作为 de join 发生之前的 where 工作
          • 这样做是不好的风格,并且会导致事情以错误的顺序执行,正如 Tony Andrews 的回答中所指出的那样。
          猜你喜欢
          • 2016-02-03
          • 2020-04-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多