Základy SQL

Základy SQL

Proč porozumět SELECT, WHERE a JOIN

SQL (Structured Query Language) je standardní jazyk pro práci s relačními databázemi. Základem prakticky každého dotazu jsou tři stavební kameny: SELECT pro výběr sloupců a výpočtů, WHERE pro filtrování řádků a JOIN pro spojování tabulek. Důkladná znalost jejich syntaxe, pořadí vyhodnocování a běžných úskalí je klíčová pro správné i výkonné dotazy.

Modelový datový model pro příklady

V příkladech budeme pracovat s tabulkami:

  • customers(customer_id, name, city, created_at)
  • orders(order_id, customer_id, order_date, status, total_amount)
  • order_items(order_id, product_id, qty, unit_price)
  • products(product_id, sku, product_name, category)

Základní kostra dotazu a pořadí vyhodnocování

Typická kostra dotazu:

SELECT [DISTINCT] sloupce/výrazy
FROM tabulka [JOIN ...]
WHERE podmínky
GROUP BY ...
HAVING ...
ORDER BY ...
LIMIT/OFFSET ...

Logické pořadí vyhodnocení (důležité pro pochopení chování): FROM → ON → JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT. Například alias definovaný v SELECT nelze použít ve WHERE (s výjimkou některých dialektů), protože WHERE se vyhodnocuje dříve.

SELECT: výběr sloupců, aliasy a výrazy

  • Výběr konkrétních sloupců: SELECT customer_id, name FROM customers; Minimalizujte SELECT * kvůli výkonu a stabilitě schématu.
  • Alias sloupce: SELECT name AS customer_name (zlepšuje srozumitelnost výstupu; AS je volitelné).
  • Výrazy a výpočty: SELECT qty * unit_price AS line_total FROM order_items;
  • Agregační funkce: SELECT COUNT(*) AS orders_cnt FROM orders; (vyžadují GROUP BY, pokud vybíráte i neagregované sloupce).
  • Odstranění duplicit: SELECT DISTINCT city FROM customers;

WHERE: filtrování řádků a práce s NULL

  • Porovnání a logické operátory: =, <>, <, <=, >, >=, AND, OR, NOT
  • Rozsahy a množiny: BETWEEN, IN (...), LIKE (pozor na % a _), ILIKE (PostgreSQL) pro case-insensitive.
  • Datumy: WHERE order_date >= DATE '2025-01-01'; vyhýbejte se funkci na sloupci v podmínce (např. WHERE DATE(order_date)=...) kvůli indexům.
  • NULL není hodnota: porovnává se pomocí IS NULL / IS NOT NULL; výraz col = NULL vrací neznámou (NULL) a neprojde filtrem.
  • Tříhodnotová logika: výsledek podmínky může být TRUE, FALSE nebo UNKNOWN (NULL). WHERE propustí pouze TRUE.

JOIN: spojování tabulek a volba správného typu

INNER JOIN vrací průnik, LEFT JOIN všechny řádky z levé tabulky (pravé chybějící doplní NULL), RIGHT JOIN analogicky, FULL OUTER JOIN sjednocení, CROSS JOIN kartézský součin.

Typ JOIN Popis Typický příklad
INNER JOIN Pouze páry s odpovídající shodou Objednávky s existujícím zákazníkem
LEFT JOIN Vše z levé + shody z pravé, jinak NULL Zákazníci i bez objednávek
RIGHT JOIN Vše z pravé + shody z levé Méně běžné; použijte raději LEFT a prohoďte pořadí
FULL OUTER JOIN Všechny řádky z obou stran Sladění dvou seznamů bez ztráty nesouladů
CROSS JOIN Kartézský součin (bez podmínky) Generování kombinací (např. kalendář × kategorie)

JOIN: ON vs. USING, kvalifikace sloupců a duplikace řádků

  • ON umožňuje libovolnou podmínku: ... JOIN orders o ON o.customer_id = c.customer_id AND o.status = 'PAID'.
  • USING (sloupec) (ANSI SQL) zkracuje zápis při stejném jménu sloupce na obou stranách: ... JOIN orders USING (customer_id) a sloupec se ve výsledku objeví jednou.
  • Kvalifikace: vždy kvalifikujte sloupce aliasem tabulky v dotazech s JOINy (zamezí kolizím jmen a chybám).
  • Násobení řádků: pokud vazba není 1:N/1:1, může JOIN kartézsky násobit řádky (např. více položek objednávky). Pro agregované výsledky používejte GROUP BY nebo DISTINCT s rozmyslem.

Příklady: SELECT + WHERE

  • Zákazníci z konkrétního města registrovaní po datu
    SELECT customer_id, name, city
    FROM customers
    WHERE city = 'Brno' AND created_at >= DATE '2025-01-01';
  • Případy s NULL
    SELECT order_id FROM orders WHERE status IS NULL;
  • Textové vyhledávání
    SELECT product_id, product_name FROM products WHERE product_name LIKE '%kabel%';

Příklady: JOIN a filtrování

  • Seznam zaplacených objednávek s jménem zákazníka
    SELECT o.order_id, c.name, o.total_amount
    FROM orders o
    JOIN customers c ON c.customer_id = o.customer_id
    WHERE o.status = 'PAID';
  • Zákazníci bez jediné objednávky
    SELECT c.customer_id, c.name
    FROM customers c
    LEFT JOIN orders o ON o.customer_id = c.customer_id
    WHERE o.order_id IS NULL;
  • Objednávky s rozpisem položek a kategorií
    SELECT o.order_id, p.category, oi.qty, oi.unit_price, (oi.qty*oi.unit_price) AS line_total
    FROM orders o
    JOIN order_items oi ON oi.order_id = o.order_id
    JOIN products p ON p.product_id = oi.product_id
    WHERE o.order_date >= DATE '2025-09-01';

