- 1 1. Úvod
- 2 2. Základy klauzule WITH (Common Table Expressions)
- 3 3. Základní použití MySQL klauzule WITH
- 4 4. Praktické příklady rekurzivních klauzulí WITH
- 5 5. Poznámky a úvahy při používání klauzule WITH
- 6 6. Praktické případy použití v reálných scénářích
- 7 7. FAQ (Často kladené otázky)
- 7.1 Q1: Kdy bych měl použít klauzuli WITH?
- 7.2 Q2: Kdy je rekurzivní CTE užitečný?
- 7.3 Q3: Jsou dotazy používající klauzuli WITH efektivnější než pohledy?
- 7.4 Q4: Co způsobuje degradaci výkonu při používání klauzule WITH?
- 7.5 Q5: Jaké alternativy existují pro verze MySQL, které nepodporují klauzuli WITH?
- 7.6 Q6: Jaké jsou osvědčené postupy při používání klauzule WITH?
- 8 8. Závěr
1. Úvod
MySQL je systém pro správu databází široce používaný vývojáři a správci databází, který poskytuje výkonnou a flexibilní funkčnost SQL. Mezi jeho funkcemi je klauzule WITH (Common Table Expression: CTE), zavedená v MySQL 8.0, což je mocný nástroj, který činí SQL dotazy čitelnějšími a zlepšuje jejich udržovatelnost.
Tento článek vysvětluje klauzuli WITH od základů po pokročilé použití, zaměřený na začátečníky až po středně pokročilé uživatele. Konkrétně se věnujeme praktickým tématům, jako je nahrazování poddotazů a implementace rekurzivních dotazů.
Pro ty, kteří se učí SQL nebo mají potíže s optimalizací dotazů v každodenní práci, má tento článek poskytnout konkrétní řešení. Postupujte podle níže uvedeného obsahu, abyste pochopili základy klauzule WITH a aplikovali ji v reálných scénářích.
2. Základy klauzule WITH (Common Table Expressions)
Co je klauzule WITH?
Klauzule WITH je syntaxe používaná k definování dočasného výsledkového souboru (Common Table Expression, CTE) v rámci SQL dotazu a k jeho odkazování v následných dotazech. Je podporována od MySQL 8.0 výše a umožňuje přepsat složité poddotazy do přehlednější a stručnější podoby.
Například při psaní poddotazů přímo může čitelnost klesnout a celý dotaz se může stát rozsáhlým. Použitím klauzule WITH můžete rozdělit dotazy do logických bloků, což usnadňuje jejich pochopení.
Základní syntaxe klauzule WITH
Níže je uvedena základní syntaxe klauzule WITH:
WITH table_name AS (
SELECT column1, column2
FROM original_table
WHERE condition
)
SELECT column1, column2
FROM table_name;
V této syntaxi je po WITH definována virtuální tabulka (Common Table Expression) a následně použita v hlavním dotazu. To usnadňuje stručné vyjádření často opakovaných poddotazů.
Rozdíly oproti poddotazům a pohledům
Klauzule WITH vytváří dočasně dostupný výsledkový soubor a liší se od poddotazů a pohledů v několika ohledech.
| Feature | WITH Clause | Subquery | View |
|---|---|---|---|
| Scope | Valid only within the query | Usable only where defined | Reusable across the entire database |
| Persistence | Temporary | Temporary | Permanent |
| Purpose | Simplifies complex queries | Temporary data extraction | Frequently reused data extraction |
Klauzule WITH je čitelnější než poddotazy a je ideální, když nepotřebujete vytvářet trvalý objekt, jako je pohled.
Výhody používání klauzule WITH
- Zlepšená čitelnost dotazu – I když existuje více poddotazů, jejich organizace pomocí klauzule WITH objasňuje strukturu.
- Zvýšená znovupoužitelnost – Definováním dočasného výsledkového souboru jej můžete v dotazu odkazovat vícekrát.
- Zlepšená udržovatelnost – Protože lze dotazy logicky rozdělit, úpravy a rozšíření jsou snazší.
3. Základní použití MySQL klauzule WITH
Nahrazování poddotazů
Klauzule WITH je mocný nástroj pro zjednodušení složitých poddotazů. Vkládání poddotazů přímo může celý dotaz zkomplikovat a učinit jej těžko čitelným, ale použití klauzule WITH zlepšuje čitelnost.
Níže je základní příklad nahrazení poddotazu pomocí klauzule WITH.
Použití poddotazu:
SELECT AVG(sales.total) AS average_sales
FROM (
SELECT SUM(amount) AS total
FROM orders
GROUP BY customer_id
) AS sales;
Použití klauzule WITH:
WITH sales AS (
SELECT SUM(amount) AS total
FROM orders
GROUP BY customer_id
)
SELECT AVG(sales.total) AS average_sales
FROM sales;
V tomto příkladu je pomocí klauzule WITH definován dočasný výsledkový soubor s názvem sales, který je následně odkazován v hlavním dotazu. To činí celý dotaz srozumitelnějším a lépe uspořádaným.
Definování více Common Table Expressions (CTE)
Klauzule WITH umožňuje definovat více CTE. To umožňuje další modularizaci složitých dotazů.
Příklad:
WITH
sales_per_customer AS (
SELECT customer_id, SUM(amount) AS total_sales
FROM orders
GROUP BY customer_id
),
high_value_customers AS (
SELECT customer_id
FROM sales_per_customer
WHERE total_sales > 10000
)
SELECT customer_id
FROM high_value_customers;
V tomto příkladu sales_per_customer vypočítá celkové tržby na zákazníka a na základě tohoto výsledku high_value_customers vybere zákazníky s vysokými částkami nákupů. Použitím více CTE postupně lze dotazy sestavit krok za krokem.
Použití vnořených CTE
Pomocí vnořených CTE můžete provádět složitější operace s daty.
Example:
WITH
sales_data AS (
SELECT product_id, SUM(amount) AS total_sales
FROM orders
GROUP BY product_id
),
ranked_sales AS (
SELECT product_id, total_sales,
RANK() OVER (ORDER BY total_sales DESC) AS rank
FROM sales_data
)
SELECT product_id, total_sales
FROM ranked_sales
WHERE rank <= 5;
V tomto dotazu sales_data agreguje tržby podle produktu a ranked_sales přiřazuje hodnocení na základě objemu prodeje. Nakonec jsou vybrány nejlepších pět produktů.
Klíčové body pro praktické použití
- Myslete v logických krocích Vytvářejte CTE krok za krokem, aby se zlepšila čitelnost a usnadnilo ladění.
- Ukládejte mezivýsledky výpočtů Skupinové výsledky výpočtů nebo filtrační podmínky použité vícekrát uložte do CTE, abyste snížili duplicitní kód.
- Buďte opatrní s velkými datovými sadami Protože CTE generují dočasné výsledkové sady, zvažte dopad na výkon při práci s velkým množstvím dat.
4. Praktické příklady rekurzivních klauzulí WITH
Co je rekurzivní klauzule WITH?
Rekurzivní klauzule WITH (rekurzivní CTE) je metoda, která používá Common Table Expression k opakovanému provádění dotazu odkazujícího na sebe samého, což umožňuje zpracovávat hierarchická data a iterativní výpočty. Rekurzivní CTE jsou podporovány v MySQL 8.0 a novějších a jsou zvláště užitečné při práci s vztahy rodič‑dítě a hierarchickými strukturami.
Základní syntaxe rekurzivního CTE
Pro definování rekurzivního CTE použijte klíčové slovo WITH RECURSIVE. Základní syntaxe je následující:
WITH RECURSIVE recursive_table_name AS (
initial_query -- starting point of the recursion
UNION ALL
recursive_query -- query called recursively
)
SELECT * FROM recursive_table_name;
- Počáteční dotaz : Načte první datovou sadu pro rekurzivní proces.
- Rekurzivní dotaz : Vytváří nové řádky na základě počátečního dotazu nebo výsledků předchozí iterace.
- UNION ALL : Kombinuje výsledky počátečního dotazu a rekurzivního dotazu.
Příklad: Zpracování hierarchických dat
Rekurzivní CTE se často používají k rozšíření dat s hierarchickou strukturou (např. organizační stromy nebo strom kategorií).
Příklad: Rozšíření hierarchie řízení zaměstnanců
Uvažujme následující tabulku employees:
| employee_id | name | manager_id |
|---|---|---|
| 1 | Alice | NULL |
| 2 | Bob | 1 |
| 3 | Charlie | 1 |
| 4 | David | 2 |
Pomocí těchto dat můžeme vytvořit dotaz, který načte celou hierarchii počínaje zadaným zaměstnancem.
WITH RECURSIVE employee_hierarchy AS (
-- Initial query: get top-level employees
SELECT employee_id, name, manager_id, 1 AS level
FROM employees
WHERE manager_id IS NULL
UNION ALL
-- Recursive query: get direct reports
SELECT e.employee_id, e.name, e.manager_id, eh.level + 1
FROM employees e
INNER JOIN employee_hierarchy eh
ON e.manager_id = eh.employee_id
)
SELECT * FROM employee_hierarchy;
Výsledek:
| employee_id | name | manager_id | level |
|---|---|---|---|
| 1 | Alice | NULL | 1 |
| 2 | Bob | 1 | 2 |
| 3 | Charlie | 1 | 2 |
| 4 | David | 2 | 3 |
V tomto dotazu jsou podřízení vyhledáváni rekurzivně na základě manager_id, čímž se rozšiřuje celá hierarchie.
Omezení a upozornění pro rekurzivní CTE
- Je vyžadována koncová podmínka Pokud rekurzivní dotaz nesplní koncovou podmínku, může dojít k nekonečné smyčce. Vždy zahrňte vhodné podmínky, aby se zabránilo nekonečné rekurzi.
- Dopad na výkon Rekurzivní CTE mohou zahrnovat mnoho výpočtů nad velkými datovými sadami, což může prodloužit dobu provádění. Používejte klauzule
LIMITa filtrační podmínky pro zlepšení efektivity. - Limity hloubky rekurze MySQL má limit hloubky rekurze, proto buďte opatrní při provádění velmi hlubokých rekurzivních procesů. Tento limit lze nastavit pomocí parametru
max_recursive_iterations.
Scénáře, kde jsou užitečné rekurzivní CTE
- Procházení struktury složek : Rekurzivně prohledávejte složky a podsložky.
- Vytváření organizačních diagramů : Vizualizujte hierarchie od manažerů po podřízené.
- Zobrazování stromů kategorií : Získejte hierarchické produktové kategorie nebo struktury štítků.
Rekurzivní CTE jsou výkonný způsob, jak psát stručné SQL dotazy pro tyto scénáře a zároveň zlepšovat čitelnost.
5. Poznámky a úvahy při používání klauzule WITH
Dopad na výkon a optimalizace
- Přepočet CTE Obecně je CTE definované pomocí klauzule WITH přepočítáno pokaždé, když je odkazováno. Proto může použití stejného CTE vícekrát zvýšit dobu provádění dotazu. Příklad:
WITH sales AS ( SELECT product_id, SUM(amount) AS total_sales FROM orders GROUP BY product_id ) SELECT * FROM sales WHERE total_sales > 1000; SELECT COUNT(*) FROM sales;
Ve výše uvedeném případě je sales odkazováno dvakrát, takže je vypočítáno dvakrát. Aby se tomu předešlo, když potřebujete výsledky odkazovat vícekrát, může být efektivní uložit výsledek do dočasné tabulky.
Řešení:
CREATE TEMPORARY TABLE temp_sales AS
SELECT product_id, SUM(amount) AS total_sales
FROM orders
GROUP BY product_id;
SELECT * FROM temp_sales WHERE total_sales > 1000;
SELECT COUNT(*) FROM temp_sales;
- Rozdělení složitých CTE Pokud se klauzule WITH stane příliš hluboce vnořenou, může se celý dotaz stát složitým a obtížně laditelným. Je důležité logiku vhodně rozdělit, aby zpracování v rámci jednoho CTE nebylo nadměrně komplikované.
Používání klauzulí WITH na velkých datových sadách
Klauzule WITH během provádění vytváří dočasné datové sady. Při práci s velkým množstvím dat může to zatížit paměť nebo úložiště.
Opatření:
- Filtrování dat pomocí klauzulí WHERE Snižte výpočet tím, že odfiltrujete zbytečná data uvnitř CTE.
WITH filtered_orders AS ( SELECT * FROM orders WHERE order_date > '2023-01-01' ) SELECT customer_id, SUM(amount) FROM filtered_orders GROUP BY customer_id;
- Použití klauzulí LIMIT Pokud je datová sada velká, použijte
LIMITk získání pouze potřebných dat.
Kompatibilita verzí MySQL
Klauzule WITH v MySQL je podporována od MySQL 8.0 a výše. Protože starší verze WITH nepodporují, musíte zvážit alternativy.
Alternativy:
- Použití poddotazů Použijte poddotazy přímo místo klauzule WITH.
SELECT AVG(total_sales) FROM ( SELECT customer_id, SUM(amount) AS total_sales FROM orders GROUP BY customer_id ) AS sales;
- Vytvoření pohledů Pokud potřebujete opakovaně použitelné dotazy, může být efektivní použití pohledu.
CREATE VIEW sales_view AS SELECT customer_id, SUM(amount) AS total_sales FROM orders GROUP BY customer_id; SELECT AVG(total_sales) FROM sales_view;
Jak správně používat klauzuli WITH
- Upřednostňujte čitelnost Účelem klauzule WITH je organizovat dotazy a zlepšovat čitelnost. Nadměrné používání může dotazy učinit složitějšími, proto ji používejte jen když je to nutné.
- Ověřte výkon Zkontrolujte plán provádění (příkaz
EXPLAIN) a zvažte, jak optimalizovat výkon.EXPLAIN WITH sales AS ( SELECT product_id, SUM(amount) AS total_sales FROM orders GROUP BY product_id ) SELECT * FROM sales WHERE total_sales > 1000;
6. Praktické případy použití v reálných scénářích
Agregace prodejních dat
Zde je příklad agregace prodejních dat po měsících a následného použití tohoto výsledku k výpočtu průměrných měsíčních prodejů.
Příklad: Agregace měsíčních prodejů a výpočet průměru
WITH monthly_sales AS (
SELECT
DATE_FORMAT(order_date, '%Y-%m') AS sales_month,
SUM(amount) AS total_sales
FROM orders
GROUP BY sales_month
)
SELECT
sales_month,
total_sales,
AVG(total_sales) OVER () AS average_sales
FROM monthly_sales;
V tomto dotazu monthly_sales vypočítává prodeje za měsíc a na základě tohoto výsledku se počítá celkový průměrný prodej. To umožňuje data jasně uspořádat a zjednodušuje analýzu.
Filtrování dat na základě konkrétních podmínek
Oddělením složité logiky filtrování do klauzule WITH lze zlepšit čitelnost.
Příklad: Vytvoření seznamu zákazníků s vysokými výdaji
WITH customer_totals AS (
SELECT
customer_id,
SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id
)
SELECT
customer_id,
total_spent
FROM customer_totals
WHERE total_spent > 100000;
V tomto dotazu customer_totals vypočítává celkovou částku nákupů pro každého zákazníka a zákazníci splňující zadanou podmínku jsou vybráni.
Analýza hierarchických dat
Při analýze hierarchických dat, jako jsou organizační struktury nebo kategorie, jsou rekurzivní klauzule WITH mimořádně užitečné.
Příklad: Získání seznamu přímých a nepřímých podřízených
WITH RECURSIVE employee_hierarchy AS (
SELECT
employee_id,
name,
manager_id,
1 AS level
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT
e.employee_id,
e.name,
e.manager_id,
eh.level + 1
FROM employees e
INNER JOIN employee_hierarchy eh
ON e.manager_id = eh.employee_id
)
SELECT
employee_id,
name,
manager_id,
level
FROM employee_hierarchy
ORDER BY level, manager_id;
Tento dotaz vytváří hierarchická data v employee_hierarchy a získává zaměstnance seskupené podle úrovně. Umožňuje dynamické generování informací podobných organizačnímu diagramu.
Pokročilá analýza pomocí více CTE
Využitím více klauzulí WITH lze data zpracovávat krok za krokem, což zjednodušuje složitou analýzu.
Příklad: Extrakce nejprodávanějších produktů podle kategorie
WITH category_sales AS (
SELECT
category_id,
product_id,
SUM(amount) AS total_sales
FROM orders
GROUP BY category_id, product_id
),
ranked_sales AS (
SELECT
category_id,
product_id,
total_sales,
RANK() OVER (PARTITION BY category_id ORDER BY total_sales DESC) AS rank
FROM category_sales
)
SELECT
category_id,
product_id,
total_sales
FROM ranked_sales
WHERE rank <= 3;
V tomto dotazu se vypočítají prodeje podle kategorií a vyberou se tři nejlepší produkty v každé kategorii. Tento přístup je efektivní při zúžení dat na základě konkrétních podmínek.
Klíčové body pro praktické použití
- Navrhněte dotazy v logických fázích Použijte klauzuli WITH k rozdělení dotazů a zpracování dat krok za krokem při zachování čitelnosti.
- Extrahujte pouze potřebná data Použijte klauzule WHERE a LIMIT, abyste se vyhnuli zpracování zbytečných dat a navrhli efektivní dotazy.
- Flexibilní obchodní aplikace Klauzuli WITH lze flexibilně použít pro analýzu prodeje, segmentaci zákazníků, správu zásob a další.

