Вложенные запросы SQL (Microsoft Access SQL)
Вложенный запрос — это оператор SELECT, вложенный в оператор SELECT…INTO, INSERT…INTO, DELETE или UPDATE или в другой вложенный запрос.
Синтаксис
Вы можете использовать три формы синтаксиса для создания вложенного запроса:
сравнение [ANY | ALL | SOME] (sqlstatement)
expression [NOT] IN (sqlstatement)
[NOT] EXISTS (sqlstatement)
Вложенный запрос состоит из следующих частей:
Выражение и оператор сравнения, который сравнивает выражение с результатами вложенного запроса.
Выражение, для которого выполняется поиск по набору результатов для вложенного запроса.
Оператор SELECT с тем же форматом и правилами, что и любой другой оператор SELECT. Его необходимо включать в скобки.
Примечания
Вы можете использовать вложенный запрос вместо выражения в списке полей оператора SELECT или предложении WHERE или HAVING. Во вложенном запросе вы используете оператор SELECT для предоставления набора одного или нескольких определенных значений для оценки в выражении для предложения WHERE или HAVING.
Используйте предикат ANY или SOME, которые являются синонимами, для получения записей в основном запросе, который удовлетворяет сравнению с любыми записями, полученными во вложенном запросе. Следующий пример возвращает все продукты, для которых цена за единицу выше, чем у любого продукта, продаваемого со скидкой 25 процентов или более:
SELECT * FROM Products WHERE UnitPrice > ANY (SELECT UnitPrice FROM OrderDetails WHERE Discount >= .25);
Используйте предикат ALL для получения записей в основном запросе, который удовлетворяет сравнению со всеми записями, полученными во вложенном запросе. Если вы изменили предикат с ANY на ALL в предыдущем примере, запрос будет возвращать только те продукты, у которых цена за единицу больше, чем у всех продуктов, проданных со скидкой 25 процентов или более. Это гораздо более строгое ограничение.
Используйте предикат IN для получения только тех записей в основном запросе, для которых определенная запись во вложенном запросе содержит одинаковое значение. В примере ниже возвращаются все продукты со скидкой 25 процентов или больше:
SELECT * FROM Products WHERE ProductID IN (SELECT ProductID FROM OrderDetails WHERE Discount >= .25);
С другой стороны, вы можете использовать NOT IN для получения только тех записей в основном запросе, для которых ни одна запись во вложенном запросе не содержит одинаковое значение.
Используйте предикат EXISTS (с необязательным зарезервированным словом NOT) в сравнениях ИСТИНА/ЛОЖЬ, чтобы определить, возвращает ли вложенный запрос какие-либо записи.
Также можно использовать псевдонимы имени таблицы во вложенном запросе для ссылки на таблицы, указанные в предложении FROM за пределами вложенного запроса. Пример ниже возвращает имена сотрудников, чья заработная плата равна или выше средней заработной платы всех сотрудников на аналогичной должности. Для таблицы «Сотрудники» присваивается псевдоним «T1»:
SELECT LastName, FirstName, Title, Salary FROM Employees AS T1 WHERE Salary >= (SELECT Avg(Salary) FROM Employees WHERE T1.Title = Employees.Title) Order by Title;
В приведенном выше примере зарезервированное слово AS не является обязательным.
Некоторые вложенные запросы поддерживаются в перекрестных запросах, в частности, в качестве предикатов (например в предложении WHERE). Вложенные запросы в виде выходных данных (в списке SELECT) не поддерживаются в перекрестных запросах.
Пример
В данном примере перечислены имена и контактные данные каждого клиента, разместившего заказ во втором квартале 1995 года. В этом примере выполняется вызов процедуры EnumFields, которую можно найти в примере для оператора SELECT.
Sub SubQueryX() Dim dbs As Database, rst As Recordset ' Modify this line to include the path to Northwind ' on your computer. Set dbs = OpenDatabase("Northwind.mdb") ' List the name and contact of every customer ' who placed an order in the second quarter of ' 1995. Set rst = dbs.OpenRecordset("SELECT ContactName," _ & " CompanyName, ContactTitle, Phone" _ & " FROM Customers" _ & " WHERE CustomerID" _ & " IN (SELECT CustomerID FROM Orders" _ & " WHERE OrderDate Between #04/1/95#" _ & " And #07/1/95#);") ' Populate the Recordset. rst.MoveLast ' Call EnumFields to print the contents of the ' Recordset. Pass the Recordset object and desired ' field width. EnumFields rst, 25 dbs.Close End Sub
Вложенные запросы в T-SQL – описание и примеры
Приветствую Вас на сайте Info-Comp.ru! В этой заметке мы рассмотрим вложенные запросы языка SQL, я расскажу, что такое вложенные запросы, где и в каких конструкциях их можно использовать, покажу примеры их использования, а также расскажу про особенности и некоторые ограничения вложенных SQL запросов или, как еще их иногда называют, подзапросов SQL.
Что такое вложенные запросы SQL?
Вложенный SQL запрос – это отдельный запрос, который используется внутри SQL инструкции. Вложенный запрос также называют внутренним SQL запросом или подзапросом, а инструкцию, в которой используется вложенный запрос, называют внешним SQL запросом.
Вложенные SQL запросы могут быть использованы везде, где разрешено использовать SQL выражения, это может быть и секция SELECT, и FROM, и WHERE, и даже JOIN, чуть ниже я покажу примеры использования вложенных запросов в каждой из перечисленных выше секций.
Использовать вложенные запросы иногда бывает очень удобно, но обязательно стоит отметить и то, что в некоторых случаях использование вложенного SQL запроса может снизить производительность, т.е. замедлить работу всей SQL инструкции. Тем более что не редко вложенный SQL запрос можно заменить простым объединением.
Кроме того, вложенные запросы могут быть вложены друг в друга (в некоторых случаях вплоть до 32-го уровня), но тем самым значительно снижается читабельность SQL инструкций и ее понятность, а также повышается ее сложность.
Кстати, о том, как писать хорошие понятные SQL инструкции на языке T-SQL, которые будут понятны и Вам спустя время, и другим программистам, я подробно рассказал в своей книге – «Стиль программирования на T-SQL – основы правильного написания кода».
Заметка! Для комплексного изучения языка T-SQL рекомендую посмотреть мои видеокурсы по T-SQL, в которых используется последовательная методика обучения и рассматриваются все конструкции языка SQL и T-SQL.
Особенности вложенных запросов
Вложенные SQL запросы имеют несколько важных особенностей, про которые не стоит забывать при конструировании SQL инструкций:
- Вложенный запрос всегда заключен в скобки;
- Вложенный запрос не может содержать предложения COMPUTE, INTO и FOR BROWSE;
- Вложенный запрос может содержать конструкцию сортировки ORDER BY, только если он содержит оператор TOP, т.е. без TOP, ORDER BY в подзапросе использовать не получится;
- Если вложенный запрос используется в операции сравнения (за исключением операторов EXISTS и IN), он должен возвращать одно значение и один столбец;
- Типы данных ntext, text и image не могут участвовать в списке выбора вложенных запросов.
Примеры вложенных SQL запросов в Microsoft SQL Server
Ну а теперь пора переходить к практике, сейчас мы рассмотрим несколько примеров использования вложенных SQL запросов, при этом я, как и обещал, покажу применение вложенных запросов в разных конструкциях языка T-SQL.
Примечание! Все примеры тестовые, они сконструированы исключительно для демонстрации работы вложенных запросов.
Исходные данные для примеров
Сначала давайте определимся с исходными данными, чтобы Вы понимали, какие именно данные у нас есть, и наглядно видели, каким образом в примерах ниже получаются те или иные результаты.
Также сразу скажу, что в качестве SQL сервера у меня выступает версия Microsoft SQL Server 2017 Express.
Следующая инструкция создает таблицы, которые мы будет использовать в примерах, и добавляет в них данные.
--Создание таблицы Goods CREATE TABLE Goods ( ProductId INT IDENTITY(1,1) NOT NULL CONSTRAINT PK_ProductId PRIMARY KEY, Category INT NOT NULL, ProductName VARCHAR(100) NOT NULL, Price MONEY NULL, ); GO --Создание таблицы Categories CREATE TABLE Categories ( CategoryId INT IDENTITY(1,1) NOT NULL CONSTRAINT PK_CategoryId PRIMARY KEY, CategoryName VARCHAR(100) NOT NULL ); --Добавление строк в таблицу Categories INSERT INTO Categories(CategoryName) VALUES ('Комплектующие ПК'), ('Мобильные устройства'); GO --Добавление строк в таблицу Goods INSERT INTO Goods(Category, ProductName, Price) VALUES (1, 'Системный блок', 300), (1, 'Монитор', 200), (2, 'Смартфон', 250); GO --Выборка данных SELECT * FROM Goods; SELECT * FROM Categories;

