Вопрос

Рассмотрим следующую таблицу:

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 условие h.type = 'home' является частью условий внешнего соединения и не является фильтром результатов. Для всех записей, где h.type = 'cell', условие h.type = 'home' имеет значение FALSE, поэтому & Quot; match & Quot; Строка 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;

Другие советы

При выполнении левых соединений я подхожу к вещам таким образом. В объединении вам нужно указать любые поля, которые фактически связывают две таблицы вместе, и любое условие фильтрации с правой стороны (вторая таблица в соединении) объединения (за одним исключением, я скоро расскажу). Условия фильтрации с левой стороны объединения (1-я таблица) должны быть в предложении where, иначе они будут неправильно влиять на объединение, как вы видели (и, как Тони так хорошо объяснил). Единственный раз, когда правая сторона объединения должна быть в предложении where, это если вы ищете пустые значения в этой таблице (т.е. записи, которые находятся в первой таблице, но не во второй).

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

Вы можете попробовать этот запрос, надеюсь, он будет работать для вас.

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

Я не знаю, исправит это или нет, но ...

Операторы, начинающиеся с " и " должен быть частью предложения WHERE, а не частью предложения ON. Предложение ON должно только содержать операторы, в которых указаны столбцы, используемые для объединения таблиц.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top