Внутренние и внешние соединения таблиц.



Внутреннее соединение таблиц

В условии поиска может сравниваться значение столбца из одной таблицы со значением столбца из другой таблицы:

<имя столбца таблицы1> <оператор> <имя столбца таблицы2>

 Такие условия часто используются для реализации механизма, аналогичного Lookup-полям локальных БД.

Например, извлечь информацию из таблицы лиц, с указанием реальных наименований типов лиц и подразделений, а не их условных номеров:

SELECT Lica.Name, Tipy.Name, Podrazd.Name

FROM Lica, Tipy, Podrazd

WHERE Tipy.NTip=Lica.Tip AND Lica.Podr=Podrazd.NPodr;

В соответствии с этим оператором, для каждой строки из таблицы лиц будет найдена строка с таким же условным номером типа лица в таблице типов лиц и строка с таким же условным номером подразделения в таблице подразделений. В результирующий НД будут включены не условные номера типов и подразделений, а их реальные наименования (при необходимости можно включить и условные номера).

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

Такой способ объединения информации из разных таблиц получил название внутреннего соединения таблиц.

Замечание: Для внутреннего соединения порядок перечисления таблиц в условии поиска не имеет значения (не важно, столбец какой из таблиц упоминается слева, а какой – справа от знака равенства).

Логически внутреннее соединение таблиц выполняется следующим образом. Вначале строится полное декартово произведение перечисленных таблиц, то есть перебираются все возможные комбинации строк этих таблиц:

строка1 таблицы1, строка1 таблицы2, строка1 таблицы3

строка1 таблицы1, строка1 таблицы2, строка2 таблицы3

строка1 таблицы1, строка1 таблицы2, строка3 таблицы3

. . .

строка1 таблицы1, строка2 таблицы2, строка1 таблицы3

строка1 таблицы1, строка2 таблицы2, строка2 таблицы3

. . .

строка2 таблицы1, строка1 таблицы2, строка1 таблицы3

строка2 таблицы1, строка1 таблицы2, строка2 таблицы3

строка2 таблицы1, строка1 таблицы2, строка3 таблицы3

. . .

Затем из полученного (вероятно очень большого) НД выбираются строки, удовлетворяющие условиям поиска. (Фактически, в целях минимизации работы, SQL-сервер работает несколько иначе, но логически – процесс выглядит именно так.)

Например, пусть таблицы T1 и T2 имеют столбцы C1, C2, C3 и C1, C2, соответственно. И пусть T2 является родительской по отношению к T1, причем связаны они по значению столбцов T2.C1 и T1.C2:

 


 


Таблица T2

C1 C2
1 x
2 y
3 z

Тогда выполнение оператора:

SELECT T1.C1, T2.C2, T1.C3 FROM T1, T2 WHERE T1.C2=T2.C1;

приведет к построению следующего декартова произведения:

Замечание 1. При внутреннем соединении таблиц, в результирующий НД не включаются записи, для которых нет соответствия в парной таблице (в рассмотренном выше примере выборки из таблицы лиц с реальными наименованиями подразделений и типов в результирующий НД не включены поставщики и направления списания, так как для них нет соответствия в таблице подразделений). Если такие записи необходимо включить (например, для включения в выборку лиц поставщиков и направлений списания), следует использовать внешнее соединение таблиц (оно будет рассмотрено ниже).

Замечание 2. Рассмотренную в этом пункте форму записи внутреннего соединения таблиц называют неявной формой внутреннего соединения. Альтернативная явная форма предполагает использование предложения JOIN … ON для каждой присоединяемой таблицы. В этом случае приведенный выше пример будет выглядеть следующим образом:

SELECT Lica.Name, Tipy.Name, Podrazd.Name

FROM Lica

JOIN Tipy ON Tipy.NTip=Lica.Tip

JOIN Podrazd ON Lica.Podr=Podrazd.NPodr;

Рекомендуется использовать такую форму записи, поскольку она более информативна и позволяет четко разграничивать условия соединения таблиц (в предложениях JOIN после ключевого слова ON) от условий выбора строк (в предложении WHERE).

Внешние соединения таблиц

