Řídicí struktury v MySQL
- 14. Červenec 2009
- Publikováno v MySQL
- Napište komentář
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á:
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> 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í.
-> 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.
+---------+
| 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.
-> 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ů:
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> 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 ENDPříklad:
-> (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> 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á:
mnozina_prikazu;
END WHILE;
Následující příklad vypíše čísla od jedničky po číslo zadané v parametru:
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
mnozina_prikazu;
UNTIL podminka
END REPEAT;
Příklad opět vypisuje čísla od jedničky po to, které bylo zadáno v parametru:
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)
Excellent post. I was checking continuously this blog and I am impressed! Very useful information specifically the last part
I care for such info a lot. I was looking for this particular info for a long time. Thank you and best of luck.