Skip to main content

5.1 Vnorený dopyt jednoriadkový

Vnorený dopyt

V niektorých situáciách potrebujeme pred vykonaním hlavného dopytu získať nejaký pomocný údaj. V praxi je to možné riešiť na úrovni aplikácie (napr. PHP), no i SQL jazyk samotný nám dáva možnosť využívať vnorený dopyt (subquery). Hlavný dopyt nazývame vonkajší (outer) a v ňom vnorený dopyt je vnútorný (inner).

Vnútorný dopyt celý uzatvárame do bežných zátvoriek a údaje môže (ale nemusí) čerpať z úplne inej tabuľky ako vonkajší dopyt. Vnútorný dopyt sa vždy vykonáva len raz (teda neznižuje efektivitu), a to pred vonkajším dopytom. Výnimkou je takzvaný „korelujúci vnorený dopyt“, ktorým sa budeme zaoberať v kapitole „5.3 Vnorený dopyt korelujúci“.

Jednoriadkový vs. viacriadkový

Je veľmi dôležité rozlíšiť, či vnútorný dopyt vždy a za každých okolností (pri akýchkoľvek dátach) vráti len jeden riadok výsledkov - vtedy ho nazývame jednoriadkový (single-row) alebo môže potenciálne vrátiť aj viac riadkov - vtedy ho nazývame viacriadkový (multiple-row).

Jednoriadkový vnorený dopyt

Jednoriadkový vnorený dopyt sa typicky používa v klauzule WHERE alebo HAVING. Keďže vracia len jeden riadok výsledkov a obvykle ním získavame len jeden stĺpec, môžeme hodnotu vybraného stĺpca porovnávať využitím bežných operátorov (=, !=, <, >, <=, >=).

Vnorené dopyty je často možné využívať aj ako náhradu spájania tabuliek, napríklad ak chceme počet zamestnancov z oddelenia „IT“, môžeme využiť spojenie tabuliek alebo vnorený dopyt:

-- riešenie cez spojenie tabuliek
SELECT COUNT(*)
FROM employees e
  JOIN departments d USING(department_id)
WHERE d.department_name = 'IT';

-- riešenie cez vnorený dopyt:
SELECT COUNT(*)
FROM employees
WHERE department_id = (
  SELECT department_id
  FROM departments
  WHERE department_name = 'IT'
);

V prípade tohto vnoreného dopytu si musíme byť istí, že nemôžu existovať viaceré oddelenia s menom „IT“, inak by dopyt zlyhal! Nešlo by totiž o jednoriadkový dopyt. V ďalšej kapitole sa naučíme, ako sa s tým vysporiadať.

Využitie agregácie

Vo vnorených dopytoch môžeme využívať agregačné funkcie, napríklad pre zistenie priemeru / súčtu / minima / maxima. V takom prípade máme zaručené, že pôjde o jednoriadkový dopyt (pokiaľ nepoužívame zoskupovanie).

Vnorený dopyt ako zdroj údajov

Vnorený dopyt je možné použiť aj v klauzule FROM, čo má význam hlavne pri vnorenej agregácii. Vtedy je však potrebné použiť preň alias (ktorý sa využije ako virtuálna tabuľka):

SELECT názov.stĺpec
FROM (
  SELECT stĺpec
  FROM …
) AS názov;

Napríklad, ak chceme z prehľadu mien a počtu ich výskytov získať počty a priemery:

SELECT
  COUNT(mena.meno) AS "počet mien",
  AVG(mena.pocet) AS "priemerný počet výskytov"
FROM (
  SELECT
    first_name AS meno,
    COUNT(*) AS pocet
  FROM employees
  GROUP BY first_name
) AS mena;

Vnorený dopyt v klauzule FROM je možné realizovať aj prehľadnejšie - výrazom WITH, s ktorým sa zoznámime v kapitole „5.3 Vnorený dopyt korelujúci“. Uvedený príklad by bol:

WITH mena AS (
  SELECT
    first_name AS meno,
    COUNT(*) AS pocet
  FROM employees
  GROUP BY first_name
)
SELECT
  COUNT(meno) AS "počet mien",
  AVG(pocet) AS "priemerný počet výskytov"
FROM mena;