Подробно останавливаться на том, что делает представленная выше инструкция, в этой статье я не буду, так как это совершенно другая тема, но если эта SQL инструкция Вам не понятна, и Вам интересно узнать, что конкретно она делает, можете почитать следующие статьи, а для комплексного изучения языка T-SQL — книгу, которую я уже упоминал:
- Создание таблиц в Microsoft SQL Server (CREATE TABLE);
- Изменение таблиц в Microsoft SQL Server (ALTER TABLE);
- Добавление данных в таблицы (INSERT INTO);
- SQL код – самоучитель по SQL для начинающих программистов.
Пример 1 – Вложенный запрос в секции SELECT
В этом примере мы рассмотрим стандартную ситуацию использования вложенного запроса в списке выборки оператора SELECT.
Допустим, что нам нужно получить список товаров с названием категорий, а так как названия категории в таблице Goods у нас нет, это название мы будем получать из таблицы Categories.
Это можно сделать с помощью вложенного запроса, в котором будет происходить объединение с внешним запросом в секции WHERE, посредством уточняющих псевдонимов. В данном случае вложенный запрос обязательно должен возвращать одно значение и один столбец.
А также это можно реализовать и с помощью объединения JOIN, что на самом деле предпочтительней, и в подобных случаях я рекомендую использовать именно JOIN, тем самым SQL запрос становится более читабельным и простым для понимания. Ниже я представлю оба SQL запроса.
--Выводим название категории с помощью вложенного запроса SELECT G.ProductName, (SELECT CategoryName FROM Categories C WHERE C.CategoryId = G.Category) AS CategoryName FROM Goods G; --Эквивалент с использованием объединения JOIN SELECT G.ProductName, C.CategoryName FROM Goods G INNER JOIN Categories C ON G.Category = C.CategoryId;

