Что такое вложенные запросы
Подзапросы являются одним из самых мощных инструментов в SQL, который можно использовать в любых видах запросов. В ближайших уроках мы познакомимся с основными типами подзапросов и рассмотрим примеры как их можно использовать.
Подзапрос — это запрос, использующийся в другом SQL запросе. Подзапрос всегда заключён в круглые скобки и обычно выполняется перед основным запросом.
Как и любой другой SQL запрос, подзапрос возвращает результирующий набор, который может быть одним из следующих:
- одна строка и один столбец;
- нескольких строк с одним столбцом;
- нескольких строк с несколькими столбцами.
В зависимости от типа результирующего набора подзапроса определяются операторы, которые могут использоваться в основном запросе.
Получим список всех бронирований самого дорогого на данный момент жилого помещения:
MySQLSELECT * FROM Reservations WHERE Reservations.room_id = ( SELECT id FROM Rooms ORDER BY price DESC LIMIT 1 )В данном случае запрос на получение самого дорого жилого помещения выполняется в качестве подзапроса, а затем результат результирующего набора применяется в основном запросе.
MySQLSELECT id FROM Rooms ORDER BY price DESC LIMIT 1Руководство по 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
Здравствуйте, уважаемые читатели! В этой статье мы поговорим о том, что такое вложенные запросы в SQL. Традиционно, рассмотрим несколько примеров с той базой данных, которую создавали в первых статьях.
Введение
Итак, само название говорит о том, что запрос во что-то вложен. Так вот, вложенный запрос в SQL означает, что запрос select выполняется в еще одном запросе select — на самом деле вложенность может быть и многоуровневой, то есть select в select в select и т.д. Такие запросы обычно используются для получения данных из двух и более таблиц. Они нужны чтобы данные из разных таблиц можно было соотнести и по зависимости осуществить выборку. У вложенных запросов есть и недостаток — зачастую слишком долгое время работы занимает запрос, потому что идет большая нагрузка на сервер. Тем не менее, саму конструкцию необходимо знать и использовать при возможности.
Структура ранее созданных таблиц
Основы вложенных запросов в SQL
Вывести сумму заказов и дату, которые проводил продавец с фамилией Колованов.
Начнем с такого примера и для начала вспомним, как бы делали этот запрос ранее: посмотрели бы в таблицу Salespeople, определили бы snum продавца Колыванова — он равен 1. И выполнили бы запрос SQL с помощью условия WHERE. Вот пример такого SQL запроса:
SELECT amt, odate FROM orders WHERE snum = 1Очевидно, какой будет вывод:
amt odate 348 2017-04-08 80 2017-09-02 Такой запрос, очевидно, не очень универсален, если нам захочется выбрать тоже самое для другого продавца, то всегда придется определять его snum. А теперь посмотрим на вложенный запрос:
SELECT amt, odate FROM orders where snum = (SELECT snum FROM salespeople WHERE sname = 'Колованов')В этом примере мы определяем с помощью вложенного запроса идентификатор snum по фамилии из таблицы salespeople, а затем, в таблице orders определяем по этому идентификатору нужные нам значения. Таким образом работают вложенные запросы SQL.
Рассмотрим еще один пример:
Показать уникальные номера и фамилии продавцов, которые провели сделки в 2016 году.SELECT snum, sname FROM salespeople where snum IN (SELECT snum FROM orders WHERE YEAR(odate) = 2016)Этот SQL запрос отличается тем, что вместо знака = здесь используется оператор IN. Его следует использовать в том случае, если вложенный подзапрос SQL возвращает несколько значений. То есть в запросе происходит проверка, содержится ли идентификатор snum из таблицы salespeople в массиве значений, который вернул вложенный запрос. Если содержится, то SQL выдаст фамилию этого продавца.
Получился такой результат:
snum sname 3 Плотников 4 Кучеров 7 Мозякин 8 Проворов Вложенные запросы SQL с несколькими параметрами
Те примеры, которые мы уже рассмотрели, сравнивали в условии WHERE одно поле. Это конечно хорошо, но стоит отметить, что в SQL предусмотрена возможность сравнения сразу нескольких полей, то есть можно использовать вложенный запрос с несколькими параметрами.
Вывести пары покупателей и продавцов, которые осуществили сделку между собой в 2017 году.
Запрос чем то похож на предыдущий, только теперь мы добавляем еще одно поле для сравнения. Итоговый запрос SQL будет выглядеть таким образом:
SELECT cname as 'Покупатель', sname as 'Продавец' FROM customers cus, salespeople sal where (cus.cnum, sal.snum) IN (SELECT cnum, snum FROM orders WHERE YEAR(odate) = 2017)
Покупатель Продавец Краснов Колованов Колесников Кучеров Лермонтов Колованов Кириллов Мозякин В этом примере мы сравниваем сразу два поля одновременно по идентификаторам. То есть из таблицы orders берутся те строки, которые удовлетворяют условию по 2017 году, затем вместо идентификаторов подставляются значение имен покупателей и продавцов.
На самом деле, такой запрос SQL используется крайне редко, обычно используют оператор INNER JOIN, о котором будет сказано в следующей статье.
Дополнительно скажем о конструкциях, которые использовались в этом запросе. Оператор as нужен для того, чтобы при выводе SQL показывал не имена полей, а то, что мы зададим. И после оператора FROM за именами таблиц стоят сокращения, которые потом используются — это псевдонимы. Псевдонимы можно называть любыми именами, в этом запросе они используются для явного определения поля, так как мы несколько раз обращаемся к одному и тому же полю, только из разных таблиц.
Примеры на вложенные запросы SQL
1.Напишите запрос, который бы использовал подзапрос для получения всех Заказов для покупателя с фамилией Краснов. Предположим, что вы не знаете номера этого покупателя, указываемого в поле cnum.
SELECT * FROM orders where cnum = (SELECT cnum FROM customers WHERE cname = 'Краснов')2. Напишите запрос, который вывел бы имена и рейтинг всех покупателей, которые имеют Заказы, сумма которых выше средней.
SELECT cname, rating FROM customers where cnum IN (SELECT cnum FROM orders WHERE amt > (SELECT AVG(amt) from orders))3. Напишите запрос, который бы выбрал общую сумму всех приобретений в Заказах для каждого продавца, у которого эта общая сумма больше, чем сумма наибольшего Заказа в таблице.
SELECT snum, SUM(AMT) FROM orders GROUP BY snum HAVING SUM(amt) > (SELECT MAX(amt) FROM orders)4. Напишите запрос, который бы использовал подзапрос для получения всех Заказов для покупателей проживающих в Москве.
SELECT * FROM orders where cnum IN (SELECT cnum FROM customers WHERE city = 'Москва')5. Используя подзапрос определить дату заказа, имеющего максимальное значение суммы приобретений (вывести даты и суммы приобретений).
SELECT amt, odate FROM orders WHERE AMT = (SELECT MAX(AMT) FROM orders)6. Определить покупателей, совершивших сделки с максимальной суммой приобретений.
SELECT cname FROM customers WHERE cnum IN (SELECT cnum FROM orders WHERE amt = (SELECT MAX(amt) FROM orders))Заключение
На этом сегодня все, мы познакомились с вложенными запросам в SQL. Очевидно, что это достаточно удобный и понятный способ получения данных из таблиц, но не всегда рационален с точки зрения скорости и нагрузки на сервер. Основные примеры, которые мы разобрали, действительно встречаются на практике языка SQL.
Поделиться ссылкой:
SQL - Урок 5. Вложенные запросы
В прошлом уроке мы столкнулись с одним неудобством. Когда мы хотели узнать, кто создал тему "велосипеды", и делали соответствующий запрос:
Вместо имени автора, мы получали его идентификатор. Это и понятно, ведь мы делали запрос к одной таблице - Темы, а имена авторов тем хранятся в другой таблице - Пользователи. Поэтому, узнав идентификатор автора темы, нам надо сделать еще один запрос - к таблице Пользователи, чтобы узнать его имя:
В SQL предусмотрена возможность объединять такие запросы в один путем превращения одного из них в подзапрос (вложенный запрос). Итак, чтобы узнать, кто создал тему "велосипеды", мы сделаем следующий запрос:
То есть, после ключевого слова WHERE, в условие мы записываем еще один запрос. MySQL сначала обрабатывает подзапрос, возвращает id_author=2, и это значение передается в предложение WHERE внешнего запроса.
В одном запросе может быть несколько подзапросов, синтаксис у такого запроса следующий:
SELECT имя_столбца FROM имя_таблицы WHERE часть условия IN (SELECT имя_столбца FROM имя_таблицы WHERE часть условия IN (SELECT имя_столбца FROM имя_таблицы WHERE условие) ) ;
Обратите внимание, что подзапросы могут выбирать только один столбец, значения которого они будут возвращать внешнему запросу. Попытка выбрать несколько столбцов приведет к ошибке.
Давайте для закрепления составим еще один запрос, узнаем, какие сообщения на форуме оставлял автор темы "велосипеды":
Теперь усложним задачу, узнаем, в каких темах оставлял сообщения автор темы "велосипеды":
Сначала MySQL выполнит самый глубокий запрос:
SELECT id_author FROM topics WHERE topic_name='велосипеды'
SELECT id_topic FROM posts WHERE id_author IN (2);
SELECT topic_name FROM topics WHERE id_topic IN (4,1);SELECT name FROM users WHERE id_user IN
(SELECT id_author FROM topics WHERE topic_name='велосипеды');SELECT name FROM users WHERE id_user =
(SELECT id_author FROM topics WHERE topic_name='велосипеды');Научись программировать на Python прямо сейчас!
- Научись программировать на Python прямо сейчас
- Бесплатный курс
Если этот сайт оказался вам полезен, пожалуйста, посмотрите другие наши статьи и разделы.
Предыдущая запись