7. FAQ (Často kladené otázky)
Q1: Kdy bych měl použít klauzuli WITH?
A1:
Klauzule WITH je zvláště účinná v následujících situacích:
- Když chcete zjednodušit složité poddotazy.
- Když potřebujete opakovaně použít stejnou datovou sadu v rámci dotazu.
- Když chcete logicky rozdělit dotaz pro zlepšení čitelnosti.
Například v dotazech, které několikrát používají stejné agregační výsledky, klauzule WITH umožňuje efektivnější organizaci.
Q2: Kdy je rekurzivní CTE užitečný?
A2:
Rekurzivní CTE jsou užitečné při zpracování hierarchických struktur nebo iterativních výpočtů. Konkrétně:
- Zpracování hierarchických dat (např. organizační stromy, struktury kategorií).
- Zobrazování hierarchií složek nebo souborů.
- Sekvenční výpočty čísel nebo časových období (např. výpočet Fibonacciho posloupnosti).
Použití rekurzivních CTE usnadňuje rozšiřování a zpracování samoreferenčních dat.
Q3: Jsou dotazy používající klauzuli WITH efektivnější než pohledy?
A3:
Záleží na konkrétním použití.
- klauzule WITH : Vytvoří dočasnou množinu výsledků, která se používá pouze v rámci dotazu. Vhodné pro data, která nepotřebují časté opakované použití.
- Pohled : Trvale uložený v databázi a znovu použitelný v dalších dotazech. Vhodné pro dotazy, které se používají opakovaně.
Je důležité zvolit vhodnou metodu podle konkrétního scénáře.
Q4: Co způsobuje degradaci výkonu při používání klauzule WITH?
A4:
Hlavní příčiny degradace výkonu při používání klauzule WITH zahrnují:
- Přepočítávání CTE : Výsledky se přepočítávají pokaždé, když jsou odkazovány, což zvyšuje dobu zpracování.
- Zpracování velkých datových sad : Generování velkých datových sad v rámci CTE zvyšuje využití paměti a snižuje výkon.
- Nedostatek vhodných indexů : Pokud dotazy uvnitř CTE nepoužívají vhodné indexy, může výkon klesnout.
Opatření:
- Zvažte dočasné tabulky nebo pohledy, pokud je frekvence opakovaného použití vysoká.
- Používejte klauzule WHERE a LIMIT k řádnému omezení dat.
Q5: Jaké alternativy existují pro verze MySQL, které nepodporují klauzuli WITH?
A5:
Ve verzích před MySQL 8.0 není klauzule WITH podporována, proto použijte následující alternativy:
- Použít poddotazy Použijte poddotazy přímo místo klauzule WITH.
SELECT AVG(total_sales) FROM ( SELECT customer_id, SUM(amount) AS total_sales FROM orders GROUP BY customer_id ) AS sales;
- Použít dočasné tabulky Uložte opakovaně použitelné datové sady do dočasné tabulky.
CREATE TEMPORARY TABLE temp_sales AS SELECT customer_id, SUM(amount) AS total_sales FROM orders GROUP BY customer_id; SELECT AVG(total_sales) FROM temp_sales;
Q6: Jaké jsou osvědčené postupy při používání klauzule WITH?
A6:
Mějte na paměti následující osvědčené postupy:
- Upřednostňujte jednoduchost : Nenuťte složitou logiku do jedné klauzule WITH. Rozdělte ji vhodně.
- Ověřte výkon : Zkontrolujte plán provádění pomocí příkazu
EXPLAINa optimalizujte podle potřeby. - Zvažte znovupoužitelnost : Pokud je frekvence opakovaného použití vysoká, využijte pohledy nebo dočasné tabulky.
8. Závěr
Tento článek se zabýval klauzulí WITH (Common Table Expression, CTE) zavedenou v MySQL 8.0, od základů po pokročilé aplikace. Klauzule WITH je mimořádně užitečná pro zjednodušení a zpřehlednění složitých dotazů. Níže jsou hlavní poznatky.
Hlavní výhody klauzule WITH
- Zlepšená čitelnost dotazů Uspořádává složité poddotazy, čímž zvyšuje čitelnost a udržovatelnost SQL kódu.
- Znovupoužitelnost dotazů Efektivně zpracovává data při opakovaném odkazování na stejnou datovou sadu.
- Umožňuje rekurzivní operace s daty Rekurzivní CTE zjednodušují zpracování hierarchických dat a iterativních výpočtů.
Praktické body použití
- Užitečné pro analýzu prodeje a zákaznických dat, umožňující postupnou agregaci.
- Rekurzivní CTE jsou efektivní pro zpracování hierarchických dat (např. organizační diagramy nebo struktury kategorií).
- Kombinace klauzulí WITH s pohledy nebo dočasnými tabulkami umožňuje flexibilní a efektivní operace s databází.
Důležité úvahy
- Klauzule WITH je výkonná, ale nesprávné použití může snížit výkon.
- Posuzujte znovupoužitelnost a výkon případ od případu a v případě potřeby zvolte mezi pohledy nebo dočasnými tabulkami.
- Vždy ověřujte efektivitu dotazu pomocí plánu provádění (příkaz
EXPLAIN).
Další kroky
Používáním klauzule WITH můžete vytvářet efektivnější a udržovatelnější SQL dotazy. Vyzkoušejte ji ve svých reálných projektech podle následujících kroků:
- Začněte s jednoduchými dotazy a procvičujte jejich strukturování pomocí klauzule WITH.
- Vyzkoušejte si rekurzivní CTE pro hierarchická data a složité scénáře.
- Zaměřte se na optimalizaci výkonu, abyste dále zlepšili své SQL dovednosti.
Tímto končí článek. Používejte své znalosti klauzule WITH v MySQL ve své každodenní práci a studiu.


