Лекция 11 Вложенные запросы Вопрос 1. Простые вложенные подзапросы Вложенный подзапрос - это подзапрос, заключенный в круглые скобки и вложенный в WHERE (HAVING) фразу предложения SELECT или других предложений, использующих WHERE фразу. Вложенный подзапрос может содержать в своей WHERE (HAVING) фразе другой вложенный подзапрос и т.д. Нетрудно догадаться, что вложенный подзапрос создан для того, чтобы при отборе строк таблицы, сформированной основным запросом, можно было использовать данные из других таблиц. Существуют простые и коррелированные вложенные подзапросы. Они включаются в WHERE (HAVING) фразу с помощью условий IN, EXISTS или одного из условий сравнения ( = | <> | < | <= | > | >= ). Простые вложенные подзапросы обрабатываются системой "снизу вверх". Первым обрабатывается вложенный подзапрос самого нижнего уровня. Множество значений, полученное в результате его выполнения, используется при реализации подзапроса более высокого уровня и т.д. Запросы с коррелированными вложенными подзапросами обрабатываются системой в обратном порядке. Сначала выбирается первая строка рабочей таблицы, сформированной основным запросом, и из нее выбираются значения тех столбцов, которые используются во вложенном подзапросе (вложенных подзапросах). Если эти значения удовлетворяют условиям вложенного подзапроса, то выбранная строка включается в результат. Затем выбирается вторая строка и т.д., пока в результат не будут включены все строки, удовлетворяющие вложенному подзапросу (последовательности вложенных подзапросов). Следует отметить, что SQL обладает большой избыточностью в том смысле, что он часто предоставляет несколько различных способов формулировки одного и того же запроса. Поэтому во многих примерах данной главы будут использованы уже знакомые нам по предыдущей главе концептуальные формулировки запросов. И несмотря на то, что часть из них успешнее реализуется с помощью соединений, здесь все же будут приведены их варианты с использованием вложенных подзапросов. Это связано с необходимостью детального знакомства с созданием и принципом выполнения вложенных подзапросов, так как существует немало задан (особенно на удаление и измены—; данных), которые не могут быть реализованы другим способом. Кроме того, разные формулировки одного и того же запроса требуют для своего выполнения различных ресурсов памяти и могут значительно отличаться по времени реализации в разных СУБД. Использование вложенных подзапросов связано с некоторыми ограничениями. При создании вложенных подзапросов обычно принято придерживаться следующих правил: Вложенный подзапрос должен быть заключен в скобки; Если в данном месте задано выражение использующее одно значение, то вложенный подзапрос возвращать одно значение; Вложенный подзапрос нельзя использовать в директиве ORDER BY; В директиве IN вложенный запрос не может иметь в списке столбцов более одного столбца; В директиве EXISTS вложенный запрос задается в виде SELECT *; Вложенный запрос не может содержать директивы ORDER BY, COMPUTE BY или SELECT INTO. Вложенные простые подзапросы демонстрируют следующие примеры. Вывести сведения о книгах, которые были проданы хотя бы один раз: SELECT id, publishers, author, title, price, style КОД FROM Books WHERE id IN (SELECT book FROM Sales) Вывести сведения о книгах, которые были проданы 16 января 2005года: SELECT id, publishers, author, title FROM Books WHERE id = (SELECT book FROM Sales WHERE data_sale='2005/01/16') Найти все книги по зарубежным детективам в названии, которых встречается слово "Тайна": КОД SELECT id, publishers, author, title, style FROM Books WHERE style='Заруб. детективы1 AND id IN (SELECT id FROM Books WHERE title LIKE '%Тайна%') Пример, демонстрирующий использование агрегатных функций в подзапросе: SELECT * FROM Customers WHERE age>=(SELECT AVG(age) FROM Customers) Вопрос 2. Коррелированные вложенные подзапросы Коррелированный вложенный запрос ссылается на таблицу внешнего запроса и обрабатывает каждую его строку. В этом отношении коррелированный вложенный запрос отличается от обычного вложенного запроса тем, что последний выполняется независимо от внешнего запроса. В следующем примере запрос с объединением переписан как коррелированный вложенный запрос. Оба запроса выводят одну и ту же информацию: список всех заказчиков, которые живут в одном городе и имеют одинаковые имена: Используется объединение: SELECT Custl.fname, Custl.Iname, Cust2.fname, Cust2.1name, Custl.address FROM Customers AS Custl INSZr. JOIN Customers AS Cust2 CN Custl- address = Cust2.address AND Custl. Iname = Cust2 . Inar<e WHERE Custl.id < Cust2._d ORDER BY Custl.address Используется коррелированный вложенный запрос SELECT Custl.fname, Custl.Iname, Custl.address FROM Customers AS Custl WHERE Custl.Iname IN (SELECT Iname FROM Customers AS Cust2 WHERE Custl.address = Cust2.address AND Custl.Iname = Cust2 . Iname AND Custl. idoCust2 . id) Order By Custl.address Вопрос 3. Запросы, использующие EXISTS Квантор EXISTS (существует) - понятие, заимствованное из формальной логики. В языке SQL предикат с квантором существования представляется выражением EXISTS (SELECT * FROM ...). Такое выражение считается истинным только тогда, когда результат вычисления "SELECT * FROM ..." является непустым множеством, т.е. когда существует какая-либо запись в таблице, указанной во фразе FROM подзапроса, которая удовлетворяет условию WHERE подзапроса (Практически этот подзапрос всегда будет коррелированным множеством.) Например, нам надо составить запрос, который выводил бы сведения о тех заказчиках, которые покупали книги с идентификатором 2 SELECT * FROM Customers WHERE NOT EXISTS (SELECT customer FROM Sales WHERE book = 2 AND Customers.id=Sales.customer) Хотя этот пример только показывает иной способ формулировки запроса для задачи, решаемой и другими путями (с помощью оператора IN или соединения), EXISTS представляет собой одну из наиболее важных возможностей SQL, Фактически любой запрос, который выражается через IN, может быть альтернативным образом сформулирован также с помощью EXISTS. Однако обратное высказывание несправедливо.