Pokud se při práci s MySQL neomezujete jen na jednoduché dotazy, dříve nebo později narazíte na potřebu řídit běh programových jednotek. Právě o podmínkách a cyklech v MySQL je tento článek.
Konkrétně se zmíním o příkazech IF, CASE, LOOP, ITERATE, LEAVE, WHILE DO a REPEAT UNTIL.

IF - ELSEIF - ELSE, IFNULL, NULLIF


Rozhodování na základě splnění podmínky lze provést jak v programové jednotce, tak přímo v dotazu. Popíšu zde obě možnosti.

IF v programové jednotce


Základní struktura je jednoduchá:

MySQL:
IF podminka THEN mnozina_prikazu;
ELSEIF podminka THEN mnozina_prikazu;
...
ELSE mnozina_prikazu;
END IF;

Chybu zde lze udělat snad jen ve scházejícím středníku. A to buď za každým příkazem z množiny příkazů, nebo častěji za klíčovými slovy END IF.
Pro názornost jednoduchý příklad, který vypíše pohlaví osoby zadaného jména:

MySQL:
mysql> DELIMITER //
mysql> CREATE FUNCTION pohlavi(jm VARCHAR(15))
    -> RETURNS VARCHAR(30)
    -> BEGIN
    -> DECLARE p TINYINT(1);
    -> DECLARE TEXT VARCHAR(30);
    -> SELECT pohlavi INTO p FROM lide WHERE jmeno = jm;
    ->
    -> IF p = '0' THEN SET TEXT = 'muz';
    -> ELSEIF p = '1' THEN SET TEXT = 'zena';
    -> ELSE SET TEXT = 'divny(a)';
    -> END IF;
    ->
    -> SET TEXT = CONCAT(jm, ' je ', TEXT);
    -> RETURN TEXT;
    -> END;//
Query OK, 0 rows affected (0.00 sec)

mysql> DELIMITER ;
mysql> SELECT pohlavi('Eva');
+----------------+
| pohlavi('Eva') |
+----------------+
| Eva je zena    |
+----------------+
1 row in SET (0.00 sec)

IF v dotazu


Tady jsou možnosti tři.
První je konstrukce IF(podminka, vyraz_1, vyraz_2). Pokud je podmínka splněna, platí vyraz_1. Pokud není splněna, platí vyraz_2.
Jako příklad uvedu přepis příznaku do čitelnější podoby. Vymyslet se dá však spousta více či méně užitečných věcí.

MySQL:
mysql> SELECT jmeno, IF(pohlavi = 0,'Muz','Zena') AS pohlavi           
    -> FROM lide;
+-------+---------+
| jmeno | pohlavi |
+-------+---------+
| Marta | Zena    |
| Petr  | Muz     |
| Jarka | Zena    |
| Eva   | Zena    |
| Ondra | Muz     |
| Marek | Muz     |
+-------+---------+
6 rows in SET (0.00 sec)

Druhou možností je IFNULL(vyraz_1, vyraz_2). Pokud je vyraz_1 NULL, platí vyraz_2. V opačném případě platí vyraz_1.

MySQL:
mysql> SELECT IFNULL(NULL, 'je null') AS test;
+---------+
| test    |
+---------+
| je NULL |
+---------+
1 row in SET (0.01 sec)

mysql> SELECT IFNULL('neni null', 'je null') AS test;
+-----------+
| test      |
+-----------+
| neni NULL |
+-----------+
1 row in SET (0.00 sec)

Do třetice je tu NULLIF(vyraz_1, vyraz_2). Pokud jsou si výrazy rovny, pak je výsledek NULL. Pokud si rovny nejsou, platí vyraz_1.

MySQL:
mysql> SELECT NULLIF(jmeno, pohlavi) AS test
    -> FROM lide
    -> WHERE jmeno = 'Eva';
+------+
| test |
+------+
| Eva  |
+------+
1 row in SET (0.00 sec)

mysql> SELECT NULLIF(jmeno, jmeno) AS test
    -> FROM lide
    -> WHERE jmeno = 'Eva';
+------+
| test |
+------+
| NULL |
+------+
1 row in SET (0.00 sec)

CASE


Vícecestné větvení lze, stejně jako IF, použít jak v příkazech, tak programových jednotkách.

CASE v programové jednotce


Ani zde není struktura nijak složitá, či odlišná od programovacích jazyků:

MySQL:
CASE promenna
WHEN hodnota_1 THEN mnozina_prikazu;
WHEN hodnota_2 THEN mnozina_prikazu;
...
ELSE mnozina_prikazu;
END CASE;

Jelikož v tomto článku nejde o vysvětlování jednotlivých příkazů, přejdu rovnou k příkladu. Ten by měl dělat to samé, co příklad u příkazu IF.

MySQL:
mysql> DELIMITER //
mysql> CREATE FUNCTION pohlavi2(jm VARCHAR(15))
    -> RETURNS VARCHAR(30)
    -> BEGIN
    -> DECLARE p TINYINT(1);
    -> DECLARE TEXT VARCHAR(30);
    -> SELECT pohlavi INTO p FROM lide WHERE jmeno = jm;
    ->
    -> CASE p
    -> WHEN 0 THEN SET TEXT = 'muz';
    -> WHEN 1 THEN SET TEXT = 'zena';
    -> ELSE SET TEXT = 'divny(a)';
    -> END CASE;
    ->
    -> SET TEXT = CONCAT(jm, ' je ', TEXT);
    -> RETURN TEXT;
    -> END;//
Query OK, 0 rows affected (0.00 sec)

mysql> DELIMITER ;
mysql> SELECT pohlavi2('Eva');
+-----------------+
| pohlavi2('Eva') |
+-----------------+
| Eva je zena     |
+-----------------+
1 row in SET (0.00 sec)

CASE v dotazu


Zápis v dotazu je obdobný jako v programové jednotce, jen možnosti použití jsou menší.
CASE promenna WHEN hodnota_1 THEN vyraz_1 WHEN hodnota_2 THEN vyraz_2 ELSE vyraz_3 END
Příklad:

MySQL:
mysql> SELECT jmeno,                                                           
    -> (CASE pohlavi WHEN 0 THEN 'Muz' WHEN 1 THEN 'Zena' END) AS pohlavi
    -> FROM lide;
+-------+---------+
| jmeno | pohlavi |
+-------+---------+
| Marta | Zena    |
| Petr  | Muz     |
| Jarka | Zena    |
| Eva   | Zena    |
| Ondra | Muz     |
| Marek | Muz     |
+-------+---------+
6 rows in SET (0.00 sec)

LOOP, ITERATE, LEAVE


Smyčka, tedy příkaz LOOP, je určena k opakování všech příkazů umístěných ve smyčce. Opakování smyčky lze ukončit příkazem LEAVE a nového opakování před koncem smyčky (tedy END LOOP) lze docílit příkazem ITERATE.
Použití všech tří příkazů předvedu na příkladu. Výstupem funkce je řada čísel, které jsou násobky prvního parametru a to až do výše parametru druhého:

MySQL:
mysql> DELIMITER //                                     
mysql> CREATE FUNCTION ciselnaRada(c1 INT(3), c2 INT(3))
    -> RETURNS VARCHAR(30)
    -> BEGIN
    -> DECLARE pocet INT(3) DEFAULT 1;
    -> DECLARE vypocet INT(5);
    -> DECLARE vystup VARCHAR(30) DEFAULT '';
    ->
    -> smycka: LOOP
    -> IF pocet <= c2 THEN
    -> BEGIN
    -> SET vypocet = c1 * pocet;
    -> SET vystup = CONCAT(vystup, ' ', CAST(vypocet AS CHAR));
    -> SET pocet = pocet + 1;
    -> ITERATE smycka;
    -> END;
    -> ELSE LEAVE smycka;
    -> END IF;
    -> END LOOP smycka;
    ->
    -> RETURN vystup;
    -> END;//
Query OK, 0 rows affected (0.00 sec)

mysql> DELIMITER ;
mysql> SELECT ciselnaRada(4,7);
+---------------------+
| ciselnaRada(4,7)    |
+---------------------+
4 8 12 16 20 24 28 |
+---------------------+
1 row in SET (0.00 sec)

Jen upozorním, že konkrétně tento příklad by fungoval stejně i bez příkazu ITERATE smycka. Dodám ještě, že funkce CAST slouží k přetypování výsledku výpočtu, aby jej bylo možné dále zřetězit.

WHILE - DO


Na řadu přichází cyklus s podmínkou na začátku, díky které nemusí být tělo cyklu provedeno ani jednou. Cyklus bude prováděn tak dlouho, dokud bude podmínka platit.
Struktura je opět jednoduchá:

MySQL:
WHILE podminka DO
mnozina_prikazu;
END WHILE;

Následující příklad vypíše čísla od jedničky po číslo zadané v parametru:

MySQL:
mysql> DELIMITER //
mysql> CREATE FUNCTION cyklus2(c INT(3))
    -> RETURNS VARCHAR(30)
    -> BEGIN
    -> DECLARE pocet INT(3) DEFAULT 1;
    -> DECLARE vystup VARCHAR(30) DEFAULT '';
    ->
    -> WHILE pocet <= c DO
    -> SET vystup = CONCAT(vystup, ' ', CAST(pocet AS CHAR));
    -> SET pocet = pocet + 1;
    -> END WHILE;
    ->
    -> RETURN vystup;
    -> END;//
Query OK, 0 rows affected (0.01 sec)

mysql> DELIMITER ;
mysql> SELECT cyklus2(4);
+------------+
| cyklus2(4) |
+------------+
1 2 3 4   |
+------------+
1 row in SET (0.00 sec)

mysql> SELECT cyklus2(0);
+------------+
| cyklus2(0) |
+------------+
|            |
+------------+
1 row in SET (0.00 sec)

REPEAT - UNTIL


Poslední v tomto článku je cyklus s podmínkou na konci. Ta zaručuje, že tělo cyklu bude vykonáno vždy alespoň jednou. Rozdíl oproti předchozímu cyklu je také ten, že se ukončí ve chvíli, kdy je podmínka splněna.
Že struktura celého cyklu je jednoduchá, je snad už zbytečné zmiňovat :-)

MySQL:
REPEAT
mnozina_prikazu;
UNTIL podminka
END REPEAT;

Příklad opět vypisuje čísla od jedničky po to, které bylo zadáno v parametru:

MySQL:
mysql> DELIMITER //
mysql> CREATE FUNCTION cyklus1(c INT(3))
    -> RETURNS VARCHAR(30)
    -> BEGIN
    -> DECLARE pocet INT(3) DEFAULT 1;
    -> DECLARE vystup VARCHAR(30) DEFAULT '';
    ->
    -> REPEAT
    -> SET vystup = CONCAT(vystup, ' ', CAST(pocet AS CHAR));
    -> SET pocet = pocet + 1;
    -> UNTIL pocet> c
    -> END REPEAT;
    ->
    -> RETURN vystup;
    -> END;//
Query OK, 0 rows affected (0.01 sec)

mysql> DELIMITER ;
mysql> SELECT cyklus1(4);
+------------+
| cyklus1(4) |
+------------+
1 2 3 4   |
+------------+
1 row in SET (0.00 sec)

mysql> SELECT cyklus1(0);
+------------+
| cyklus1(0) |
+------------+
1         |
+------------+
1 row in SET (0.01 sec)