Реляционные операторы
А теперь предположим, что вам требуются данные как о представительствах, так и связанные с представительствами данные об отделах и сотрудниках. Это "уже совсем другая история", потому что в представительстве может не быть никаких отделов. Поэтому для получения нужных данных используйте, как показано в следующем примере, внешнее объединение:
SELECT * FROM LOCATION L LEFT OUTER JOIN DEPT D ON (L.LocationID = D.LocationID) LEFT OUTER JOIN EMPLOYEE E ON (D.DeptID = E.DeptID);
В этом объединении данные берутся из трех таблиц. Сначала объединяются таблицы LOCATION и DEPT. Затем получившаяся таблица объединяется с таблицей EMPLOYEE. Даже если строки из таблицы, расположенной левее оператора LEFT OUTER JOIN, и не имеют соответствующих строк в таблице, расположенной правее этого оператора, они все равно входят в результат. Таким образом, при первом объединении в результат войдут все представительства, даже без отделов. А при втором объединении – войдут все отделы, даже без персонала. И вот какой получается результат:
1 | Boston | 24 | 1 | Admin | 61 | 24 | Kirk |
5 | Chicago | 27 | 5 | Repair | 63 | 27 | McCoy |
3 | Tampa | NULL | NULL | NULL | NULL | NULL | NULL |
5 | Chicago | 29 | 5 | Stock | NULL | NULL | NULL |
1 | Boston | 21 | 1 | Sales | NULL | NULL | NULL |
В нем первые две строки такие же, как и строки из предыдущего примера. А в третьей строке в столбцах, относящихся к отделам и сотрудникам, находятся неопределенные значения, потому что в Тампе нет никаких отделов и никто из сотрудников там постоянно не работает. В четвертой и пятой строках находятся данные о складе и об отделе продаж, но в столбцах этих строк, относящихся к сотрудникам, находятся неопределенные значения, так как в этих двух отделах персонала нет. Это внешнее объединение сообщает все то же, что и объединение, основанное на равенстве, а также предоставляет следующую информацию:
- обо всех представительствах компании, с отделами или без таковых;
- обо всех отделах компании, с персоналом или без него.
Нет никакой гарантии, что строки из последнего примера выведены в нужном вам порядке. Этот порядок в различных реализациях может быть разным. Чтобы выводить строки в том порядке, который вам нужен, вставьте предложение ORDER BY в оператор SELECT, как, например, в этот:
SELECT * FROM LOCATION L LEFT OUTER JOIN DEPT D ON (L.LocationID = D.LocationID) LEFT OUTER JOIN EMPLOYEE E ON (D.DeptID = E.DeptID) ORDER BY L.LocationID, D.DeptID, E.EmpID;
Совет:
Так как левого внутреннего объединения не существует, то левое внешнее объединение можно назвать покороче – левое объединение (в коде SQL это ключевые слова LEFT JOIN).
Правое внешнее объединение
Готов поклясться, что вы уже знаете, как ведет себя правое внешнее объединение. И вы правы! Правое внешнее объединение (right outer join) сохраняет в выводе несоответствующие строки, взятые из правой таблицы, но удаляет из него несоответствующие строки, взятые из левой. Это внешнее объединение можно использовать с теми же таблицами, что в левом внешнем объединении, и получить при этом те же результаты. Для этого надо, заменив в операторе ключевые слова левого внешнего объединения на ключевые слова правого, поменять порядок следования таблиц на обратный:
SELECT * FROM EMPLOYEE E RIGHT OUTER JOIN DEPT D ON (D.DeptID = E.DeptID) RIGHT OUTER JOIN LOCATION L ON (L.LocationID = D.LocationID);
В такой формулировке первое объединение создает таблицу, в которой находятся все отделы, с персоналом или без него. А второе объединение создает таблицу со всеми представительствами, независимо от наличия в них отделов.
Так как правого внутреннего объединения не существует, то правое внешнее объединение можно называть правое объединение (в коде SQL это ключевые слова RIGHT JOIN).