Poddotaz je dotaz SQL (Structured Query Language), který je vnořen do jiného dotazu SQL. Příkaz, ve kterém je poddotaz vnořen, se nazývá nadřazený dotaz. Poddotazy se používají k předběžnému zpracování dat, která se používají v nadřazeném dotazu. Poddotazy lze použít v SELECT
, INSERT
, UPDATE
a DELETE
operace.
Při provádění poddotazů je poddotaz zpracován jako první před nadřazeným dotazem. Při vytváření aplikací MySQL nabízí použití poddotazů několik výhod:
- Rozdělují příkazy SQL do jednoduchých logických celků, což usnadňuje jejich pochopení a údržbu. Jinými slovy, dílčí dotazy pomáhají izolovat složité části dotazů.
- Odstraňují potřebu používat složitý
UNION
prohlášení aJOIN
prohlášení. - Používají se k vynucení referenční integrity ve scénáři, kde nejsou implementovány cizí klíče.
- Pomáhají vývojářům kódovat obchodní logiku do dotazů MySQL.
V této příručce se dozvíte:
- Jak používat korelovaný poddotaz
- Jak používat korelovaný poddotaz v operátoru porovnání
- Jak používat poddotaz jako odvozenou tabulku
Než začnete
Chcete-li pokračovat v této příručce, ujistěte se, že máte následující:
-
Pokud jste tak ještě neučinili, vytvořte si účet Linode a Compute Instance. Podívejte se na naše příručky Začínáme s Linode a Vytvoření výpočetní instance.
-
Při aktualizaci systému postupujte podle našeho průvodce nastavením a zabezpečením výpočetní instance. Můžete také chtít nastavit časové pásmo, nakonfigurovat název hostitele, vytvořit omezený uživatelský účet a posílit přístup SSH.
-
Serverový software MySQL (nebo MariaDB) nainstalovaný na vašem Linode. Podívejte se prosím do sekce MySQL, která obsahuje průvodce popisující, jak nainstalovat MySQL na několik distribucí Linuxu.
Nastavení databáze
Chcete-li pochopit, jak fungují poddotazy, vytvořte nejprve ukázkovou databázi. Tato ukázková databáze se používá ke spouštění různých příkladů dotazů v této příručce:
-
SSH
na váš server a přihlaste se k MySQL jako root:mysql -u root -p
Po zobrazení výzvy zadejte heslo uživatele root vašeho serveru MySQL a stiskněte Enter pokračovat. Všimněte si, že root heslo vašeho MySQL serveru není stejné jako root heslo vašeho Linode.
Poznámka
Pokud vaše heslo nebude přijato, možná budete muset spustit předchozí příkaz pomocí
sudo
:sudo mysql -u root -p
-
Pokud je vaše heslo přijato, měli byste vidět výzvu MySQL:
mysql >
Poznámka
Pokud používáte MariaDB, může se vám místo toho zobrazit výzva podobná následující:
MariaDB [(none)]>
-
Chcete-li vytvořit ukázkovou databázi s názvem
test_db
, spustit:CREATE DATABASE test_db;
Měli byste vidět tento výstup, který potvrzuje, že databáze byla úspěšně vytvořena:
Query OK, 1 row affected (0.01 sec)
-
Přepněte na
test_db
databáze:USE test_db;
Měli byste vidět tento výstup:
Database changed
-
Vytvořili jste
test_db
a vybral to. Dále vytvořte tabulku s názvemcustomers
:CREATE TABLE customers ( customer_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_name VARCHAR(50) ) ENGINE = InnoDB;
Měli byste vidět tento výstup:
Query OK, 0 rows affected (0.03 sec)
-
Přidejte nějaké záznamy do
customers
stůl. Spusťte níže uvedený příkazINSERT
příkazy jeden po druhém: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');
Tento výstup se zobrazí po vložení každého záznamu:
Query OK, 1 row affected (0.00 sec) ...
-
Ověřte, že informace o zákaznících byly vloženy do databáze. Spusťte tento
SELECT
příkaz:SELECT * FROM customers;
Měli byste vidět tento seznam zákazníků:
+-------------+-----------------+ | 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)
-
Vytvořte
sales
stůl. Tato tabulka používá sloupeccustomer_id
odkazovat nacustomers
tabulka:CREATE TABLE sales ( order_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_id BIGINT, sales_amount DECIMAL(17,2) ) ENGINE = InnoDB;
Zobrazí se tento výstup:
Query OK, 0 rows affected (0.03 sec)
-
Dále vyplňte
sales
tabulka s některými záznamy. Spusťte níže uvedený příkazINSERT
příkazy jeden po druhém: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');
Tento výstup se zobrazí po vložení každého záznamu:
Query OK, 1 row affected (0.01 sec) ...
-
Ověřte údaje v
sales
stůl. Spusťte tentoSELECT
příkaz:SELECT * FROM sales;
Nyní by se měl zobrazit tento seznam údajů o prodeji:
+----------+-------------+--------------+ | 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)
Po nastavení databáze a souvisejících tabulek nyní můžete implementovat různé poddotazy v MySQL.
Jak používat korelovaný poddotaz
Korelovaný poddotaz je typ vnořeného dotazu, který používá hodnoty z nadřazeného dotazu. Tyto druhy dotazů odkazují na nadřazený dotaz se sloupcem. Vnořený dotaz se provede jednou pro každý řádek v nadřazeném dotazu.
Níže uvedený příklad představuje dotaz, který vybere všechny zákazníky. Uvnitř dotazu je korelovaný dílčí dotaz, který načte celkovou částku prodeje pro každého zákazníka z sales
tabulka.
-
Spusťte příklad dotazu:
SELECT customer_id, customer_name, (SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id) as total_sales_amount FROM customers;
V tomto příkladu je poddotaz
SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id
, který je uveden v závorkách.Zobrazí se seznam celkových prodejů uskutečněných zákazníky:
+-------------+-----------------+--------------------+ | 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)
Výše uvedený výstup z korelovaného dílčího dotazu vám může poskytnout souhrnný seznam objednávek zákazníků. Vezměte prosím na vědomí, protože
customer_id
s3
a6
nemají žádné přidružené záznamy v tabulce prodejů, jejichtotal_sales_amount
jeNULL
. -
Elegantnějším způsobem prezentace tohoto seznamu je vrátit
0
místoNULL
pro zákazníky s nulovým prodejem. Chcete-li to provést, uzavřete výstup generovaný poddotazem pomocíIFNULL(expression, 0)
prohlášení. Spusťte tento aktualizovaný příkaz: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;
Zobrazí se následující výstup. MySQL vrací 0,00 pro všechny řádky, které by jinak vrátily
NULL
hodnoty.+-------------+-----------------+--------------------+ | 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)
Tento přístup pomáhá zajistit, že výstup nepoškodí žádné další výpočty v záznamech.
Jak používat korelovaný poddotaz v porovnávacím operátoru
Poddotazy jsou užitečné pro přesun obchodní logiky na úroveň databázového dotazu. Následující obchodní případy použití obsahují korelované poddotazy umístěné v klauzuli WHERE nadřazeného dotazu:
-
Zvažte scénář, kdy byste chtěli získat seznam všech zákazníků registrovaných v databázi, kteří nemají přidružené prodeje. Poddotaz můžete použít společně s operátorem porovnání MySQL
NOT IN
a získat tyto zákazníky:SELECT customer_id, customer_name FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
V tomto příkladu je poddotaz
SELECT customer_id FROM sales
, který je uveden v závorkách. Příkaz SQL uvedený výše zobrazí seznam dvou zákazníků, kteří nejsou nalezeni v tabulce prodejů:+-------------+---------------+ | customer_id | customer_name | +-------------+---------------+ | 3 | MARY DOE | | 6 | FRANK BRIAN | +-------------+---------------+ 2 rows in set (0.00 sec)
V produkčním prostředí můžete tento druh sady záznamů použít k lepším obchodním rozhodnutím. Můžete například vytvořit skript pomocí jiného jazyka, jako je PHP nebo Python, k odeslání e-mailu těmto zákazníkům a dotazu, zda nemají problém s objednávkou.
-
Dalším případem použití je čištění dat. Můžete například použít dílčí dotaz k odstranění zákazníků, kteří nikdy nezadali objednávku:
DELETE FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
Příkaz SQL výše odstraní dva zákazníky a zobrazí následující:
Query OK, 2 rows affected (0.01 sec)
Pokud znovu spustíte příkaz pro seznam všech zákazníků, tito zákazníci by se již neměli v tabulce objevovat:
SELECT * FROM customers;
Níže uvedený výstup potvrzuje, že zákazníci bez přidružených objednávek byli smazáni:
+-------------+-----------------+ | customer_id | customer_name | +-------------+-----------------+ | 1 | JOHN PAUL | | 2 | PETER DOE | | 4 | CHRISTINE JAMES | | 5 | MARK WELL | +-------------+-----------------+ 4 rows in set (0.00 sec)
Jak používat poddotaz jako odvozenou tabulku
Když jsou poddotazy použity v FROM
klauzule nadřazeného dotazu, jsou označovány jako odvozené tabulky . Jsou velmi důležité při implementaci složitých dotazů, které by jinak vyžadovaly VIEW
MySQL , JOIN
nebo UNION
doložka. Odvozená tabulka existuje v dotazu, který ji vytvořil, a není trvale uložena do databáze.
Když jsou poddotazy použity jako odvozené tabulky, izolují různé části příkazu SQL. Jinými slovy, poddotaz poskytuje zjednodušený výraz tabulky, který lze použít v rámci nadřazeného dotazu.
Poznámka Pamatujte, že každá odvozená tabulka musí mít alias.
Spuštěním příkazu níže vytvořte odvozený poddotaz tabulky s aliasem 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;
PoznámkaV tomto příkazu se poddotaz zobrazí v závorkách jako:
SELECT customer_id, count(order_id) as total_orders FROM sales group by customer_id
Výše uvedený příkaz se dotazuje na prodejní tabulku, aby určil zákazníky s více než 1 objednávkou. Po spuštění dotazu se zobrazí tento výstup:
+-------------+
| customer_id |
+-------------+
| 1 |
| 2 |
| 5 |
| 4 |
+-------------+
4 rows in set (0.00 sec)
Výše uvedený seznam obsahuje čtyři customer_id
s, které mají více než jednu objednávku. Jako příklad obchodního použití můžete takový dotaz použít ve skriptu, který odmění zákazníky bonusem při jejich příštím nákupu.
Další informace
Další informace o tomto tématu můžete získat v následujících zdrojích. Přestože jsou poskytovány v naději, že budou užitečné, vezměte prosím na vědomí, že nemůžeme ručit za přesnost nebo aktuálnost externě hostovaných materiálů.
- Poddotazy MySQL