Какие уровни вложения подзапросов допускаются sql
Акции Сегодня:
➦PQ Hosting VPS в 30+ странах. Промокод WOW2TOP скидка 15% для новых клиентов.
SQL (ˈɛsˈkjuˈɛl; англ. structured query language — «язык структурированных запросов») — декларативный язык программирования, применяемый для создания, модификации и управления данными в реляционной базе данных.

Операторы SQL: Команда Команда CREATE TABLE
Операторы SQL: Команда EXPLAIN
Транзакция. Уровни изоляции.
Соответствие стандартам SQL разных БД:
Движок БД MySQL: MySQL Standards Compliance: выражение «SQL Standard» означает поддержку текущего(последнего) стандарта SQL, то есть SQL:2008 — шестой версии.
SQL (Structured Query Language — язык структурированных запросов). SQL является, прежде всего, информационно-логическим языком, предназначенным для описания хранимых данных, для извлечения хранимых данных и для модификации данных.
SQL не является языком программирования. В связи с усложнением язык SQL стал более языком прикладного программирования, а пользователи получили возможность использовать визуальные построители запросов.
SQL является регистронезависимым языком. Cтроки в SQL берутся в одинарные кавычки.
Язык SQL представляет собой совокупность операторов. Операторы SQL делятся на:
операторы определения данных (Data Definition Language, DDL) — язык описания схемы в ANSI, состоит из команд, которые создают объекты (таблицы, индексы, просмотры, и так далее) в базе данных (CREATE, DROP, ALTER и др.).
операторы манипуляции данными (Data Manipulation Language, DML) — это набор команд, которые определяют, какие значения представлены в таблицах в любой момент времени (INSERT, DELETE, SELECT, UPDATE и др.).
операторы определения доступа к данным (Data Control Language, DCL) — состоит из средств, которые определяют, разрешить ли пользователю выполнять определенные действия или нет (GRANT/REVOKE , LOCK/UNLOCK).
операторы управления транзакциями (Transaction Control Language, TCL)
К сожалению, эти термины не используются повсеместно во всех реализациях. Они подчеркиваются ANSI и полезны на концептуальном уровне, но большинство SQL программ практически не обрабатывают их отдельно, так что они по существу становятся функциональными категориями команд SQL.
SQL:2008 — шестая (последняя) версия (ревизия) языка запросов баз данных SQL. Стандарт SQL не является свободно доступным. Полный стандарт можно приобрести у организации ISO как ISO/IEC 9075(1-4,9-11,13,14):2008.
Декларативность. С помощью SQL программист описывает только то, какие данные нужно извлечь или модифицировать. То, каким образом это сделать, решает СУБД непосредственно при обработке SQL-запроса. Однако не стоит думать, что это полностью универсальный принцип — программист описывает набор данных для выборки или модификации, однако ему при этом полезно представлять, как СУБД будет разбирать текст его запроса. Чем сложнее сконструирован запрос, тем больше он допускает вариантов написания, различных по скорости выполнения, но одинаковых по итоговому набору данных
Сложность. Хотя SQL и задумывался как средство работы конечного пользователя, в конце концов он стал настолько сложным, что превратился в инструмент программиста.
Процедурные расширения. Поскольку SQL не является языком программирования (то есть не предоставляет средств для автоматизации операций с данными), вводимые разными производителями расширения касались в первую очередь процедурных расширений. Это хранимые процедуры (stored procedures) и процедурные языки-«надстройки». Практически в каждой СУБД применяется свой процедурный язык. Стандарт для процедурных расширений представлен спецификацией SQL/PSM.
В SQL различаются следующие виды объектов:
Объединение запросов
Связанные подзапросы допускаются во многих реализациях SQL. Концепция связанного подзапроса определяется стандартом ANSI SQL и поэтому рассматривается здесь. Связанный подзапрос – это подзапрос, зависящий от информации, предоставляемой главным запросом.
В следующем примере в подзапросе определение связи между таблицами CUSTOMER_TBL и ORDERS_TBL использует псевдоним таблицы CUSTOMER_TBL (С), определенный в главном запросе. Этот оператор возвращает имена всех покупателей, заказавших более 10 единиц товара.
SELECT C.CUST_NAME FROM CUSTOMER_TBL С WHERE 10 < (SELECT SUM (O.QTY)
FROM ORDERS_TBL О WHERE O.CUST_ID = C.CUST_ID);
MARYS GIFT SHOP
В случае связанного подзапроса ссылка на таблицу главного запроса должна быть определена до начала выполнения подзапроса.
В следующем операторе этот запрос немного модифицирован, чтобы получить список всех заказчиков с соответствующим количеством заказанных товаров и иметь возможность проверить результаты предыдущего примера.
SELECT C.CUST_NAME, SUM(O.QTY) FROM CUSTOMER_TBL С,
ORDERS_TBL О GROUP BY CUST_NAME;
GAVINS PLACE 10
LESLIE GLEASON 1
MARYS GIFT SHOP 100
SCHYLERS NOVELTIES 25
SCOTTYS MARKET 20
Ключевое слово GROUP BY здесь требуется потому, что по отношению ко второму столбцу используется итоговая функция SUM. Это позволяет подсчитать суммы для каждого из заказчиков. В предыдущем примере ключевое слово GROUP BY не требовалось, поскольку там функция зим использовалась для суммирования всех результатов запроса, выполняемого для каждого конкретного заказчика.
Попросту говоря, подзапрос представляет собой запрос, выполняемый в рамках другого запроса для задания дополнительных условий на выводимые данные. Подзапрос можно использовать в выражениях ключевых слов WHERE и HAVING. Подзапросы обычно используют в других запросах (операторах DQL – языка запросов к данным), но подзапросы можно использовать и в операторах DML (языка манипуляций данными) таких, как INSERT, UPDATE и DELETE. Все основные правила использования операторов языка манипуляций данными применимы и при использовании в них подзапросов.
Синтаксис подзапросов практически не отличается от синтаксиса обычного запроса, имеются лишь небольшие ограничения. Одним из таких ограничений является запрет на использование в подзапросах ключевого слова ORDER BY, однако, вместо него можно использовать ORDER BY, чем достигается практически тот же эффект. Подзапросы используются для размещения в запросах условий, точные данные для которых не известны, тем самым расширяя возможности и гибкость SQL.
Вопросы и ответы
В примерах подзапросов обращает на себя внимание использование многочисленных отступов. Являются ли отступы необходимым элементом синтаксиса подзапроса?
Нет. Отступы используются исключительно для того, чтобы разбить оператор на части, чтобы его было легче читать и проще понять.
Имеются ли ограничения на число вложений подзапросов в запросы?
Ограничения на число уровней вложения подзапросов в запросы и число связываемых в запросе таблиц зависят от конкретной реализации SQL. В некоторых реализациях языка таких ограничений вообще нет, хотя использование слишком большого числа вложенных подзапросов может существенно замедлить выполнение соответствующего оператора. По большей части такие ограничения фактически определяются возможностями оборудования, скоростью процессора, объемами памяти и другими подобными факторами.
Отладка операторов с подзапросами кажется непростым делом, особенно если используются еще и вложенные подзапросы. Есть ли какие-либо рекомендации по поводу оптимизации процесса отладки запросов с подзапросами?
Лучше всего для отладки выделить из сложного запроса составляющие его запросы. Сначала следует проверить внутренний подзапрос самого низшего уровня и постепенно продвигаться по уровням до главного запроса (точно так же, как запрос обрабатывается базой данных). На каждом шагу после обработки выделенного из сложного оператора подзапроса можно подставить возвращенные этим подзапросом значения в исходный оператор, чтобы проверить правильность работы последнего. Чаще всего ошибки возникают из-за выражений, содержащих неправильное использование знаков операций для оценки результатов подзапроса, таких как =, IN, >, < и т. п.
1. В чем состоит назначение подзапроса при использовании его в операторе SELECT?
2. Можно ли одновременно обновить несколько столбцов таблицы с помощью оператора UPDATE с подзапросом?
3. Будут ли работать следующие операторы? Если нет, то что в них следует исправить?
· SELECT CUST_ID, CUST_NAME FROM CUSTOMER_TBL WHERE CUST_ID =
(SELECT CUST_ID FROM ORDERS_TBL WHERE ORD_NUM = ‘ 16C17’);
- SELECT EMP_ID, SALARY FROM EMPLOYEE_PAY_TBL WHERE SALARY BETWEEN ‘20000’
AND (SELECT SALARY FROM EMPLOYEE_ID WHERE SALARY = ‘40000’);
- UPDATE PRODUCTS_TBL SET COST = 1.15 WHERE CUST_ID =
(SELECT CUST_ID FROM ORDERS_TBL WHERE ORD_NUM = ’32A132′);
4. Каков будет результат выполнения следующего оператора?
DELETE FROM EMPLOYEE_TBL WHERE EMP_ID IN (SELECT EMP_ID FROM EMPLOYEE_PAY_TBL>;
Выполните упражнения для следующих таблиц.
1. Используя подзапрос, запишите оператор SQL, который в таблице CUSTOMER_TBL заменит имя заказчика, разместившего заказ с номером 23Е934, на DAVIDS MARKET.
2. Используя подзапрос, создайте запрос, возвращающий имена всех служащих, которые имеют более высокую зарплату, чем служащий по имени JOHN DOE, чей табельный номер 343559876.
3. Используя подзапрос, создайте запрос, возвращающий список всех товаров с ценой, превышающей среднюю цену всех имеющихся товаров.
Из этого урока вы узнаете, как объединить несколько запросов SQL в один с помощью команд UNION, UNION ALL, INTERSECT и EXCEPT. Особенности использования UNION, UNION ALL, INTERSECT и EXCEPT в случае используемой вами конкретной реализации SQL вы должны выяснить по соответствующей документации Основными на этом уроке будут следующие темы.
- Обзор команд для объединения запросов
- Когда следует использовать команды объединения запросов
- Использование GROUP BY ссоставными операторами
- Использование ORDER BY с составными операторами
- Обеспечение правильности результатов
Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:
SQL подзапросы: руководство по использованию
Рассказываем, что такое подзапросы в SQL и как их использовать.

Николай Антонов
Автор статьи
14 ноября 2022 в 14:07
Есть задачи, которые нельзя решить с помощью одного обычного запроса. Пример такой задачи — выборка всех записей со значением больше среднего по всей таблице. Для одного запроса нельзя и выбрать значения, и посчитать агрегатную функцию по всей таблице. Чтобы решить такие задачи, используют подзапросы.
Рассказываем в статье, что такое подзапросы в SQL и для чего они нужны.
Аналитик данных: новая работа через 5 месяцев
Получится, даже если у вас нет опыта в IT

Что такое подзапросы в SQL
SQL-подзапрос — это SELECT-запрос, вложенный в другой запрос или подзапрос.
Подзапрос — это внутренний запрос. Внешний запрос — это оператор, который содержит подзапрос.
Для чего нужны
Подзапросами пользуются, когда нужно использовать результат выполнения одного запроса в следующем запросе.
Такие задачи — не редкость в работе аналитика данных. Освоить эту профессию можно в Skypro на курсе «Аналитик данных». Там изучают основы SQL для получения и обработки информации.
Приведем пример на базе данных из трех таблиц: «Студенты», «Учебные курсы», «Оценки».
CREATE TABLE Students ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(32) NOT NULL, surname VARCHAR(32) NOT NULL ); CREATE TABLE Classes ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(64) NOT NULL, featured TINYINT(1) DEFAULT 0 NOT NULL ); CREATE TABLE Marks ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, student_id INT NOT NULL, class_id INT NOT NULL, mark TINYINT UNSIGNED NOT NULL, CONSTRAINT `fk_Marks_student_id__id` FOREIGN KEY (`student_id`) REFERENCES Students(`id`) ON DELETE CASCADE, CONSTRAINT `fk_Marks_class_id__id` FOREIGN KEY (`class_id`) REFERENCES Classes(`id`) ON DELETE CASCADE );
Объединим два последовательных запроса в один, чтобы найти любимые студентами предметы — то есть предметы, по которым средний балл выше среднего балла всех предметов.
Для этого разобьем задачу на две части. Сначала найдем средний балл среди всех студентов по всем предметам:
SELECT AVG(mark) FROM Marks; +-----------+ | AVG(mark) | +-----------+ | 3.4286 | +-----------+ 1 row in set (0.00 sec)
Потом напишем запрос, который находит средний балл для каждого учебного предмета:
SELECT Classes.id, Classes.name, AVG(mark) AS avg_mark FROM Classes INNER JOIN Marks ON Classes.id = Marks.class_id GROUP BY Classes.id;
Чтобы найти любимые предметы, нужно в разделе HAVING подставить значение из первого запроса. В нашем случае — это HAVING avg_mark 3.4286. Если выполним такой запрос, получим корректный результат.
Чтобы не заниматься ручной подстановкой значений в запросы, воспользуемся подзапросом. Для этого нужно вместо значения подставить тело запроса, обернув его в скобки:
SELECT Classes.id, Classes.name, AVG(mark) AS avg_mark FROM Classes INNER JOIN Marks ON Classes.id = Marks.class_id GROUP BY Classes.id HAVING avg_mark (SELECT AVG(mark) FROM Marks); +----+----------------+----------+ | id | name | avg_mark | +----+----------------+----------+ | 1 | Rocket science | 4.0000 | +----+----------------+----------+ 1 row in set (0.00 sec)
Так аналитики автоматизируют и ускоряют свою работу. Выучить основы SQL для решения задач анализа данных можно на курсе Skypro «Аналитик данных». А найти работу по новой профессии — еще в процессе обучения. В этом поможет центр карьеры.
Синтаксис
Синтаксически подзапрос — это SELECT-запрос, обернутый в круглые скобки ( , ). Подзапрос может быть вложен в любой другой оператор. Можно вкладывать подзапросы в подзапросы.
Вложенные запросы можно использовать практически во всех частях внешнего запроса — везде, где разрешено использовать значения.
Типы вложенных запросов
Результат выполнения подзапроса подставляют во внешний запрос. Подзапросы могут возвращать как скалярные значения, так и табличные значения. От типа возвращаемого значения зависит, с какими операциями имеет смысл использовать подзапрос.
Скалярное значение — это когда возвращается одно значение. Обычно это число или строка. Со скалярными значениями можно использовать операторы сравнения (, =), можно передавать как аргумент функции или как значение колонки в операторе SELECT. Например, посчитаем для каждого ученика, какой процент курсов он посещал:
SELECT Students.name, Students.surname, count(distinct Marks.class_id) / (SELECT count(*) FROM Classes) AS pcnt FROM Students INNER JOIN Marks ON Students.id = Marks.student_id GROUP BY Students.id; +---------+----------+--------+ | name | surname | pcnt | +---------+----------+--------+ | Philip | Fry | 1.0000 | | Turanga | Leela | 1.0000 | | Bender | Rodrigez | 0.5000 | +---------+----------+--------+ 3 rows in set (0.01 sec)
Табличное значение — когда возвращается несколько строк. Заранее неизвестно сколько: может, ноль, одна или больше. С табличными значениями используют операции IN, ANY, ALL, EXISTS, NOT EXISTS. Все эти операции проверяют вхождение строк(и) внешнего запроса в табличное значение, возвращаемое подзапросом. Еще табличное значение можно использовать в разделе FROM как таблицу-источник.
Пример подзапроса, возвращающего табличное значение. Найдем учебные курсы, где есть студенты с хотя бы одной отметкой. Это можно сделать с помощью оператора IN, который проверяет вхождение Classes.id в список ID классов, для которых есть оценки:
SELECT * FROM Classes WHERE id IN (SELECT class_id FROM Marks); +----+----------------+----------+ | id | name | featured | +----+----------------+----------+ | 1 | Rocket science | 1 | | 2 | Coolinary | 1 | +----+----------------+----------+ 2 rows in set (0.00 sec)
И с помощью оператора EXISTS, который проверяет для каждого учебного курса наличие хотя бы одной оценки в таблице Marks.
SELECT * FROM Classes WHERE EXISTS (SELECT class_id FROM Marks WHERE Classes.id = Marks.class_id); +----+----------------+----------+ | id | name | featured | +----+----------------+----------+ | 1 | Rocket science | 1 | | 2 | Coolinary | 1 | +----+----------------+----------+ 2 rows in set (0.00 sec)
Нужно быть аккуратным при работе с NOT IN: Если в список значений попадет NULL, результат выборки будет пустым:
mysql> SELECT * FROM Students WHERE id NOT IN (1, 2, 3, NULL); Empty set (0.00 sec)
Отличить подзапросы по возвращаемому значению очень просто: скалярные выбирают только одну колонку. А еще используют агрегатные функции без группировки GROUP BY. В таком случае СУБД видит, что запрос может вернуть только одну колонку и одну строку, то есть скалярное значение. Отсюда следует практическая рекомендация: если хочется использовать подзапрос как скалярное значение, нужно использовать агрегатную функцию.
Порядок выполнения подзапросов
По способу выполнения выделяют два типа подзапросов.
Простые. Такие подзапросы не зависят от внешнего запроса. СУБД выполнит такой подзапрос один раз перед выполнением внешнего запроса — и позже будет использовать значение столько раз, сколько понадобится. Пример простого подзапроса: найти всех студентов, которые не записались ни на один курс:
SELECT * FROM Students WHERE id NOT IN (SELECT DISTINCT student_id FROM Marks);
Сложные (коррелированные подзапросы — Correlated Subqueries). Такие подзапросы обращаются к полям внешнего запроса. СУБД будет вынуждена выполнить подзапрос для каждой строки, подставляя значение строки внешнего значения как параметр подзапроса.
Пример сложного подзапроса: найти всех студентов со средним баллом больше четырех. В этом примере важно заметить, что подзапрос использует Strudents.id из внешнего запроса.
SELECT * FROM Students WHERE (SELECT AVG(mark) FROM Marks WHERE Students.id = Marks.student_id) > 4;
Примеры вложенных запросов
Рассмотрим примеры вложенных запросов в различных операторах SQL.
SELECT
Выберем всех учеников, у которых по одному из курсов есть лучшая оценка среди всех студентов. Для этого воспользуемся операцией ALL. Синтаксически она немного отличается от уже рассмотренных операций: сначала идет оператор сравнения, потом ALL или ANY, после чего следует подзапрос в круглых скобках:
SELECT S.name, S.surname, C.name FROM Students AS S INNER JOIN Marks AS M ON S.id = M.student_id INNER JOIN Classes AS C ON C.id = M.class_id WHERE M.mark >= ALL (SELECT mark FROM Marks WHERE M.class_id = Marks.class_id); +---------+----------+----------------+ | name | surname | name | +---------+----------+----------------+ | Philip | Fry | Rocket science | | Bender | Rodrigez | Coolinary | | Turanga | Leela | Rocket science | +---------+----------+----------------+ 3 rows in set (0.00 sec)
INSERT
В новую таблицу BestStudents2022 скопируем всех студентов со средней оценкой, которая больше, чем средняя оценка среди всех студентов. Воспользуемся конструкциями INSERT … SELECT. Они позволят вставлять строки, которые возвращают SELECT-часть запроса.
Нам нужно посчитать сразу два средних арифметических значения: средний балл для каждого студента и для всех студентов. Напишем запрос с двумя подзапросами: коррелированным и обычным.
INSERT INTO BestStudents2022(`name`, `surname`) SELECT name, surname FROM Students WHERE (SELECT AVG(mark) FROM Marks WHERE Students.id = Marks.student_id) > (SELECT AVG(mark) FROM Marks); SELECT name, surname FROM BestStudents2022; +---------+----------+ | name | surname | +---------+----------+ | Philip | Fry | | Turanga | Leela | | Bender | Rodrigez | +---------+----------+ 3 rows in set (0.00 sec)
UPDATE
Можно использовать подзапрос, чтобы изменить данные в таблицах. Например, можно отметить предметы, по которым есть более десяти оценок, как популярные (featured) — и таким образом рекомендовать их другим студентам.
Так аналитики делают, чтобы данные в таблицах и на графиках обновлялись автоматически. А еще можно использовать программирование для визуализации данных. Всему этому учат на курсе Skypro «Аналитик данных».
Можно использовать следующий запрос:
UPDATE Classes SET featured = 1 WHERE (SELECT count(*) FROM marks WHERE class_id = id) > 10; Query OK, 3 rows affected (0.00 sec) Rows matched: 3 Changed: 3 Warnings: 0
В результате два учебных класса отмечены как популярные:
mysql> SELECT * FROM Classes; +----+----------------+----------+ | id | name | featured | +----+----------------+----------+ | 1 | Rocket science | 1 | | 2 | Coolinary | 1 | | 3 | Hospitality | 0 | +----+----------------+----------+ 3 rows in set (0.00 sec)
DELETE
SQL-подзапросы можно использовать с оператором DELETE. Давайте удалим все курсы, для которых нет ни одной оценки. Воспользуемся подзапросом и операцией NOT EXISTS:
DELETE FROM Classes WHERE NOT EXISTS (SELECT * FROM Marks WHERE Marks.class_id = Classes.id);
Можно легко убедиться, что такие курсы удалены.
SELECT * FROM Classes; +----+----------------+----------+ | id | name | featured | +----+----------------+----------+ | 1 | Rocket science | 1 | | 2 | Coolinary | 1 | +----+----------------+----------+ 2 rows in set (0.00 sec)
Please verify you are a human
Access to this page has been denied because we believe you are using automation tools to browse the website.
This may happen as a result of the following:
- Javascript is disabled or blocked by an extension (ad blockers for example)
- Your browser does not support cookies
Please make sure that Javascript and cookies are enabled on your browser and that you are not blocking them from loading.
Reference ID: #c2821f49-8787-11ee-beed-af791879a820
Powered by PerimeterX , Inc.