Пример 2 – Вложенный запрос в секции FROM
Сейчас давайте я покажу, как можно использовать вложенный запрос в секции FROM в качестве источника данных. Такие вложенные запросы обычно называют – Производные таблицы, так как они возвращают табличные данные.
SELECT ProductId, ProductName FROM (SELECT ProductId, ProductName FROM Goods WHERE Category = 1) AS Query;

В данном примере в качестве источника данных в секции FROM мы указали вложенный запрос, который возвращает идентификатор и наименование товаров из первой категории.
Пример 3 – Вложенный запрос в секции JOIN
В этом примере мы используем вложенный запрос в конструкции объединения JOIN, такие вложенные запросы также называют производными таблицами, так как в этом случае они возвращают табличные данные.
SELECT G.ProductName, C.CategoryName FROM Goods G INNER JOIN (SELECT CategoryId, CategoryName FROM Categories WHERE CategoryId = 1) AS C ON G.Category = C.CategoryId;

Здесь во вложенном запросе мы получаем идентификатор и наименование первой категории, а затем полученные табличные данные объединяем с таблицей Goods.
Пример 4 – Вложенный запрос в секции WHERE
Очень часто вложенные запросы используют в условии WHERE, при этом здесь стоит понимать, с каким именно оператором сравнения используется вложенный запрос, так как это важно.
Например, если использовать вложенный запрос с оператором равно (=), то он не может возвращать больше одного значения, т.е. если он вернет больше одного значения, выйдет ошибка, и SQL запрос не выполнится. Однако если использовать вложенный запрос с оператором IN (включая NOT IN) или EXISTS (включая NOT EXISTS), то вложенный запрос уже может возвращать список значений.
Вложенный запрос с оператором = (равно)
В этом запросе мы выводим все товары из таблицы Goods, у которых идентификатор категории равен значению, которое возвращает вложенный запрос, а он возвращает идентификатор категории с наименованием «Комплектующие ПК», таким образом, в нашем случае вложенный запрос возвращает только одно значение.
SELECT ProductId, ProductName FROM Goods G WHERE Category = (SELECT CategoryId FROM Categories WHERE CategoryName = 'Комплектующие ПК');

Вложенный запрос с оператором IN
Здесь мы используем для сравнения оператор IN, поэтому вложенный запрос в таком случае может уже возвращать несколько значений, для примера мы просто уберем условие WHERE во вложенном запросе.
SELECT ProductId, ProductName FROM Goods G WHERE Category IN (SELECT CategoryId FROM Categories);

