V průběhu doby jsem při řešení různých projektů vytvořil užitečné procedury a funkce, které usnadňují vývoj procedur pro MySQL a mohly by se kdekomu hodit. Proto je na těchto stránkách zveřejňuji.
Nejprve něco o principu, jak procedury pracují. Většinou je jejich
výstupem tabulka. A jelikož v MySQL 5.0 není žádná
možnost, jak výsledek selectu vraceného procedurou zpracovat
v jiné proceduře, osvojil jsem si pravidlo, že výsledek uložím do
TEMPORARY TABLE
se stejným názvem, jako je název procedury. Tedy
např. takto:
CALL lib_Explode(); SELECT * FROM lib_Explode; DROP TEMPORARY TABLE IF EXISTS lib_Explode; -- Volitelně
O uvoňování se obvykle nemusíte starat, funkce si sama tabulku
příště přepíše, a TEMPORARY
tabulky se samy uvolní při
ukončení vlákna (tedy např. po odpojení od databáze).
Procedury, které vracejí tabulku, se snažím psát tak, aby ji vracely pokaždé; při chybě vracejí prázdnou. Pokud tomu tak u některé není, považujte to za chybu a nahlašte.
Pro pohodlí uvádím procedury s určením oddělovače pro MySQL Query Browser. Proto příklady začínají a končí takto:
DELIMITER $$ ... END; $$
lib_Expode()
– obdoba expode() z PHP.F1() - F6()
– "sprintf()"
s 1 až 6 parametry.a výpočet vzdálenosti na (země)kouli podle zadané zeměpisné polohy.
CREATE TABLE lib_logg ( `whn` datetime NOT NULL, `thread` int(10) unsigned NOT NULL, `level` enum('info','warn','error') NOT NULL default 'info', `str` text NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DELIMITER $$ CREATE PROCEDURE Logg( sStr TEXT ) BEGIN INSERT DELAYED INTO lib_logg SET str = sStr, whn = NOW(), thread = CONNECTION_ID(); END; $$ CREATE PROCEDURE Logg_warn( sStr TEXT ) BEGIN INSERT DELAYED INTO lib_logg SET level = 'warn', str = sStr, whn = NOW(), thread = CONNECTION_ID(); END; $$ CREATE PROCEDURE Logg_error( sStr TEXT ) BEGIN INSERT DELAYED INTO lib_logg SET level = 'error', str = sStr, whn = NOW(), thread = CONNECTION_ID(); END; $$ CREATE PROCEDURE LoggP( sRout VARCHAR(255), sStr TEXT ) BEGIN INSERT DELAYED INTO lib_logg SET rout = sRout, str = sStr, whn = NOW(), thread = CONNECTION_ID(); END $$ CREATE PROCEDURE LoggEnter(sRout VARCHAR(255)) BEGIN INSERT INTO lib_logg SET rout = SUBSTRING_INDEX(sRout,'(',1), level='enter', str = sRout, whn = NOW(), thread = CONNECTION_ID(); END $$ CREATE PROCEDURE LoggLeave(sRout VARCHAR(255)) BEGIN INSERT INTO lib_logg SET rout = sRout, level='leave', str = NULL, whn = NOW(), thread = CONNECTION_ID(); END $$
lib_Explode()
–
obdoba Explode()
z PHPDELIMITER $$ CREATE PROCEDURE lib_Explode( sSepar VARCHAR(255), saVal TEXT ) body: BEGIN DROP TEMPORARY TABLE IF EXISTS lib_Explode; CREATE TEMPORARY TABLE lib_Explode( `pos` int unsigned NOT NULL auto_increment, `val` VARCHAR(255) NOT NULL, PRIMARY KEY (`pos`) ) ENGINE=Memory COMMENT='Explode() results.'; IF sSepar IS NULL OR saVal IS NULL THEN LEAVE body; END IF; SET @saTail = saVal; SET @iSeparLen = LENGTH( sSepar ); create_layers: WHILE @saTail != '' DO # Get the next value SET @sHead = SUBSTRING_INDEX(@saTail, sSepar, 1); SET @saTail = SUBSTRING( @saTail, LENGTH(@sHead) + 1 + @iSeparLen ); INSERT INTO lib_Explode SET val = @sHead; END WHILE; END; $$
Použití:
CALL lib_Explode( ',' , 'Ahoj, jak se máte, 212' );
Výsledek:
pos | val |
---|---|
1 | Ahoj |
2 | jak se máte |
3 | 212 |
Poznámka: Pokud byste hledali něco jako lib_Implode()
, tedy
ekvivalent k explode()
, poohlédněte se po „agregační
funkci“ GROUP_CONCAT()
:
CALL lib_GenerateSequence( 5, 15, 2 ); SELECT GROUP_CONCAT(i SEPARATOR ' a ') AS vysledek FROM lib_GenerateSequence;
Výsledek:
vysledek |
---|
5 a 7 a 9 a 11 a 13 a 15 |
F1() - F6()
–
obdoba "sprintf()"
s 1 až 6 parametry.Ve funkci F1() se nahrazuje string %s, v ostatních {1}
až
{6}
.
DELIMITER $$ CREATE FUNCTION F1 ( sFormat TEXT, sPar1 TEXT ) RETURNS text CHARSET utf8 BEGIN RETURN REPLACE(sFormat, '%s', sPar1); END; $$ CREATE FUNCTION F2 ( sFormat TEXT, sPar1 TEXT, sPar2 TEXT ) RETURNS text CHARSET utf8 BEGIN RETURN REPLACE( REPLACE(sFormat, '{1}', sPar1) , '{2}', sPar2); END; $$ CREATE FUNCTION F3 ( sFormat TEXT, sPar1 TEXT, sPar2 TEXT, sPar3 TEXT ) RETURNS text CHARSET utf8 BEGIN RETURN REPLACE( REPLACE( REPLACE(sFormat, '{3}', sPar3), '{1}', sPar1), '{2}', sPar2); END; $$ CREATE FUNCTION F4 ( sFormat TEXT, sPar1 TEXT, sPar2 TEXT, sPar3 TEXT, sPar4 TEXT ) RETURNS text CHARSET utf8 BEGIN RETURN REPLACE( REPLACE( REPLACE( REPLACE( sFormat, '{1}', sPar1), '{2}', sPar2), '{3}', sPar3), '{4}', sPar4); END; $$ CREATE FUNCTION F5 ( sFormat TEXT, sPar1 TEXT, sPar2 TEXT, sPar3 TEXT, sPar4 TEXT, sPar5 TEXT ) RETURNS text CHARSET utf8 BEGIN RETURN REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( sFormat, '{1}', sPar1), '{2}', sPar2), '{3}', sPar3), '{4}', sPar4), '{5}', sPar5); END; $$ CREATE FUNCTION F6 ( sFormat TEXT, sPar1 TEXT, sPar2 TEXT, sPar3 TEXT, sPar4 TEXT, sPar5 TEXT, sPar6 TEXT ) RETURNS text CHARSET utf8 BEGIN RETURN REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( sFormat, '{1}', sPar1), '{2}', sPar2), '{3}', sPar3), '{4}', sPar4), '{5}', sPar5), '{6}', sPar6); END; $$
Použití:
SELECT F2( 'Ve městě {1} je {2} stupňů.', 'Praha', 31.2 ) FROM DUAL;
Výsledek:
Ve městě Praha je 31.2 stupňů. |
Somethimes you need to ensure that no parameter of a function is
NULL
, e.g. in case of calling CONCAT(), which returns
NULL
if any of parameters is NULL
. Writing
IFNULL(@param,'') every time can be tedious; so here are some convenience
functions. Mainly for debugging purposes.
Funkce hlavně pro potřeby logování.
If the only argument is NULL
, returns the string „NULL“.
Otherwise returns:
DELIMITER $$ CREATE FUNCTION NS( s VARCHAR(255) ) RETURNS varchar(255) CHARSET utf8 BEGIN RETURN IF( s IS NULL, 'NULL', CONCAT('"',s,'"') ); END $$ CREATE FUNCTION NSB(b BOOLEAN) RETURNS char(5) CHARSET utf8 NO SQL DETERMINISTIC BEGIN RETURN IF( b IS NULL, 'NULL', IF(b,'TRUE','FALSE') ); END $$ CREATE FUNCTION NSQ(s VARCHAR(255)) RETURNS varchar(255) CHARSET utf8 NO SQL DETERMINISTIC BEGIN RETURN IF( s IS NULL, 'NULL', CONCAT('"',s,'"') ); END $$ DELIMITER ;
Použití:
CALL Logg( F1('Computing level %s.', NS(@iLevel)) )
DELIMITER $$ CREATE PROCEDURE lib_GenerateSequence( iFrom INTEGER, iTo INTEGER, iStep INTEGER ) body: BEGIN DROP TEMPORARY TABLE IF EXISTS lib_GenerateSequence; CREATE TEMPORARY TABLE lib_GenerateSequence (i INTEGER NOT NULL); ## Exit if one of arguments is NULL. IF iFrom IS NULL OR iTo IS NULL OR iStep IS NULL THEN LEAVE body; END IF; SET @iMin = iFrom; SET @iMax = iTo; InsertLoop: LOOP IF @iMin > @iMax THEN LEAVE InsertLoop; END IF; INSERT INTO lib_GenerateSequence SET i = @iMin; SET @iMin = @iMin + iStep; END LOOP; END; $$
Použití:
CALL lib_GenerateSequence( 5, 15, 2 )
Výsledek:
i |
---|
5 |
7 |
9 |
11 |
13 |
15 |