Пара слов о соединении в SQL
Не знаю, как дела обстоят у других людей, ну а мне легче понять и запомнить что-либо, применив это на практике.
Посему - исходные данные, причем очень реальные, так как используются мной в админке на сайте БиблиоТЕЛЕка.
Итак. Есть две таблицы.
1. feedback - таблица с вопросами, которые написали пользователи в службу поддержки :)
Поля - id; name; mail; mess.
Содержание - уникальный номер записи в таблице; имя человека, написавшего вопрос; его почта; и собственно, сообщение.
id name mail mess
1 ебари eb@vas.net отвалите
2 ты это мне? vne@pisem.net 1232
3 пошкл в жопец f@u.net afasdf
2. responses - таблицами с моими ответами на эти вопросы.
Поля - rid; fid; response.
Содержание - уникальный номер записи "моего ответа" в таблице; номер записи в таблице feedback (на какую именно запись я отвечаю); и собственно, мой ответ.
rid fid response
1 1 сам вали. придурок
Таким образом, мой ответ был на первое (весьма оскорбительное) сообщение в мой адрес.
А теперь постановка задачи. Я хочу видеть в админке таблицу, которая бы содержала такую информацию:
Номер вопроса; Имя спросившего; Его почта; Его вопрос; Мой ответ (если он был написан).
Т.е. мы должны каким-то образом взять информацию из ДВУХ таблиц и представить её в ОДНОЙ.
Собственно, в этом и есть сила концепции реляционных БД в целом и языка SQL в частности. Сейчас покажу как это легко и просто делается.
Данная операция называется соединение таблиц. Я опускаю здесь виды этой операции, такие как Декартово произведение таблиц, Тета- и Экви-соединение.
Рассмотрим простое соединение.
SELECT * FROM `feedback`, `responses` выдаст таблицу состоящую из N строк, где N=кол-во строк в таблице feedback
id name mail mess rid fid response
1 ебари eb@vas.net отвалите 1 1 сам вали. придурок
2 ты это мне? vne@pisem.net 1232 1 1 сам вали. придурок
3 пошкл в жопец f@u.net afasdf 1 1 сам вали. придурок
о_О, что это? почему мой ответ распространился на все вопросы?!
Потому что мы не использовали никаких дополнительных условий в операции соединения. Если бы в таблице responses было три разных ответа, итоговая таблица состояла бы из 3х3=9 строк, т.е. таблица формируется по принципу "каждый с каждым".
Понятно, нас это не устраивает. Можно дополнить запрос условиями, которые отрежут ненужные строки,например.
SELECT * FROM feedback, responses WHERE feedback.id=responses.fid.
Это логично, верно? "Выбрать всё из таблиц feedback, responses где feedback.id=responses.fid
Что в результате?
id name mail mess rid fid response
1 ебари eb@vas.net отвалите 1 1 сам вали. придурок
Только одна строка! Почему? Потому доп. условию, которое мы ввели, не удовлетворяют строки 2 и 3 таблицы feedback, потому им нет соответствия в таблице responses
Но если в итоговую таблицу необходимо поместить строки одной из таблиц, которые не удовлетворяют условиям? Т.е. это как раз наш случай. Нам необходимо включить в итоговую таблицу строки из responses, поле response которых пустое, чтобы получить такое:
id name mail mess rid fid response
1 ебари eb@vas.net отвалите 1 1 сам вали. придурок
2 ты это мне? vne@pisem.net 1232
3 пошкл в жопец f@u.net afasdf
Для этого и применяется внешнее соединение.
Суть: итоговая таблица должна содержать все строки из одной таблицы, дополненные полями из другой таблицы, даже если они не удовлетворяют условиям соединения.
Transact-SQL поддерживает только левое или правое внешнее соединение.
левое пишется так : SELECT * FROM feedback, responses WHERE feedback.id *= responses.fid
правое SELECT * FROM feedback, responses WHERE feedback.id =* responses.fid
Левое включит в таблицу feedback поля из responses, которые не удовлетворяют нашему условию.
Правое включит в таблицу responses поля из feedback, которые не удовлетворяют нашему условию.
Всё зависит от задачи, конечно. Нам, естественно, подходит левое соединение.
Единственный нюанс - в MySql такая форма *= не работает, зато есть другая форма записи...
SELECT * FROM feedback LEFT JOIN responses ON feedback.id=responses.fid
Вот и все. Желаемая таблица получена.