Сложные (вложенные) SQL запросы
С помощью SQL можно вкладывать запросы внутрь друг друга . Обычно внутренний запрос генерирует значение, которое проверяется в предикате внешнего запроса (в предложении WHERE или HAVING), определяющего, верно оно или нет. Схема связывания основного и вложенного подзапросов представлена на рисунке1.
Рисунок1
На рисунке 2 представлено связывание подзапроса на уровне анализа агрегатных функций
Рисунок 2
Совместно с подзапросом можно использовать EXISTS , который возвращает истину, если вывод подзапроса не пуст. В сочетании с другими возможностями оператора выбора, такими как группировка, подзапрос представляет собой мощное средство для достижения нужного результата.
Вложенный запрос по-другому называют внутренним запросом или внутренней операцией выбора, в то время как инструкцию, содержащую вложенный запрос, называют внешним запросом или внешней операцией выбора .
Вложенные запросы могут быть зависимыми и независимыми. Зависимыми назовем такие вложенные запросы, результат которых зависит от текущей строки или группы внешнего запроса. В этом случае, если вложенный запрос применяется на уровне предложения WHERE , то он вычисляется для каждой строки внешнего запроса и его значение зависит от значений атрибутов в текущей строке. Если вложенный запрос применяется на уровне предложения HAVING , то его значение зависит от значения постоянных атрибутов текущей группы.
При построении зависимых вложенных запросов часто требуется использовать псевдонимы, для того чтобы различить экземпляр отношения в главном запросе и в подзапросе. Псевдонимы задаются с использованием ключевого слова AS, которое может быть вообще опущено.
Поэтому часть FROM может выглядеть следующим образом:
FROM R1 AS A, R1 AS B
или
FROM R1 A, R1 B;
оба выражения эквивалентны и рассматриваются как применения оператора SELECT к двум экземплярам таблицы R1.
Пример зависимого вложенного запроса, который формируется на уровне WHERE. Для этого построим запрос, который позволяет вывести список групп, студенты которых не получили двоек на сессии.
SELECT DISTINCT R2. Группа
FROM R2
WHERE NOT EXISTS (SELECT R1. ФИО
FROM R1, R2 R22
WHERE R1. ФИО = R22. ФИО and
R1.Оценка = 2 and
R2.Группа = R22.Группа);
Результат:
В основном запросе мы просматриваем последовательно строки из отношения R2 и для каждой строки строим подчиненный запрос, в котором ищем фамилии студентов, которые получили двойки и которые учатся в этой группе. Так как в главном запросе и в подзапросе мы используем одно и то же отношение R2 и при этом в подзапросе выбираем только студентов из текущей группы, которая определяется строкой внешнего запроса, нам надо различать эти экземпляр.
Тот же запрос можно построить с использованием независимого вложенного запроса. Такой запрос строится один раз, а далее каждая текущая строка сравнивается с этим общим подзапросом и по результатам сравнения принимается решение включать атрибут текущей строки в результат или нет.
Найдем группы, которые не входят в число групп, в которых есть двоечники». В этом случае в качестве подзапроса выступает запрос на перечень всех групп с двоечниками, а этот перечень не зависит от текущего значения группы и для всех групп одинаков. Текст запроса в этом случае будет выглядеть следующим образом:
SELECT DISTINCT R2.Группа
FROM R2
WHERE R2. Группа NOT IN (SELECT R2. Группа
FROM R2,R1
WHERE R1. ФИО = R2. ФИО and
R1.Оценка = 2);
Результат будет тем же.
Второй запрос будет более эффективен, потому что в этом случае только один раз выполняется встроенный запрос, а далее выполняется только операция сравнения. SQL позволяет построить множество текстов запросов, которые по смыслу эквивалентны, т. е. правильно отвечают на поставленный запрос, но оказывается, что они не эквивалентны по эффективности.
Операция "Объединение", позволяющая получить отношение, состоящее из всех строк, входящих в одно или оба объединяемых отношения. Но при этом исходные отношения или их объединяемые проекции должны быть совместимыми по объединению. Для SQL это означает, что две таблицы можно объединять тогда и только тогда, когда:
они имеют одинаковое число столбцов, например, m;
для всех i (i = 1, 2, ..., m) i-й столбец первой таблицы и i-й столбец второй таблицы имеют в точности одинаковый тип данных.
Например, выдать названия продуктов, в которых нет жиров, либо входящих в состав блюда с кодом БЛ = 1:
Многотабличные запросы
Операция "Объединение", позволяющая получить отношение, состоящее из всех строк, входящих в одно или оба объединяемых отношения. Но при этом исходные отношения или их объединяемые проекции должны быть совместимыми по объединению. Для SQL это означает, что две таблицы можно объединять тогда и только тогда, когда они имеют одинаковое число столбцов и одинаковый тип данных в этих столбцах.
Например, выдать названия продуктов, в которых нет жиров, либо входящих в состав блюда с кодом БЛ = 1:
Избыточные дубликаты всегда исключаются из результата UNION. Поэтому, хотя в рассматриваемом примере Помидоры, Зелень и Яблоки выбираются обеими из двух составляющих предложения SELECT, в окончательном результате они появляются только один раз.
Предложением с UNION можно объединить любое число таблиц (проекций таблиц). Так, к предыдущему запросу можно добавить (перед точкой с запятой) конструкцию.
Это позволяет добавить к списку продуктов Масло, Рис, Мука и Кофе. Однако тот же результат можно получить простым изменением фразы WHERE первой части исходного запроса.
WHERE Жиры=0 OR Ca
Например, чтобы получить список имен узлов и имен сайтов в виде одного набора данных, выполним такой запрос:
При таком подходе возможны проблемы с сортировкой записей. Чтобы список сайтов шел после списка узлов, можно добавить целочисленное поле, где указывать номер, который будет участвовать в сортировке.
Например