Een subquery is een SQL-query (Structured Query Language) die is genest in een andere SQL-query. De opdracht waarin de subquery is genest, wordt de bovenliggende query genoemd. Subquery's worden gebruikt om gegevens die in de bovenliggende query worden gebruikt, vooraf te verwerken. Subquery's kunnen worden toegepast in SELECT
, INSERT
, UPDATE
, en DELETE
operaties.
Wanneer subquery's worden uitgevoerd, wordt de subquery eerst verwerkt vóór de bovenliggende query. Bij het bouwen van MySQL-applicaties biedt het gebruik van subquery's verschillende voordelen:
- Ze splitsen de SQL-instructies op in eenvoudige logische eenheden, waardoor ze gemakkelijker te begrijpen en te onderhouden zijn. Met andere woorden, subquery's helpen bij het isoleren van complexe delen van query's.
- Ze elimineren de noodzaak voor het gebruik van complexe
UNION
verklaringen enJOIN
verklaringen. - Ze worden gebruikt om referentiële integriteit af te dwingen in een scenario waarin externe sleutels niet worden geïmplementeerd.
- Ze helpen ontwikkelaars om bedrijfslogica in de MySQL-query's te coderen.
In deze gids leer je:
- Een gecorreleerde subquery gebruiken
- Een gecorreleerde subquery gebruiken in een vergelijkingsoperator
- Een subquery gebruiken als een afgeleide tabel
Voordat u begint
Zorg ervoor dat u over het volgende beschikt om deze handleiding te volgen:
-
Als je dit nog niet hebt gedaan, maak dan een Linode-account en Compute Instance aan. Zie onze handleidingen Aan de slag met Linode en Een rekeninstantie maken.
-
Volg onze handleiding voor het instellen en beveiligen van een rekeninstantie om uw systeem bij te werken. Mogelijk wilt u ook de tijdzone instellen, uw hostnaam configureren, een beperkt gebruikersaccount maken en SSH-toegang versterken.
-
De MySQL-serversoftware (of MariaDB) die op uw Linode is geïnstalleerd. Raadpleeg de sectie MySQL, die handleidingen bevat die beschrijven hoe MySQL op verschillende Linux-distributies moet worden geïnstalleerd.
De database instellen
Maak eerst een voorbeelddatabase om te begrijpen hoe subquery's werken. Deze voorbeelddatabase wordt gebruikt om de verschillende voorbeeldquery's in deze handleiding uit te voeren:
-
SSH
naar uw server en log in op MySQL als root:mysql -u root -p
Voer desgevraagd het root-wachtwoord van uw MySQL-server in en druk op Enter doorgaan. Merk op dat het root-wachtwoord van je MySQL-server niet hetzelfde is als het root-wachtwoord voor je Linode.
Opmerking
Als uw wachtwoord niet wordt geaccepteerd, moet u mogelijk de vorige opdracht uitvoeren met
sudo
:sudo mysql -u root -p
-
Als uw wachtwoord is geaccepteerd, zou u de MySQL-prompt moeten zien:
mysql >
Opmerking
Als u MariaDB gebruikt, ziet u in plaats daarvan mogelijk een prompt zoals de volgende:
MariaDB [(none)]>
-
Een voorbeelddatabase maken met de naam
test_db
, rennen:CREATE DATABASE test_db;
U zou deze uitvoer moeten zien, die bevestigt dat de database met succes is gemaakt:
Query OK, 1 row affected (0.01 sec)
-
Schakel over naar de
test_db
databank:USE test_db;
Je zou deze uitvoer moeten zien:
Database changed
-
Je hebt de
test_db
. gemaakt en selecteerde het. Maak vervolgens een tabel met de naamcustomers
:CREATE TABLE customers ( customer_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_name VARCHAR(50) ) ENGINE = InnoDB;
Je zou deze uitvoer moeten zien:
Query OK, 0 rows affected (0.03 sec)
-
Voeg enkele records toe aan de
customers
tafel. Voer de onderstaandeINSERT
. uit commando's een voor een: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');
Deze uitvoer wordt weergegeven nadat elke record is ingevoegd:
Query OK, 1 row affected (0.00 sec) ...
-
Controleer of de informatie van de klant in de database is ingevoerd. Voer deze
SELECT
uit commando:SELECT * FROM customers;
U zou deze lijst met klanten moeten zien:
+-------------+-----------------+ | 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)
-
Maak een
sales
tafel. Deze tabel gebruikt de kolomcustomer_id
om te verwijzen naar decustomers
tafel:CREATE TABLE sales ( order_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_id BIGINT, sales_amount DECIMAL(17,2) ) ENGINE = InnoDB;
Deze uitvoer verschijnt:
Query OK, 0 rows affected (0.03 sec)
-
Vul vervolgens de
sales
tabel met enkele records. Voer de onderstaandeINSERT
. uit commando's een voor een: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');
Deze uitvoer wordt weergegeven nadat elke record is ingevoegd:
Query OK, 1 row affected (0.01 sec) ...
-
Controleer de gegevens in de
sales
tafel. Voer dezeSELECT
uit commando:SELECT * FROM sales;
Deze lijst met verkoopgegevens zou nu moeten worden weergegeven:
+----------+-------------+--------------+ | 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)
Na het instellen van de database en de gerelateerde tabellen, kunt u nu de verschillende subquery's in MySQL implementeren.
Een gecorreleerde subquery gebruiken
Een gecorreleerde subquery is een type geneste query die de waarden van een bovenliggende query gebruikt. Dit soort query's verwijzen naar de bovenliggende query met een kolom. De geneste query wordt één keer uitgevoerd voor elke rij in de bovenliggende query.
In het onderstaande voorbeeld wordt een query weergegeven die alle klanten selecteert. Binnen de zoekopdracht is er een gecorreleerde subquery die het totale verkoopbedrag voor elke klant ophaalt uit de sales
tafel.
-
Voer de voorbeeldquery uit:
SELECT customer_id, customer_name, (SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id) as total_sales_amount FROM customers;
In dit voorbeeld is de subquery
SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id
, die tussen haakjes verschijnt.Er verschijnt een lijst met de totale verkopen van klanten:
+-------------+-----------------+--------------------+ | 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)
De bovenstaande uitvoer van de gecorreleerde subquery kan u een samengevatte lijst geven van de bestellingen van de klanten. Let op, aangezien
customer_id
s3
en6
geen gekoppelde records in de verkooptabel hebben, huntotal_sales_amount
isNULL
. -
Een elegantere manier om deze lijst weer te geven, is door
0
te retourneren in plaats vanNULL
voor de klanten zonder verkoop. Om dit te doen, moet u de uitvoer die door de subquery is gegenereerd, omsluiten met eenIFNULL(expression, 0)
uitspraak. Voer deze bijgewerkte opdracht uit: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;
De volgende uitvoer verschijnt. MySQL retourneert 0.00 voor alle rijen die anders
NULL
zouden hebben geretourneerd waarden.+-------------+-----------------+--------------------+ | 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)
Deze aanpak helpt ervoor te zorgen dat de uitvoer geen verdere berekeningen op de records schaadt.
Een gecorreleerde subquery gebruiken in een vergelijkingsoperator
Subquery's zijn handig om bedrijfslogica naar het databasequeryniveau te verplaatsen. De volgende zakelijke use-cases bevatten gecorreleerde subquery's die in de WHERE-component van een bovenliggende query zijn geplaatst:
-
Overweeg een scenario waarin u een lijst wilt krijgen van alle klanten die in de database zijn geregistreerd en waaraan geen verkopen zijn gekoppeld. U kunt een subquery gebruiken samen met de MySQL-vergelijkingsoperator
NOT IN
en haal deze klanten op:SELECT customer_id, customer_name FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
In dit voorbeeld is de subquery
SELECT customer_id FROM sales
, die tussen haakjes wordt weergegeven. Het bovenstaande SQL-commando geeft een lijst met twee klanten die niet in de verkooptabel staan:+-------------+---------------+ | customer_id | customer_name | +-------------+---------------+ | 3 | MARY DOE | | 6 | FRANK BRIAN | +-------------+---------------+ 2 rows in set (0.00 sec)
In een productieomgeving kunt u dit soort records gebruiken om betere zakelijke beslissingen te nemen. U kunt bijvoorbeeld een script maken met een andere taal zoals PHP of Python om deze klanten te e-mailen en te informeren of ze een probleem hebben met het plaatsen van een bestelling.
-
Een andere use-case is het opschonen van gegevens. U kunt bijvoorbeeld een subquery gebruiken om klanten te verwijderen die nog nooit een bestelling hebben geplaatst:
DELETE FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
Het bovenstaande SQL-commando verwijdert de twee klanten en geeft het volgende weer:
Query OK, 2 rows affected (0.01 sec)
Als u een opdracht uitvoert om alle klanten opnieuw op te sommen, zouden deze klanten niet langer in de tabel moeten verschijnen:
SELECT * FROM customers;
De onderstaande output bevestigt dat de klanten zonder bijbehorende bestellingen zijn verwijderd:
+-------------+-----------------+ | customer_id | customer_name | +-------------+-----------------+ | 1 | JOHN PAUL | | 2 | PETER DOE | | 4 | CHRISTINE JAMES | | 5 | MARK WELL | +-------------+-----------------+ 4 rows in set (0.00 sec)
Een subquery gebruiken als een afgeleide tabel
Wanneer subquery's worden gebruikt in de FROM
clausule van een bovenliggende zoekopdracht, worden ze afgeleide tabellen genoemd . Ze zijn erg belangrijk bij het implementeren van complexe zoekopdrachten waarvoor anders een MySQL VIEW
nodig zou zijn , JOIN
, of UNION
clausule. Er bestaat een afgeleide tabel in de query die deze heeft gemaakt en wordt niet permanent in de database opgeslagen.
Wanneer subquery's worden gebruikt als afgeleide tabellen, isoleren ze de verschillende delen van de SQL-instructie. Met andere woorden, de subquery biedt een vereenvoudigde uitdrukking van een tabel die kan worden gebruikt binnen het bereik van de bovenliggende query.
Opmerking Onthoud dat elke afgeleide tabel een alias moet hebben.
Voer de onderstaande opdracht uit om een afgeleide tabelsubquery te maken met de alias 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;
OpmerkingIn deze opdracht verschijnt de subquery tussen haakjes als:
SELECT customer_id, count(order_id) as total_orders FROM sales group by customer_id
De bovenstaande opdracht doorzoekt de verkooptabel om klanten met meer dan 1 bestelling te bepalen. Wanneer u de query uitvoert, verschijnt deze uitvoer:
+-------------+
| customer_id |
+-------------+
| 1 |
| 2 |
| 5 |
| 4 |
+-------------+
4 rows in set (0.00 sec)
De bovenstaande lijst toont vier customer_id
s die meer dan één bestelling hebben. Als voorbeeld van een zakelijke use-case kunt u een dergelijke zoekopdracht gebruiken in een script dat klanten beloont met een bonus bij hun volgende aankoop.
Meer informatie
U kunt de volgende bronnen raadplegen voor aanvullende informatie over dit onderwerp. Hoewel deze worden verstrekt in de hoop dat ze nuttig zullen zijn, houd er rekening mee dat we niet kunnen instaan voor de nauwkeurigheid of tijdigheid van extern gehost materiaal.
- MySQL-subquery's