запрос самостоятельного соединения
Вопрос
Рассмотрим следующую таблицу:
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 должно только содержать операторы, в которых указаны столбцы, используемые для объединения таблиц.