En underforespørgsel er en SQL-forespørgsel (Structured Query Language), der er indlejret i en anden SQL-forespørgsel. Kommandoen, som underforespørgslen er indlejret i, omtales som den overordnede forespørgsel. Underforespørgsler bruges til at forbehandle data, der bruges i den overordnede forespørgsel. Underforespørgsler kan anvendes i SELECT
, INSERT
, OPDATERING
og SLET
operationer.
Når underforespørgsler udføres, behandles underforespørgslen først før den overordnede forespørgsel. Når du bygger MySQL-applikationer, giver det flere fordele at bruge underforespørgsler:
- De opdeler SQL-sætningerne i simple logiske enheder, som kan gøre dem nemmere at forstå og vedligeholde. Med andre ord hjælper underforespørgsler med at isolere komplekse dele af forespørgsler.
- De eliminerer behovet for at bruge kompleks
UNION
udsagn ogJOIN
udsagn. - De bruges til at håndhæve referenceintegritet i et scenario, hvor fremmednøgler ikke er implementeret.
- De hjælper udviklere med at kode forretningslogik ind i MySQL-forespørgslerne.
I denne guide lærer du:
- Sådan bruges en korreleret underforespørgsel
- Sådan bruges en korreleret underforespørgsel i en sammenligningsoperator
- Sådan bruges en underforespørgsel som en afledt tabel
Før du begynder
For at følge denne vejledning skal du sørge for at have følgende:
-
Hvis du ikke allerede har gjort det, skal du oprette en Linode-konto og Compute Instance. Se vores vejledninger Kom godt i gang med Linode og Oprettelse af en beregningsinstans.
-
Følg vores guide til konfiguration og sikring af en computerinstans for at opdatere dit system. Du ønsker måske også at indstille tidszonen, konfigurere dit værtsnavn, oprette en begrænset brugerkonto og skærpe SSH-adgang.
-
MySQL-serversoftwaren (eller MariaDB) installeret på din Linode. Se venligst MySQL-sektionen, som indeholder vejledninger, der beskriver, hvordan du installerer MySQL på flere Linux-distributioner.
Opsætning af databasen
For at forstå, hvordan underforespørgsler fungerer, skal du først oprette en prøvedatabase. Denne eksempeldatabase bruges til at køre de forskellige eksempelforespørgsler i denne vejledning:
-
SSH
til din server og log ind på MySQL som root:mysql -u root -p
Når du bliver bedt om det, skal du indtaste root-adgangskoden til din MySQL-server og trykke på Enter at fortsætte. Bemærk, at din MySQL-servers root-adgangskode ikke er det samme som root-adgangskoden til din Linode.
Bemærk
Hvis din adgangskode ikke accepteres, skal du muligvis køre den forrige kommando med
sudo
:sudo mysql -u root -p
-
Hvis din adgangskode accepteres, bør du se MySQL-prompten:
mysql>
Bemærk
Hvis du bruger MariaDB, kan du i stedet se en prompt som følgende:
MariaDB [(ingen)]>
-
For at oprette en prøvedatabase med navnet
test_db
, kør:CREATE DATABASE test_db;
Du bør se dette output, som bekræfter, at databasen blev oprettet:
Forespørgsel OK, 1 række påvirket (0,01 sek.)
-
Skift til
test_db
database:BRUG test_db;
Du bør se dette output:
Database ændret
-
Du har oprettet
test_db
og valgte det. Opret derefter en tabel med navnetkunder
:CREATE TABLE-kunder ( customer_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_name VARCHAR(50) ) ENGINE =InnoDB;
Du bør se dette output:
Forespørgsel OK, 0 rækker påvirket (0,03 sek.)
-
Tilføj nogle poster til
kunderne
bord. Kør nedenståendeINSERT
kommandoer én efter én: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');
Dette output vises efter hver post er indsat:
Forespørgsel OK, 1 række påvirket (0,00 sek.)...
-
Bekræft, at kundernes oplysninger blev indsat i databasen. Udfør denne
SELECT
kommando:VÆLG * FRA kunder;
Du bør se denne liste over kunder:
+-------------+----------------+| kunde_id | kundenavn |+-------------+----------------+| 1 | JOHN PAUL || 2 | PETER DOE || 3 | MARY DOE || 4 | CHRISTINE JAMES || 5 | MÆRK GODT || 6 | FRANK BRIAN |+-------------+----------------+6 rækker i sæt (0,00 sek.)
-
Opret en
salg
bord. Denne tabel bruger kolonnencustomer_id
for at henvise tilkunderne
tabel:CREATE TABLE sales(order_id BIGINT PRIMARY KEY AUTO_INCREMENT,customer_id BIGINT,sales_amount DECIMAL(17,2)) ENGINE =InnoDB;
Dette output vises:
Forespørgsel OK, 0 rækker påvirket (0,03 sek.)
-
Udfyld derefter
salg
tabel med nogle poster. Kør nedenståendeINSERT
kommandoer én efter én: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');
Dette output vises efter hver post er indsat:
Forespørgsel OK, 1 række påvirket (0,01 sek.)...
-
Bekræft dataene i
salg
bord. Udfør denneSELECT
kommando:VÆLG * FRA salg;
Denne liste over salgsdata skulle nu blive vist:
+----------+-------------+-------------+| ordre_id | kunde_id | salgsbeløb |+----------+-------------+-------------+| 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 rækker i sæt (0,00 sek. )
Efter opsætning af databasen og de relaterede tabeller, kan du nu implementere de forskellige underforespørgsler i MySQL.
Sådan bruges en korreleret underforespørgsel
En korreleret underforespørgsel er en type indlejret forespørgsel, der bruger værdierne fra en overordnet forespørgsel. Disse typer forespørgsler refererer til den overordnede forespørgsel med en kolonne. Den indlejrede forespørgsel udføres én gang for hver række i den overordnede forespørgsel.
Eksemplet nedenfor præsenterer en forespørgsel, der udvælger alle kunder. Inde i forespørgslen er der en korreleret underforespørgsel, der henter det samlede salgsbeløb for hver kunde fra salg
tabel.
-
Kør eksempelforespørgslen:
SELECTcustomer_id,customer_name,(SELECT SUM(sales_amount)FROM sales WHERE customer_id =customers.customer_id) as total_sales_amountFROMcustomers;
I dette eksempel er underforespørgslen
SELECT SUM(sales_amount) FROM sales WHERE customer_id =customers.customer_id
, som står i parentes.En liste over det samlede salg foretaget af kunder vises:
+-------------+------------------------+---------------- ----------+| kunde_id | kundenavn | samlet_salgsbeløb |+-------------+----------------+-------------- -----+| 1 | JOHN PAUL | 125,75 || 2 | PETER DOE | 130,25 || 3 | MARY DOE | NULL || 4 | CHRISTINE JAMES | 216,55 || 5 | MÆRK GODT | 91,35 || 6 | FRANK BRIAN | NULL |+-------------+------------------------+-------------------- -----+6 rækker i sæt (0,00 sek.)
Outputtet ovenfor fra den korrelerede underforespørgsel er i stand til at give dig en opsummeret liste over kundernes ordrer. Bemærk venligst, da
customer_id
s3
og6
ikke har nogen tilknyttede poster i salgstabellen, derestotal_sales_amount
erNULL
. -
En mere elegant måde at præsentere denne liste på er at returnere
0
i stedet forNULL
for kunder med nul salg. For at gøre dette skal du omslutte output genereret af underforespørgslen med enIFNULL(udtryk, 0)
udmelding. Kør denne opdaterede 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ølgende output vises. MySQL returnerer 0,00 for alle rækker, der ellers ville have returneret
NULL
værdier.+-------------+------------------------+---------------- ----------+| kunde_id | kundenavn | samlet_salgsbeløb |+-------------+----------------+-------------- -----+| 1 | JOHN PAUL | 125,75 || 2 | PETER DOE | 130,25 || 3 | MARY DOE | 0,00 || 4 | CHRISTINE JAMES | 216,55 || 5 | MÆRK GODT | 91,35 || 6 | FRANK BRIAN | 0,00 |+-------------+----------------+------------------- -----+6 rækker i sæt (0,00 sek.)
Denne tilgang hjælper med at sikre, at outputtet ikke skader yderligere beregninger på posterne.
Sådan bruges en korreleret underforespørgsel i en sammenligningsoperatør
Underforespørgsler er nyttige til at flytte forretningslogik til databaseforespørgselsniveauet. Følgende business use-cases indeholder korrelerede underforespørgsler placeret i WHERE-sætningen af en overordnet forespørgsel:
-
Overvej et scenario, hvor du gerne vil have en liste over alle kunder, der er registreret i databasen, og som ikke har tilknyttet salg. Du kan bruge en underforespørgsel sammen med MySQL-sammenligningsoperatoren
NOT IN
og hente disse kunder:SELECT customer_id, customer_name FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
I dette eksempel er underforespørgslen
SELECT customer_id FROM sales
, som står i parentes. SQL-kommandoen ovenfor udsender en liste over to kunder, der ikke findes i salgstabellen:+-------------+--------------+| kunde_id | kundenavn |+-------------+---------------+| 3 | MARY DOE || 6 | FRANK BRIAN |+-------------+------------+2 rækker i sæt (0,00 sek.)
I et produktionsmiljø kan du bruge denne form for rekordsæt til at træffe bedre forretningsbeslutninger. For eksempel kan du oprette et script ved hjælp af et andet sprog som PHP eller Python for at e-maile disse kunder og spørge, om de har problemer med at placere en ordre.
-
En anden use-case er i dataoprydning. For eksempel kan du bruge en underforespørgsel til at slette kunder, der aldrig har afgivet en ordre:
SLET FRA kunder, HVOR customer_id NOT IN (SELECT customer_id FROM sales);
SQL-kommandoen ovenfor sletter de to kunder og udsender følgende:
Forespørgsel OK, 2 rækker påvirket (0,01 sek.)
Hvis du udfører en kommando for at liste alle kunder igen, bør disse kunder ikke længere vises i tabellen:
VÆLG * FRA kunder;
Outputtet nedenfor bekræfter, at kunderne uden tilknyttede ordrer blev slettet:
+-------------+----------------+| kunde_id | kundenavn |+-------------+----------------+| 1 | JOHN PAUL || 2 | PETER DOE || 4 | CHRISTINE JAMES || 5 | MÆRK GODT |+-------------+----------------+4 rækker i sæt (0,00 sek.)
Sådan bruges en underforespørgsel som en afledt tabel
Når underforespørgsler bruges i FROM
klausul i en overordnet forespørgsel, omtales de som afledte tabeller . De er meget vigtige, når du implementerer komplekse forespørgsler, der ellers ville kræve en MySQL VIEW
, JOIN
eller UNION
klausul. En afledt tabel findes i forespørgslen, der oprettede den, og den gemmes ikke permanent i databasen.
Når underforespørgsler bruges som afledte tabeller, isolerer de de forskellige dele af SQL-sætningen. Med andre ord giver underforespørgslen et forenklet udtryk for en tabel, der kan bruges inden for rammerne af den overordnede forespørgsel.
Bemærk Husk, at hver afledt tabel skal have alias.
Kør kommandoen nedenfor for at oprette en afledt tabelunderforespørgsel, der er kaldet order_summary
:
SELECT customer_idFROM ( SELECT customer_id, count(order_id) as total_orders FROM sales group by customer_id ) as order_summaryWHERE order_summary.total_orders> 1;
BemærkI denne kommando vises underforespørgslen i parentes som:
SELECTcustomer_id,count(order_id) as total_ordersFROM salesgroup by customer_id
Ovenstående kommando forespørger salgstabellen for at bestemme kunder med mere end 1 ordre. Når du kører forespørgslen, vises dette output:
+-------------+| kunde_id |+-------------+| 1 || 2 || 5 || 4 |+-------------+4 rækker i sæt (0,00 sek.)
Ovenstående liste viser fire customer_id
s, der har mere end én ordre. Som et eksempel på business use-case kan du bruge sådan en forespørgsel i et script, der belønner kunder med en bonus ved deres næste køb.
Flere oplysninger
Du ønsker måske at konsultere følgende ressourcer for yderligere oplysninger om dette emne. Selvom disse leveres i håb om, at de vil være nyttige, bemærk venligst, at vi ikke kan stå inde for nøjagtigheden eller aktualiteten af eksternt hostede materialer.
- MySQL-underforespørgsler