Введение
Язык структурированных запросов (SQL) используется для управления данными в системе управления реляционными базами данных (RDBMS). Полезной функцией в SQL является создание запроса внутри другого запроса, также известного как подзапрос или вложенный запрос. Вложенный запрос представляет собой оператор SELECT
, обычно заключенный в скобки и вложенный в основную операцию SELECT
, INSERT
или DELETE
.
В этом руководстве вы будете использовать вложенные запросы с операторами SELECT
, INSERT
и DELETE
. Вы также будете использовать агрегатные функции внутри вложенного запроса для сравнения значений данных с отсортированными значениями данных, указанными в WHERE
и LIKE
выражениях.
Предварительные требования
Для выполнения этого руководства вам понадобится компьютер, на котором установлена некоторая система управления реляционными базами данных (RDBMS), использующая SQL. Инструкции и примеры в этом руководстве были проверены в следующей среде:
- A server running Ubuntu 20.04, with a non-root user with
sudo
administrative privileges and firewall enabled. Follow our Initial Server Setup with Ubuntu 20.04 to get started. - MySQL установлен и защищен на сервере. Следуйте нашему руководству Как установить MySQL на Ubuntu 20.04, чтобы настроить это. В этом руководстве предполагается, что вы также настроили неадминистративного пользователя MySQL, как описано в Шаге 3 этого руководства.
Примечание: Обратите внимание, что многие системы управления реляционными базами данных используют свои собственные уникальные реализации SQL. Хотя команды, описанные в этом руководстве, будут работать в большинстве СУБД, точный синтаксис или вывод могут отличаться, если вы их протестируете на системе, отличной от MySQL.
Чтобы попрактиковаться в использовании вложенных запросов в этом учебнике, вам понадобится база данных и таблица, загруженные образцовыми данными. Если у вас нет готовой для вставки, вы можете прочитать следующий раздел Подключение к MySQL и настройка образцовой базы данных, чтобы узнать, как создать базу данных и таблицу. Этот учебник будет ссылаться на эту образцовую базу данных и таблицу в дальнейшем.
Подключение к MySQL и настройка образцовой базы данных
Если ваша база данных SQL работает на удаленном сервере, выполните вход в свой сервер через SSH с вашего локального компьютера:
Затем откройте командную строку MySQL, заменив sammy
на информацию о вашей учетной записи пользователя MySQL:
Создайте базу данных с именем zooDB
:
Если база данных была успешно создана, вы получите следующий вывод:
OutputQuery OK, 1 row affected (0.01 sec)
Чтобы выбрать базу данных zooDB
, выполните следующее выражение USE
:
OutputDatabase changed
После выбора базы данных создайте в ней таблицу. В этом примере урока мы создадим таблицу, которая хранит информацию о гостях, посещающих зоопарк. Эта таблица будет содержать следующие семь столбцов:
guest_id
: хранит значения для гостей, посещающих зоопарк, и использует тип данныхint
. Это также служит в качестве первичного ключа таблицы, что означает, что каждое значение в этом столбце будет функционировать как уникальный идентификатор для соответствующей строки.first_name
: содержит имя каждого гостя с использованием типа данныхvarchar
с максимальной длиной в 30 символов.last_name
: использует тип данныхvarchar
, также с максимальной длиной в 30 символов, для хранения фамилии каждого гостя.guest_type
: содержит тип гостя (взрослый или ребенок) для каждого гостя с использованием типа данныхvarchar
с максимальной длиной в 15 символов.membership_type
: представляет тип членства, который у каждого гостя, с использованием типа данныхvarchar
для хранения максимум 30 символов.membership_cost
: хранит стоимость различных типов членства. Этот столбец использует тип данныхdecimal
с точностью пяти и масштабом два, что означает, что значения в этом столбце могут иметь пять цифр и две цифры справа от десятичной точки.total_visits
: использует тип данныхint
для записи общего количества посещений от каждого гостя.
Создайте таблицу с именем guests
, содержащую каждый из этих столбцов, запустив следующую команду CREATE TABLE
:
Затем вставьте некоторые примеры данных в пустую таблицу:
OutputQuery OK, 15 rows affected (0.01 sec)
Records: 15 Duplicates: 0 Warnings: 0
После вставки данных вы готовы начать использовать вложенные запросы в SQL.
Использование вложенных запросов с SELECT
В SQL запрос – это операция, которая извлекает данные из таблицы в базе данных и всегда включает оператор SELECT
. Вложенный запрос – это полный запрос, встроенный в другую операцию. Вложенный запрос может иметь все элементы, используемые в обычном запросе, и любой допустимый запрос может быть встроен в другую операцию, чтобы стать вложенным запросом. Например, вложенный запрос может быть встроен в операции INSERT
и DELETE
. В зависимости от операции вложенный запрос должен быть встроен, заключив оператор в правильное количество скобок, чтобы следовать определенному порядку операций. Вложенный запрос также полезен в ситуациях, когда вы хотите выполнить несколько команд в одном запросе, а не писать несколько запросов, чтобы получить желаемый результат(ы).
Для лучшего понимания вложенных запросов давайте проиллюстрируем, как они могут быть полезными, используя пример данных из предыдущего шага. Например, предположим, вы хотите найти всех гостей в таблице guests
, которые посещали зоопарк чаще, чем в среднем. Вы можете предположить, что вы можете найти эту информацию с помощью запроса, подобного следующему:
Однако запрос с использованием этого синтаксиса приведет к ошибке:
OutputERROR 1111 (HY000): Invalid use of group function
Причина этой ошибки заключается в том, что агрегатные функции, такие как AVG()
, не работают, если они не выполняются в пределах оператора SELECT
.
Один из вариантов получения этой информации состоит в том, чтобы сначала выполнить запрос для нахождения среднего числа посещений гостями, а затем выполнить другой запрос для поиска результатов на основе этого значения, как в следующих двух примерах:
Output+-----------------+
| avg(total_visits) |
+-----------------+
| 57.5333 |
+-----------------+
1 row in set (0.00 sec)
Output+----------+---------+------------+
| first_name | last_name | total_visits |
+----------+---------+------------+
| Judy | Hopps | 168 |
| Idris | Bogo | 79 |
| Gideon | Grey | 100 |
| Nangi | Reddy | 241 |
| Calvin | Roo | 173 |
+----------+---------+------------+
5 rows in set (0.00 sec)
Однако вы можете получить этот же набор результатов с помощью одного запроса, вложив первый запрос (SELECT AVG(total_visits) FROM guests;
) внутрь второго. Имейте в виду, что при использовании вложенных запросов необходимо использовать правильное количество скобок, чтобы завершить операцию, которую вы хотите выполнить. Это связано с тем, что вложенный запрос является первой операцией, которая выполняется:
Output+------------+-----------+--------------+
| first_name | last_name | total_visits |
+------------+-----------+--------------+
| Judy | Hopps | 168 |
| Idris | Bogo | 79 |
| Gideon | Grey | 100 |
| Nangi | Reddy | 241 |
| Calvin | Roo | 173 |
+------------+-----------+--------------+
5 rows in set (0.00 sec)
Согласно этому выводу, пять гостей посещали зоопарк чаще, чем в среднем. Эта информация может предложить полезные идеи для разработки креативных способов обеспечения того, чтобы текущие члены продолжали часто посещать зоопарк и каждый год продлевали свои абонементы. Более того, этот пример демонстрирует ценность использования вложенного запроса в одном полном операторе для получения желаемых результатов, вместо необходимости запускать два отдельных запроса.
Использование Вложенных Запросов с INSERT
С вложенным запросом вы не ограничены только вставкой его в другие SELECT
операторы. Фактически, вы также можете использовать вложенные запросы для вставки данных в существующую таблицу, вложив ваш вложенный запрос в операцию INSERT
.
Чтобы проиллюстрировать, предположим, что аффилированный зоопарк запрашивает некоторую информацию о ваших гостях, потому что они заинтересованы в предоставлении 15% скидки гостям, которые приобретают членство “Резидент” в их заведении. Для этого используйте CREATE TABLE
, чтобы создать новую таблицу с названием upgrade_guests
, которая будет содержать шесть столбцов. Обратите особое внимание на типы данных, такие как int
и varchar
, а также на максимальное количество символов, которые они могут содержать. Если они не соответствуют исходным типам данных из таблицы guests
, созданной в разделе настройка образцовой базы данных, то при попытке вставки данных из таблицы guests
с использованием вложенного запроса вы получите ошибку, и данные не будут переданы правильно. Создайте вашу таблицу со следующей информацией:
Для согласованности и точности мы сохранили большую часть информации о типах данных в этой таблице такой же, как в таблице guests
. Мы также удалили любые лишние столбцы, которые не нужны в новой таблице. Когда эта пустая таблица готова к использованию, следующим шагом будет вставка желаемых значений данных в таблицу.
В этой операции напишите INSERT INTO
и новую таблицу upgrade_guests
, чтобы было ясно, куда вставляются данные. Затем напишите ваш вложенный запрос с оператором SELECT
, чтобы извлечь соответствующие значения данных, и FROM
, чтобы убедиться, что они берутся из таблицы guests
.
Дополнительно примените 15% скидку к любым членам “Resident”, включив операцию умножения *
на 0.85 внутри вложенного запроса (membership_cost * 0.85
). Затем используйте оператор WHERE
для сортировки значений в столбце membership_type
. Вы можете сузить это еще больше, чтобы получить только результаты для членств “Resident”, используя LIKE
clause и поместите знак процента %
перед и после слова “Resident” в одинарные кавычки, чтобы выбрать любые членства, которые следуют тому же шаблону, или в данном случае тому же словесному описанию. Ваш запрос будет записан следующим образом:
OutputQuery OK, 5 rows affected, 5 warnings (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 5
Результаты указывают, что в новую таблицу upgrade_guests
было добавлено пять записей. Чтобы подтвердить, что запрошенные вами данные успешно перенесены из таблицы guests
в созданную вами пустую таблицу upgrade_guests
, и с условиями, которые вы указали для вложенного запроса и оператора WHERE
, выполните следующее:
Output+----------+------------+------------+-----------------------+-----------------+--------------+
| guest_id | first_name | last_name | membership_type | membership_cost | total_visits |
+----------+------------+------------+-----------------------+-----------------+--------------+
| 1 | Judy | Hopps | Resident Premium Pass | 93.50 | 168 |
| 3 | Duke | Weaselton | Resident Pass | 72.25 | 4 |
| 6 | Jenny | Bellwether | Resident Premium Pass | 93.50 | 20 |
| 10 | Octavia | Otterton | Resident Pass | 72.25 | 11 |
| 11 | Calvin | Roo | Resident Premium Pass | 93.50 | 173 |
+----------+------------+------------+-----------------------+-----------------+--------------+
5 rows in set (0.01 sec)
Согласно этому выводу из вашей новой таблицы upgrade_guests
, информация о гостевых членствах, связанных с “Resident”, из таблицы guest
была вставлена правильно. Кроме того, новая стоимость членства membership_cost
была пересчитана с применением 15% скидки. В результате данная операция помогла сегментировать и нацелить аудиторию, а также предоставила сниженные цены, готовые к предоставлению потенциальным новым членам.
Использование вложенных запросов с оператором DELETE
Для практики использования вложенного запроса с оператором DELETE
, предположим, что вы хотите удалить всех гостей, которые часто посещают, потому что вы хотите сосредоточиться на продвижении скидки на обновленный премиум-пропуск для членов, которые в настоящее время не часто посещают зоопарк.
Начните эту операцию с оператора DELETE FROM
, чтобы было ясно, откуда удаляются данные, в данном случае, из таблицы upgrade_guests
. Затем используйте оператор WHERE
, чтобы отсортировать любые total_visits
, которые больше, чем количество, указанное во вложенном запросе. В вашем встроенном вложенном запросе используйте SELECT
, чтобы найти среднее значение, AVG
, total_visits
, чтобы предшествующий оператор WHERE
имел соответствующие значения данных для сравнения. Наконец, используйте FROM
, чтобы извлечь эту информацию из таблицы guests
. Полный оператор запроса будет следующим:
OutputQuery OK, 2 rows affected (0.00 sec)
Подтвердите, что эти записи успешно удалены из таблицы upgrade_guests
и используйте ORDER BY
, чтобы организовать результаты по total_visits
в числовом и по возрастанию порядке:
Примечание: Использование оператора DELETE
для удаления записей из вашей новой таблицы не приведет к удалению их из исходной таблицы. Вы можете выполнить запрос SELECT * FROM original_table
, чтобы убедиться, что все исходные записи учтены, даже если они были удалены из вашей новой таблицы.
Output+----------+------------+------------+-----------------------+-----------------+--------------+
| guest_id | first_name | last_name | membership_type | membership_cost | total_visits |
+----------+------------+------------+-----------------------+-----------------+--------------+
| 3 | Duke | Weaselton | Resident Pass | 72.25 | 4 |
| 10 | Octavia | Otterton | Resident Pass | 72.25 | 11 |
| 6 | Jenny | Bellwether | Resident Premium Pass | 93.50 | 20 |
+----------+------------+------------+-----------------------+-----------------+--------------+
3 rows in set (0.00 sec)
Как указывает этот вывод, оператор DELETE
и вложенный запрос работали должным образом при удалении указанных данных. Теперь эта таблица содержит информацию о трех гостях с количеством посещений ниже среднего, что является отличной отправной точкой для представителя зоопарка для связи с ними с предложением обновиться до премиум-абонемента по сниженной цене и, надеемся, мотивировать их посещать зоопарк чаще.
Заключение
Вложенные запросы полезны, потому что они позволяют получать очень детализированные результаты, которые вы бы в противном случае могли получить только с помощью выполнения отдельных запросов. Кроме того, использование операторов INSERT
и DELETE
с вложенными запросами предоставляет вам еще один способ вставки или удаления данных в один шаг. Если вы хотите узнать больше о том, как организовать свои данные, о ознакомьтесь с нашей серией статей по теме Как использовать SQL.
Source:
https://www.digitalocean.com/community/tutorials/how-to-use-nested-queries