подзаявка е SQL (Structured Query Language) заявка, която е вложена в друга SQL заявка. Командата, в която е вложена подзаявката, се нарича родителска заявка. Подзаявките се използват за предварителна обработка на данни, които се използват в родителската заявка. Подзаявките могат да се прилагат в SELECT
, INSERT
, UPDATE
и DELETE
операции.
Когато се изпълняват подзаявки, подзаявката се обработва първо преди родителската заявка. Когато създавате MySQL приложения, използването на подзаявки предлага няколко предимства:
- Те разбиват SQL изразите на прости логически единици, което може да ги направи по-лесни за разбиране и поддържане. С други думи, подзаявките помагат да се изолират сложни части от заявките.
- Те премахват необходимостта от използване на комплекс
UNION
изявления иJOIN
изявления. - Те се използват за налагане на референтна цялост в сценарий, при който не се прилагат външни ключове.
- Те помагат на разработчиците да кодират бизнес логиката в MySQL заявките.
В това ръководство ще научите:
- Как да използвате корелирана подзаявка
- Как да използвате корелирана подзаявка в оператор за сравнение
- Как да използваме подзаявка като производна таблица
Преди да започнете
За да следвате това ръководство, уверете се, че имате следното:
-
Ако все още не сте го направили, създайте акаунт в Linode и Compute Instance. Вижте нашите ръководства Първи стъпки с Linode и Създаване на изчислителен екземпляр.
-
Следвайте нашето ръководство за настройка и осигуряване на изчислителен екземпляр, за да актуализирате вашата система. Може също да пожелаете да зададете часовата зона, да конфигурирате името на хоста си, да създадете ограничен потребителски акаунт и да укрепите SSH достъпа.
-
MySQL сървърният софтуер (или MariaDB), инсталиран на вашия Linode. Моля, вижте раздела MySQL, който съдържа ръководства, които описват как да инсталирате MySQL в няколко Linux дистрибуции.
Настройване на базата данни
За да разберете как работят подзаявките, първо създайте примерна база данни. Тази примерна база данни се използва за изпълнение на различните примерни заявки в това ръководство:
-
SSH
към вашия сървър и влезте в MySQL като root:mysql -u root -p
Когато бъдете подканени, въведете root паролата на вашия MySQL сървър и натиснете Enter продължавам. Имайте предвид, че root паролата на вашия MySQL сървър не е същата като root паролата за вашия Linode.
Забележка
Ако паролата ви не е приета, може да се наложи да изпълните предишната команда с
sudo
:sudo mysql -u root -p
-
Ако вашата парола е приета, трябва да видите подканата за MySQL:
mysql >
Забележка
Ако използвате MariaDB, вместо това може да видите подкана като следната:
MariaDB [(none)]>
-
За да създадете примерна база данни с име
test_db
, стартирайте:CREATE DATABASE test_db;
Трябва да видите този изход, който потвърждава, че базата данни е създадена успешно:
Query OK, 1 row affected (0.01 sec)
-
Превключете към
test_db
база данни:USE test_db;
Трябва да видите този изход:
Database changed
-
Създадохте
test_db
и го избра. След това създайте таблица с имеcustomers
:CREATE TABLE customers ( customer_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_name VARCHAR(50) ) ENGINE = InnoDB;
Трябва да видите този изход:
Query OK, 0 rows affected (0.03 sec)
-
Добавете някои записи към
customers
маса. Изпълнете долнияINSERT
команди една по една:INSERT INTO customers(customer_name) VALUES ('JOHN PAUL'); INSERT INTO customers(customer_name) VALUES ('PETER DOE'); INSERT INTO customers(customer_name) VALUES ('MARY DOE'); INSERT INTO customers(customer_name) VALUES ('CHRISTINE JAMES'); INSERT INTO customers(customer_name) VALUES ('MARK WELL'); INSERT INTO customers(customer_name) VALUES ('FRANK BRIAN');
Този изход се показва след вмъкване на всеки запис:
Query OK, 1 row affected (0.00 sec) ...
-
Проверете дали информацията за клиентите е вмъкната в базата данни. Изпълнете този
SELECT
команда:SELECT * FROM customers;
Трябва да видите този списък с клиенти:
+-------------+-----------------+ | customer_id | customer_name | +-------------+-----------------+ | 1 | JOHN PAUL | | 2 | PETER DOE | | 3 | MARY DOE | | 4 | CHRISTINE JAMES | | 5 | MARK WELL | | 6 | FRANK BRIAN | +-------------+-----------------+ 6 rows in set (0.00 sec)
-
Създайте
sales
маса. Тази таблица използва колонатаcustomer_id
за справка сcustomers
таблица:CREATE TABLE sales ( order_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_id BIGINT, sales_amount DECIMAL(17,2) ) ENGINE = InnoDB;
Появява се този изход:
Query OK, 0 rows affected (0.03 sec)
-
След това попълнете
sales
таблица с някои записи. Изпълнете долнияINSERT
команди една по една:INSERT INTO sales (customer_id, sales_amount) VALUES ('1','25.75'); INSERT INTO sales (customer_id, sales_amount) VALUES ('2','85.25'); INSERT INTO sales (customer_id, sales_amount) VALUES ('5','3.25'); INSERT INTO sales (customer_id, sales_amount) VALUES ('4','200.75'); INSERT INTO sales (customer_id, sales_amount) VALUES ('5','88.10'); INSERT INTO sales (customer_id, sales_amount) VALUES ('1','100.00'); INSERT INTO sales (customer_id, sales_amount) VALUES ('2','45.00'); INSERT INTO sales (customer_id, sales_amount) VALUES ('4','15.80');
Този изход се показва след вмъкване на всеки запис:
Query OK, 1 row affected (0.01 sec) ...
-
Проверете данните в
sales
маса. Изпълнете тозиSELECT
команда:SELECT * FROM sales;
Сега трябва да се покаже този списък с данни за продажбите:
+----------+-------------+--------------+ | order_id | customer_id | sales_amount | +----------+-------------+--------------+ | 1 | 1 | 25.75 | | 2 | 2 | 85.25 | | 3 | 5 | 3.25 | | 4 | 4 | 200.75 | | 5 | 5 | 88.10 | | 6 | 1 | 100.00 | | 7 | 2 | 45.00 | | 8 | 4 | 15.80 | +----------+-------------+--------------+ 8 rows in set (0.00 sec)
След като настроите базата данни и свързаните таблици, вече можете да внедрите различните подзаявки в MySQL.
Как да използвате корелирана подзаявка
Корелираната подзаявка е тип вложена заявка, която използва стойностите от родителска заявка. Тези видове заявки препращат към родителската заявка с колона. Вложената заявка се изпълнява веднъж за всеки ред в родителската заявка.
Примерът по-долу представя заявка, която избира всички клиенти. Вътре в заявката има свързана подзаявка, която извлича общата сума на продажбите за всеки клиент от sales
таблица.
-
Изпълнете примерната заявка:
SELECT customer_id, customer_name, (SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id) as total_sales_amount FROM customers;
В този пример подзаявката е
SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id
, което се показва в скоби.Появява се списък с общите продажби, направени от клиенти:
+-------------+-----------------+--------------------+ | customer_id | customer_name | total_sales_amount | +-------------+-----------------+--------------------+ | 1 | JOHN PAUL | 125.75 | | 2 | PETER DOE | 130.25 | | 3 | MARY DOE | NULL | | 4 | CHRISTINE JAMES | 216.55 | | 5 | MARK WELL | 91.35 | | 6 | FRANK BRIAN | NULL | +-------------+-----------------+--------------------+ 6 rows in set (0.00 sec)
Резултатът по-горе от свързаната подзаявка може да ви даде обобщен списък с поръчките на клиентите. Моля, обърнете внимание, тъй като
customer_id
s3
и6
нямат свързани записи в таблицата за продажби, тяхнатаtotal_sales_amount
еNULL
. -
По-елегантен начин да представите този списък е да върнете
0
вместоNULL
за клиенти с нулеви продажби. За да направите това, оградете изхода, генериран от подзаявката сIFNULL(expression, 0)
изявление. Изпълнете тази актуализирана команда:SELECT customer_id, customer_name, IFNULL((SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id), 0) as total_sales_amount FROM customers;
Появява се следният изход. MySQL връща 0.00 за всички редове, които иначе биха върнали
NULL
стойности.+-------------+-----------------+--------------------+ | customer_id | customer_name | total_sales_amount | +-------------+-----------------+--------------------+ | 1 | JOHN PAUL | 125.75 | | 2 | PETER DOE | 130.25 | | 3 | MARY DOE | 0.00 | | 4 | CHRISTINE JAMES | 216.55 | | 5 | MARK WELL | 91.35 | | 6 | FRANK BRIAN | 0.00 | +-------------+-----------------+--------------------+ 6 rows in set (0.00 sec)
Този подход помага да се гарантира, че изходът няма да навреди на по-нататъшни изчисления на записите.
Как да използвате корелирана подзаявка в оператор за сравнение
Подзаявките са полезни за преместване на бизнес логиката на ниво заявка за база данни. Следните бизнес случаи на използване включват корелирани подзаявки, поставени в клаузата WHERE на родителска заявка:
-
Помислете за сценарий, при който бихте искали да получите списък с всички клиенти, регистрирани в базата данни, които нямат свързани продажби. Можете да използвате подзаявка заедно с оператора за сравнение на MySQL
NOT IN
и извлечете тези клиенти:SELECT customer_id, customer_name FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
В този пример подзаявката е
SELECT customer_id FROM sales
, което се появява в скоби. Командата SQL по-горе извежда списък с двама клиенти, които не са открити в таблицата за продажби:+-------------+---------------+ | customer_id | customer_name | +-------------+---------------+ | 3 | MARY DOE | | 6 | FRANK BRIAN | +-------------+---------------+ 2 rows in set (0.00 sec)
В производствена среда можете да използвате този вид набор от записи, за да вземате по-добри бизнес решения. Например, можете да създадете скрипт, използвайки друг език като PHP или Python, за да изпратите имейл до тези клиенти и да попитате дали имат проблем с поставянето на поръчка.
-
Друг случай на употреба е почистването на данни. Например, можете да използвате подзаявка, за да изтриете клиенти, които никога не са направили поръчка:
DELETE FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
Командата SQL по-горе изтрива двата клиента и извежда следното:
Query OK, 2 rows affected (0.01 sec)
Ако изпълните команда за изброяване на всички клиенти отново, тези клиенти вече не трябва да се показват в таблицата:
SELECT * FROM customers;
Изходът по-долу потвърждава, че клиентите без свързани поръчки са били изтрити:
+-------------+-----------------+ | customer_id | customer_name | +-------------+-----------------+ | 1 | JOHN PAUL | | 2 | PETER DOE | | 4 | CHRISTINE JAMES | | 5 | MARK WELL | +-------------+-----------------+ 4 rows in set (0.00 sec)
Как да използвате подзаявка като производна таблица
Когато се използват подзаявки в FROM
клауза на родителска заявка, те се наричат производни таблици . Те са много важни при внедряване на сложни заявки, които иначе биха изисквали MySQL VIEW
, JOIN
или UNION
клауза. В заявката, която я е създала, съществува извлечена таблица и не е запазена за постоянно в базата данни.
Когато подзаявките се използват като производни таблици, те изолират различните части на SQL израза. С други думи, подзаявката предоставя опростен израз на таблица, която може да се използва в обхвата на родителската заявка.
Забележка Не забравяйте, че всяка извлечена таблица трябва да има псевдоним.
Изпълнете командата по-долу, за да създадете подзаявка на извлечена таблица, която е с псевдоним като order_summary
:
SELECT customer_id
FROM
(
SELECT
customer_id,
count(order_id) as total_orders
FROM sales
group by customer_id
) as order_summary
WHERE order_summary.total_orders > 1;
ЗабележкаВ тази команда подзаявката се появява в скоби като:
SELECT customer_id, count(order_id) as total_orders FROM sales group by customer_id
Горната команда прави заявка в таблицата за продажби, за да определи клиенти с повече от 1 поръчка. Когато стартирате заявката, се появява този изход:
+-------------+
| customer_id |
+-------------+
| 1 |
| 2 |
| 5 |
| 4 |
+-------------+
4 rows in set (0.00 sec)
Горният списък показва четири customer_id
които имат повече от една поръчка. Като примерен случай на бизнес употреба можете да използвате такава заявка в скрипт, който награждава клиентите с бонус при следващата им покупка.
Повече информация
Може да пожелаете да се консултирате със следните ресурси за допълнителна информация по тази тема. Въпреки че те са предоставени с надеждата, че ще бъдат полезни, моля, имайте предвид, че не можем да гарантираме за точността или навременността на външно хостваните материали.
- Подзаявки за MySQL