Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка SQL(14) (оптимизация).docx
Скачиваний:
62
Добавлен:
17.03.2015
Размер:
452.16 Кб
Скачать

3.3.1. Соединения «с условием where».

Вообще, соединения - это подмножества декартова произведения. Так как декартово произведение n таблиц - это таблица, содержащая все возможные строки r, такие, что r является сцеплением какой-либо строки из первой таблицы, строки из второй таблицы, ... и строки из n-й таблицы (а мы уже научились выделять с помощью SELECT любое подмножество реляционной таблицы), то осталось лишь выяснить, можно ли с помощью SELECT получить декартово произведение. Для получения декартова произведения нескольких таблиц, надо указать в предложении FROM перечень перемножаемых таблиц, а в предложении SELECT – все их столбцы.

Пример 17.

Предположим нам необходимо получить состав продуктов для каждого блюда.

Информация для этого запроса хранится в таблицах Блюда, Состав и Продукты. Для получения декартова произведения таблиц Блюда(n-строк), Состав (m-строк) и Продукты (k - строк) надо написать запрос

SELECT Блюда.*, Состав.*, Продукты.*

FROM Блюда, Состав, Продукты;

Получим таблицу, содержащую (n × m × k) строк:

ID_блюда

Блюдо

Вид

Основа

Вес

Труд

Блюдо

Продукт

Вес

ID_продукта

Продукт

Белки

Жиры

Углеводы

К

Са

Na

B2

PP

C

1

Салат летний

1

Овощи

200

3

1

4

15

1

Говядина

189

124

NULL

3150

90

600

1,5

28

0

1

Салат летний

1

Овощи

200

3

1

11

100

1

Говядина

189

124

NULL

3150

90

600

1,5

28

0

1

Салат летний

1

Овощи

200

3

1

12

5

1

Говядина

189

124

NULL

3150

90

600

1,5

28

0

1

Салат летний

1

Овощи

200

3

1

15

80

1

Говядина

189

124

NULL

3150

90

600

1,5

28

0

Результат далек от нужного, так как содержит лишние строки. Если из декартова произведения убрать ненужные строки и столбцы, то можно получить актуальные таблицы, соответствующие операций соединение.

Очевидно, что отбор актуальных строк обеспечивается вводом в запрос фразы WHERE, в которой устанавливается соответствие между кодами блюд в таблицах Блюда и Состав (Блюда.ID_Блюда = Состав.Блюдо) и кодами продуктов в таблицах Состав и Продукты (Состав.Продукт = Продукты.ID_Продукта).

Такой скорректированный запрос имеет вид:

SELECT Блюда.Блюдо, Продукты.Продукт, Состав.Вес

FROM Блюда, Состав, Продукты

WHERE Блюда.ID_Блюда = Состав.Блюдо

and Состав.Продукт = Продукты.ID_Продукта;

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

Результат

Блюдо

Продукт

Вес

Салат летний

Майонез

15

Салат летний

Помидоры

100

Салат летний

Зелень

5

Салат летний

Яблоки

80

Салат мясной

Говядина

65

Салат мясной

Майонез

20

Салат мясной

Яйца

20

Салат мясной

Морковь

40

Салат мясной

Помидоры

35

Салат мясной

Зелень

20

Салат витаминный

Сметана

50

Салат витаминный

Лук

15

Салат витаминный

Помидоры

55

Салат витаминный

Зелень

20

Рассмотренный вид соединения является внутренним, так как исключает несовпадающие по значению строки. То есть, если в БД занесено блюдо, но для него ещё не указан состав, то информация о таком блюде не появится в результирующей таблице, а иногда такая информация необходима.

Решить эту проблему помогают внешние соединения. Для получения внешнего соединения применяют один из трех подходов:

  1. Использование подзапроса с предикатом EXISTS

  2. Объединение двух запросов с помощью UNION

  3. Применение специальной конструкции JOIN в предложении FROM

Все они будут рассмотрены далее.

Следует отметить, что в предложении SELECT доступны все поля соединённых таблиц, даже если они не используются в запросе. Каждое имя поля уточняется с помощью точечной нотации, при которой имя поля следует через точку за именем таблицы. Такое уточнение необходимо, когда одно имя поля в запросе встречается более одного раза. (Конечно, эти поля будут находиться в разных таблицах, ведь невозможно создать два поля с одинаковыми именами в одной таблице.) Если не идентифицировать однозначно эти поля, то получим синтаксическую ошибку о неопределённости имён. Уточнение имён необходимо производить вне зависимости от того, ссылается ли запрос на оба поля или нет — каждая ссылка должна быть уточнена.

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

SELECT Блюда.Блюдо, Продукты.Продукт, остав.Вес

FROM Блюда, Состав, Продукты

WHERE ID_Блюда = Состав.Блюдо

and Состав.Продукт = ID_Продукта;

Тем не менее, указывать полные имена полей — это хорошая практика, поскольку иначе, взглянув на запрос, вы не всегда сможете сказать, к какой таблице относится каждое поле.

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

Псевдонимы таблиц

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

SELECT b.Блюдо, p.Продукт, s.Вес

FROM Блюда b, Состав s, Продукты p

WHERE b.ID_Блюда = s.Блюдо and s.Продукт = p.ID_Продукта;

Здесь, таблице Блюда присвоен псевдоним b, таблице Состав — псевдоним s, а таблице Продукты – псевдоним p. Вы можете использовать в качестве псевдонима любые имена, псевдонимы создаются лишь на время выполнения запроса. Многие программисты стараются использовать однобуквенные псевдонимы по мере возможности, поскольку так уменьшается объём кода и повышается его читаемость. Единственная тонкость состоит в том, что как только вы определили псевдоним для таблицы, то в текущем запросе уже не можете использовать реальное имя таблицы, можно указывать только её псевдоним. Псевдонимы действуют только на протяжении одного запроса.