Agregace a GROUP BY ve spojení s JOIN

  • Tržby podle kategorie
    SELECT p.category, SUM(oi.qty*oi.unit_price) AS revenue
    FROM order_items oi
    JOIN products p ON p.product_id = oi.product_id
    GROUP BY p.category
    HAVING SUM(oi.qty*oi.unit_price) > 10000;
  • Počet objednávek na zákazníka za posledních 30 dní
    SELECT c.customer_id, c.name, COUNT(o.order_id) AS orders_30d
    FROM customers c
    LEFT JOIN orders o ON o.customer_id = c.customer_id
    AND o.order_date >= CURRENT_DATE - INTERVAL '30' DAY
    GROUP BY c.customer_id, c.name;

Výkon: indexy, sargabilita a filtry

  • Sargabilita: pište podmínky tak, aby šly využít indexy (vyhněte se funkcím na sloupcích v WHERE a JOIN). Např. místo WHERE DATE(order_date)=... použijte interval: WHERE order_date >= '2025-10-01' AND order_date < '2025-11-01'.
  • Indexy na cizích klíčích: orders.customer_id, order_items.order_id, order_items.product_id – zrychlují JOIN i referenční integritu.
  • Kombinované indexy: slaďte s typickými filtry a řazením (např. (status, order_date)). Pořadí sloupců v indexu záleží na selektivitě.
  • SELECT pouze potřebné sloupce: zmenší se I/O; u analytických dotazů může pomoci sloupcové uložení (data warehouse).
  • EXPLAIN/EXPLAIN ANALYZE: používejte k porozumění plánům (nested loop/hash join/merge join, cost, kardinalita).

Časté chyby a jak se jim vyhnout

  • Nekvalifikované sloupce v JOIN: kolize jmen (id v obou tabulkách) → používejte aliasy (c.id, o.id).
  • Filtr ve špatné části dotazu: podmínka v WHERE po LEFT JOIN může „zrušit“ levé řádky. Filtry týkající se pravé tabulky dejte do ON, pokud chcete zachovat nulové shody.
  • Porovnání s NULL: používejte IS NULL/IS NOT NULL, nikoli = NULL.
  • Nechtěné násobení řádků: chybí jednoznačná vazba (např. vícenásobné shody) → zvažte deduplikaci (ROW_NUMBER()) nebo agregaci před JOINem.
  • LIKE s předponou %: výraz %text nevyužije běžný index; zvažte fulltext nebo trigramy.

Dialekty SQL: rozdíly, na které dát pozor

  • Limity: LIMIT/OFFSET (PostgreSQL, MySQL) vs. FETCH FIRST ... ROWS ONLY (ANSI/Oracle/DB2) vs. TOP (SQL Server).
  • Case-insensitive LIKE: ILIKE je v PostgreSQL; v jiných dialektech použijte LOWER() a kolace.
  • DATUM/INTERVAL: syntaxe intervalů a funkcí se liší; preferujte standardní literály (DATE 'YYYY-MM-DD').
  • JOIN USING: ne všechny dialekty jej implementují shodně (SQL Server preferuje pouze ON).

Okna (Window Functions) jako doplněk SELECT

I když nejsou součástí názvu tohoto článku, okna často doplňují SELECT bez nutnosti GROUP BY:

  • Běžící součet: SUM(total_amount) OVER (PARTITION BY customer_id ORDER BY order_date)
  • Řazení v rámci skupiny: ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC)

Mikro-vzor: „bezobjednávkoví“ zákazníci (správné použití LEFT JOIN)

Cíl: vrátit zákazníky bez objednávek v období. Správné řešení filtruje období v ON, aby zachovalo i ty, kteří nemají shodu:

SELECT c.customer_id, c.name
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.customer_id
AND o.order_date >= DATE '2025-10-01' AND o.order_date < DATE '2025-11-01'
WHERE o.order_id IS NULL;

Kontrolní checklist pro SELECT–WHERE–JOIN

  1. Jsou vybrány pouze potřebné sloupce a pojmenovány srozumitelnými aliasy?
  2. Je WHERE sargabilní a využije dostupné indexy?
  3. Jsou všechny sloupce v JOIN kvalifikované aliasy a vazby jednoznačné?
  4. Je filtr na pravé tabulce u LEFT JOIN správně umístěn do ON, pokud nechcete ztratit nulové shody?
  5. Je ošetřena logika s NULL a porovnání používají IS NULL/IS NOT NULL?
  6. Byl zkontrolován plán (EXPLAIN) u náročných dotazů a doplněny indexy?

„Tahák“: syntaktické šablony

Úloha Šablona
Výběr s filtrem SELECT col1, col2 FROM t WHERE cond AND col3 BETWEEN a AND b;
INNER JOIN SELECT ... FROM a JOIN b ON a.key = b.key WHERE ...;
LEFT JOIN (zachovat levé) SELECT ... FROM a LEFT JOIN b ON a.key=b.key AND b.cond WHERE b.key IS NULL;
Agregace SELECT k, SUM(x) FROM t WHERE ... GROUP BY k HAVING SUM(x) > n;
Limit + řazení SELECT ... FROM t WHERE ... ORDER BY col DESC FETCH FIRST 20 ROWS ONLY;

Závěr

Stavebnice SELECTWHEREJOIN představuje jádro dotazování v SQL. Porozumění logickému pořadí vyhodnocování, práci s NULL, správnému umístění filtrů a volbě vhodného typu JOIN výrazně snižuje chybovost a zlepšuje výkon. Pečlivé indexování, kvalifikace sloupců a kontrola plánů dotazů jsou praktiky, které posunou vaše dotazy od „funguje“ k „funguje rychle a správně“.

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *