Skip to main content

4.1 Agregačné funkcie

Prehľad agregačných funkcií

Agregačné (group) funkcie umožňujú z viacerých riadkov tabuľky získať nejaký súhrn, napríklad súčet (SUM), počet (COUNT), priemer (AVG), minimum (MIN) a maximum (MAX). Vždy musíme ako parameter funkcie uviesť názov toho stĺpca, s ktorým má počítať.

SELECT
	MIN(salary) AS "najnižší plat",
	MAX(salary) AS "najvyšší plat",
	ROUND(AVG(salary), 2) AS "priemerný plat",
	COUNT(employee_id) AS "počet zamestnancov"
FROM employees;

Pri počítaní priemeru je veľmi vhodné zaokrúhliť výsledok pred zobrazením, pretože SQL vracia výsledok s prehnane veľkým počtom desatinných miest.

Funkcie MIN, MAX a COUNT môžeme použiť aj na hodnoty, ktoré nie sú čísla.

SELECT
	MIN(first_name), -- abecedne prvé meno
	MAX(first_name)  -- abecedne posledné meno
FROM employees;

Obmedzenia agregačných funkcií

Keďže súhrn je len jeden a riadkov v tabuľke veľa, v klauzule SELECT nemôžeme kombinovať agregačné funkcie a jednotlivé stĺpce. Môžeme napríklad získať súčasne minimum i maximum platu, dokonca aj počet zamestnancov, no už nie zároveň aj meno zamestnanca. Databázový server by nevedel, ktoré meno by mal k vypočítanému priemeru či súčtu priradiť. Meno z prvého riadku tabuľky? Posledného? Náhodného?

-- toto nepôjde
SELECT MIN(salary), last_name
FROM employees;

Pozor na MySQL a MariaDB! Kým väčšina SQL systémov vyššie uvedený výraz odmietne spustiť a oznámi chybu, v predvolenom nastavení MariaDB (a v niektorých konfiguráciách MySQL) tento dopyt neskončí chybou, ale vykoná sa! Výsledok je však zradný a logicky nesprávny. Systém určí správne minimum, no meno je vybrané nepredvídateľne a nesúvisí s minimálnym platom.

Filtrovanie údajov

Každá z týchto funkcií má v zátvorke uvedený názov stĺpca (alebo výraz), ktorý má spracovať. Napríklad SUM(salary) v dopyte nad tabuľkou zamestnancov vráti súčet platov. A ktorých zamestnancov? Ak má dopyt aj selekciu s klauzulou WHERE, tak len tých, ktorí vyhovujú uvedenej podmienke.

Dôležité je poradie operácií: agregácia sa vykoná až po selekcii. Databázový server najprv vyfiltruje riadky (WHERE) a až z tých, ktoré zostanú, počíta súčty, či priemery. Preto v podmienke WHERE nemôžeme použiť agregačnú funkciu - v tom čase ešte jej výsledok neexistuje.

-- toto nepôjde, lebo MIN(salary) sa počíta až po vyhodnotení WHERE
SELECT last_name
FROM employees
WHERE salary = MIN(salary);

Na čo si treba dávať pozor

Pri používaní agregačných funkcií si treba uvedomiť určité špecifiká, pozrime sa na niektoré situácie…

NULL hodnoty

Pozor, agregačné funkcie ignorujú NULL hodnoty. Čiže napríklad COUNT(salary) vráti počet len tých zamestnancov, ktorí majú uvedený plat. A tiež AVG(salary) spočíta priemer platov, ignorujúci zamestnancov s neuvedeným platom. Ak chceme NULL hodnotu nahradiť číslom nula (alebo inou hodnotou), použijeme už známu funkciu COALESCE().

Syntax však nie je to, čo by sme mali primárne riešiť - prvoradý je význam dopytu. Napríklad by sme chceli určiť priemernú províziu zamestnancov. Niektorí ju však nemajú vôbec. Situácia sa dá vyložiť dvojako:

  1. Niektorí zamestnanci majú províziu. Chceme vedieť, aká je jej priemerná výška.
    • Počítame teda priemer len tých zamestnancov, ktorí províziu majú.
  2. Chceme vo všeobecnosti poznať, aká je v priemere provízia našich zamestnancov.
    • Počítame všetkých zamestnancov - aj tých, ktorí províziu nemajú. Tým započítame hodnotu 0.
-- v tomto prípade počítame len s tými, ktorí majú nejakú hodnotu
SELECT
	ROUND(AVG(commission_pct) * 100, 1) || ' %'
FROM employees;

-- v tomto prípade rátame so všetkými zamestnancami - dva spôsoby riešenia
SELECT
	ROUND(SUM(commission_pct) / COUNT(*) * 100, 1) || ' %',
	ROUND(AVG(COALESCE(commission_pct, 0)) * 100, 1) || ' %'
FROM employees;

Ktoré riešenie je správne?

Záleží len na tom, čo potrebujeme, prípadne čo potrebuje zadávateľ úlohy.

Voľba stĺpca pre počet

Už pri riešení triviálnej situácie, ako je napríklad určenie počtu oddelení, musíme riešiť otázku, ktorý stĺpec dáme ako parameter funkcie COUNT. Na prvý pohľad sa zdá, že je to jedno, no nie je. Môžeme dať počet mien, ale majú naozaj všetci zamestnanci meno? A budú ho mať aj kedykoľvek v budúcnosti? Čo ak sa časom zmení voliteľnosť atribútu?

Pre zistenie počtu všetkých riadkov vo výsledkoch (bez ohľadu na to, či sú v stĺpcoch NULL hodnoty) by sme mohli počítať výskyt primárnych kľúčov, no jednoduchšie je použiť zápis s hviezdičkou - COUNT(*).

SELECT COUNT(*) AS "počet zamestnancov"
FROM employees;

Na túto zdanlivo banálnu vec treba myslieť hlavne pri komplikovanejších spájaniach viacerých tabuliek.

Eliminácia duplikátov

Ak potrebujeme v agregačnej funkcii spracovať každú opakujúcu sa hodnotu len raz, môžeme využiť kľúčové slovo DISTINCT vo vnútri agregačnej funkcie pred názvom stĺpca, napríklad COUNT(DISTINCT first_name) vráti počet rôznych (neopakujúcich sa) mien.

-- počet rôznych krstných mien
SELECT COUNT(DISTINCT first_name)
FROM employees;