Пример 5 – Множественная вложенность SQL запросов
Как я уже отмечал, вложенный запрос может быть вложен в другой вложенный SQL запрос, тем самым получается множественная вложенность.
В этом примере мы в качестве источника данных укажем вложенный SQL запрос, т.е. производную таблицу, который в свою очередь также будет содержать еще один вложенный запрос.
SELECT ProductId, ProductName FROM (SELECT ProductId, ProductName FROM Goods WHERE Category = (SELECT CategoryId FROM Categories WHERE CategoryName = 'Комплектующие ПК') ) AS Query;

Дополнительные примеры использования вложенных запросов, например, с использованием оператора EXISTS, можете посмотреть в статье – Логический оператор EXISTS в T-SQL – Описание и примеры.
На сегодня у меня все, надеюсь, материал был Вам полезен, пока!
Руководство по SQL. Вложенные запросы.
Вложенный запрос – это запрос, который находится внутри другого SQL запроса и встроен внутри условного оператора WHERE.
Данный вид запросов используется для возвращения данных, которые будут использоваться в основном запросе, как условие для ограничения получаемых данных.
Вложенные запросы должны следовать следующим правилам:
- Вложенный запрос должен быть заключён в родительский запрос.
- Вложенный запрос может содержать только одну колонку в операторе SELECT.
- Оператор ORDER BY не может быть использован во вложенном запросе. Для обеспечения функционала ORDER BY, во вложенном запросе может быть использован GROUP BY.
- Вложенные запросы, возвращающие более одной записи могут использоваться с операторами нескольких значений, как оператор IN.
- Вложенный запрос не может заканчиваться в функции.
- SELECT не может включать никаких ссылок на значения BLOB, ARRAY, CLOB и NCLOB.
- Оператор BETWEEN не может быть использован вместе с вложенным запросом.
Вложенный запрос имеет следующий вид:
SELECT имя_колонки [, имя_колонки2 ] FROM таблица1 [, таблица2 ] WHERE имя_колонки ОПЕРАТОР (SELECT имя_колонки [, имя_колонки2 ] FROM таблица1 [, таблица2 ] [WHERE])
Предположим, что у нас есть таблица developers, которая содержит следующие записи:
+----+-------------------+-----------+------------+--------+ | ID | NAME | SPECIALTY | EXPERIENCE | SALARY | +----+-------------------+-----------+------------+--------+ | 1 | Eugene Suleimanov | Java | 2 | 2500 | | 2 | Peter Romanenko | Java | 3 | 3500 | | 3 | Andrei Komarov | C++ | 3 | 2500 | | 4 | Konstantin Geiko | C# | 2 | 2000 | | 5 | Asya Suleimanova | UI/UX | 2 | 1800 | | 6 | Ludmila Geiko | UI/UX | 2 | 1800 | | 7 | Ivan Ivanov | C# | 1 | 900 | +----+-------------------+-----------+------------+--------+
Попробуем выполнить следующий вложенный запрос:
SELECT * FROM developers WHERE ID IN (SELECT ID FROM developers WHERE SALARY > 2000);
Предположим, что у нас есть клон таблицы developers, который имеет имя developers_clone и имеет следующую структуру:
+------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+-------+ | ID | int(11) | NO | PRI | NULL | | | NAME | varchar(100) | NO | | NULL | | | SPECIALTY | varchar(100) | YES | | NULL | | | EXPERIENCE | int(11) | NO | | NULL | | | SALARY | int(11) | YES | | NULL | | +------------+--------------+------+-----+---------+-------+
И не содержит данных:
mysql> SELECT * FROM developers_clone; Empty set (0.00 sec)
Теперь попробуем выполнить для этой же таблицы следующий запрос:
mysql> INSERT INTO developers_clone SELECT * FROM developers WHERE ID IN (SELECT ID FROM developers);
В результате выполнения данного запроса таблица developers_clone будет содержать следующие данные:
+----+-------------------+-----------+------------+--------+ | ID | NAME | SPECIALTY | EXPERIENCE | SALARY | +----+-------------------+-----------+------------+--------+ | 1 | Eugene Suleimanov | Java | 2 | 2500 | | 2 | Peter Romanenko | Java | 3 | 3500 | | 3 | Andrei Komarov | C++ | 3 | 2500 | | 4 | Konstantin Geiko | C# | 2 | 2000 | | 5 | Asya Suleimanova | UI/UX | 2 | 1800 | | 6 | Ludmila Geiko | UI/UX | 2 | 1800 | | 7 | Ivan Ivanov | C# | 1 | 900 | +----+-------------------+-----------+------------+--------+
Другими словами, мы скопировали все данные из таблицы developers в таблицу developers_clone.
Теперь мы изменим данные в таблице developers воспользовавшись данными из таблицы developers_clone с помощью следующего запроса:
mysql> UPDATE developers SET SALARY = SALARY * 1.25 WHERE EXPERIENCE IN (SELECT EXPERIENCE FROM developers_clone WHERE EXPERIENCE >=2);
В результате этого наша таблица содержащая изначальные данные:
+----+-------------------+-----------+------------+--------+ | ID | NAME | SPECIALTY | EXPERIENCE | SALARY | +----+-------------------+-----------+------------+--------+ | 1 | Eugene Suleimanov | Java | 2 | 2500 | | 2 | Peter Romanenko | Java | 3 | 3500 | | 3 | Andrei Komarov | C++ | 3 | 2500 | | 4 | Konstantin Geiko | C# | 2 | 2000 | | 5 | Asya Suleimanova | UI/UX | 2 | 1800 | | 6 | Ludmila Geiko | UI/UX | 2 | 1800 | | 7 | Ivan Ivanov | C# | 1 | 900 | +----+-------------------+-----------+------------+--------+
Будет хранить следующие данные:
+----+-------------------+-----------+------------+--------+ | ID | NAME | SPECIALTY | EXPERIENCE | SALARY | +----+-------------------+-----------+------------+--------+ | 1 | Eugene Suleimanov | Java | 2 | 3125 | | 2 | Peter Romanenko | Java | 3 | 4375 | | 3 | Andrei Komarov | C++ | 3 | 3125 | | 4 | Konstantin Geiko | C# | 2 | 2500 | | 5 | Asya Suleimanova | UI/UX | 2 | 2250 | | 6 | Ludmila Geiko | UI/UX | 2 | 2250 | | 7 | Ivan Ivanov | C# | 1 | 900 | +----+-------------------+-----------+------------+--------+
И наконец, попробуем выполнить удаление данных из таблицы с помощью вложенного запроса:
mysql> DELETE FROM developers WHERE EXPERIENCE IN (SELECT EXPERIENCE FROM developers_clone WHERE EXPERIENCE >= 2);
В результате таблица developers содерит следующие записи:
+----+-------------+-----------+------------+--------+ | ID | NAME | SPECIALTY | EXPERIENCE | SALARY | +----+-------------+-----------+------------+--------+ | 7 | Ivan Ivanov | C# | 1 | 900 | +----+-------------+-----------+------------+--------+
Очистим таблицу developers:
mysql> TRUNCATE developers;
mysql> SELECT * FROM developers; Empty set (0.00 sec)
Теперь восстановим данные таблицы developers, с помощью резервной таблицы developers_clone используя следующий запрос:
mysql> INSERT INTO developers SELECT * FROM developers_clone WHERE ID IN (SELECT ID FROM developers_clone);
Наша таблица developers имеет исходный вид:
mysql> SELECT * FROM developers; +----+-------------------+-----------+------------+--------+ | ID | NAME | SPECIALTY | EXPERIENCE | SALARY | +----+-------------------+-----------+------------+--------+ | 1 | Eugene Suleimanov | Java | 2 | 2500 | | 2 | Peter Romanenko | Java | 3 | 3500 | | 3 | Andrei Komarov | C++ | 3 | 2500 | | 4 | Konstantin Geiko | C# | 2 | 2000 | | 5 | Asya Suleimanova | UI/UX | 2 | 1800 | | 6 | Ludmila Geiko | UI/UX | 2 | 1800 | | 7 | Ivan Ivanov | C# | 1 | 900 | +----+-------------------+-----------+------------+--------+ 7 rows in set (0.00 sec)
На этом мы заканчиваем изучение вложенных запросов.
В следующей статье мы рассмотрим использование последовательностей.
Что такое вложенный запрос в sql



Скачай курс
в приложении
Перейти в приложение
Открыть мобильную версию сайта
© 2013 — 2023. Stepik
Наши условия использования и конфиденциальности

Public user contributions licensed under cc-wiki license with attribution required
