ДО ЭТОГО, КАЖДЫЙ ЗАПРОС КОТОРЫЙ МЫ ИССЛЕДОВАЛИ
основывался на одиночной таблице.
В этой главе, вы узнаете как сделать запрос любого числа таблиц с
помощью одной команды. Это - чрезвычайно мощное средство потому
что оно не только объединяет вывод из многочисленных таблиц, но и
определяет связи между ними. Вы обучитесь различным формам кото-
рые могут использовать эти связи, а также устанавливать и использовать
их, чтобы удовлетворять возможным специальным требованиям.
ОБЪЕДИНЕНИЕ ТАБЛИЦ
Одна из наиболее важных особенностей запросов SQL - это их способ-
ность определять связи между многочисленными таблицами и выводить
информацию из них в терминах этих связей, всю внутри одной команды.
Этот вид операции называется - объединением, которое является одним
из видов операций в реляционных базах данных. Как установлено в
Главе 1, главное в реляционном подходе это связи
которые можно создавать между позициями данных в таблицах.
Используя объединения, мы непосредственно связываем информацию с
любым номером таблицы, и таким образом способны создавать связи
между сравнимыми фрагментами данных.
При объединении, таблицы представленные списком в предложении FROM
запроса, отделяются запятыми. Предикат запроса может ссылаться к лю-
бому столбцу любой связанной таблицы и, следовательно, может
использоваться для связи между ими. Обычно, предикат сравнивает значения в
столбцах различных таблиц чтобы определить, удовлетворяет ли WHERE
установленному условию.
ИМЕНА ТАБЛИЦ И СТОЛБЦОВ
Полное имя столбца таблицы фактически состоит из имени таблицы,
сопровождаемого точкой и затем именем столбца. Имеются несколько
примеров имен :
Salespeople.snum
Salespeople.city
Orders.odate
До этого, вы могли опускать имена таблиц потому что вы запрашивали
только одну таблицу одновременно, а SQL достаточно интеллектуален
чтобы присвоить соответствующий префикс, имени таблицы. Даже когда
вы делаете запрос многочисленных таблиц, вы еще можете опускать имена
таблиц, если все ее столбцы имеют различные имена. Но это не всегда
так бывает. Например, мы имеем две типовые таблицы со столбцами
называемыми city.
Если мы должны связать эти столбцы( кратковременно ), мы будем дол-
жны указать их с именами Salespeople.city или Customers.city, чтобы SQL
мог их различать.
СОЗДАНИЕ ОБЪЕДИНЕНИЯ
Предположим что вы хотите поставить в соответствии вашему продавцу
ваших заказчиков в городе в котором они живут, поэтому вы увидите все
комбинации продавцов и заказчиков для этого города. Вы будете должны
брать каждого продавца и искать в таблице Заказчиков всех заказчиков
того же самого города. Вы могли бы сделать это, введя следующую коман-
ду ( вывод показывается в Рисунке 8.1 ):
SELECT Customers.cname, Salespeople.sname,
Salespeople.city
FROM Salespeople, Customers
WHERE Salespeople.city = Customers.city;
=============== SQL Execution Log ============
| SELECT Customers.cname, Salespeople.sname, |
| Salespeople.city |
| FROM Salespeople, Customers |
| WHERE Salespeople.city = Customers.city |
| ============================================= |
| cname cname city |
| ------- -------- ---- |
| Hoffman Peel London |
| Hoffman Peel London |
| Liu Serres San Jose |
| Cisneros Serres San Jose |
| Hoffman Motika London |
| Clemens Motika London |
=============================================
Рисунок 8.1: Объединение двух таблиц
Так как это поле city имеется и в таблице Продавцов и таблице
Заказчиков, имена таблиц должны использоваться как префиксы. Хотя
это необходимо только когда два или более полей имеют одно и то же
им, в любом случае это хороша идея включать имя таблицы в объединение
для лучшего понимания и непротиворечивости. Несмотря на это,
мы будем, в наших примерах далее, использовать имена таблицы только
когда необходимо, так что будет ясно, когда они необходимы а когда нет.
Что SQL в основном делает в объединении - так это исследует
каждую комбинацию строк двух или более возможных таблиц, и
проверяет эти комбинации по их предикатам. В предыдущем примере,
требовалась строка продавца Peel из таблицы Продавцов и объединение
ее с каждой строкой таблицы Пользователей, по одной в каждый момент
времени.
Если комбинация производит значение которое делает предикат верным,
и если поле city из строк таблиц Заказчика равно London, то Peel - это
то запрашиваемое значение которое комбинация выберет для вывода. То же
самое будет затем выполнено для каждого продавца в таблице Продавцов
( у некоторых из которых не было никаких заказчиков в этих городах).
ОБЪЕДИНЕНИЕ ТАБЛИЦ ЧЕРЕЗ СПРАВОЧНУЮ ЦЕЛОСТНОСТЬ
Эта особенность часто используется просто для эксплуатации связей
встроенных в базу данных. В предыдущем примере, мы установили
связь между двум таблицами в объединении. Это прекрасно.
Но эти таблицы, уже были соединены через snum поле. Эта связь
называется состоянием справочной целостности, как мы уже говорили
в Главе 1. Используя объединение можно извлекать данные в терминах
этой связи. Например, чтобы показать имена всех заказчиков соответст-
вующих продавцам которые их обслуживают, мы будем использовать
такой запрос:
SELECT Customers.cname, Salespeople.sname
FROM Customers, Salespeople
WHERE Salespeople.snum = Customers.snum;
Вывод этого запроса показывается в Рисунке 8.2.
Это - пример объединения, в котором столбцы используются для определения
предиката запроса, и в этом случае, snum столбцы из обеих таблиц,
удалены из вывода. И это прекрасно.
Вывод показывает какие заказчики каким продавцом обслуживаются;
значения пол snum которые устанавливают связь - отсутствуют. Однако если
вы введете их в вывод, то вы должны или удостовериться что вывод понятен
сам по себе или обеспечить комментарий к данным при выводе.
=============== SQL Execution Log ============
| SELECT Customers.cname, Salespeople.sname, |
| FROM Salespeople, Customers |
| WHERE Salespeople.snum = Customers.snum |
| ============================================= |
| cname sname |
| ------- -------- |
| Hoffman Peel |
| Giovanni Axelrod |
| Liu Serres |
| Grass Serres |
| Clemens Peel |
| Cisneros Rifkin |
| Pereira Motika |
=============================================
Рисунок 8.2: Объединение продавцов с их заказчикам
ОБЪЕДИНЕНИЯ ТАБЛИЦ ПО РАВЕНСТВУ ЗНАЧЕНИЙ
В СТОЛБЦАХ И ДРУГИЕ ВИДЫ ОБЪЕДИНЕНИЙ
Объединения которые используют предикаты основанные на равенствах
называются - объединениями по равенству. Все наши примеры в этой главе
до настоящего времени, относились именно к этой категории, потому что все
условия в предложениях WHERE базировались на математических выражениях
использующих знак равно ( = ). Строки 'city = 'London' и
'Salespeople.snum = Orders.snum ' - примеры таких типов равенств, найденных
в предикатах.
Объединения по равенству - это вероятно наиболее общий вид объединения,
но имеются и другие. Вы можете, фактически, использовать любой из
реляционных операторов в объединении. Здесь показан пример
другого вида объединения ( вывод показывается в Рисунке 8.3 ):
SELECT sname, cname
FROM Salespeople, Customers
WHERE sname < cname
AND rating < 200;
=============== SQL Execution Log ============
| SELECT sname, cname |
| FROM Salespeople, Customers |
| WHERE sname < cname |
| AND rating < 200; |
| ============================================= |
| sname cname |
| -------- ------- |
| Peel Pereira |
| Motika Pereira |
| Axelrod Hoffman |
| Axelrod Clemens |
| Axelrod Pereira |
| |
=============================================
Рисунок 8.3: Объединение основанное на неравенстве
Эта команда не часто бывает полезна. Она воспроизводит все комбинации
имени продавца и имени заказчика так, что первый предшествует послед-
нему в алфавитном порядке, а последний имеет оценку меньше чем 200.
Обычно, вы не создаете сложных связей подобно этой, и, по этой причине,
вы вероятно будете строить наиболее общие объединения по равенству, но
вы должны хорошо знать и другие возможности.
ОБЪЕДИНЕНИЕ БОЛЕЕ ДВУХ ТАБЛИЦ
Вы можете также создавать запросы объединяющие более двух таблиц.
Предположим что мы хотим найти все порядки заказчиков не находящихся
в тех городах где находятся их продавцы. Для этого необходимо связать
все три наши типовые таблицы ( вывод показывается в Рисунке 8.4 ):
SELECT onum, cname, Orders.cnum, Orders.snum
FROM Salespeople, Customers,Orders
WHERE Customers.city < > Salespeople.city
AND Orders.cnum = Customers.cnum
AND Orders.snum = Salespeople.snum;
=============== SQL Execution Log ==============
| |
| SELECT onum, cname, Orders.cnum, Orders.snum |
| FROM Salespeople, Customers, Orders |
| WHERE Customers.city < > Salespeople.city |
| AND Orders.cnum = Customers.cnum |
| AND Orders.snum = Salespeople.snum; |
| =============================================== |
| onum cname cnum snum |
| ------ ------- ----- ----- |
| 3001 Cisneros 2008 1007 |
| 3002 Pereira 2007 1004 |
| 3006 Cisneros 2008 1007 |
| 3009 Giovanni 2002 1003 |
| 3007 Grass 2004 1002 |
| 3010 Grass 2004 1002 |
===============================================
Рисунок 8. 4: Объединение трех таблиц
Хотя эта команда выглядит скорее как комплексна, вы можете следовать
за логикой, просто проверяя - что заказчики не размещены в тех городах
где размещены их продавцы ( совпадение двух snum полей ), и что пере-
численные порядки - выполнены с помощью этих заказчиков( совпадение
порядков с полями cnum и snum в таблице Порядков ).