En underfråga är en SQL-fråga (Structured Query Language) som är kapslad i en annan SQL-fråga. Kommandot som underfrågan är kapslad i kallas den överordnade frågan. Underfrågor används för att förbehandla data som används i den överordnade frågan. Underfrågor kan tillämpas i SELECT
, INSERT
, UPDATE
och DELETE
operationer.
När undersökningar exekveras, bearbetas underfrågan först före den överordnade frågan. När du bygger MySQL-applikationer ger det flera fördelar att använda underfrågor:
- De delar upp SQL-satserna i enkla logiska enheter, vilket kan göra dem lättare att förstå och underhålla. Med andra ord hjälper underfrågor att isolera komplexa delar av frågor.
- De eliminerar behovet av att använda komplexa
UNION
uttalanden ochJOIN
uttalanden. - De används för att upprätthålla referensintegritet i ett scenario där främmande nycklar inte implementeras.
- De hjälper utvecklare att koda in affärslogik i MySQL-frågor.
I den här guiden kommer du att lära dig:
- Hur man använder en korrelerad underfråga
- Hur man använder en korrelerad underfråga i en jämförelseoperator
- Hur man använder en underfråga som en härledd tabell
Innan du börjar
För att följa med i den här guiden, se till att du har följande:
-
Om du inte redan har gjort det, skapa ett Linode-konto och Compute Instance. Se våra guider Komma igång med Linode och Skapa en beräkningsinstans.
-
Följ vår guide för att ställa in och säkra en beräkningsinstans för att uppdatera ditt system. Du kanske också vill ställa in tidszonen, konfigurera ditt värdnamn, skapa ett begränsat användarkonto och förstärka SSH-åtkomsten.
-
MySQL-servermjukvaran (eller MariaDB) installerad på din Linode. Se avsnittet MySQL, som innehåller guider som beskriver hur du installerar MySQL på flera Linux-distributioner.
Konfigurera databasen
För att förstå hur underfrågor fungerar, skapa en exempeldatabas först. Denna exempeldatabas används för att köra de olika exempelfrågorna i den här guiden:
-
SSH
till din server och logga in på MySQL som root:mysql -u root -p
När du uppmanas, ange root-lösenordet för din MySQL-server och tryck på Retur att fortsätta. Observera att din MySQL-servers root-lösenord inte är detsamma som root-lösenordet för din Linode.
Obs
Om ditt lösenord inte accepteras kan du behöva köra det föregående kommandot med
sudo
:sudo mysql -u root -p
-
Om ditt lösenord accepteras bör du se MySQL-prompten:
mysql >
Obs
Om du använder MariaDB kan du se en prompt som följande istället:
MariaDB [(none)]>
-
För att skapa en exempeldatabas med namnet
test_db
, kör:CREATE DATABASE test_db;
Du bör se denna utdata, som bekräftar att databasen skapades framgångsrikt:
Query OK, 1 row affected (0.01 sec)
-
Byt till
test_db
databas:USE test_db;
Du bör se denna utdata:
Database changed
-
Du har skapat
test_db
och valde den. Skapa sedan en tabell med namnetcustomers
:CREATE TABLE customers ( customer_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_name VARCHAR(50) ) ENGINE = InnoDB;
Du bör se denna utdata:
Query OK, 0 rows affected (0.03 sec)
-
Lägg till några poster till
customers
tabell. Kör nedanståendeINSERT
kommandon ett efter ett: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');
Denna utdata visas efter att varje post har infogats:
Query OK, 1 row affected (0.00 sec) ...
-
Verifiera att kundens information har infogats i databasen. Kör denna
SELECT
kommando:SELECT * FROM customers;
Du bör se den här listan över kunder:
+-------------+-----------------+ | 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)
-
Skapa en
sales
tabell. Den här tabellen använder kolumnencustomer_id
för att referera tillcustomers
tabell:CREATE TABLE sales ( order_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_id BIGINT, sales_amount DECIMAL(17,2) ) ENGINE = InnoDB;
Denna utdata visas:
Query OK, 0 rows affected (0.03 sec)
-
Fyll sedan i
sales
tabell med några poster. Kör nedanståendeINSERT
kommandon ett efter ett: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');
Denna utdata visas efter att varje post har infogats:
Query OK, 1 row affected (0.01 sec) ...
-
Verifiera uppgifterna i
sales
tabell. Kör dennaSELECT
kommando:SELECT * FROM sales;
Denna lista med försäljningsdata ska nu visas:
+----------+-------------+--------------+ | 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)
Efter att ha ställt in databasen och de relaterade tabellerna kan du nu implementera de olika underfrågorna i MySQL.
Hur man använder en korrelerad underfråga
En korrelerad underfråga är en typ av kapslad fråga som använder värdena från en överordnad fråga. Den här typen av frågor refererar till den överordnade frågan med en kolumn. Den kapslade frågan exekveras en gång för varje rad i den överordnade frågan.
Exemplet nedan visar en fråga som väljer ut alla kunder. Inuti frågan finns en korrelerad underfråga som hämtar det totala försäljningsbeloppet för varje kund från sales
bord.
-
Kör exempelfrågan:
SELECT customer_id, customer_name, (SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id) as total_sales_amount FROM customers;
I det här exemplet är underfrågan
SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id
, som visas inom parentes.En lista över kundernas totala försäljning visas:
+-------------+-----------------+--------------------+ | 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)
Utdata ovan från den korrelerade underfrågan kan ge dig en sammanfattad lista över kundernas beställningar. Observera, eftersom
customer_id
s3
och6
har inga associerade poster i försäljningstabellen, derastotal_sales_amount
ärNULL
. -
Ett mer elegant sätt att presentera den här listan är att returnera
0
istället förNULL
för kunder med noll försäljning. För att göra detta, omslut utdata som genereras av underfrågan med enIFNULL(expression, 0)
påstående. Kör detta uppdaterade kommando: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;
Följande utgång visas. MySQL returnerar 0,00 för alla rader som annars skulle ha returnerat
NULL
värden.+-------------+-----------------+--------------------+ | 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)
Detta tillvägagångssätt hjälper till att säkerställa att utdata inte skadar några ytterligare beräkningar på posterna.
Hur man använder en korrelerad delfråga i en jämförelseoperatör
Underfrågor är användbara för att flytta affärslogik till databasfrågenivån. Följande affärsanvändningsfall innehåller korrelerade underfrågor placerade i WHERE-satsen i en överordnad fråga:
-
Tänk på ett scenario där du vill få en lista över alla kunder som är registrerade i databasen och som inte har associerad försäljning. Du kan använda en underfråga tillsammans med MySQL-jämförelseoperatorn
NOT IN
och hämta dessa kunder:SELECT customer_id, customer_name FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
I det här exemplet är underfrågan
SELECT customer_id FROM sales
, som visas inom parentes. SQL-kommandot ovan ger en lista över två kunder som inte finns i försäljningstabellen:+-------------+---------------+ | customer_id | customer_name | +-------------+---------------+ | 3 | MARY DOE | | 6 | FRANK BRIAN | +-------------+---------------+ 2 rows in set (0.00 sec)
I en produktionsmiljö kan du använda den här typen av rekord för att fatta bättre affärsbeslut. Du kan till exempel skapa ett skript med ett annat språk som PHP eller Python för att skicka e-post till dessa kunder och fråga om de har problem med att göra en beställning.
-
Ett annat användningsfall är datarensning. Du kan till exempel använda en underfråga för att ta bort kunder som aldrig har lagt en beställning:
DELETE FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
SQL-kommandot ovan tar bort de två kunderna och matar ut följande:
Query OK, 2 rows affected (0.01 sec)
Om du kör ett kommando för att lista alla kunder igen, bör dessa kunder inte längre visas i tabellen:
SELECT * FROM customers;
Utdata nedan bekräftar att kunder utan tillhörande beställningar raderades:
+-------------+-----------------+ | customer_id | customer_name | +-------------+-----------------+ | 1 | JOHN PAUL | | 2 | PETER DOE | | 4 | CHRISTINE JAMES | | 5 | MARK WELL | +-------------+-----------------+ 4 rows in set (0.00 sec)
Hur man använder en underfråga som en härledd tabell
När underfrågor används i FROM
klausul i en överordnad fråga kallas de för härledda tabeller . De är mycket viktiga när du implementerar komplexa frågor som annars skulle kräva en MySQL VIEW
, JOIN
, eller UNION
klausul. En härledd tabell finns i frågan som skapade den och sparas inte permanent i databasen.
När underfrågor används som härledda tabeller, isolerar de de olika delarna av SQL-satsen. Med andra ord ger underfrågan ett förenklat uttryck för en tabell som kan användas inom ramen för den överordnade frågan.
Obs Kom ihåg att varje härledd tabell måste ha alias.
Kör kommandot nedan för att skapa en härledd tabellunderfråga som har alias som 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;
ObsI det här kommandot visas underfrågan inom parentes som:
SELECT customer_id, count(order_id) as total_orders FROM sales group by customer_id
Ovanstående kommando frågar försäljningstabellen för att fastställa kunder med mer än 1 beställning. När du kör frågan visas denna utdata:
+-------------+
| customer_id |
+-------------+
| 1 |
| 2 |
| 5 |
| 4 |
+-------------+
4 rows in set (0.00 sec)
Listan ovan visar fyra customer_id
s som har mer än en beställning. Som ett exempel på affärsanvändning kan du använda en sådan fråga i ett skript som belönar kunder med en bonus vid deras nästa köp.
Mer information
Du kanske vill konsultera följande resurser för ytterligare information om detta ämne. Även om dessa tillhandahålls i hopp om att de kommer att vara användbara, vänligen observera att vi inte kan garantera noggrannheten eller aktualiteten hos externt värdmaterial.
- MySQL-underfrågor