Выше было рассмотрено внутреннее соединение таблиц, при котором строится полное декартово произведение этих таблиц, из него отбираются записи, удовлетворяющие условию соединения, и в результирующий набор данных не включаются строки, не имеющие соответствия в парной таблице. Поэтому, например, если попытаться построить список всех лиц с указанием подразделений для подотчетных лиц:

SELECT L.Name, D.Name

FROM Lica L

JOIN Podrazd D ON D.NPodr=L.Podr;

то в результирующий набор не будут включены поставщики и направления списания, так как для них не указываются подразделения.

В таких случаях следует использовать внешние соединения таблиц, при которых в результирующий набор данных включаются и те записи ведущей таблицы, которым нет соответствия в ведомой таблице. Какая таблица является ведущей, определяется видом соединения:

SELECT <список столбцов>

FROM <таблица_1>

<вид_соединения> JOIN <таблица_2> ON <условие_поиска>;

где в качестве вида соединения может быть указано:

LEFT - левое внешнее соединение (ведущей является таблица_1);

RIGHT - правое внешнее соединение (ведущей является таблица_2).

Предложение ON используется, так же как и предложение WHERE для внутреннего соединения.

Приведенный выше пример может быть реализован с помощью следующего внешнего соединения:

 

SELECT L.Name, D.Name

FROM Lico L

LEFT JOIN Podrazd D ON D.NPodr=L.Podr;

Вложенные запросы.

При необходимости операторы SELECT могут быть вложенными. Например, дать информацию о наиболее дорогостоящем предмете:

SELECT Name, Cena FROM Predmety

WHERE Cena=(SELECT MAX(Cena) FROM Predmety);

Здесь необходим вложенный SELECT, так как в предложении WHERE нельзя использовать агрегатную функцию.

Замечание. Если вложенный запрос используется в сравнении со знаком равенства, то необходимо следить, чтобы он возвращал единственное значение (в противном случае будет  сгенерирована ошибка). Если же нет уверенности в том, что будет возвращено единственное значение, то вместо знака равенства следует использовать ключевое слово включения в множество IN. Например, список проводок в отношении самого дорогостоящего предмета (следует учесть, что несколько различных предметов могут иметь одну и ту же максимальную цену):

SELECT * FROM Provodki WHERE Predmet IN (

SELECT NPredm FROM Predmety WHERE Cena=(

SELECT MAX(Cena) FROM Predmety));

Иногда для вложенного запроса важно знать, что существует хотя бы одна соответствующая запись, а количество этих записей не важно. В этом случае используется выражение:

[NOT] EXISTS (<запрос>)

Например, выбрать подотчетных лиц, у которых нет ни одной записи в таблице наличия (пусть условный номер типа лица для подотчетных лиц равен 2):

SELECT Name FROM Lica L WHERE Tip=2 AND NOT EXISTS(

SELECT * FROM Nalichie N WHERE N.Lico=L.NLic);

Если необходимо отобрать записи, для которых вложенный запрос возвращает одну и только одну строку, то используется выражение:

SINGULAR(<запрос>)

Например, выбрать подотчетные лица, у которых имеется единственная запись в таблице наличия:

SELECT Name FROM Lica L WHERE Tip=2 AND SINGULAR(

SELECT * FROM Nalichie N WHERE N.Lico=L.NLic);

В операторе SELECT имеется возможность сравнить значение некоторого выражения со всеми значениями, возвращаемыми вложенным запросом:

<выражение> <оператор> {ALL|SOME|ANY} (<запрос>)

В случае ALL сравнение дает истину, если значение выражения находится в отношении, указываемом оператором, со всеми значениями, возвращенными вложенным запросом. Для SOME (ANY – синоним) достаточно выполнения отношения хотя бы для одного значения, возвращенного вложенным запросом.

Например, выбрать подотчетные лица, у которых нет предметов, с ценой свыше тысячи рублей:

SELECT Name FROM Lica L WHERE 1000 > ALL(

SELECT P.Cena FROM Predmety P, Nalichie N

WHERE N.Lico=L.NLic AND P.NPredm=N.Predmet);

или выбрать лиц, у которых есть предметы с ценой выше 10 000 рублей:

SELECT Name FROM Lica L WHERE 10000 < SOME(

SELECT P.Cena FROM Predmety P, Nalichie N

WHERE N.Lico=L.NLic AND P.NPredm=N.Predmet);


Дата добавления: 2018-05-31; просмотров: 278; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!