205
MySQL .......:::: Obsah :::...................................................................... MySQL (1) - pestrý svět databází............................................................................................................... 3 MySQL (2) - Instalujeme databázi MySQL............................................................................................... 6 MYSQL (3) Instalujeme MySQL podruhé................................................................................................. 9 MySQL (4) - něco terminologie................................................................................................................. 12 MySQL (5) - tajuplné SQL......................................................................................................................... 16 MySQL (6) - Ukládáme řetězce................................................................................................................. 19 MySQL (7) - hrátky s čísly......................................................................................................................... 22 MySQL (8) - Ukládání datumů.................................................................................................................. 25 MySQL (9) - Další datové typy.................................................................................................................. 28 MySQL (10) - tvorba databáze. Základy DDL........................................................................................... 31 MySQL (11) - vytváříme tabulky............................................................................................................... 34 MySQL (12) - tipy k tvorbě tabulek........................................................................................................... 37 MySQL (13) - Vkládáme data.................................................................................................................... 40 MySQL (14) - Jak v databázi MySQL zaktualizovat data, aneb příkaz UPDATE na sto způsobů. ......... 43 MySQL (15) - Odstraňujeme data.............................................................................................................. 46 MySQL (16) - Něco o příkazu REPLACE. Jak lze jednoduše odstranit z tabulky duplicitní záznamy..... 49 MySQL (17) - vybíráme data......................................................................................................................52 MySQL (18) - Filtrujeme data.................................................................................................................... 56 MySQL (19) - Řadíme data........................................................................................................................ 58 MySQL (20) - spojení více tabulek............................................................................................................ 61 MySQL (21) - klauzule JOIN..................................................................................................................... 64 MySQL (22) - tipy a triky ke spojování tabulek........................................................................................ 66 MySQL (23) - Co znamenají zkratky 1:N a N:N? Proč by nestačilo mít jen jeden typ spojení?............... 69 MySQL (24) - Seskupujeme záznamy....................................................................................................... 72 MySQL (25) - hrátky se seskupenými záznamy......................................................................................... 75 MySQL (26) – Poddotazy.......................................................................................................................... 78 MySQL (27) - Složitější dotazy................................................................................................................. 81 MySQL (28) - Dotazy pro pokročilé.......................................................................................................... 84 MySQL (29) - Vracení nejvyšších záznamů.............................................................................................. 87 MySQL (30) - průběžné součty.................................................................................................................. 90 MySQL (31) – Indexy................................................................................................................................ 93 MySQL (32) - ještě k indexům...................................................................................................................96 MySQL (33) - Příkaz UNION.................................................................................................................... 99 MySQL (34) - větvení kódu a pivotní tabulky........................................................................................... 102 MySQL (35) - vestavěné funkce................................................................................................................ 105 MySQL (36) - Regulární výrazy.................................................................................................................108 MySQL (37) - MySQL umí vyhledávat fulltextem.................................................................................... 111 MySQL (38) - Fulltext a praxe................................................................................................................... 114 MySQL (39) - typy tabulek v MySQL....................................................................................................... 117 MySQL (40) - další typy tabulek................................................................................................................ 120 MySQL (41) – Transakce........................................................................................................................... 123 MySQL (42) - ještě k transakcím............................................................................................................... 126 MySQL (43) - Uložené procedury..............................................................................................................129 MySQL (44) - parametry uložených procedur........................................................................................... 132 MySQL (45) - větvení kódu uložených procedur....................................................................................... 135 MySQL (46) – Triggery............................................................................................................................. 137 MySQL (47) - Triggery a praxe................................................................................................................. 140

MySQL Obsah

Embed Size (px)

DESCRIPTION

MySQL czech

Citation preview

Page 1: MySQL Obsah

MySQL….......:::: Obsah :::......................................................................MySQL (1) - pestrý svět databází...............................................................................................................3MySQL (2) - Instalujeme databázi MySQL............................................................................................... 6MYSQL (3) Instalujeme MySQL podruhé.................................................................................................9MySQL (4) - něco terminologie................................................................................................................. 12MySQL (5) - tajuplné SQL.........................................................................................................................16MySQL (6) - Ukládáme řetězce................................................................................................................. 19MySQL (7) - hrátky s čísly......................................................................................................................... 22MySQL (8) - Ukládání datumů.................................................................................................................. 25MySQL (9) - Další datové typy.................................................................................................................. 28MySQL (10) - tvorba databáze. Základy DDL...........................................................................................31MySQL (11) - vytváříme tabulky............................................................................................................... 34MySQL (12) - tipy k tvorbě tabulek........................................................................................................... 37MySQL (13) - Vkládáme data.................................................................................................................... 40MySQL (14) - Jak v databázi MySQL zaktualizovat data, aneb příkaz UPDATE na sto způsobů. ......... 43MySQL (15) - Odstraňujeme data.............................................................................................................. 46MySQL (16) - Něco o příkazu REPLACE. Jak lze jednoduše odstranit z tabulky duplicitní záznamy.....49MySQL (17) - vybíráme data......................................................................................................................52MySQL (18) - Filtrujeme data....................................................................................................................56MySQL (19) - Řadíme data........................................................................................................................58MySQL (20) - spojení více tabulek............................................................................................................61MySQL (21) - klauzule JOIN.....................................................................................................................64MySQL (22) - tipy a triky ke spojování tabulek........................................................................................ 66MySQL (23) - Co znamenají zkratky 1:N a N:N? Proč by nestačilo mít jen jeden typ spojení?...............69MySQL (24) - Seskupujeme záznamy....................................................................................................... 72MySQL (25) - hrátky se seskupenými záznamy.........................................................................................75MySQL (26) – Poddotazy.......................................................................................................................... 78MySQL (27) - Složitější dotazy................................................................................................................. 81MySQL (28) - Dotazy pro pokročilé.......................................................................................................... 84MySQL (29) - Vracení nejvyšších záznamů.............................................................................................. 87MySQL (30) - průběžné součty..................................................................................................................90MySQL (31) – Indexy................................................................................................................................ 93MySQL (32) - ještě k indexům...................................................................................................................96MySQL (33) - Příkaz UNION....................................................................................................................99MySQL (34) - větvení kódu a pivotní tabulky........................................................................................... 102MySQL (35) - vestavěné funkce................................................................................................................ 105MySQL (36) - Regulární výrazy.................................................................................................................108MySQL (37) - MySQL umí vyhledávat fulltextem....................................................................................111MySQL (38) - Fulltext a praxe...................................................................................................................114MySQL (39) - typy tabulek v MySQL....................................................................................................... 117MySQL (40) - další typy tabulek................................................................................................................120MySQL (41) – Transakce...........................................................................................................................123MySQL (42) - ještě k transakcím............................................................................................................... 126MySQL (43) - Uložené procedury..............................................................................................................129MySQL (44) - parametry uložených procedur........................................................................................... 132MySQL (45) - větvení kódu uložených procedur.......................................................................................135MySQL (46) – Triggery............................................................................................................................. 137MySQL (47) - Triggery a praxe................................................................................................................. 140

Page 2: MySQL Obsah

MySQL (48) – UDF................................................................................................................................... 143MySQL (49) – pohledy.............................................................................................................................. 146MySQL (50) - Pohledy podruhé.................................................................................................................149MySQL (51) – Metadata............................................................................................................................ 152MySQL (52) - A co zálohování?................................................................................................................155MySQL (53) - SELECT INTO OUTFILE................................................................................................. 156MySQL (54) - zálohování MySQL z webu................................................................................................ 161MySQL (55) - zálohování MySQL z pohledu správce...............................................................................164MySQL (56) - Obnova zálohovaných dat.................................................................................................. 167MySQL (57) - Ach, ta čeština.................................................................................................................... 170MySQL (58) - čeština v praxi.....................................................................................................................173MySQL (59) - české řazení........................................................................................................................ 176MySQL (60) - řádkový klient.....................................................................................................................178MySQL (61) – Oprávnění.......................................................................................................................... 181MySQL (62) - Oprávnění podruhé............................................................................................................. 184MySQL (63) - jemné nastavení práv.......................................................................................................... 188MySQL (64) - nad dotazy čtenářů..............................................................................................................191MySQL (65) - Ladíme server..................................................................................................................... 195MySQL (66) - Ještě k ladění serveru..........................................................................................................198MySQL – (67)............................................................................................................................................ 200MySQL (68) - Ukončíme seriál o MySQL. Lehce zamyslíme nad budoucností této databáze..................203

Page 3: MySQL Obsah

MySQL (1) - pestrý svět databází

Začínáme seriál o populární databází MySQL.

1.3.2005 15:00 | Petr Zajíc | přečteno 35122×

Komerční sdělení: Pořádáme Kurzy MySQL

MySQL (1) - Pestrý svět databází

Tímto dílem začínáme seriál o MySQL databázi. Měli byste se v něm dozvědět proč, jak a kde používat tentodatabázový software a také s jakými problémy se přitom můžete setkat. Série bude zaměřena na vývojářepracující s MySQL, na své si však možná přijdou i kolegové používající jiné databáze, protože řešení některýchproblémů bude podobné.

Tento seriál si však především zaslouží, abychom jej začali nějakým obecným pojednáním o databázích.Pojďme to rovnou udělat a podívejme se, kde ve světě databází stojí MySQL.

Databáze, kam se podíváš

S databázemi se samozřejmě setkáváme denně. V nejširším slova smyslu je databáze i seznam věcí, které mámkoupit k obědu, výpis z účtu nebo třebas seznam uskutečněných telefonních hovorů. V počítačovém slovasmyslu se pod výrazem "databáze" obvykle rozumí software, který spravuje určitý "balík" dat a umožňujeuživatelům tento "balík" dat nějak rozumně měnit a spravovat.

Když se například vrátím k výpisu telefonních hovorů, bude situace následující:

Někdo nebo něco (dejme tomu telefonní ústředna) bude zapisovat do databáze údaje o uskutečněnýchhovorech.

Někdo nebo něco jiného bude ze zapsaných údajů nějaké vybírat (například program pro tisk výpisubude vybírat podle telefonního čísla a období)

Někdo další může chtít data upravovat (třebas reklamační oddělení může chtít změnit záznamy v případěoprávněné reklamace)

Z toho vidíme, že databáze není jen prosté shromaždiště, úložiště dat, ale že většinou slouží zároveň k jejichorganizaci, třídění, prohledávání, seskupování a podobně. K typické dnešní databázi patří rovněž to, že zároveňchce s daty pracovat více uživatelů.

S tím souvisí jiná důležitá věc: S rozvojem sítí a zejména internetu se stalo obvyklé, že databáze mohou býtpřístupné vzdáleně. Taková databáze umístěná centrálně může poskytovat data mnoha víceméně nezávislýmodběratelům. Z celého toho popisu bude pravděpodobně všem zřejmé, že databázové programy obecně zažívajízlaté časy a že databází bude existovat celá řada.

Page 4: MySQL Obsah

Dělení databází

Rozdělit databáze je kupodivu čím dál tím složitější, protože jednotlivá kritéria se v poslední době vzájemněpřekrývají a mnoho databází umí hodně podobných věcí. Nicméně, pokusím se alespoň nastínit, jak různě sedají databáze dělit.

Objektové a relační - tam se databáze liší podle způsobu, jak ukládají data. Ve světě převládá relačnímodel, který ještě podrobněji vysvětlíme v některém z následujících dílů. MySQL je relační databáze

Jednouživatelské a víceuživatelské - Podle toho, kolik uživatelů se k databázi může připojit.Pochopitelně, v komerční sféře jednouživatelským databázím prakticky odzvonilo. Je ale užitečné vědět,že i víceuživatelskou databázi lze většinou nakonfigurovat jako jednouživatelskou a že to může mít svéopodstatnění. MySQL je víceuživatelská databáze.

Souborové a systémové - liší se tím, zda použijí pro uložení dat jeden soubor (např. dbf), nebo zda jeúložiště dat nějak zabudováno do systému. U souborových databází typicky stačí příslušný souborpřenést na jiný stroj a může být ihned používán, u systémových databází se musí záloha a obnova dělatnějak jinak. V poslední době toto dělení poněkud ztratilo význam, protože většina databází jesystémových. MySQL je systémová databáze.

Podle licence a ceny - Asi víte, co tím myslím. Kód databáze může být uzavřený nebo otevřený, šířenísoftware může být svobodné nebo může podléhat nějakým podmínkám, databáze se může využívat bezpoplatků nebo může jít o placené software. Licence MySQL je duální, je trochu složitá a nebudeme se jíteď zabývat. Více byste se mohli dozvědět na stránkách projektu; teď jen prohlásíme, že pokud budetevyvíjet software pod GPL kompatibilní licencí, můžete použít MySQL pod licencí GPL.

Podle toho, kde běží - na jednoplatformní a multiplatformní. Jednoplatformní poběží jen na některémsystému (třeba na Windows), multiplatformní na více systémech. MySQL je multiplatformní databáze aběží na systémech GNU/Linux, Microsoft Windows, FreeBSD, Sun Solaris, IBM's AIX, Mac OS X, HP-UX, AIX, QNX, Novell NetWare, SCO OpenUnix, SGI Irix, and Dec OSF.

Podle velikosti, výkonu a vhodnosti nasazení - Databáze mívají limity ve velikosti, počtu současněpřihlášených uživatelů, počtu současně probíhajících procesů a podobně. Je těžké někam zařaditMySQL. Obecně je totiž obtížné nějak rovnoprávně posoudit databáze. Diplomaticky můžeme říci, žeMySQL je někde uprostřed pomyslného žebříčku vhodnosti nasazení a že v malých až středníchprojektech ji rozhodně použít můžete

Databáze lze samozřejmě dělit i podle celé řady dalších kritérií. Nejdůležitější přitom je, co všechno danádatabáze "umí" s daty provádět. V seriálu budeme postupně mluvit o tom, co s daty "umí" dělat MySQL, takžesi toto téma necháme na později.

Popularita MySQL

MySQL je velmi populární databáze. Podle mnoha zdrojů je to rovněž velmi rychlá databáze. Nemá však tolikfunkcí a možností jako některé konkurenční databázové systémy. Vybrat si vhodnou databázi je tedy klasickýkompromis mezi rychlostí softwaru a jeho schopnostmi. MySQL má samozřejmě své zastánce a odpůrce.

Page 5: MySQL Obsah

Odpůrci například často tvrdí, že MySQL je tak rozšířená proto, že webhostingové společnosti ji často nabízejípro hostované weby jako součást portfolia svých služeb. Kdyby se webhostingové společnosti rozhodlyupřednostnit jiný software, popularita MySQL by podle jejich odpůrců podstatně klesla.

Naproti tomu zastánci MySQL tvrdí, že webhostingové společnosti nabízejí MySQL proto, že je dobrá, a kdybyexistovala lepší databáze než MySQL, byla by nabízena. Zastánci MySQL prostě tvrdí, že trh si MySQL vybral -a to podle nich jasně poukazuje na její kvality.

Asi tušíte, že pravda bude někde uprostřed mezi těmito tvrzeními. Nemám na to vyhraněný názor, ale MySQLpodle mého ještě nějakou dobu bude velmi rozšířená, takže se vyplatí ji používat. Abych byl ale objektivní,podívejme se ještě na to, jaké nejvážnější konkurenty MySQL ve světě databází má.

Konkurenční databáze

Pozor: Slovem "konkurenční" zde myslím rivaly MySQL z hlediska možností, nikoli ceny. Jinými slovy, je toúvaha o softwaru, nikoli marketingu. Jelikož marketing databází se rozvíjí tak prudce jako celé toto odvětví, jenvelmi dobře informovaní lidé by mohli předpovědět, jakým směrem se bude vývoj ubírat (a ještě to není jisté).

Asi největším soupeřem MySQL o pozornost uživatelů byla donedávna databáze PostgreSQL. Na linuxu o nímáme seriál. PostgreSQL umí běžet na Windows NT (2000, XP) a na celé řadě UN*X platforem a má podstatněvíce možností pro uživatele než MySQL. Je však o něco pomalejší.

Podle výsledků nedávného průzkumu firmy Evans Data Corporation však v poslední době dobývá tento segmenttrhu poměrně výrazným způsobem databáze Firebird. To upřímě řečeno mnoho lidí překvapilo. Firebird jerovněž open-source databáze, může běžet na systémech Windows, Linux, Mac OS X, HP-UX a Solaris a márovněž více možností než MySQL. Je také o něco pomalejší. Pokud vím, na našem serveru o Firebirdu zatímžádné ucelené informace nevyšly.

Bylo by asi zajímavé nějak fundovaně srovnat PostgreSQL a Firebird, ale o tom náš seriál není. Troufnu si všaktvrdit, že pokud někdy něco vytlačí MySQL z pozice, kterou teď má, bude to jedna z dvojice PostgreSQL |Firebird. Jiné vážné konkurenty MySQL podle mě v současné době nemá.

Proč seriál o MySQL

Mezi systémy, na nichž běží MySQL je i GNU/Linux, takže na server www.linuxsoft.cz tento seriál rozhodněpatří. Mezi typická použití databáze MySQL můžeme zařadit její nasazení na internetové servery spolu sApache a PHP. Tato řešení jsou poměrně často linuxová a fungují velmi dobře. Není tedy divu, že mezilinuxovou komunitou je používání MySQL relativně časté a že mnoho programátorů pracujících v linuxu sahápráve po této databázi.

Page 6: MySQL Obsah

MySQL (2) - Instalujeme databázi MySQL

Dnes to bude pro nedočkavé - hned si totiž nějakou tu MySQL databázi nainstalujeme.

4.3.2005 15:00 | Petr Zajíc | přečteno 20697×

Komerční sdělení: Pořádáme Kurzy MySQL

Přestože je toho ještě hodně na vysvětlování, pravděpodobně prahnete po tom, nainstalovat si hned nějakou tuverzi MySQL. Pojďme se tedy letmo podívat na rozdíly mezi jednotlivými verzemi MySQL a říci si, co a jakbudeme ke zprovoznění této databáze potřebovat.

Verze MySQL

V současné době se můžete setkat s mnoha verzemi MySQL, proto bychom si měli alespoň zhruba vysvětlitrozdíly mezi nimi. MySQL je poměrně mladá databáze a prochází (někteří to formulují tak, že trpí) velmidynamickým vývojem. Na mnoha produkčních serverech se tedy dodnes můžete setkat s verzemi "trojkové"řady MySQL (poslední byla 3.23.x). Verze je to stabilní, ale není nejnovější. Instalací trojkové řady MySQL sezabývat nebudeme, přestože ji dodnes mají některé distribuce obsaženu ve svých balíčcích.

V době psaní tohoto článku byla nejnovější stabilní verzí MySQL verze 4.1.10. Právě o instalaci "čtyřkové"verze MySQL budu zanedlouho mluvit a tato varianta bude rovněž nosnou verzí pro mnoho dílů v našemseriálu. Takže většinu věcí budu vysvětlovat právě na 4.1.x. Mám k tomu dobrý důvod - je to určitá rovnováhamezi vymoženostmi a stabilitou.

MySQL se stále vyvíjí, což v současné době znamená, že již existuje verze 5.0.x. NENÍ VŠAK OZNAČENAJAKO STABILNÍ, proto byste ji neměli instalovat na produkční servery. Pětkové verze MySQL nicméně dostipodstatným způsobem rozšiřují možnosti této databáze a nedá mi to, abych se o nich tu a tam v seriálu nezmínil.Pokud si tedy budete chtít vyzkoušet některé z nejnovějších rysů MySQL a máte k dispozici stroj, na němž tobudete moci bez obav udělat, jděte do toho.

Rozebírat tolik verzí databáze najednou je samozřejmě v praxi pro tento seriál poměrně komplikované.Nicméně, pokusím se o to, protože budu chtít být lehce nadčasový. Cílem je, abyste se k tomuto pojednánímohli vracet i v době, kdy už bude MySQL 5.x ve stabilní verzi a bude standardně instalována na většinusystémů a webů.

Pozn.: Já opravdu nevím, kdy to bude.

Architektura MySQL

Page 7: MySQL Obsah

Teď pár slov k architektuře databáze MySQL. Jelikož je to systémová databáze, dělí se MySQL na "serverovou"a "klientskou" část. Neboli, odděleně lze nainstalovat MySQL server a odděleně program, který je prokomunikaci s mysql zapotřebí (klienta). To není rozporuplná situace. Můžete mít celkem tři scénáře:

1. Na stroji je nainstalován MySQL server, ale ne klient. Všichni klienti se připojují z jiných strojů a tak tonení potřeba.

2. Na stroji je nainstalován pouze MySQL klient. Připojovat se budeme k nějakému jinému stroji, kdepoběží server.

3. Na počítači bude jak server, tak klient. Typické pro testovací prostředí, kde je k dispozici pouze jedenpočítač.

Scénář číslo tři tedy bude pro čtenáře tohoto seriálu zřejmě typický a proto si nainstalujeme jak MySQL server,tak řádkového klienta. Jedna perlička na úvod, aby nedocházelo k matení pojmů: databázový server se spouštípomocí příkazu mysqld, kdežto řádkový klient pomocí příkazu mysql. Když si k tomu přidáte, že v některýchdistribucích se bude startovat databázový server příkazem

service mysql start

je z toho pro začátečníky docela slušný zmatek. Zapamatujte si ale, že počítač bude většinou spouštět MySQLserver automaticky a že se budete setkávat spíše s klientem, tedy s programem mysql.

Typy instalace MySQL

Aby to nebylo zase až tak jednoduché, dodejme ještě pro upřesnění, že existují dvě různé instalovatelné verzeMySQL (teď hovořím o Linuxu). Jsou to:

1. "Standardní" MySQL obsahující obvyklé funkce, a

2. "Rozšířená" verze MySQL - max, obsahující další funkce, způsoby uložení dat a rozšíření

Momentálně se rozšířeními nebudeme zabývat; probereme je postupně tak, jak na ně v seriálu přijde řada. Mělibyste ale vědět, že postupy uvedené níže instalují standardní verzi MySQL.

Pozn.: Na Windows je situace ještě trochu komplikovanější. Typů serveru je tam víc, instalují se všechnynajednou a typ běžícího serveru se zvolí tak, že se spustí příslušný exe soubor (například mysqld.exe nebomysqld-max.exe).

Instalace na Fedoře 3

Na instalačním DVD Fedory 3 je k dispozici MySQL ve verzi 3.23.58, kterou ale instalovat nebudeme. Namístotoho si stáhneme rpm balíček verze 4.1.10 z nějakého zrcadlícího serveru:

Page 8: MySQL Obsah

wget http://mysql.linux.cz/Downloads/MySQL-4.1/MySQL-server-4.1.10-0.i386.rpm

A nainstalujeme jej obvyklým způsobem:

rpm -i ./MySQL-server-4.1.10-0.i386.rpm

Tím bychom měli mít serverovou část mysql funkční. Součástí instalace je i vytvoření startovacích skriptů,takže po restartu počítače se MySQL spustí automaticky. Klienta stáhneme ze serveru naprosto obdobně:

wget http://mysql.linux.cz/Downloads/MySQL-4.1/MySQL-client-4.1.10-0.i386.rpm

A nainstalujeme rovněž typickým způsobem:

rpm -i ./MySQL-client-4.1.10-0.i386.rpm

Neměli byste mít žádné problémy. To, že instalace serveru i klienta proběhla, můžete ověřit zadáním příkazu

mysql

což by vám mělo klienta spustit. Ten by se měl krátce představit a prozradit verzi serveru, s níž komunikuje (vnašem případě 4.1.10). Klienta mysql prozatím vypneme příkazem exit a budeme se mu věnovat později.

Pozor: Takto nainstalovaný systém je absolutně nezabezpečený, protože po instalaci není pro přístup k serveruvyžadováno žádné heslo. Příště si tedy ukážeme, jak takové heslo nastavit a co se může stát, když to neuděláte.

V dalším díle se zmíním rovněž o instalaci MySQL na SUSE a Mandrake (bude to velmi podobné), dotknemese instalace v systému Windows a probereme krátce instalaci s kompilací.

Page 9: MySQL Obsah

MYSQL (3) Instalujeme MySQL podruhé

Jak na kompilaci a jak na Windows. Také něco o nastavení hesel.

8.3.2005 15:00 | Petr Zajíc | přečteno 19019×

Komerční sdělení: Pořádáme Kurzy MySQL

Podívejme se teď, jak na instalaci nejnovější stabilní verze MySQL na dalších typických distribucích.

Instalace na Mandrake 10.1

Mandrake 10.1 obsahuje verzi 4.0.20 databáze MySQL. To je již novější verze než ta u Fedory 3, stále to všaknení 4.1.10, na níž budeme zkoušet většinu příkladů. Ale nainstalovat novější balíček není ani tady žádný většíproblém. Postup z minulého dílu funguje téměř beze zbytku; pouze na notebooku jsem se setkal při spuštěníserveru s nějakou těžko popsatelnou chybou. Po restartu stroje se mi ji nicméně nepovedlo napodobit a servervesele šlape.

Instalace na SUSE 9.1

Suse 9.1 má k dispozici verzi 4.0.18 databáze MySQL na instalačním DVD. Postup z minulého dílu jsem zkusili zde a funguje naprosto bez problémů. Narozdíl od Mandrake jsem nenarazil ani na ty nejmenší problémy přirozjetí serveru. Úpravu konfigurace spouštění MySQL serveru pak v SUSE distribucích můžete samozřejměprovádět pomocí instalačního nástroje YAST. Provedete to pomocí Systém / Editor úrovní běhu.

Jiné způsoby instalace

Instalace z tar archivuProč? Ve většině případů to bude naprosto zbytečné, protože pro vaši distribuci bude velmi pravděpodobněexistovat pohodlnější způsob instalace pomocí balíčků. Nicméně, pokud chcete nebo musíte instalovat z tararchivu, můžete. Na stránce downloadu MySQL je odkaz na tar soubor, který si můžete stáhnout z nejbližšíhozrcadla.

Kompilace MySQLAčkoli to asi pro úvodní přehled potřebovat nebudete a MySQL nainstalujete pohodlně z balíčku, lzesamozřejmě server i kompilovat ze zdrojových kódů. To může mít smysl například v případě, kdy budeme chtítdefinovat optimalizační volby kompilátoru, když budeme chtít přikompilovat podporu věcí, které ve výchozíkonfiguraci nejsou, nebo když naopak budeme chtít něco vynechat. Zdrojový kód stáhneme z nejbližšíhozrcadla

wget http://mysql.linux.cz/Downloads/MySQL-4.1/mysql-4.1.10.tar.gz

rozbalíme:

tar -xvzf mysql-4.1.10.tar.gzcd mysql-4.1.10

Page 10: MySQL Obsah

a použijeme klasickou "trojkombinaci"

./configuremakemake install

Pozn.: To samozřejmě dopadne tak, že získáme téměř stejné binární soubory, jako kdybychom je nekompilovali.Kouzlo kompilace spočívá v přidání parametrů. Tak například zkompilovat myslq s podporou pouze výchozíznakové sady (což je ISO-8859-1) lze pomocí přepínače --with-extra-charsets=none a tak dále.

V závislosti na systému může být pro úspěšné rozběhnutí MySQL v tomto případě ještě nutné ručně vytvořittabulky oprávnění a změnit vlastnictví některých souborů. Pro konkrétní pokyny bude nutné podívat se domanuálu.

Windows

Ve Windows lze instalovat MySQL asi nejjednodušeji pomocí instalátoru. Pozor, počínaje verzí 4.1.5 seinstalace trochu měnila. Například teď se již jako výchozí složka nenabízí C:\MYSQL, ale C:\ProgramFiles\MY SQL. Instalátor pro Windows najdete na stránce downloadů. Na stránkách MySQL je hezký článek orozdílech při provozování MySQL na Windows oproti Linuxu. Pokud chcete provozovat MySQL na Windows,prostudujte si rovněž pečlivě licenci.

Více serverů na jednom stroji

Někdo se mě na to ptal: Na jednom stroji můžete mít více verzí MySQL, ale je to jen pro odvážné. I tak ovšembude potřeba změnit konfigurační soubory, aby:

V případě připojení přes TCP/IP používal každý server jiný port

V případě připojení přes socketové soubory používal každý server jiný socket

A navíc bude potřeba zajistit, aby se servery "nepohádaly" o data a soubory protokolu. Není to tedy vůbecjednoduché a vyžaduje to znalost konfigurace mysql.

Po instalaci

Po instalaci není databázový server chráněn heslem. To může snižovat jeho bezpečnost. K nastavení heslamůžete použít například následující postup:

1. Spusťte mysql.

2. Do příkazového řádku napište:

set password = password('nejake_heslo');

Page 11: MySQL Obsah

Pokud teď ukončíte příkazový řádek mysql (pomocí Ctrl+C nebo zadáním příkazu exit;) a znovu jej spustíte,obdržíte hlášku ve stylu "Access denied for user 'user'@'machine'. To je správně. Pokud budete chtít spustitřádkového klienat mysql a zadat heslo, musíte jej od nynějška spouštět s volbou -p,

mysql -p

která způsobí, že program při startu o heslo slušně požádá. K tomu ještě několik poznámek:

Pokud není počítač připojen k síti a slouží pouze pro testování, možná nebudete chtít heslo nastavovat.

Pokud budete chtít jednou nastavené heslo změnit na "režim bez hesla", přepněte do řádkového klientamysql a zadejte

set password = password('');

Jinak - to, že někteří administrátoři podcenili bezpečnost a připojili počítač s MySQL do sítě bez kvalitněnastavených hesel vedlo v nedávné době k šíření červa Forbot.

Page 12: MySQL Obsah

MySQL (4) - něco terminologie

Abychom si rozumněli, je pro databázové zelenáče v dnešním dílu připraven slovníček nejběžnějších pojmů.

11.3.2005 15:00 | Petr Zajíc | přečteno 15552×

Komerční sdělení: Pořádáme Kurzy MySQL

V každém odvětví lidské činnosti je zažitá nějaká terminologie. Nejinak je tomu v databázích a situace na tomtopoli je celkem jednotná. To znamená, že stejné věci se stejně říká v mnoha databázích. Pojďme dnešní dílvěnovat tomu, že si většinu základních pojmů databázového světa nějak definujeme. Profíci to asi budou moci sčistým svědomím přeskočit, pro začátečníky to bude čtení téměř povinné.

Databáze je když...

Každý, kdo se nějak zabýval daty, narazil ve svém životě na tabulkové kalkulátory (nebo procesory). Databáze atabulkové procesory mají mnoho společného, proto jsem si dovolil při vysvětlování databázových pojmů použítmalé srovnání. Použiju k tomu vykonstruovaný dokument OpenOffice.org Calc.

Databázový server - to je název softwaru, který "zastřešuje" a řídí jednotlivé databáze. Má na starosti takovévěci, jako je autorizace uživatelů, poskytování a vracení dat, jejich organizace, sdílení po síti a správu.Databázový server je v našem případě tvořen právě nainstalovanou MySQL. Slovo "server" se v této častopoužívá pro zdůraznění toho, že celé řešení je síťové, nebo proto, aby se odlišil od "klienta". V našem srovnání sOpenOffice.org Calcem bychom mohli přirovnat "server" k tomu, když nainstalujeme samotný kancelářskýbalík. Teprve ten totiž umožní vytvářet soubory dokumentů a pracovat s nimi.

Databázový klient - je název libovolného software, který s databázovým serverem komunikuje (tzn. buď mupředává nějaká data k uložení, nebo po něm data chce). Typicky se může jednat o řádkového klienta, o webovoustránku zobrazující data, o obchodní aplikaci nebo o cokoli podobného. Slovem "klient" v takovém případěvyjadřujeme buď závislost na databázi (tzn. bez serveru by existence klienta byla k ničemu), nebo fakt, že můžeběžet "oproti" serveru; často v jiném PC v počítačové síti.

Pozn.: V praxi bývá mezi klientem a serverem někdy ještě třetí vrstva. Pro pochopení práce s databází ji všaknepotřebujeme a můžeme ji teď klidně ignorovat.

Databáze - termín pro označení kolekce tabulek. Jedna databáze může mít nula až mnoho tabulek. Dalo by se topřirovnat k jednotlivým sešitům OpenOffice.org Calcu. Jeden sešit můžete mít například pro evidenci zboží adalší sešit pro seznam fotbalových zápasů. V praxi se databáze používají zejména pro logické oddělenívzájemně nesouvisejících tabulek a pro zjednodušení správy oprávnění (databázím se totiž dají přidělovatoprávnění).

Příklad: Webhostingová společnost nabízí k hostingu i databázi MySQL. Každý uživatel, který to využije,dostane přidělenu jednu databázi, která se typicky jmenuje stejně jako jeho uživatelské jméno, a dostaneoprávnění používat jen tuto databázi.

Page 13: MySQL Obsah

Tabulka - základní organizační jednotka databáze. Každá databáze může obsahovat nula a více tabulek.Tabulky se svým charakterem podobají jednotlivým listům sešitu OpenOffice.Org Calc.

Řádek - někdy též záznam nebo věta. Každý řádek obsahuje informace o jedné položce (například jméno,příjmení a telefon pro jednoho zaměstnance). Narozdíl od listu sešitu tabulkového kalkulátoru však musí býtvšechny řádky v databázi stejně dlouhé. Znamená to například, že nelze mít u jednoho zaměstnance jednotelefonní číslo a u jiného pět.

Pozn.: Výjimkou je samozřejmě situace, kdy sestavíme tabulku tak, že může obsahovat pět telefonních čísel aněkomu zadáme jen jedno. Nicméně, stále je prostor pro dopsání zbývajících, ale není možné zadat šesté.

Řádky lze do tabulky přidávat z klientské aplikace, z jiné tabulky nebo z externího zdroje (pak se tomu říkáimport).

Sloupec - prostor pro uložení jedné položky záznamů. V jednom sloupci v tabulce databáze musí být datastejného typu (například všechno to musí být čísla, všechno datumy a podobně). Rovněž tím se databázovétabulky liší od sešitů kalkulátorů.

Page 14: MySQL Obsah

Index - pomocná datová struktura popisující vztah mezi hodnotou v tabulce a jeho umístěním. Slouží provyhledávání a spojování tabulek. Rovněž může hlídat, aby v jednom sloupci byly jedinečné hodnoty. Ještě oněm bude v našem seriálu řeč.

Klíč - ve skutečnosti se výrazy "klíč" a "index" často zaměňují. Přesto je mezi nimi jemný významový odstín -klíč reprezentuje logickou strukturu, kdežto index fyzickou.

Pohled - virtuální tabulka, která vybírá řádky a sloupce z jedné nebo více existujících tabulek. Může je rovněžnapříklad filtrovat nebo řadit.

Uložená procedura - programový kód, který je uložen na databázovém serveru a vykonává příkazy jazyka SQL(viz níže). Uložené procedury se používají proto, že mohou být serverem kompilovány a optimalizovány, a taképroto, že zjednodušují práci v situaci, kdy několik klientů potřebuje provést stejné nebo podobné úkony naserveru.

Trigger (spoušť) - uložená procedura, která se spouští automaticky poté, co klient změní data v tabulce naserveru.

Oprávnění - sada pravidel definujících, co jednotliví uživatelé smějí s databázovým serverem dělat. Podobné,jako v systému.

Zkratky

V tomto odvětví se rovněž používá celá řada zkratek. Uvedu pro úplnost ty nejběžnější:

DBMS - z anglického "database management system"; nic jiného než obecný název pro databázové systémy.Český ekvivalent SŘBD (systém řízení báze dat) se naštěstí moc neujal.

SQL - z anglického "structured query language", strukturovaný dotazovací jazyk. To je jazyk, s nímž databázovíklieti komunikují s databázovými servery. Existuje bohužel řada jeho dialetů, což komplikuje život vývojářům,pracujícím s několika DBMS.

DDL - z anglického "data definition language", jazyk pro definici dat. Podmnožina SQL, která je tu pro definicidatabáze. Pomocí DDL se definují tabulky, sloupce a tak dále.

Page 15: MySQL Obsah

DML - z anglického "data manipulation language", jazyk pro manipulaci s daty. Podmnožina SQL, kterázajišťuje vlastní práci s daty v tabulkách - jejich vkládání, mazání a aktualizaci.

Page 16: MySQL Obsah

MySQL (5) - tajuplné SQL

Co se skrývá za zkratkou SQL a co z toho pro nás vyplývá. Ach, ty normy.

15.3.2005 15:00 | Petr Zajíc | přečteno 15081×

Komerční sdělení: Pořádáme Kurzy MySQL

V předchozím díle jsme narazili na pojem SQL. Pojďme se dnes podívat podrobněji na to, co se za tímtooznačením skrývá, a jakými peripetiemi prošel tento jazyk během svého vývoje.

SQL

SQL je jazyk, kterým databázoví klienti komunikují z databázovým serverem. Údajně pochází jeho předek,který se jmenoval Sequel (Structured English Query Language), již z roku 1974 a vyvinuli jej inženýři IBM vJan Jose, Kalifornii. Záměrem bylo vytvořit takový jazyk, který by se co nejvíce podobal běžné řeči. Kdybystenapříklad chtěli vybrat z tabulky faktur záznamy z roku 2005, můžete v SQL napsat něco ve stylu:

SELECT * FROM FAKTURY WHERE DATUM >= 1.ledna 2005

Nápad použít jazyk SQL, alespoň principielně, začala postupně přebírat celá řada dalších firem a zabudovávatjej do svých databázových produktů. Tak například firma Relational Software, Inc. (nyní Oracle), Ashton-Tate(dBASE IV), Informix, SyBase a další. V roce 1986 byl SQL jazyk prvně standardizován díky skupině ANSI.(Perlička: ANSI původně chtěla vyvinout vlastní standard na základě zcela jiného jazyka, ale SQL se jaksiprosadil sám jakožto rozšířenější - a byl přejat).

Vývoj však šel dál a v roce 1992 bylo SQL znovu revidováno. Standard začal být znám jakožto SQL92 neboSQL2. Původní definice z roku 86 byla v té době rozšířena především o možnost definovat pomocí SQLprimární klíče a specifikace SQL92 řešila rovněž pravidla referenční integrity (pokud vám tyto pojmy nicneříkají, nezoufejte. Až se k nim v seriálu dostaneme, vysvětlím je).

Od té doby již používají databáze převážně nějakou tu formu SQL. (Mimochodem, SQL není omezena jen narelační databáze. Mohou ji používat a používají ji i například databáze objektově-relační). Konečně, v roce 1999byl přijat další standard, a to pod názvem SQL99 nebo také SQL3. Jeho cílem bylo pochopitelně reagovat navývoj v dané oblasti a SQL99 tak přináší do databázového jazyka objektová rozšíření. Mezi věci definované vSQL99 patří například nové datové typy (large object, boolean, array, row a uživatelsky definované typy), novézpůsoby spojování tabulek a nějaké ty prvky OLAP.

Pozn. OLAP je zkratka pro "online analytic processing". Zahrnuje nástroje, které umožňují z dat efektivnězískávat nějaké smysluplné analytické informace - třeba pomocí jejich seskupování. Často se v této souvislostihovoří o "managerských" informacích, protože potřebu efektivní analýzy si vyžádal zejména prudký nárůstpočtu databází v obchodních aplikacích.

Nestadndardní standard

Page 17: MySQL Obsah

Z předchozího oddílu by člověk snadno mohl nabýt dojem, že všechny databáze budou nějakým způsobemjednotně komunikovat pomocí standardizovaného jazyka. Bohužel, není tomu tak. Skutečnost je podobnásituaci, v níž se nachází jazyk HTML. V případě jazyka HTML byly přijaty určité standardy, ale jednotlivéprohlížeče s nimi zacházejí různě. Někdy prohlížeče neumějí správně zobrazit ani takové stránky, které jsoupodle normy korektní. Úplně stejně je na tom standard SQL. Jednotlivé databáze se sice snaží implementovatnormu, ale dochází přitom k následujícím nepříjemným jevům:

Většina databází vyhovuje normě (ať už SQL92 nebo SQL99) s výjimkami. Znamená to, že některé věciz normy nejsou implementovány

Většina databází si ke standardním (normalizovaným) konstrukcím a prvkům SQL přidává vlastnírozšíření. To z principu nevadí, ale vede to k tomu, že každá databáze má svá specifika.

Většina rozšíření není mezi jednotlivými databázemi kompatibilní. Neboli, musíte se je naučit prokaždou databázi, kterou budete chtít používat

To znamená jedno: Kód SQL je sice principielně přenositelný mezi jednotivými databázemi, v praxi to všakvětšinou není pravda. Vývojáři aplikace tedy musejí vědět, s jakou databází budou pracovat.

Nemám samozřejmě nic proti rozšířením jazyka SQL. Konec konců to, co bylo dříve považováno za módnívýstřelek toho či onoho výrobce DBMS se zvolna mění ve standard a bývá to časem zařazováno do normy.Rovněž je dobré si uvědomit, že rozšíření SQL nevznikají proto, že by dodavatelé neměli co dělat, ale proto, žesi chtějí udržet zákazníky.

Problém je však s tou kompatibilitou. Výkon databázových systémů je často pro aplikace klíčový. Jednotlivározšíření standardu SQL vedou k tomu, že lze napsat kód jazyk SQL, který se bude rychleji vykonávat nebo sebude snadněji číst a spravovat. Proto odborníci na jednotlivé databáze tato rozšíření znají a používají. Praxe jetdy taková, že aby mohl být člověk databázovým specialistou, musí většinou

buď být mimořádně schopný a pamatovat si rozšíření jazyka pro všechny databázové systémy, s nimižpracuje, nebo

soustředit svou pozornost na jednu databázi, důkladně ji poznat a důsledně využívat možnosti, kterénabízí.

Jak je na tom MySQL

Databáze MySQL na svých stránkách lišácky uvádí: "Databáze MySQL podporuje širokou podmnožinu syntaxeANSI 99, společně s dalšími rozšířeními, jako je příkaz REPLACE nebo klauzule LIMIT u příkazu SELECT aDELETE. Jsou podporovány rovněž alternativní syntaxe známé z jiných databázových systémů...Průběžněrozšiřujeme... verze 4.0 například přichází s podporou příkazu UNION". Otevřeně řečeno, MySQL si sostatními DBMS v ničem nezadá a chová se úplně stejně. Nemůžeme jí to mít moc za zlé, je to přece jen dánotakovými faktory, jako je názor zákazníků nebo tlak trhu.

Page 18: MySQL Obsah

V našm seriálu prostě přijmeme určité odchýlení od normy jako fakt. Budu se snažit poukazovat na všechnymožné syntaxe včetně alternativních a nebudu příliš často moralizovat o tom, zda daná věc plně odpovídádefinici v normě. Je to dáno praxí - pokud budete vyvíjet nějakou tu aplikaci, zákazníka bude zajímatpředevším:

1. Jak budou pro něj jeho data dostupná

2. Jak rychle se dozví to, co potřebuje, a

3. Jak budou jeho data bezpečná.

Zákazníky běžně nezajímá, jakými prostředky toho bude dosaženo. Někdy je ponecháno na programátorovi i to,jaký programovací jazyk použije nebo jakou nasadí pro uskladnění dat databázi. V příkladech tedy budemepředpokládat, že nasazena je MySQL a budeme uvažovat, jak dané problémy s pomocí této databáze co možnánejjednodušeji vyřešit.

Page 19: MySQL Obsah

MySQL (6) - Ukládáme řetězce

Jak správně využít datové typy - dnes o řetězcích.

18.3.2005 15:00 | Petr Zajíc | přečteno 16983×

Komerční sdělení: Pořádáme Kurzy MySQL

Pojďme se v několika dalších dílech seriálu podrobně podívat na datové typy, které má databáze MySQL prouložení dat k dispozici. Jejich zvládnutí, jak ještě uvidíme, je totiž základním pilířem úspěšné práce s databází avede rovněž k tomu, že je práce daty prováděna tím nejrychleším možným způsobem.

Srovnání s programovacími jazyky

Nejprve jedno malé varování. Jestliže zvolíte nesprávný datový dyp pro uložení proměnné v klasickýchprogramovacích jazycích (např. v C apod.), je to samozřejmě nesprávně. Například zbytečně velký datový typspotřebuje o něco více paměti a program může běžet výrazně pomaleji. V databázích je to však MNOHEMHORŠÍ.

Nesprávný datový typ může způsobit to, že databáze o dost naroste a že se zpomalí. Jak již jsme totiž v seriáluuvedli, musí být pro jeden sloupec pevně stanoven datový typ a ten budou používat všechny řádky. Drsnost, sjakou se vám vrátí špatný návrh datových typů pro jednotlivé sloupce bude tedy přímo úměrná počtu řádků v tékteré tabulce. Když k tomu přičtete fakt, že tabulka se obvykle navrhuje jen jednou a pak se již "jen" plní daty,je při nepozorně zvoleném datovém typu zaděláno na pořádné problémy.

Abych ale jen nestrašil: V MySQL, stejně jako v mnoha jiných databázových systémech je možné změnit typsloupce, a to obvykle bez ztráty dat (například změna z celého čísla na řetězec a podobně). Někdy to ovšemmožné není a někdy konverzi existujících dat provází změna jejich přesnosti nebo jiné problémy, není proto niclepšího, než si vše řádně promyslet předem.

Rozdělení datových typů MySQL

Stejně, jako je tomu v každém DBMS, jsou i v MySQL určité "základní" datové typy. Tím mám na mysli ty,které se vám vyplatí znát z hlavy, protože se budou objevovat téměř v každé tabulce. Úplně to nejjednoduššírozdělení je, že v databázi MySQL můžete skladovat:

řetězce

čísla

datumy

prázdné hodnoty (tedy nic)

Page 20: MySQL Obsah

Obecně mohou mít řetězce pevnou či proměnnou délku, a mívají specifikovánu znakovou sadu. Čísla mohoubýt se znaménkem nebo bez znaménka, celá či desetinná, přesná nebo nepřesná. Datumy pak mohou obsahovatúdaj o datu, čase nebo oba údaje. A prázdná hodnota je natolik zajímavým databázovým jevem, že se k ní ještěpodrobně vrátíme. Pojďme se teď podívat na jednotlivé datové typy trochu podrobněji - dnes na řetězce.

Řetězce

Chcete-li uložit do databáze krátké řetězce (například jména a příjmení), použijte datový typ CHAR neboVARCHAR. Pokud chcete tyto typy použít, musíte vědět, jak dlouhé mohou znaky maximálně být. Rozdíl meziCHAR a VARCHAR je především v tom, že se jinak ukládají:

Datový typ CHAR se ukládá vždy jako řetězec s daným počtem znaků. Je-li definován například jakoCHAR (30) a zadáte-li do něj hodnotu HONZA, bude v databázi uloženo HONZA a k tomu pětadvacetmezer. Když se z databáze údaj načítá, jsou mezery na konci řetězce odřízuty a údaj je vrácen bez nich

Datový typ VARCHAR se ukládá jako řetězec s proměnlivým počtem znaků. Neboli, je vždy uložen jakřetězec, tak počet znaků, které zabírá. V předchozím případě by například byl uložen řetězec HONZA aúdaj o tom, že je 5 znaků dlouhý. Když se údaj z databáze načítá, jsou mezery na konci řetězce odřízutya údaj je vrácen bez nich stejně, jako je tomu při použití typu CHAR.

Možná se ptáte, jaký má smysl ukládat u typu CHAR do databáze zbytečné mezery. Databáze tím přece nabydena objemu, ne? To je pravda; na druhou stranu je však získávání dat s pevnou délkou mnohem rychlejší nežzískávání dat s délkou proměnlivou. Obecná rada tedy je: Mají-li data pevnou nebo víceméně pevnou šířku,ukládejte je jako CHAR, jestliže se šířka dost mění, používejte VARCHAR.

Výchozí chování MySQL je takové, že při ukládání a vracení řetězců nemění velikost písmen. To je ostatně to,co bychom asi čekali. Jinak je k manipulaci s řetězci v MySQL k dispozici celá řada funkcí; budeme se jimizabývat později.

Z toho, co bylo řečeno výše vyplývá jedna dosti podstatná nepříjemnost. Jelikož oba uvedené datové typyodřezávají koncové mezery, neexistovala donedávna žádná možnost, jak uložit a spolehlivě vrátit pomocí typůCHAR nebo VARCHAR řetězce, mající na konci mezery. Jediná možnost byla použít typ BLOB, o němž budev seriálu řeč zanedlouho. Toto chování, kdy se nevracejí uživatelem zadané mezery na konci řetězců navícodporuje normě. Ve verzi MySQL 5.0.3 je tato nepříjemnost odstraněna a typy CHAR a VARCHAR jdounastavit tak, aby vracely i mezery na konci (samozřejmě jen tehdy, pokud byly součástí zadávaných dat).

Další důležitá informace: Když se do polí typu CHAR nebo VARCHAR pokusíte uložit delší data, než jaká jesloupec schopen pojmout, příkaz NESELŽE. V závislosti na tom, co se stalo může nastat jedna z následujícíchtří věcí:

1. Data se oříznou a příkaz se tváří, jako by se nic nestalo. To nastane v případě, kdy oříznutými znaky jsoupouze mezery.

2. Data se oříznou a příkaz vrátí varování (warning). To nastane v případě, kdy oříznutím "utrpí" i jinéznaky kromě mezer.

Page 21: MySQL Obsah

3. Data se oříznou a příkaz vrátí chybu (error). To nastane v případě, kdy oříznutím utrpí i jiné znakykromě mezer a server je nastaven, aby místo varování skončil příkaz chybou

V souvislosti s řetězci je často slyšet výrazy "character set" (znaková sada) a "collation" (porovnávání). Znakovásada je přesně to, co například v HTLM stránce - tedy kódování textu. MySQL podporuje všechny běžné českéznakové sady (utf-8, latin2 neboli ISO-8859-2 a cp1250, středoevropské windows) a to jak na úrovni serveru,tak na úrovni sloupce. Neboli, znakovou sadu můžete definovat jako součást sloupce typů CHAR aVARCHAR; když to neuděláte, použije se výchozí znaková sada serveru. Zobrazit použitelné znakové sadymůžete zadávním MySQL příkazu

show character set;

Collation (neboli třídění) je jiná věc. Dalo by se zjednodušeně říci, že každá znaková sada může mít jedno avíce třídění. Seznam dostupných třídění dané instance serveru lze zobrazit pomocí příkazu

show collation;

Pokud chceme, můžeme ke znakové sadě sloupce datového typu přiřadit některé z existujících způsobů řazení;pokud to neuděláme, použije se to řazení, které je pro danou znakovou sadu nastaveno jako výchozí.Předpokládám, že již asi tušíte, k čemu povedou následující příkazy:

show collation like 'utf8%';show collation like 'latin2%';show collation like 'cp1250%';

Práce se znakovými sadami a řazeními je tak důležitá, že ji později v seriálu věnujeme více prostoru. Příště sevšak zaměříme na práci s nejrůznějšími datovými typy, do nichž se v MySQL dají uložit čísla.

Page 22: MySQL Obsah

MySQL (7) - hrátky s čísly

Další trocha databázové teorie MySQL, dnes o ukládání čísel.

22.3.2005 15:00 | Petr Zajíc | přečteno 14790×

Komerční sdělení: Pořádáme Kurzy MySQL

V předešlém díle jsme uvedli některé základní věci, které byste měli znát při ukládání řetězců do databázeMySQL. Dnes se podíváme na to, jak MySQL ukládá čísla. Uvidíte, že s tím může být docela zábava.

MySQL a celá čísla

Z programátorských důvodů existuje celá řada datových typů, do nichž lze v MySQL uložit celá čísla. Liší sezejména tím, jak velká čísla může takový sloupec pojmout. Nejmenším celočíselným typem je TINYINT, kterýmůže nabývat hodnot od -128 do +127, včetně. V praxi jej zřejmě moc často nepoužijete, leda snad pro uloženíčísel, které zkrátka nikdy větší nebudou (například den v týdnu). Pro TINYINT je v databázi potřeba jen jedenbajt místa.

SMALLINT je již rozsahem větší a bude se tedy používat mnohem častěji. Uloží celá čísla od -32 768 do+32 767. S oblibou jej nasazuji třebas v účetních programech na číslování dokladů, málokdo má totiž víc než32767 dokladů v účetním roce. SMALLINT zabírá v databázi dva bajty.

Potom má MySQL k dispozici datový typ MEDIUMINT. Slouží pro uložení čísel od -8 388 608 do 8 388 607(to je +-2^23). V databázi zabírá tři bajty a nemůžu si na něj zvyknout. Ono ve skutečnosti typu MEDIUMINTnic není, jen se v některých DBMS systémech nevyskytuje a tak ho nemám v krvi. Dokážu si ale docela dobřepředstavit, že by se na spoustě míst dal použít místo typu INTEGER, o němž je řeč níže. Tak třeba automatickáčísla řádků by klidně mohla být MEDIUMINT, protože obvykle stačí dimenzovat tabulku na osm milionů řádků.

Datový typ INTEGER je naopak databázová klasika. Lze jej zkráceně deklarovat jako INT a pojme celá čísla vrozpětí od -2 147 483 648 do 2 147 483 647. Typicky se používá pro údaje sloužící k číslování řádků, protožepro většinu aplikací jsou dvě miliardy řádků v jedná tabulce víc než dost. INTEGER zabere v databázi 4 bajtymísta.

MySQL však jde ještě dál a "umí" uložit i větší celá čísla. Typ BIGINT je schopen pracovat s numery od-9 223 372 036 854 775 808 do 9 223 372 036 854 775 807. Tak veliké číslo ani neumím přečíst ;-). Nenapadámě žádný důvod, proč by v praxi musel programátor sáhnout k používání něčeho tak obrovského. Snad jen nanějaké vědeckotechnické výpočty. V manuálu je navíc popsáno, že práce s tímto datovým typem přináší určitáúskalí, takže pokud jej musíte používat, nastudujte to.

Celá čísla bez znaménka

Page 23: MySQL Obsah

Aby to s těmi čísly nebylo tak jednoduché, dodejme ještě, že MySQL umožňuje použít v definici čísla klauzuliUNSIGNED ("bez znaménka"). To způsobí, že se v daném typu budou skladovat pouze nezáporná čísla."Ušetřený" bajt se pak použije na zvýšení rozsahu čísla. Nejlépe se to dá pochopit na příkladu: TINYINT pojmečísla od -127 do +128, TINYINT UNSIGNED od 0 do 255. Neboli, stále se jedná o interval zahrnující 256 čísel,jsou však "posunuta" tak, aby začínala nulou.

Tip: K automatickému číslování řádků se obyčejně používají kladná čísla (ačkoli to principielně není nutné).Dokážu si tedy představit pro sloupec s automatickým číslem například použití typu MEDIUMINT UNSIGNED,což mi dává rozsah od nuly do 16 777 215.

Nepřesná desetinná čísla

Existují dva datové typy, které se v MySQL používají pro uložení nepřesných desetinných čísel. Pročnepřesných? Protože při uložení čísel v takovém případě dojde k jejich zaokrouhlení. Datové typy FLOAT aDOUBLE se liší víceméně jen zobrazovaným rozsahem a počtem desetinných míst. Rozsahy nebudu uvádět;jsou obrovské a jsou v manuálu.

Se zaokrouhlováním čísel typu FLOAT a DOUBLE je ale docela zábava. Představte si například, že chcete dosloupce FLOAT a DOUBLE uložit výsledek výpočtu "pět děleno třemi". Jak pravděpodobně víte, výsledkem ječíslo s nekonečným periodickým rozvojem a v databázi to dopadne tak, že se do sloupce typu float uloží1.66667 a do sloupce typu double 1.66666666666667.

Naštěstí můžete přesnost uložení trochu ovlivnit. U FLOAT a DOUBLE můžete při jejich definici zadatpožadovaný počet desetinných míst, například FLOAT (10,5) nebo DOUBLE (20,10). Uvedené příkladyznamenají to, že:

U FLOAT(10,5) se použije celkem deset znaků k zobrazení a pět desetinných míst. Pět děleno třemi seuloží jako 1.66667. Číslo 500000:3 se ale uloží jako 99999.99999 a vznikne varování. Na uložení takvelkého čísla je typ FLOAT(10,5) malý.

U DOUBLE(20,10) se použije celkem dvacet znaků k zobrazení a 10 desetinných míst. Pět děleno třemise uloží jako 1.6666666667. Číslo 500000:3 dopadne v pohodě jako 166666.6666666667.

Z toho, co bylo řečeno asi tušíte, že s nepřesnými desetinnými čísly je docela potíž. Moje rada je: nepoužívejteje, pokud vysloveně nemusíte. Rozhodně je nepoužívejte na uložení takových věcí, jako je množství zboží vefaktuře nebo kupříkladu sazba DPH. Početními operacemi s nepřesnými čísly se totiž zaokrouhlovací chybykumulují. Rvněž bídně selže pokus nepřesná čísla nějak porovnávat nebo použít jako zákad pro spojení. Kdyžuž musíte tato čísla porovnávat, použijte nějaké intervaly. Takže namísto myšlenky typu:

jestliže [nepřesné číslo] = 10000 tak ...

použijte (pokud opravdu musíte) něco ve smyslu

jestliže [nepřesné číslo] >= 9999.9 a [nepřesné číslo] <= 10000.1 tak ...

je to ale poměrně otravné (a pomalé). Daleko lepší je používat přesná desetinná čísla.

Přesná desetinná čísla

Page 24: MySQL Obsah

Existuje MySQL datový typ DECIMAL, který ukládá desetinná čísla s pevnou čárkou. Deklaruje se jakoDECIMAL (x,y), přičemž o parametrech platí to, co bylo řečeno výše u typů FLOAT a DOUBLE. Protožeukládá vnitřně čísla jako řetězec, netrpí chybami při zaokrouhlování. S výhodou se používá pro uloženípeněžních hodnot; některé DBMS mají dokonce definován typ MONEY, který odpovídá DECIMAL (x,4).

Rozhodně doporučuji používat DECIMAL všude tam, kde se jedná o peněžní hodnoty (například, v účetníchprogramech) nebo o přesně stanovitelné zlomky (třeba "půl kila hřebíků"). Teto typ je sice teoreticky pomalejšínež nepřesná čísla, ale konec potíží se zaokrouhlováním za to ve většině případů stojí.

U všech typů desetinných čísel (přesných i nepřesných) můžete použít příznak UNSIGNED. Jen pozor, fungujeto jinak než u čísel celých. Stane se to, že do sloupce nepůjdou uložit záporné hodnoty, ale rozsah kladnýchhodnot, které sloupec pojme se nezvýší.

Překročení rozsahu

Upřímě řečeno mi způsob, jakým se MySQL chová při překročení rozsahu sloupce vůbec nevyhovuje. Jestližese totiž například do pole, kam má být uložen TINYINT pokusíme vložit číslo mimo rozsah, příkaz NESELŽE,vyvolá varování, a vloží NEJBLIŽÍ povolenou hodnotu (v případě TINYINT tedy hodnotu 128). Ve většiněpřípadů tedy nepůjde při práci s MySQL spoléhat na to, že při práci s čísly mimo rozsah skončí operace chyboua bude se to moci nějak řešit. Pamatujte na to; toto chování vede k tomu, že v databázi můžete mít hodnoty,které jste tam nezadali!

Page 25: MySQL Obsah

MySQL (8) - Ukládání datumů

Dnes se popereme s kalendářem - budeme totiž do MySQL ukládat datum a čas.

29.3.2005 15:00 | Petr Zajíc | přečteno 16118×

Komerční sdělení: Pořádáme Kurzy MySQL

Snad každý soudobý DBMS systém má podporu pro zpracování a ukládání hodnot reprezentujících datum a čas.Nejinak je tomu v případě MySQL a proto se dnes podíváme, co nám tato databáze může při zpracováníčasových údajů nabídnout.

Pozn.: V tomto článku, a vlastně v celém seriálu se pokusím používat termín "data" (jednotné číslo to nemá) proobecné označení údajů v databázi a termín "datumy" (jedn. č. datum) pro údaje o čase. Abychom si rozumněli.

Datový typ Date

MySQL používá pro uložení kalendářních datumů datový typ Date. Pojme datumy od 1.1.1000 do 31.12.9999,což je myslím více než dostatečné. V databázi zabere 3 bajty místa. Při vkládání údajů do sloupce typu Date jeMySQL více než benevolentní, takže všechny níže uvedené způsoby můžete použít:

20041231'2004-12-31''04-12-31'

Jestliže při zadávání datumu překročíte povolený rozsah, vyvolá to varování a do databáze se vloží 0000-00-00.Datový typ Date budete asi běžně používat na takové věci, jako je ukládání datumů v obchodních aplikacích.Třeba v účetnictví.

Typ Time

MySQL datový typ Time neukládá datum, ale čas. Může se jednat o čas během skutečného dne, nebo prostěmůže jít o interval mezi dvěma událostmi. To také vysvětluje, proč sloupec typu Time nemá rozsah 00:00:00 -23:59:59 (jak byste možná čekali), ale -838:59:59 až +838:59:59. Rovněž údaje o čase lze vkládat různýmizpůsoby:

1020'00:10:20''001020'

V databázi zabírá tento typ 3 bajty místa, stejně jako Date. Při překročení rozsahu se vyvolá varování a vloží sehodnota 00:00. Na co použijete typ Time? Třeba na ukládání sportovních výsledků.

Typ Datetime

Page 26: MySQL Obsah

Typ datetime vlastně kombinuje předchozí dva typy, a to tím, že ukládá jak datum, tak i čas. Umím si jej doceladobře představit třeba jako kandidáta pro uložení datumů z píchaček (díky nočním směnám totiž můžete skončitpráci jiný den, než jste ji začali). O zadávání platí to, co bylo řečeno výše. V databázi zabírá osm bajtů místa.

Na tomto místě se sluší podotknout, že MySQL má rovněž k dispozici celou řadu funkcí pro práci s datem ačasem. Povíme si o nich později v našem seriálu; teď jen naznačím, že takové funkce umějí datumy sčítat,testovat, zda událost je v nějakém intervalu, konvertovat a podobně.

Typ Year

Přizám se, že datový typ YEAR jsem až doposud neznal. Slouží pro uložení roku, a to buď jako dvojciferné,nebo jako čtyřciferné číslo. Pokud je číslo dvojciferné, může nabývat hodnot od nuly do 99, přičemž 69=2069,ale 70=1970. Čtyřmístná varianta ukládá roky od 1901 do 2155. Docela by mě zajímalo, jestli někdo tuhlekulišárnu používate; kdyžtak můžete přispět do diskuse.

Unixové časové razítko

MySQL má velmi dobrou podporu, pokud jde o výpočty s unixovými časovými razítky. Unix-timestamp, jaksamozřejmě víte, reprezentuje počet sekund uplynulých od půlnoci 1.1.1970 a MySQL umí převádět jakklasické datumy na unix-timestampy, tak i naopak. Skutečně jsem viděl aplikace, které všechny datumyukládaly jako unixová časová razítka.

Typ Timestamp

Timestamp jsem si nechal nakonec. Ukládá do databáze informace o tom, kdy byl daný řádek založen neboaktualizován. Timestampy mohou nabývat hodnot od 1.1.1970 do 31.12.2037 a v databázi zabírají 4 bajty místa.Jejich chování se v posledních verzích MySQL dost měnilo, takže pokud chcete timestampy používat,prostudujte si dokumentaci.

MySQL, datumy a praxe

Z čistě praktického hlediska bych při používání datumů v MySQL předložil čtenáři několik postřehů:

MySQL NEKONTROLUJE, zda je zdadávané datum platné. MySQL pouze kontroluje rozsah, tzn.například u datumů to, zda je mezi 1.1.1000 až 31.12.9999. MySQL tedy klidně zbaští například31.4.2005 a nevyvolá ani varování. Kontrola platnosti zadávaných datumů bude tedy vždy na straněklienta. Jeví se mi to jako hotová katastrofa, protože MySQL neplatné datum klidně uloží. Pozor na to,protože jiné DBMS se chovají jinak.

MySQL v případě překročení rozsahu, jak už bylo uvedeno, uloží do polí typu date, time a datetimespeciální nulovou hodnotu. Jestliže však budete s touto hodnotou pracovat pomocí ODBC, budezkonvertována na NULL. Osobně by mi bylo mnohem milejší, kdyby MySQL takovou hodnotunevložila a místo toho by vrátila chybu.

Page 27: MySQL Obsah

Nespoléhejte na to, že MySQL je dost benevolentní co se týče formátu zadávaného datumu nebo času.Může se to vymstít. V praxi to řeším tak, že si v klientské aplikaci napíšu funkci, která datum jednakzkontroluje (viz výše), a jednak zformátuje. Pak jej teprve pošlu MySQL. Můžete si tak ušetřit mnohonepříjemností, dělejte to tedy rovněž.

Page 28: MySQL Obsah

MySQL (9) - Další datové typy

Dnes naposled o datových typech v MySQL.

1.4.2005 15:00 | Petr Zajíc | přečteno 14338×

Komerční sdělení: Pořádáme Kurzy MySQL

Typy dat, reprezentující čísla, řetězce a datumy jsou běžně používány ve většině databázových aplikací. Existujívšak ještě další skupiny. Dnes si je probereme. Nepoužívají se sice již tak často, ale vyplatí se o nich vědět.

Datový typ ENUM

Datový typ ENUM umožní při definici pole definovat nějaký seznam hodnot s tím, že některá z hodnot pakmůže být ve sloupci vybrána. Seznam hodnot přitom představuje pole řetězců. Takže například můžete mítENUM pole PIZZA a to může obsahovat následující seznam:

'tuňáková', 'šunková', 'havai'

Funkčně bychom mohli přirovnat typ enum k takovému grafickému rozhraní, kde vybíráme ze seznamu pomocíOption buttonů (nebo radio buttonů), viz obrázek:

Neboli, vybrána může být vždy přávě jen jedna volba. Jinak může mít typ enum až 65535 hodnot v setu. Co seale stane, když vložíme hodnotu mimo seznam? Pokud je zadávaná hodnota je mimo rozsah, bude do sloupcetypu ENUM vložena zvláštní hodnota NULL. Ještě o ní bude dnes řeč. Typ ENUM bych si dokázal představittřeba u aplikace na objednávku něčeho podle lístku nebo tam, kde se opakují více než dvě hodnoty.

Datový typ SET

SET je bratříček typu ENUM a funguje tak, že umožňuje vybrat žádnou nebo více hodnot ze seznamu najednou.K naší pizze bychom tedy mohli chtít třeba:

'česnek', 'olivový olej', 'kečup'

a to buď sólo, nebo třeba i všechno najednou (zastánci dobré pizzy, braňte se...). V počítačovém světě bychomto snadno mohli přirovnat k situaci, kdy vybíráme pomocí checkboxů:

Page 29: MySQL Obsah

Datový typ SET může nabízet k "zaškrtnutí" až 64 hodnot. Interně pracuje s hodnotami pomocí bitových map abitových masek, takže pokud se vyznáte v bitových operátorech, je to něco pro vás. Používám to například naskladování oprávnění v obchodních aplikacích, kde uživatel může mít kombinaci práv o obchodnímu objektu vestylu ('založit', 'zrušit', 'změnit', 'načíst', 'delegovat' atd.).

BLOB a CLOB

Co by to MySQL byla za databázi, kdyby neuměla ukládat rozsáhlá data. Asi víte, že zkratka BLOB znamená"binary large object" a CLOB "character large object" a že to znamená dlouhá binární (či znaková) data. Můžetesi za tím představit třeba schopnost databáze "pojmout" do svých útrob hudbu ve formátu mp3 (to by bylBLOB), nebo třeba text tohoto článku (to by byl CLOB).

MySQL podporuje oba typy dlouhých dat. BLOB je možné uložit do MySQL pomocí typů TINYBLOB, BLOB,MEDIUMBLOB a LONGBLOB. Znaková data pak mohou být vepsána do typů TINYTEXT, TEXT,MEDIUMTEXT a LONGTEXT. Těch typů je tolik jen proto, že umožňují uložit různě dlouhá data.

Svým chováním se ovšem typy BLOB a TEXT počítají k typům s pohyblivou délkou (jako například varchar).To znamená, že je uložena vždy i délka dat a že různé položky zabírají v databázi různě místa. Typy BLOB aTEXT jsou vždy vráceny do databáze bez ořezávání koncových mezer.

Jestliže se pokusíte uložit do pole BLOB (text) více dat, než kolik je toto pole schopno pojmout, přebytečná databudou oříznuta. Obecně je používání polí BLOB dosti dvojsečné; databáze tím může narůst a ztratit na výkonu.Často se proto používá technika, kdy jsou obsahy polí BLOB (nebo CLOB) uloženy v souborech operačníhosystému a databáze na ně obsahuje pouze odkazy.

Jiným důležitým faktorem, poněkud limitujícím používání BLOB polí databáze je fakt, že je potřeba toto polenejen ukládat, ale také zpracovávat. Jestliže potřebujete zpracovat pole velké několik MB, mohou přijít napřetřes takové faktory, jako je přenosová kapacita sítě, velikost paměti nebo schopnost klintské aplikacetakovou paměť využít. Čili - to, že lze BLOBy ukládat, není samospasitelné.

Hodnota NULL

NULL, o níž byla zmínka výše, není samostatný datový typ, a tak do tohoto dílu pojednání přísně řečenonepatří. Ale výše byla zmíněna, a stojí proto za vysvětlení. NULL je zvláštní hodnota reprezentující stav"nezadáno" nebo "neznámé". To zda sloupec smí nebo nesmí obsahovat hodnoty NULL se dá definovat při jehovzniku. S použitím hodnot NULL je databázový život snažší, KDYŽ JI SPRÁVNĚ POCHOPÍTE.

Tak například je jasné, že když si vyberu se tří pizz výše calzone, skončí to tím, že mě databáze nepochopí,protože pizzu calzone nezná. A právě proto bude do databáze uložena hodnota NULL (v našem případěreprezentující neznámou pizzu). O hodnotách NULL rovněž platí, že pěkně cvičí s matematikou. Co bystenapříklad řekli, že bude výsledkem výrazu

1+NULL

Jednička? Rozhodně ne! Výraz by totiž měl být chápán jako "jedna plus neznámá hodnota" a vyhodnocenjako ... neznámá hodnota! Podobně, řekli byste, že platí následující rovnost?

NULL = NULL

Page 30: MySQL Obsah

Neplatí! Jedna hodnota NULL se nikdy nerovná jiné hodnotě NULL, protože se jedná o dvě neznámé hodnoty.Tento úkaz nás bude provázet celý zbytek seriálu, tak na to zkusme pamatovat.

Page 31: MySQL Obsah

MySQL (10) - tvorba databáze. Základy DDL

Konec teorie. Dnes vytvoříme v našem seriálu první databázi.

5.4.2005 15:00 | Petr Zajíc | přečteno 17848×

Komerční sdělení: Pořádáme Kurzy MySQL

Teorie o datových typech již bylo dost na to, abychom se dnes pustili do něčeho praktičtějšího. V tomto díleseriálu se tedy zamyslíme nad příkazy jazyka pro definici databázových objektů (DDL) a hned si nějakévytvoříme.

Rychlé připojení k MySQL

Protože se chceme připojit k MySQL nějakým jednotným způsobem, použijeme řádkového klienta. Tomu budeještě věnován celý díl seriálu, takže dnes jen to nejpodstatnější. Abyste se mohli úspěšně připojit k MySQL,budete potřebovat:

vědět, že řádkový klient MySql se spouští příkazem mysql (narozdíl od serveru, jež startuje příkazmysqld)

vědět, jaký je název hostitele serveru, a znát svoje uživatelské jméno a heslo pro přístup

vědět, že pokud se chcete připojit k nějaké vzdálené databázi, lze zadat programu mysql údaje pomocípřepínačů -h, -u a -p (hostitel, uživatel, heslo)

Nějakým způsobem byste tedy měli být schopni se přihlásit spuštěním příkazu mysql; objevit by se mělo něcove smyslu:

mysqlWelcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 17 to server version: 4.1.10a-ntType 'help;' or '\h' for help. Type '\c' to clear the buffer.mysql>

Program mysql teď čeká na zadání uživatele; pro nás je ještě důležité vědět, že jednotlivé příkazy se v programumysql oddělují středníkem (;). Takže, vzhůru do světa DDL.

Založení nové databáze

První příkaz, který se naučíme, je příkaz pro tvorbu databáze. (Možná bude pro někoho užitečné podívat se dodílu o terminologii). Když se připojíte k databázovému serveru, mohou totiž nastat v zásadě tři situace:

Page 32: MySQL Obsah

Máte povolení pracovat s databází, ale musíte si ji nejprve vytvořit

Máte povolení pracovat s právě jednou databází, a již ji máte vytvořenu (typické u webhostingů)

Jste administrátor nebo se jedná o instalaci na vývojářský stroj - a pak si většinou můžete vytvořitdatabází, kolik chcete.

Novou databázi vytvoříte pomocí příkazu CREATE DATABASE. Viz příklad níže:

create database test;

V názvu databáze mysql nerozlišuje mezi malými a velkými písmeny, POKUD BEŽÍ SERVER na WINDOWS.Jestliže poběží na Linuxu, bude na tom záležet a databáze Test bude moci existovat vedle databáze test.Zapamatujete si to, když si uvědomíte, že každá databáze je v MySQL reprezentována adresářem. Řídící příkazynaproti tomu mohou být na všech systémech libovolnou kombinací malých a velkých písmen.

Ponz.: Kromě toho, že v Linuxu jdou vytvořit databáze, lišící se pouze velikostí písmen v názvech, byste ještěměli vědět, že se to moc nepoužívá. Například hodně vývojářů dává přednost tomu, pojmenovávat všechnyobjekty malými písmeny.

Jestliže právě zakládaná databáze již existuje, příkaz selže:

mysql> create database test;ERROR 1007 (HY000): Can't create database 'test'; database exists

Tomu však lze zabránit použitím klauzule IF NOT EXISTS, jak vidíte níže.

create database if not exists test;

MySQL používá rozšíření IF NOT EXISTS k potlačení chybových hlášení celkem často. Není to standardní, aledá se na to zvyknout. Další věc, kterou byste měli vědět je ta, že příkaz CREATE DATABASE může volitelněpřijímat pokyn týkající se znakové sady a způsobu řazení, které se v nově vytvořené databázi budou uplatňovat:

create database latin character set latin2 collate latin2_czech_cs;

Názvy znakových sad a způsobů řazení si samozřejmě nemůžete vymyslet, musíte je převzít z těch, kteréMySQL podporuje.

Jak poznáte, že nová databáze byla skutečně založena? MySQL má příkaz:

show databases;

který vám všechny databáze na daném serveru vypíše. Konečně, pokud se budete chtít k dané databázi naserveru připojit, slouží k tomu syntaxe:

use test;

A ještě malá poznámka: Řádkový klient mysql podporuje zadání více příkazů najednou, takže následujícísystaxe je platná:

create database priklad; use priklad;[enter]

Page 33: MySQL Obsah

Zrušení databáze

Stejně, jako lze databázi založit, lze ji rovněž zrušit. Slouží k tomu příkaz DROP DATABASE:

drop database [if exists] test;

Jak ovšem nejspíš tušíte, zruší to nejen databázi samotnou, ale rovněž všechny tabulky a všechna data v ní.Buďte proto při používání tohoto příkazu maximálně opatrní - zejména pokud si nejste jisti, že mažete to, copotřebujete. Kromě obnovy z nějakých existujících záloh totiž není způsob, jak omylem odstraněnou databázizískat zpět.

Příště si v seriálu ukážeme na to, jak se dají v nově vzniklé databázi vytvářet tabulky.

Page 34: MySQL Obsah

MySQL (11) - vytváříme tabulky

Databázi již vytvořit umíme; dnes se podíváme na tvorbu tabulek. V MySQL nic, co by se nedalo pochopit.

8.4.2005 15:00 | Petr Zajíc | přečteno 17563×

Komerční sdělení: Pořádáme Kurzy MySQL

Dnes si rozšíříme vědomosti o DDL. Půjdeme na to tak, že se naučíme v MySQL vytvářet tabulky. Uvidíte, žeto není až tak složité a že se to dá docela dobře zvládnout.

Proč umět tvořit tabulky

V případě, že s MySQL (nebo s jakoukoli jinou databází) již nějakou dobu pracujete, pravděpodobně jste sizvykli používat pro úlohy typu "tvorba tabulek" nějaké grafické klienty. V případě MySQL by takovýmklientem mohl být třeba PhpMyAdmin (psali jsme o něm). Proč byste se tedy měli učit definiční příkazy zhlavy? Existuje pro to dost dobrých důvodů; níže uvádím ty, které mě napadly:

I v aplikaci (na webové stránce apod.) může být někdy potřeba "za běhu" vytvářet nebo rušit tabulky.Ačkoli to není typické, můžete se s tím setkat. Programátor by to měl znát.

Bez těchto vědomostí nemůže nikdo říct, že zná MySQL

Nástroje typu phpMyAdmin nemusejí být po ruce vždy, když jsou potřeba

Správný drsňák udělá z konzole cokoli.

Pokud jsem Vás inspiroval, čtěte dál. Pokud ne, všímejte si alespoň, jaké příkazy váš grafický klient pro tvorbutabulek používá a naučte se je časem. Uvidíte, že to byla dobrá rada.

Příkaz CREATE TABLE

Abychom vytvořili tabulku, musíme v MySQL provést následující:

1. Přihlásit se k MySQL

2. Přepnout se do databáze, v níž budeme tabulku tvořit (viz minulý díl)

3. Spustit příkaz CREATE table

Page 35: MySQL Obsah

Obecná syntaxe příkazu CREATE TABLE je přitom tato:

create table [název tabulky] ([název sloupce] [typ sloupce]...);

Za názvem typu sloupce lze uvést klauzuli NULL nebo NOT NULL, která povoluje (zakazuje) vkládáníneznámých hodnot do sloupce. Podobně lze uvést klauzuli DEFAULT, která stanoví, jaká hodnota bude prosloupec výchozí. Stejně jako v případě tvorby databází, i zde můžete použít klauzuli IF NOT EXISTS, cožvypne chybové hlášení, pokud by snad vytvářená tabulka již existovala. Následuje několik příkladů:

create table seznam (id int);create table knihy (nazev VARCHAR (50), rok_vydani YEAR, zakoupeno DATETIME);create table zamestanci (jmeno VARCHAR (20) NOT NULL, prijmeni VARCHAR (25) NOT NULL);

V prvním případě jsme vytvořili tabulku jen s jedním sloupcem, což není příliš typické. Ve druhém případě jižbyly sloupce tři a každý z nich měl jiný datový typ. Konečně, v posledním případě bude mít tabulka dva sloupces tím, že jak pole jméno, tak i pole příjmení musí být zadáno.

Pozn.:Přesněji řečeno v poli jmeno a prijmeni nesmí být hodnota NULL (neznámo, nezadáno). Může tam alebýt prázdný řetězec.

Teď ještě jeden příklad na definici pole s výchozí hodnotou:

create table lidi (prijmeni VARCHAR (50) NOT NULL, rok_nastupu YEAR DEFAULT 2005 NOTNULL);

Což znamená toto: Jestliže se nevloží žádná jiná hodnota do pole rok_nastupu, bude tam po uložení do databázečíslo 2005.

Pozn.: To je samozřejmě hodně vykonstruovaný příklad. Daleko rozumnější by bylo použít funkci, která budevracet aktuální rok. MySQL však bohužel nepodporuje v klauzuli DEFAULT funkce, pouze konstanty. Vloženíaktuálního data by nicméně šlo realizovat pomocí slouce typu timestamp.

Docela dobrou (a málo známou) vychytávkou u MySQL je možnost založit jednu tabulku kopírováním strukturytabulky jiné. Máte-li například v databázi tabulku account a chcete mít ještě tabulku account2, založíte ji rychlepomocí příkazu:

create table account2 like account;

Výsledkem bude to, že v databázi vznikne tabulka account2. Bude mít stejnou strukturu jako tabulka account,ale bude bez dat. Úmyslně jsem nemluvil o dalších dvou věcech, které lze při definici tabulky v MySQL udělat -a to o specifikaci voleb pro nově vzniklou tabulku, a o indexech. Obojí se ještě bude probírat v seriálu;nedočkavci se mohou podívat do manuálu.

Příkaz ALTER TABLE

Čas od času může být nutné existující tabulku v databázi změnit. To, když se nad tím zamyslíte, může znamenatv podstatě tři věci:

přidat nějaký sloupec k existující tabulce

Page 36: MySQL Obsah

odebrat sloupec z tabulky

změnit existující sloupec - buď jeho typ, nebo jeho název, nebo obojí.

MySQL přímo podporuje všechny tyto operace. Takže jednoduše můžete přidat sloupec:

alter table account add column account_balance decimal (10,2);

můžete změnit sloupec, a to dokonce název i typ najednou:

alter table account change column account_balance account_balance2 decimal (14,2);

a konečně, sloupec můžete nemilosrdně odstranit:

alter table account drop column account_balance2;

Ale varování: To, že tyto operace jdou tak jednoduše provést neznmená, že se při návrhu databáze nemusíuvažovat! Změna existující tabulky totiž občas může přinášet zajímavé problémy. Například, nevhodnouzměnou tabulky může vaše databáze ztratit na výkonu nebo na přehlednosti. Při změně sloupců v neprázdnétabulce musíte být zvláště opatrní, protože změna struktury bude mít vliv na data. Při změně typu sloupce můžedojít ke ztrátě přesnosti nebo ke ztrátě dat. Zlaté pravidlo tedy zní: Před změnou tabulky zálohovat.

Příkaz DROP TABLE

Je jedoduchý:

drop table [if exists] table_name;

A platí o něm do značné míry to, co bylo řečeno při mazání databází: je dosti destruktivní. Po příkazu DROPDATABASE je to druhý nejvíce ničivý příkaz, takže pozor, ať při jeho použití nepřijdete o data, která ještěbudete potřebovat! Běžnou praxí (zejména ve webových aplikacích) je takové příkazy do aplikace vůbecnedávat a odstraňovat tabulky pouze prostředky mimo aplikaci.

Page 37: MySQL Obsah

MySQL (12) - tipy k tvorbě tabulek

MySQL, tabulky a speciality - automaticky číslovaná pole, dočasné tabulky a tak dále.

12.4.2005 12:00 | Petr Zajíc | přečteno 15647×

Komerční sdělení: Pořádáme Kurzy MySQL

Stejně, jako je tomu v kterémkoli zákoutí práce s počítačem, má i tvorba tabulek v databázích svoji "třináctoukomnatu". Proto se dnes podíváme na některé podrobnosti práce s tabulkami, které se vám v praxi mohou velmihodit.

Seznam tabulek

MySQL, stejně jako prakticky každá jiná databáze, má příkaz, kterým zobrazíte seznam existujících tabulek vdatabázi. Provedete to pomocí tohoto kódu:

SHOW TABLES;

Aby to fungovalo, musíte mít zvolenu nějakou databázi. Jinými slovy, bezprostředně po přihlášení k serveru,pokud nepoužijete příkaz USE [název databáze], tak to selže. Příkaz SHOW TABLES má ovšem určitérozšíření, které trochu popírá předchozí větu - ono to totiž jde napsat takto:

SHOW TABLES FROM SHOP;

A pak je samozřejmě úplně jedno, v jaké databázi jsme, protože budou vypsány tabulky ze zvolené databáze.

Pozn.: Seznam tabulek v nějaké databázi je typickým příkladem toho, čemu se říká metadata, neboli "data odatech". Pokud se budete věnovat databázím hlouběji, zjistíte, že porozumět metadatům a umět s nimi pracovatje docela důležité. Například v úlohách typu import - export dat a podobně.

Dočasné tabulky

Dočasné tabulky se od "trvalých" tabulek liší především tím, že existují pouze od jejich vytvoření do ukončeníspojení, které je má "na svědomí". Tedy - jakmile zanikne připojení, zaniknou i všechny dočasné tabulky, kteréběhem tohoto spojení vznikly. Vytvořit dočasnou tabulku přitom není nikterak složité. Stačí zavzpomínat naminulý díl a doplnit, že při manipulaci s dočasnými tabulky se mezi CREATE a TABLE vloží klíčové slovoTEMPORARY:

CREATE TEMPORARY TABLE PENIZE (MNOZSTVI int);

Většina z toho, co platí o normálních tabulkách, platí i o tabulkách dočasných. To například znamená, žemůžete použít rozšíření IF NOT EXISTS, jak o něm byla řeč v minulém díle. Stejně tak lze vytvořit dočasnoutabulku kopírováním existující (a to jak dočasné, tak trvalé) tabulky nějak takto:

CREATE TEMPORARY TABLE PENIZE2 LIKE PENIZE;

Ovšem, používání dočasných tabulek má rovněž svoje záludnosti. O nich byste měli něco vědět, pokud je chcetepoužívat. Tak především, narozdíl od trvalých tabulek mohou dvě různá připojení vytvořit dvě dočasné tabulky

Page 38: MySQL Obsah

se stejným názvem (aniž by to kolidovalo). To je celkem příjemné. Vyplývá z toho, že pokud víte, že jste určitěnevytvářeli dočasnou tabulku nějakého jména, prakticky nikdy nemusíte používat klauzuli IF NOT EXISTS.Další věc - dočasné tabulky se neobjevují ve výpise tabulek pořízeného pomocí příkazu SHOW TABLES. Anakonec, manuál tvrdí, že mohou existovat další omezení.

Proč by mohl někdo chtít používat dočasné tabulky? V praxi je používám ve třech případech:

1. Někdy existuje výpočet, který je tak složitý nebo natolik náročný na zdroje, že je rozumné nějak ukládatmezivýsledky. V takovém případě může být použití dočasné tabulky docela na místě.

2. Někdy bývá třeba pracovat s určitou podmnožinou dat z rozsáhlé tabulky, nebo dokonce s podmnožinoudat z více velkých tabulek (mám na mysli tabulky s desetitisíci nebo statisíci záznamy). V takovémpřípadě může být praktické vykopírovat si onu podmnožinu dat do dočasné tabulky a pak tuto tabulkupoužít.

3. Někdy je potřeba opakovaně použít data vzniklá nějakým výpočtem. Dočasná tabulka může v takovémpřípadě být to "pravé ořechové".

Pozn.: Uvedené zásady byste něměli chápat jako definitivní. Existuje totiž celá řada dalších mechanizmů, kteréřeší některé z problémů popsaných výše (indexy, pohledy atd.). Chtěl jsem jen, abyste měli představu, k čemu sedočasné tabulky dají použít.

Automaticky číslovaná pole

V tabulkách bývá, a to velmi často, pole jednoznačně identifikující daný řádek. V různých DBMS se vytvářejírůzně, většinou jako náhodná čísla nebo sekvence. Typické je, že existuje pole, které automaticky s každýmpřidaným řádkem zvýší čítač o jedničku. MySQL má podporu pro tuto funkci. Ačkoli to souvisí s indexy, onichž teprve v seriálu bude řeč, již teď vám ukážu, jak se automaticky číslované pole vytvoří:

CREATE TABLE cislovani (id INT AUTO_INCREMENT, PRIMARY KEY (id));

K tomu si dovolím několik postřehů:

Automaticky číslované pole se většinou označuje tak, aby z názvu bylo poznat, že se jedná o takovépole. Typicky ID (identity), nebo [název tabulky]ID a podobně.

Jak později v seriálu uvidíme, automaticky číslovaná pole musejí být součástí indexu. Uvidíme také, žetoto omezení má logický důvod.

Třebaže většinou necháme číslování řádků na aplikaci, principelně nic nebrání vložení hodnoty dotohoto pole přímo (tzn. vložení například čísla 15 projde, přestože nejvyšší dosud vložené číslo nebyla14. Vložení pochopitelně selže, pokud by tam patnáctka již byla).

MySQL nevyplňuje "díry" vzniklé odstraněním řádků (nebo vložením jiné než následující hodnoty vřadě). Je-li záznam smazán, jeho automatické číslo již nikdy nebude přiděleno.

Page 39: MySQL Obsah

V jedné tabulce smí být nejvýše jedno automatické číslování.

Pokud by při číslování měl být překročen maximální rozsah hodnot, které lze do číslovacího sloupcevložit, dojde k chybě, a řádek nebude vložen.

Automaticky číslované pole lze přidat k již existující tabulce. MySQL pochopitelně doplní čísla, pokudby snad tabulka již obsahovala nějaká data.

Automatická čísla se v tabulkách MySQL používají velmi často. Je to jednoduše řečeno proto, že prakticky vkaždé tabulce existuje důvod mít jednoznačně identifikované řádky.

Přejmenování tabulky

V MySQL existuje možnost přejmenovat existující tabulku, a to beze ztráty dat. Slouží k tomu příkaz renametable:

RENAME TABLE cislovani TO cislovani2;

Ačkoli je to jednoduché, existuje dost dobrých důvodů, proč to NEDĚLAT. Níže uvádím ty nejpodstatnější:

Nutnost přejmenovat tabulku obvykle poukazuje na to, že programátor nemá propracovanou metodikunázvu objektů, nebo že ji má "děravou".

Přejmenováním tabulky se automaticky NEUPRAVÍ všechny příkazy, v nichž tabulka byla použita.Znamená to, že může přestat bez varování fungovat nějaký kód. Zejména to platí o MySQL 5.x, kde jemožno používat uložené procedury.

Je třeba si uvědomit, že jedna nebo i více klientských aplikací může mít starý název tabulky někde vezdrojovém kódu. Je třeba to zkontrolovat a opravit i tam.

Tip: V naprosté většině editorů zdrojového kódu lze použít příkazy pro vyhledání a nahrazení, takže to nemusíbýt až takový problém. Pokud jde o příkazy uložené v databázi, existuje postup, při němž se 1) databázeoskriptuje, 2) ve vzniklém scriptu se vyhledají všechny zmínky o původním názvu tabulky a 3) ty se opraví.Nicméně, přejmenování tabulky dost často vede ke komplikacím, zejména pokud je projekt již v pokročilémstádiu vývoje.

V dalším díle seriálu se podíváme na to, jak do tabulek v MySQL vkládat data.

Page 40: MySQL Obsah

MySQL (13) - Vkládáme data

Databázi už máme, teď nějaká data. Jak je vkládat a na co přitom dávat pozor - o tom je dnešní díl seriálu oMySQL.

19.4.2005 15:00 | Petr Zajíc | přečteno 16624×

Komerční sdělení: Pořádáme Kurzy MySQL

Vkládání dat je jedním z pilířů práce s databázemi. Ostatně databáze bez dat by byla k ničemu. Proto je velmidůležité naučit se, jak vlasntě jednotlivé informace do databáze dostat. V MySQL právě k tomu slouží příkazINSERT.

Příkaz INSERT

Zkusme to nejprve na nějakém učebnicovém příkadu. Dejme tomu, že si budete chtít pořídit seznam všech knihve vaší knihovničce. Ještě předtím, než budete moci cokoli vkládat, je potřeba vytvořit odpovídající databázi avytvořit odpovídající tabulku.

create database knihovna;use knihovna;create table knihy (id int not null auto_increment,nazev varchar (50), autor varchar(50), primary key (id));

S tímto arzenálem už můžete začít do tabulky vkládat informace o jednotlivých knihách. Děje se tak pomocípříkazu INSERT. Jeho nejběžnější forma je:

insert into knihy (nazev, autor) values ('LINUX - dokumentační projekt', 'kolektivautorů');

V praxi to většinou probíhá tak, že příkaz INSERT je sestaven nějakou klientskou aplikací a odeslán databázi kezpracování. Odkud by data pro příkaz INSERT mohla pocházet? To je velmi různorodé. Pokud by byla MySQLpoužita ve webové aplikaci, je dost dobře možné, že data pro příkaz INSERT budou pocházet z formuláře nawebové stránce. Jestliže by se jednalo o desktopovou aplikaci s grafickým rozhraním, mohou data pocházet ztextových polí nebo mřížek; jestliže bude MySQL použita v obchodním domě na evidenci prodejů zboží, pakpoputují do databáze data ze čteček čárového kódu a podobně. V každém případě je třeba kontrolovat vkládanéúdaje ještě předtím, než jsou do databáze vloženy.

Pozn.: Existuje ještě jedna odlišná filozofie přístupu k věci - vložit někam data co nejrychleji (možná dodočasné tabulky) a nechat je zkontrolovat, až na to bude čas. Tento postup je někdy k vidění u velmi zatíženýchaplikací, ale příliš mi k srdci nepřirostl.

Příkazem INSERT lze rovněž vložit více než jeden řádek. Tento trik není příliš známý. Funguje to takto:

insert into knihy (nazev, autor) values ('PHP - tvorba interaktivních internetových aplikací', 'Jiří Kosek'), ('Myslíme v jazyku MySQL', 'Ian Gilfillan');

Page 41: MySQL Obsah

Za zmínku rovněž stojí, že v příkazu INSERT nemusíme specifikovat všechny sloupce. V příkladu výše jsmeneurčili, co se má vložit do sloupce id. Protože to je sloupec, kam se vkládají čísla automaticky, vlastně tovůbec nevadí. Co však vloží INSERT do sloupců, které nejsou typu autoincrement, když jim nicnespecifikujeme? Funguje to takto:

U sloupců, kde je povoleno mít hodnoty NULL bude vložena hodnota NULL.

U sloupců, kde není povoleno mít hodnoty NULL bude vložena výchozí hodnota pro daný typ sloupce(například 0 pro celá čísla)

U sloupců, které mají definovánu výchozí hodnotu DEFAULT pomocí příkazu CREATE TABLE neboALTER TABLE bude vložena definovaná hodnota.

U sloupců typu ENUM bude vložena první hodnota v seznamu.

Příkaz INSERT ... SELECT

Další varianta příkazu INSERT spočívá v tom, že se mohou vkládat do tabulky data, která již v jiné tabulkce(nebo jiných tabulkách, nebo dokonce ve stejné tabulce) existují. Jde se na to tak, že se:

1. Pomocí výběrového dotazu vyberou odpovídající data

2. Ta se vloží do tabulky pomocí speciální syntaxe příkazu INSERT.

Problém s výběrovými dotazy je ten, že jsme o nich v seriálu zatím nemluvili. Nicméně, krátká ukázka bymohla vypadat nějak takto:

INSERT INTO archiv_faktur SELECT * FROM faktury;

Jedná se o to, že data jsou nejprve vybrána ze zdrojové tabulky (tabulek) a následně vložena do tabulky cílové.Zdroj velmi často obsahuje více než jeden záznam, takže je běžné, že se takto pracuje s velkými objemy dat.Platí přitom, že výběrový dotaz (to je ta část od slova SELECT) musí obsahovat stejně sloupců jako tabulka, doníž se vkládá a že datové typy souvisejících sloupců musejí být stejné nebo schopné konverze. PříkazINSERT ... SELECT je obecně poměrně dost rychlý.

INSERT a výrazy

Nikde není řečeno, že jako součást příkazu INSERT se musejí používat data zapsaná ručně nebo data vybraná znějaké tabulky. Jako součást příkazu mohou stejně tak posloužit výrazy. Máme-li tedy tabulku:

create table vypocty (vysledek int);

bude jakákoli z následujících syntaxí platná:

Page 42: MySQL Obsah

insert into vypocty values (1+2);insert into vypocty values (3*4);insert into vypocty values (20/5);

Neboli, v příkazu INSERT, stejně jako na mnoha dalších místech v databázi mohou být výsledky nějakéhovýpočtu. Co všechno umí databáze počítat si ještě postupně ukážeme. Nechat výpočty na databázi může být,zejména v případě vkládání většího počtu řádků o dost rychlejší, než kdyby to měla děla dělat klientskáaplikace.

Poznámky k příkazu INSERTAčkoli je příkaz INSERT poměrně bezbolestný, přesto se vyplatí vědět nějaké ty záludnosti, tipy a triky. Tadyjsem jich pár popsal:

Příkaz INSERT lze spouštět s celou řadou voleb. Ty se týkají takových věcí, jako je zamykání tabulek,priorita nebo řešení některých chyb. Více je v manuálu.

Příkaz INSERT má místy nepřehledné zpracování chyb. Například, jestliže se pokusíte vložit hodnotuNULL pomocí příkazu INSERT do sloupce, kde nesmí být, skončí to chybou. Pokud ale budete vkládatvíce hodnot pomocí values (...), (...), ty vyhovující záznamy se vloží.

Rychlost příkazu INSERT se dá ovlivnit vhodným návrhem tabulky. Obecně je vkládání záznamů tímpalčivější problém, čím více je jich potřeba vložit, čím více sloupců tabulka obsahuje a čím víceobsahuje indexů (o těch se ještě také něco dozvíme).

Prakticky v každém programovacím jazyce, který lze napojit na MySQL existuje způsob, jak testovat,zda se vložení povedlo. Je velmi dobrý nápad to skutečně testovat a reagovat pružně na případnéproblémy.

Page 43: MySQL Obsah

MySQL (14) - Upravujeme data

MySQL (14) - Jak v databázi MySQL zaktualizovat data, aneb příkazUPDATE na sto způsobů.

22.4.2005 15:00 | Petr Zajíc | přečteno 14399×

Komerční sdělení: Pořádáme Kurzy MySQL

Databáze zřídkakdy bývají jen pro čtení. A z toho vyplývá, že do naprosté většiny databází se musí dát nejenzapisovat, ale musí být rovněž možné jednou zapsaná data měnit, opravovat. Právě o tom bude dnešní dílMySQL seriálu.

Příkaz UPDATE

J aktualizaci stávajících dat v tabulce slouží příkaz UPDATE. Nejjednodušší forma příkazu UPDATE můževypadat nějak takto:

update penize set castka = 100;

Tedy název tabulky, příkaz set, název pole a jeho hodnota. Jedním příkazem UPDATE se dá změnit více nežjeden sloupec. To by vypadalo nějak takhle:

update penize set castka = 100, dph=19, castka_s_dani=119;

Data, která se aktualizují, mohou nějakým způsobem záviset na datech předchozích. To například znamená, žeplošné zdražení všech výrobků v ceníku o 15% by se v databázi dalo realizovat tímto příkazem UPDATE:

update cenik set cena = cena * 1.15;

Všem třem výše uvedeným příkladům však pro reálné použití v praxi něco podstatného schází. Všechny jsoutotiž napsány tak, že zaktualizují celou tabulku. Uvědomme si, že tabulka může být buďto prázdná, nebo můžeobsahovat jeden záznam, nebo jich tam mohou být tisíce. To nás přivádí k velmi podstatné možnosti, kteroumají všechny databáze, a tou možností je:

Omezení počtu ovlivněných řádků

Co mám tím výrazem na mysli a proč se to rozebírá v díle o aktualizaci dat? Výrazem "počet ovlivněnýchřádků" se v databázové hantýrce myslí

Počet řádků, které se budou vkládat

Počet řádků, které se budou aktualizovat, nebo

Page 44: MySQL Obsah

Počet řádků, které se budou mazat, nebo

Počet řádků, které se budou vracet volající aplikaci jako data

Pokud vkládáme údaje do databáze (viz minulý díl), je počet ovlivněných záznamů předem jasný. Jestliženedojde k chybě, bude vloženo tolik záznamů, kolik si jen volající aplikace bude přát. Takže v případě vkládánínových řádků do databáze se počet ovlivněných záznamů řídí tím, kolik dat přichystáme.

Naprosto jiná situace však nastane, pokud se budou data aktualizovat (o tom je řeč dnes), mazat (rozeberemepříště) nebo vybírat (někdy později). V těchto případech tedy musí existovat nějaký způsob, jak databázi sdělit,co všechno má zaktualizovat (nebo smazat, nebo vybrat). Představte si například fakturantku, která objevilachybu v celkové částce na faktuře. V tabulce faktrur může být několik tisíc záznamů, naše pohledná asistentkavšak potřebuje upravit jen jeden - MySQL tedy musí mít nějaký mechanizmus, jak daný řádek najít,zaktualizovat a ostatních se ani nedotknout.

Tento mechanizmus spočívá v použití klíčového slova WHERE v textu příkazu. Nejlépe to bude patrné napříkladech. Naše fakturantka bude dejme tomu vědět číslo faktury, kterou chce opravit. Takže aplikace můžesměle zavolat příkaz UPDATE ve stylu:

update faktura set cena = 1500 where cislo = 20050126;

Klauzule where "donutí" databázi, aby si aktualizovanou tabulku nějakým způsobem prošla a upravila jenněkteré řádky. Tomuto přístupu se velmi často říká filtrování záznamů.

Pozn.: V našem příkladu s fakturou by se pravděpodobně jednalo o jediný řádek. Faktury totiž bývají čísloványvzestupnou řadou, aby byla zajištěna jejich jednoznačnost.

Pro osvěžení se můžete podívat na některé typické příklady použití klauzule WHERE. Zdražit banány o 10%bychom mohli v ceníku zeleniny nějak takto:

update cenik set cena = cena * 1.1 where zbozi = 'banány';

A zaktualizovat počet výrobků, které dnes udělal nějaký dělník v továrně by se dalo tímto způsobem:

update vyrobky set pocet = pocet+1 where datum = '20050420' and delnik = 'Josef Novák';

Z poslední ukázky je mimochodem pěkně vidět, že podmínka WHERE může být složená. Lze v ní používatnapříklad klíčová slova AND, OR a NOT, jak to pravděpodobně znáte z programovacích jazyků. MySQL mákromě klauzule WHERE ještě další možnost, jak ovlivnit počet aktualizovaných řádků - a to pomocí klauzuleLIMIT. Nejprve ukážu na příkladu:

update faktura set cena = 1500 where cislo = 20050126 limit 1;

A teď to vysvětlím. Klíčové slovo LIMIT omezuje počet řádků, které se budou aktualizovat, na nějaké pevnědané číslo. Pokud se použije jak klauzule WHERE, tak LIMIT, funguje MySQL následovně:

1. Vyberou se všechny řádky, které odpovídají podmínce WHERE

2. Z nich se vybere jen prvních n řádků, kde n je počet v klauzuli LIMIT

Page 45: MySQL Obsah

3. Těchto prvních n řádků se zaktualizuje, ostatní zůstanou nedotčeny.

Pokud si na používání klauzule LIMIT zvyknete, zjistíte, že je docela užitečná. Tak třebas v příkladu s fakturousi jako programátoři můžete chtít zajistit, že příkaz každopádně zaktualizuje nejvýše jeden řádek. Není žádnáostuda použít (teoreticky nadbytečnou) klauzuli LIMIT. Dotaz to téměř nezpomalí a za tu jistotu to určitě stojí.

Speciality, tipy a triky

Teď vám poradím něco z praxe. Často bývá nutné aktualizovat jeden sloupce na základě jiného, ale s určitourozhodovací logikou. Dejme tomu, že budete mít tabulku, kde čísla od jedničky do čtyřky budou značit ročníobdobí a bude existovat další sloupec, který by měl reprezentovat textové vyjádření tohoto období (jaro - zima).

create table obdobi (kvartal tinyint, nazev varchar(6));insert into obdobi (kvartal) values(1), (2), (3), (4), (1);

Dá se na to jít takto:

update obdobi set nazev = case when kvartal = 1 then 'jaro' when kvartal = 2 then 'léto' when kvartal = 3 then 'podzim' when kvartal = 4 then 'zima'end;

Pomocí příkazu CASE se dají podobné věci velmi snadno zařídit. Příkaz UPDATE obecně neselže, pokud jetabulka prázdná nebo pokud díky omezujícím podmínkám WHERE (nebo LIMIT) nevyhovuje ani jedenzáznam. Příkazem UPDATE se dají aktualizovat data v jedné tabulce daty z jiné tabulky. Nebo se jím dajíaktualizovat data v několika tabulkách najednou. K těmto věcem ještě v seriálu dojdeme, momentálně na něvšak nemáme dostatek vědomostí.

Příště se budeme bavit o odstraňování záznamů.

Page 46: MySQL Obsah

MySQL (15) - Odstraňujeme data

MySQL a odstraňování záznamů. Ale - je vůbec dobrý nápad něco v databázi mazat? Nedalo by se to obejít?Přečtěte si!

26.4.2005 15:00 | Petr Zajíc | přečteno 11519×

Komerční sdělení: Pořádáme Kurzy MySQL

Protože jsme se v předchozích dvou dílech věnovali příkazům, pomocí nichž lze data do MySQL vkládat aupravovat, asi nikoho nepřekvapí, že dnes se budeme věnovat mazání záznamů.

Příkaz DELETE

MySQL má pro odstranění záznamů z tabulky příkaz DELETE. Ten odstraní nula nebo více řádků. Jehonejjednodušší forma je:

delete from [názav tabulky];

Příkaz uvedený výše odstraní z tabulky všechny záznamy. Pozor, v některých DBMS je přípustná i formapříkazu s hvězdičkou:

delete * from [názav tabulky];

kterou však MySQL nevezme, a příkaz takto napsaný by skončil chybou. Samozřejmě, málokdy budete chtítodstranit z tabulky všechny záznamy. Mnohem častější bude situace, kdy chcete vybrat jen nějaké řádky a tyodstranit. O takové situaci platí to, co bylo řečeno v minulém díle. Lehce to shrňme. Příkaz DELETE můžeobsahovat klauzuli WHERE, která omezí mazané řádky na nějakou podmnožinu z celkového počtu pomocípodmínek. Lze tedy například napsat:

delete * from faktury where cena = 500; delete from zakaznik where id = 156;

Rovněž lze omezit maximální počet řádků, které bude třeba smazat, pomocí klauzule LIMIT. Má-li být smazánnejvýše jeden řádek, lze tedy přepsat příkazy výše ve smyslu:

delete * from faktury where cena = 500 limit 1; delete from zakaznik where id = 156 limit 1;

Moc doplňujících informací se k příkazu DELETE napsat nedá. Má pochopitelně nějaké ty přepínače, o nichž jezmínka v manuálu. DELETE však není jediný způsob, jak v MySQL odstraňovat záznamy.

Příkaz TRUNCATE TABLE

TRUNCATE TABLE je příkaz, který odstraňuje všechny záznamy v tabulce, přičemž definici tabulky samotnéponechává. Následující dva příkazy budou tedy totožné:

Page 47: MySQL Obsah

delete from faktury; truncate table faktury;

Proč tedy existují na jednu akci dva různé příkazy? Především proto, že příkaz TRUNCATE je mnohemrychlejší. Jelikož ví, že bude muset smazat celou tabulku, nemusí tento příkaz procházet a mazat řádky pojednom. U extrémně velkých tabulek je toto zrychlení markantní. Tento příkaz však nevrací počet odstraněnýchřádků.

Problémy a jak je řešit

Se samotným mazáním řádků v tabulkách obyčejně problémy nebývají. Otázka však je, jak smazání ovlivní datanebo aplikace, které s daty pracují. Potíž je v tom, že jednou smazaný řádek již nelze nijak obnovit. Dalšípozoruhodná potíž spočívá v tom, že data v jedné tabulce mohou souviset s daty v tabulce jiné (o tom ještě vseriálu uslyšíme). Ukažme si tedy, jak se to dá v praxi obejít.

Pozn.: Vnímavý čtenář namítne, že i smazaný záznam lze obnovit, pokud je operace součástí transakce. To jepravda. Zmíníme se o tom jindy. Rovněž je pravda, že data v souvisejících tabulkách lze efektivně spravovatpomocí referenční integrity. Nicméně, obecný problém s mazáním nic z toho úplně neřeší.

Stornovací záznamyPředstavte si na chvíli, že došlo k chybě v nějakém bankovním systému a nedopatřením vám někdo odečetlprostředky z běžného účtu. Mohlo se tak stát pomocí následujícího příkazu MySQL:

insert into pohyby_na_uctu (ucet, datum, castka) values ('123456', '2005-04-25 12:00:00',-50000);

Právě byste zchudli o 50 000,- Kč. Jenomže na chybu by se přišlo. Běžně v takových situacích nedochází ktomu, že by se záznam o odečtení prostředků prostě vymazal - to by totiž vedlo k tomu, že už se nikdo nedozví,co se vlastně stalo. Namísto příkazu:

delete from pohyby_na_uctu where ucet='123456' and datum = '2005-04-25 12:00:00' andcastka = -50000 limit 1;

tedy dojde nejspíš ke vložení dalšího záznamu s opačnou hodnotou částky:

insert into pohyby_na_uctu (ucet, datum, castka) values ('123456', '2005-04-25 12:10:00',50000);

PříznakyNěkdy je k vidění následující technika: Řádky se fyzicky neodstraňují, místo toho se jim nastaví hodnotanějakého zvlášť k tomu určeného sloupce (příznaku) a nechají se být. Nevýhoda tohoto přístupu spočívápochopitelně v tom, že s tím musejí aplikace počítat; výhoda na druhou stranu je ta, že "smazání" lze kdykolivrátit zpět. Namísto příkazu:

delete from knihy where rok_zakoupeni = 1999;

by se v aplikaci používající tuto techniku zapsalo něco ve smyslu:

update knihy set deleted = 1 where rok_zakoupeni = 1999;

Pokud byste si to chtěli do budoucna rozmyslet, můžete provést další příkaz UPDATE. Aplikace bypochopitelně musela počítat s tím, že nesmí vracet všechny knihy, ale jen ty, které NEMAJÍ nastavenoujedničku ve sloupci DELETE.

Page 48: MySQL Obsah

Přesun jinamTo je další oblíbená možnost: Záznam je sice z požadované tabulky smazán, ale je přemístěn do jiné tabulky,která slouží jako archiv. S vědomostmi, které jsme v tomto seriálu zatím načerpali, bychom to mohli napsatpomocí dvojice příkazů INSERT a DELETE nějak takto:

create table if not exists archiv_knih like knihy; insert into archiv_knih select * from knihy where rok_zakoupeni = 1999; delete from knihy where rok_zakoupeni = 1999;

Výhody a nevýhody? V databázi se bude skladovat mnohem více tabulkek, což je nevýhodné. Ale každýsmazaný záznam bude v archivu, což je zase velmi výhodné. Tabulka, do níž se v takovém případě přesouvá, byměla mít stejnou strukturu jako tabulka, z níž se bude mazat. Pomocí CREATE TABLE ... LIKE je velmijednoduché toho dosáhnout.

LogováníJe rovněž možné si někam (třeba do jiné tabulky) ukládat záznamy o datu, čase a uživateli, který něco smazal.Tento postup sice nevede k tomu, že by se smazaný řádek dal nějak odstranit, nicméně vede k tomu, že jealespoň možné zjistit, kdo smazání provedl.

V příštím díle našeho seriálu se podíváme na některé speciality, které provázejí příkazy pro manipulaci s daty.

Page 49: MySQL Obsah

MySQL (16) - Tipy a triky k manipulaci s daty

MySQL (16) - Něco o příkazu REPLACE. Také se dozvíte, jak lzejednoduše odstranit z tabulky duplicitní záznamy.

29.4.2005 15:00 | Petr Zajíc | přečteno 16356×

Komerční sdělení: Pořádáme Kurzy MySQL

Již byla řeč o vkládání dat, o jejich aktualizaci i o jejich odstraňování. V souvislosti s tím si dovolím nabídnoutněkolik tipů a triků, které se v této oblasti mohou hodit. Uvidíte, že MySQL může příjemně i nepříjemněpřekvapit.

Příkaz REPLACE

Příkaz REPLACE funguje podobně jako INSERT s tím, že za určitých okolností může některé řádky v tabulcepřepsat. Přepsány budou záznamy, mající stejný primární klíč nebo jedinečný index. O indexech sice ještě vseriálu řeč nebyla, měli jsme však možnost zmínit se o primárních klíčích, a to v souvislosti s automatickyčíslovanými řádky (ve skutečnosti to často je tak, že primární klíče tvoří právě automatická čísla řádků).Následuje příklad na REPLACE předpokládájící, že se rozhodneme vyměnit telefonní čísla v hypotetickémadresáři. Jako primární klíč poslouží e-mail uživatele:

create table replace_test (email varchar(50), jmeno varchar(50), telefon varchar(20),primary key (email)); insert into replace_test (email, jmeno) values('[email protected]', 'Někdo'), ('[email protected]', 'Jára Cimrman'); replace into replace_test(email, jmeno) values('[email protected]', 'Úplně někdo jiný');

Pokud to zkusíte a prohlédnete si výsledky, zjistíte, že skutečně nebyl vložen třetí záznam, ale místo toho bylpřepsán záznam druhý, protože souhlasil primární klíč - email. Upřímně řečeno, moc v lásce příkaz REPLACEnemám. A to ze tří důvodů:

1. V praxi se mi ještě nepodařilo přijít na situaci, kdy by měl reálné využití. Mám na mysli převážněwebové aplikace. Nevím, možná to souvisí s bodem č. 2 (Pokud však REPLACE používáte, šup s tím dodiskuse pod článkem).

2. Příkaz REPLACE je v SQL nestandardní. To znamená, že jej většina DBMS nemá a já si na něj nějaknemůžu zvyknout. Pochopitelně, že by podobná úloha šla řešit pomocí kombinace příkazu DELETE aINSERT.

3. Nezapomeňte, že příkaz REPLACE maže celý řádek. V našem příkladu by to třeba znamenalo, že pokudbychom přepsali řádek s telefonem a nezadali nový telefon, ten původní tam v žádném případěNEZŮSTANE. Do nezadaných polí se totiž vloží výchozí hodnota (nebo hodnota NULL).

Page 50: MySQL Obsah

Příklad je zajímavý ještě něčím - všimněte si, že jako primární klíč jsme použili e-mail. Klíčem skutečně nemusíbýt jen číslo; měla by to však být informace, která se s dostatečnou zárukou nebude moci v tabulce opakovat.Například jméno to nesplňuje (že, Josefe Nováku?), e-mail, rodné číslo nebo číslo bankovního účtu všaknejspíše ano.

Klauzule IGNORE

Bolení hlavy můžete mít z toho, když se vám povede během příkazu manipulujícího s daty způsobit v databázichybu. Mějme například následujcí tabulku:

create table seznam (id int not null auto_increment, nazev varchar(50), primary key(id));

do níž vložíme naprosto nevinný řádek:

insert into seznam (nazev) values (2, 'druhý řádek');

Co se však stane, jestliže následně spustíme tento příkaz, který se pokusí vložit tři záznamy?

insert into seznam (id, nazev) values (1, 'první řádek'), (2, 'druhý řádek'), (3, 'třetířádek');

Tento jeden příkaz by měl vložit tři položky, přičemž druhá z nich neprojde (obsahovala by duplicitu). Jak todopadne? Nejspíš vás to překvapí, ale BUDE vložen první řádek - a následně příkaz skončí chybou. Dostávámese do stavu, kdy část příkazu byla provedena, ale část ne. To je jedna z nejhorších věcí, které vás v databázovémsvětě mohou potkat. Jak z toho ven? Existují v zásadě dvě možnosti - buď všechny chyby ignorovat, nebo vpřípadě jakékoli chyby VŮBEC NIC nevkládat. My se teď budeme zabývat tou první situací. V takovémpřípadě stačí kouzelné rozšíření příkazu INSERT, a to o slovíčko IGNORE, takto:

insert ignore into seznam (id, nazev) values (1, 'první řádek'), (2, 'druhý řádek'), (3,'třetí řádek');

To povede k tomu, že druhý záznam sice rovněž nebude vložen, ALE TEN TŘETÍ ANO. Neboli, všechnychyby budou tiše ignorovány a všechno, co půjde uložit se taky uloží.

Pozn.: Ten druhý způsob - nevkládat nic - popíšu zatím pouze náznakem. Něčeho takového lze v MySQLdosáhnout použitím transakcí a tabulek používajících transakce. Tam je totiž výchozí chován to, že chybauprostřed příkazu zruší celý příkaz. A o tom ještě uslyšíme.

Kdy používat rozšíření IGNORE? Narozdíl od příkazu REPLACE mám několik tipů. Například v situaci, kdychceme rychle něco někam vložit s tím, že to bude odkontrolováno později. Nebo mám pro vás speciální trik,kterým rychle odstraníte duplicitní řádky z tabulky.

Odstranění duplicit

To je poměrně častá úloha, kterou někteří programátoři řeší dost krkolomně. Přitom to lze provést i jednoduše.Mějme následující tabulku:

create table duplicity (soucastka varchar(50), poznamka varchar(50)); insert into duplicity (soucastka) values ('matička'); insert into duplicity (soucastka) values ('matička'); insert into duplicity (soucastka) values ('šroubeček'); insert into duplicity (soucastka) values ('šroubeček');

Page 51: MySQL Obsah

insert into duplicity (soucastka) values ('podložka'); insert into duplicity (soucastka) values ('podložka'); insert into duplicity (soucastka) values ('podložka');

a chtějme z ní odstranit duplicitní záznamy. Možná tomu nebudete věřit, ale s tím, co jsme se již v seriálunaučili to je hračka:

create table bezduplicit like duplicity; alter table bezduplicit add primary key (soucastka); insert ignore bezduplicit select * from duplicity; drop table duplicity;rename table bezduplicit to duplicity;

Co se vlastně stalo? Nejdřív jsme si vytvořili kopii naší původní tabulky. Pak jsme ji trochu předefinovali, anakonec jsme se do ní pokusili vložit, co se dalo. Jelikož však nová tabulka nesmí obsahovat duplicitní údaje vesloupci soucastka, povedlo se vždy jen takové vložení, které se ještě neopakovalo. Ale, příkaz neskončí na prvníchybě, naopak pokračuje. Tento způsob vyčištění zdvojených (ztrojených ...) záznamů je jeden z nejrychlejších.Příliš jej nespomaluje ani počet duplicitních záznamů, ani to, kolikrát se jednotlivé hodnoty opakují. Výhodouje rovněž to, že z prvních vyhovoujících záznamů by byly vloženy i údaje z dalších sloupců (jako je našepoznámka). Čistě pro pořádek jsem ještě původní tabulku odstranil a tu novou přejmenoval.

V dalším díle seriálu se začneme zabývat poměrně rozsáhlou látkou - a tou bude vybírání záznamů pomocípříkazu SELECT.

Page 52: MySQL Obsah

MySQL (17) - vybíráme data

MySQL a mocný příkaz SELECT. Alespoň tedy první z několika dílů, které jej budou rozebírat.

3.5.2005 15:00 | Petr Zajíc | přečteno 16098×

Komerční sdělení: Pořádáme Kurzy MySQL

V naprosté většině aplikací, které nějak souvisejí s databázemi, je častou činností vybírání (vracení) nějakýchúdajů z tabulek. To je velmi široký pojem. Jak totiž uvidíme, všechno vybírání záznamů se děje pomocíjediného SQL příkazu - SELECT. Protože toho SELECT musí hodně umět, patří bezesporu k jednomu znejsložitěších příkazů v celé škále SQL. Ale popořadě - nejprve trocha teorie.

Teorie vybírání dat

Nesmíme zapomenout na to, že vracení dat z databáze se dosti liší od manipulace s daty. Když nějaká aplikacemanipuluje s daty (pomocí INSERT, UPDATE, DELETE nebo REPLACE), odesílá do databáze data a jakoodpověď dostává jen nějaké potvrzení. Počet ovlivněných řádků, počet varování či chyb a podobně. Jestliže alebudeme data vybírat, vrátí nám databáze nějaký objem, balík dat.

K čemu takový balík dat použijeme? V reálné aplikaci se s ním pracuje převážně tak, že se vrácená datazpracovávají řádek po řádku. Proč se to dělá? K typickým scénářům patří tyto situace:

Vrácená data jsou reprezenována pomocí nějakého GUI rozhraní - třebas komponenty jTable v jazykuJava. Někdy jako statická data, někdy umožňují aplikace zobrazená data upravovat a vracet zpět dodatabáze.

Často pracuje MySQL s weby. Tam je typické, že vrácená data jsou reprezentována v HTML stráncepomocí tabulek jazyka HTML. Pochopitelně, že k transformaci je použit nějaký skriptovací jazyk, jakoje třeba PHP.

V mnoha obchodních aplikacích bývají vybraná data podkladem pro tisk tiskových sestav, jako jsouseznamy, účetní doklady, grafy nebo čárové kódy.

Vrácená data také mohou být podrobena nějakému výpočtu a použita v jiných částech aplikace.

A teď něco terminologie. Balíku dat, vrácených z databáze se často říká recordset nebo resultset. Když se sadazáznamů zpracováví po řádcích, používá se na každý řádek termín record nebo result. Protože datové typyjazyka, v němž je aplikace napsána nemusejí přímo odpovídat datovým typům, které zná MySQL, provedeprogram (nebo ovladač připojení k databázi) občas tzv. mapování datových typů SQL na datové typyhostitelského jazyka. Každý záznam se skládá ze sloupců a mohou existovat nástroje, které jej zkonvertují naobjekty, pole a tak dále.

Page 53: MySQL Obsah

Nicméně, náš seriál se zabývá databází MySQL. Budeme tedy pracovat s výslednou množinou záznamů jen dodoby, než opustí MySQL server. Vybírání dat se děje pomocí příkazu SELECT.

Složitý SELECT

Abych vám v úvodu povídání o příkazu SELECT alespoň naznačil, co všechno umí, podívejte se na následujícísoupis:

SELECT umí vybrat všechny nebo některé sloupce z tabulky

SELECT umí omezit vybraná data na nějakou podmnožinu (filtrování dat)

Umí vrácená data seřadit

Umí se rozhodnout, zda vrátit duplicitní záznamy nebo ne

Umí vracet nejen data po řádcích, ale umí je i seskupit

Umí seskupená data filtrovat

Umí vrátit data z více než jedné tabulky pomocí procesu, kterému se říká spojování tabulek

Umí omezit počet vrácených dat na předem daný počet

Probrat to všechno bude pochopitelně práce na několik dílů seriálu, ale bezpochyby se to vyplatí. I když se tomožná nezdá, prakticky všechny uvedené věci budete totiž v reálných aplikacích používat. Ale popořadě; asinejjednodušší forma příkazu SELECT je ta, která vrátí obsah celé tabulky. Vypadá to nějak takto (a nezní tozatím až tak hrozně):

select * from [název tabulky];

Málokdy však potřebujeme vybrat všechna data z tabulky. Mnohem častější je situace, v níž nás zajímají jenněkteré její sloupce. Pak stačí tyto sloupce vyjmenovat jako seznam oddělený čárkou mezi klíčovými slovySELECT a FROM. Vypadalo by to asi takhle:

select jmeno, prijmeni, plat from zamestnanci;

Aliasy

Příkaz SELECT s vyjmenovanými sloupci může mít jeden problém - ne vždy se sloupce jmenují tak, jak by senám v aplikaci hodilo. Důvodů, proč nám názvy sloupců nemusejí vyhovovat je více:

Tabulku třeba navrhoval někdo jiný a my se musíme podřídit

Page 54: MySQL Obsah

Názvy sloupců nám nic neříkají

Názvy sloupců jsou tak krátké nebo tak dlouhé, že se s nimi nedá pracovat.

Naštěstí existuje řešení. Ve výčtu sloupců příkazu MySQL lze použít tzv. aliasy. Následuje opět ukázka:

select nesnesitelne_dlouhy_nazev_sloupce as krakty_nazev from tabulka;

Klíčové slovo AS lze vynechat, takže tohle bude taky fungovat:

select nesnesitelne_dlouhy_nazev_sloupce krakty_nazev from tabulka;

Pozn.: Ovšem pozor. Může se stát, že při vyjmenovávání sloupců někde zapomeneme čárku mezi jednotlivýminázvy. To je problém, protože pak to MySQL pochopí tak, že chceme, aby druhý název byl aliasem prvního.Nejen, že výsledná sada bude mít o sloupec méně, ale jeden sloupec se bude jinak jmenovat a příkazNESKONČÍ chybou!

Proč vyjmenovávat sloupce

Ačkoli by se mohlo zdát, že používat hvězdičku a vracet všechny sloupce tabulky je poměrně bezproblémové,měli byste se tomu pokud možno vyhýbat a vždy vyjmenovávat sloupce, které si přejete ve výsledné sadězáznamů mít. Důvodů je zase několik:

1. Je to rychlost. Tabulka může mít časem více sloupců a jestliže používáte SELECT *, může se výslednásada poměrně rychle rozrůst směrem do šířky. Pokud sloupce vyjmenujete, nestane se to.

2. Je to funkcionalita. Když máte hvězdičku, nemůžete mít aliasy.

3. Je to odolnost aplikace. Dejme tomu, že byste měli příkaz SELECT * spoléhající na to, že existujesloupec PRIJMENI. Jestliže ale někdo tento sloupec odstraní, příkaz SELECT * přesto projde, ale chybanejspíš nastane někde později v aplikaci. Pokud by SELECT požadoval přímo daný sloupec, skončí jiždotaz do databáze chybou. Obdobné to bude při přejmenování sloupce.

4. Je to snadnost úprav. Jestliže ve zdrojovém kódu aplikace máte v příkazu SELECT vyjmenoványsloupce, můžete snadno vyhledat ty části kódu, které dané sloupce požadují. Pokud byste používali zápisSELECT *, nic takového udělat nemůžete.

V dalším díle seriálu se podíváme na to, jak se v souvislosti s příkazem SELECT používá klauzule WHERE.

Page 55: MySQL Obsah

MySQL (18) - Filtrujeme data

"Zrcadlo, zrcadlo, kdo je na světě nejkrásnější"? Aneb, jak si vybrat tu pravou (množinu dat, pochopitelně).

6.5.2005 09:00 | Petr Zajíc | přečteno 17506×

Komerční sdělení: Pořádáme Kurzy MySQL

Jestliže příkaz SELECT umí vybrat z tabulky jen určitý počet sloupců, asi doufáte, že umí vybrat i určitý početřádků. A máte pravdu. Přesně k tomu slouží v SQL klauzule WHERE příkazu SELECT. Dnes uvidíme jak sepoužívá a jaké s tím může být spojeno úskalí.

Klauzule WHERE

O tomto klíčovém slově jsme již mluvili v souvislosti s úpravou dat a mazáním, takže jej známe. WHERE všaknemusí sloužit pouze k omezení počtu měněných záznamů, může rovněž filtrovat záznamy vracené. Na prvnípohled tak asi pochopíte význam následujících příkazů:

select * from knihy; select * from knihy where cena <=500;

První z nich by vrátil všechny knihy, ten druhý jen takové, které si můžeme pořídit za pětistovku. V klauzuliWHERE se velmi často porovnává hodnota nějakého sloupce s konstantou, jak jsme právě viděli.

Ovšem WHERE může být daleko složitější. Častá situace je ta, kdy se pokusíme filtrovat pomocí více kritériínajednou. V takovém případě používá MySQL arzenál logických výrazů zahrnujících operátory OR, AND,NOT a závorky. Myslím, že pokud programujete, budete asi moc dobře vědět, o čem mluvím. Následuje několikpříkladů na složitější podmínky WHERE.

select * from knihy where cena <=500 and obor='počítače'; select odberatel from faktura where cena > 2000 or prodleni > 10; select id, nazev from soucastky where not (vyprodano=1);

Vidíte, že kód SQL je v tomto případě dostatečně intuitivní a rovněž se velmi dobře čte.

Tip: V případě používání závorek buďte pragmatičtí. Pokud si nejste jisti prioritou operátorů, závorkujte.MySQL totiž stejně před provedením dotazu nadbytečné závorky odstraní a vy budete mít klidnou hlavu. Není tosice příliš profesionální rada, ale běžně to tak dělá spousta lidí.

WHERE a hodnoty NULL

Pomocí klauzule WHERE se v praxi často dotazujeme rovněž na sloupce, které mají hodnotu NULL. Protoževšak hodnota NULL je neznámá, nemůžeme ji porovnávat pomocí operátorů '<', '>' a '='. Následující dotaz jetedy principielně nesmyslný:

select * from faktura where zaplaceno_dne > null;

Page 56: MySQL Obsah

a to proto, že porovnáváme sloupec a neznámou hodnotu. Nicméně, MySQL má výraz IS NULL, s nímž to jižtak nesmyslné nebude.

select * from faktura where zaplaceno_dne is null;

Pozn.: Ještě jednou - NULL je neznámá nebo nezadaná hodnota. Dotaz se tedy ptá na faktury, u nichž je datumzaplacení neznámé nebo nezadané. Asi tušíte, že v českých podmínkách bude tento dotaz součástí většinyúčetních aplikací ;-)))

V souvislosti s WHERE a NULL bych si dovolil rozebrat ještě jeden oblíbený problém. Člověku by se mohlozdát, že dvojice dotazů

select * from faktura where zaplaceno_dne > '20050501'; select * from faktura where zaplaceno_dne <= '20050501';

musí dohromady vrátit všechna data z tabulky. Odpověď je, že to tak může být a nemusí. Pokud sloupeczaplaceno_dne NESMÍ obsahovat hodnoty NULL, je vše v pořádku. Pokud však hodnoty NULL obsahovat smí,ani jeden dotaz nevrátí řádky s nevyplněným datem zaplacení. Na to by se mělo pamatovat a buď upravit druhýdotaz ve smyslu

select * from faktura where zaplaceno_dne <= '20050501' or zaplaceno_dne is null;

nebo alespoň počítat s tím, že nezadané hodnoty mohou výběr zkomplikovat. Pokud si to budete chtít nějakzapamatovat, porovnání dvou hodnot může dopadnout ČTYŘMI (!) způsoby:

1. Obě jsou si rovny

2. První je menší než druhá

3. První je větší než druhá

4. Jedna či obě jsou NULL (neznámé)

Pozn. Než se s tím sžijete, zažijete spoustu legrace s laděním dotazů. Věřte mi, znám to.

WHERE, LIKE, BETWEEN a IN

Porovnávat hodnoty sloupců s konstantami pomocí porovnávacích operátorů a logiky není to jediné, co se vklauzuli where dá dělat. Časté je použití operátoru BETWEEN, zejména u datumů. Ačkoli by se dal přepsatpomocí znaků nerovnosti, BETWEEN se mnohem lépe čte:

select * from knihy where porizeno between '20050401' and '20050430';

Je dobré si uvědomit, že operátor BETWEEN ... AND vrátí logickou jedničku, pokud je porovnávaná hodnotauvnitř intervalu, a to včetně hraničních hodnot.

Pozn.: Rovněž je dobré si uvědomit, že použití BETWEEN ... AND není omezeno na datumy. Lze jej použít třebapro hodnoty typu integer.

Page 57: MySQL Obsah

Operátor LIKE se hodí na porovnávání řetězců. Funguje se dvěma zástupnými znaky, kde "%" (procento)zastupuje nula a více znaků, kdežto "_" (podtržítko) reprezentuje právě jeden znak. Procento se používá častěji.Všechny lidi, jejichž příjmení začíná na 'D' byste tedy z adresáře vybrali následujícím dotazem:

select * from adresar where prijmeni like 'D%';

Pozn.: Mnohem mocnější je vyhledávání pomocí regulárních výrazů, což MySQL podporuje. Bude o tom řečněkdy příště. Hodí se rovněž poznamenat, že operátor LIKE je v MySQL velice slušně optimalizován a je tudíždost rychlý.

Častá úloha je vybrat z tabulky záznamy, kde vybíraná hodnota je prvkem nějakého seznamu. Například lidi zPrahy, Brna nebo Ostravy můžete s vědomostmi, které jsme zatím načerpali, vybrat takto:

select * from lidi where mesto = 'Praha' or mesto = 'Brno' or mesto = 'Ostrava';

Tohle bude fungovat, ale je to trochu neohrabané. Zejména, pokud by hodnot seznamu bylo více. MySQL toumí zapsat jinak:

select * from lidi where mesto in ('Praha', 'Brno', 'Ostrava');

Takto sestavený seznam se mnohem lépe čte a mnohem lépe se rovněž udržuje. Ještě dodejme, že prvkyseznamu nemusejí být jen staticky zadány, že to může být výsledek dotazu SELECT. O tom se však ještě budemluvit později.

Page 58: MySQL Obsah

MySQL (19) - Řadíme data

Kromě vybírání dat je rovněž potřebujeme nějak rozumně řadit (a to nejenom podle abecedy). V dnešním díleseriálu o MySQL se podíváme, jak na to.

10.5.2005 15:00 | Petr Zajíc | přečteno 17214×

Komerční sdělení: Pořádáme Kurzy MySQL

Data mohou být do databáze vkládána v nahodilém pořadí. Často je však potřebujeme prezentovat v nějakésetříděné formě. Je jasné, že MySQL na to musí mít nějaké nástroje. A my je dnes prozkoumáme.

Klauzule ORDER BY

Příkaz SELECT může být následován klauzulí ORDER BY, která zajistí seřazení výsledné množiny záznamůpodle nějakého výrazu. Tím "nějakým výrazem" je nejčastěji hodnota polí ve sloupci, ale jak ještě uvidíme,nemusí to tak být vždy. Řadit můžeme nejen podle čísel, ale i podle datumů (databáze si poradí s lahůdkamitypu přechodných roků), a samozřejmě podle řetězců.

Tip.: Řetězce se porovnávají způsobem, který je definován při tvorbě tabulky pomocí slova collate. Jestližežádné řazení nedefinujete, bývá pro řetězce použito výchozí řazení databáze, případně serveru. Je to častýmnámětem diskusí a ještě o tom bude řeč.

Jestliže je požadováno jak filtrování, tak i řazení, musí být klauzule WHERE uvedena před klauzulí ORDERBY. Následuje několik příkladů:

select * from faktury order by datum; select * from knihy where cena >= 500 order by nazev;

Další příklady ukazují pro jistotu i nesprávnou syntaxi:

select * from faktury orderby datum; select * from knihy order by nazev where cena >= 500;

V prvním případě jsem vynechal mezeru mezi "order" a "by". Ta mezera tam skutečně musí být. To se vámmůže v zápalu psaní stát docela často. Ve druhém případě jsem umístil řazení před filtrování (to se vám mocčasto stávat nebude; příkaz SELECT je totiž přes svoji složitost poměrně intuitivní).

Řazení podle více sloupců, vzestupné a sestupné

Často budete potřebovat řadit ne podle jednoho sloupce, ale podle více údajů najednou. Například budete chtítfaktury seřadit podle data vydání a faktury se stejným datem vystavení ještě podle ceny. Není to žádný problém,když si uvědomíte, že ORDER BY může přijímat seznam výrazů. Řadí pak zleva doprava. Náš příklad bychomtedy mohli napsat asi takhle:

select * from faktury order by datum, cena;

Řazení podle více sloupců je samozřejmě časově náročnější než řazení podle jednoho sloupce; v praxi se to všakpoužívá docela často. Všechna řazení, o nichž jsme zatím mluvili, byla vzestupná. To znamená, že čísla se řadila

Page 59: MySQL Obsah

od menších k větším, události v čase od starších k novějším a řetězce od A do Z. Často ale můžeme potřebovatopačnou věc. Tak třeba bezpečnostní protokol uložený v databázi můžeme chtít seřadit od nejnovějších událostíke starším. Není to problém. Stačí uvést směr řazení pomocí klíčového slova DESC (descending = sestupně):

select * from protokol order by datum desc;

Existuje i klauzule ASC (ascending = vzestupně); jestliže se nepoužije, program ji dosadí automaticky. Přiřazení podle více sloupců lze samozřejmě kombinovat, takže následující zápis je správný a udělá to, co má:

select jmeno, prijmeni, datum_nastupu from zamestnanci order by datum nastupu desc, prijmeni asc, jmeno;

Tipy a triky s řazením záznamů

Uvádění slupců čísly

Při práci s databází se snadno můžeme dostat do situace, kdy potřebujeme řadit podle určitého sloupce vevýsledné sadě záznamů, přičemž neznáme předem jeho název. Například můžete chtít napsat obecnouproceduru, která seřadí dodanou sadu podle prvního sloupce. MySQL to umí - stačí místo názvu sloupce vklauzuli ORDER BY uvést jeho pořadové číslo. Takže například následující zápisy jsou rovnocenné:

select id, cislo, datum from smlouvy order by datum; select id, cislo, datum from smlouvy order by 3;

Ale pozor - v kombinaci s "hvězdičkovým" příkazem SELECT to může být poměrně ošemetné. Chcete li řaditnapříklad podle třetího sloupce a zároveň nemáte ani ponětí, v jakém pořadí databáze vrátí sloupce,pravděpodobně seřadíte data jinak, než jste zamýšleli.

Výjimky v řazení

Následující věc nejlépe vysvětlím na příkladu: Dejme tomu, že budete chtít seřadit jednotlivé státy na světě (atřeba je poskytnout webové aplikaci jako podklady pro formulář):

create table staty(nazev varchar (30)); insert into staty values ('Andorra'); ... insert into staty values ('Česká republika'); ... insert into staty values ('Slovenská republika'); ... insert into staty values ('Zambie');

Asi na to půjdete takto:

select nazev from staty order by nazev;

Jenomže časem za vámi přijde šéf a bude chtít, abyste na začátek seznamu dali ČR, pak SR a zbytek už podleabecedy. Je to jednoduché, pokud si uvědomíme, že součástí klauzule ORDER BY může být i výraz:

SELECT * FROM staty order by (nazev='Česká republika') DESC, (nazev='Slovenská republika') DESC, nazev

Nejprve budeme řadit podle logického výrazu "je to Česká republika?", pak totéž pro Slovensko a zbytek podleabecedy. Protože však chceme, aby ČR a SR byly nahoře a protože logická jednička se řadí POD logickou nulu,musíme v prvních dvou případech řadit sestupně. Celý výraz by se pochopitelně dal přepsat pomocí predikátuIN.

Page 60: MySQL Obsah

Řazení v cílové aplikaci

Až na malé výjimky byste se měli bránit řazení v cílových aplikacích a měli byste nechat řadit MySQL.Důvodem je fakt, že řazení data v databázích prošlo dlouhým vývojem a je silně optimalizováno. Bude tak vnaprosté většině případů mnohem rychlejší než cokoli, co byste snad vymysleli sami. Pokud je databáze najiném (a typicky silnějším) stroji než aplikace, je to o důvod navíc nechat všechnu "špinavou práci" s řazením naMySQL.

Page 61: MySQL Obsah

MySQL (20) - spojení více tabulek

Málokdy potřebujeme data jen z jedné tabulky. Dnes se v seriálu o MySQL dozvíme něco o teorii spojování aukážeme si na jednoduchý příklad.

13.5.2005 15:00 | Petr Zajíc | přečteno 16536×

Komerční sdělení: Pořádáme Kurzy MySQL

V díle seriálu o příkazu SELECT jsem uvedl, že tento příkaz umí vrátit data z více než jedné tabulky pomocíprocesu, kterému se říká spojování tabulek. To je přesně to, o čem bude dnes řeč. Podíváme se na teoriispojování tabulek, a rovněž na jeden způsob, jakým se v MySQL spojované tabulky zapisují.

Teorie

Ačkoli jsme v seriálu zatím vždy vystačili s příklady s jednou tabulkou, v praxi je to málokdy tak jednoduché.Zvažme napřílad situaci, kdy budete chtít navrhnout databázi pro evidenci knih v knihovně. Můžete samozřejmězačít tabulkou popisující knihy:

create table knihy (id int auto_increment, nazev varchar (50), primary key (id));

Jestliže bude v knihovně více druhů knih (například detektivky a odborná literatura), zjistíte třeba časem, že kekaždé knize bude užitečné evidovat druh. Můžete tedy tabulku knih rozšířit o sloupec DRUH, například takto:

alter table knihy add column druh varchar (20);

Nebo, s použitím výčtových typů možná lepší způsob:

alter table knihy add druh enum ('detektivky', 'odborná literatura');

Ačkoli principelně mohou být oba způsoby správné, mají rovněž tyto závažné nedostatky:

První způsob vůbec nevymezuje, jaký druh knih můžeme zadat

Druhý způsob sice omezuje možnosti, které můžeme do sloupce zadat na předem danou množinuhodnot, ale neřeší jiné problémy. Budeme-li chtít rozšířit počet druhů, musíme provést pokaždé příkazALTER TABLE. Navíc, k "druhu" evidované literatury už nemůžeme zadat žádné další doplňující údaje.

Například by naše virtuální knihovna mohla chtít stanovit, že každý druh půjčovaných knih bude mít maximálnídobu výpůjčky. Třeba detektivky bychom mohli postrádat měsíc, kdežto odbornou literaturu bychom chtělipůjčovat maximálně na týden. Jak na to jít? Pokud uděláme následující zásah:

alter table knihy add max_doba_vypujcky tinyint;

zjistíme, že u každé knihy se bude opakovat jak druh, do nějž kniha spadá, tak i maximální doba výpůjčky prodaný druh. Není to vůbec dobře, a to z několika důvodů:

1. Tabulka neúměrně narůstá

Page 62: MySQL Obsah

2. Skladují se duplicitní údaje

3. Když budeme chtít detektivky půjčovat ne na měsíc, ale na šest neděl, musíme kvůli tomu zaktualizovatvšechny záznamy v tabulce knih, jejichž druh je detektivka.

Asi tušíte, že se to v praxi opravdu tak nedělá. Je to pravda, obyčejně se vytvoří dvě tabulky - jedna pro knihy adalší pro druhy knih - a pak se spojí. Tabulky se vytvoří běžným způsobem s tím, že tabulce druhů dáme rovněžautomaticky číslované pole (za chvíli uvidíme proč). V tabulce knih bude pole druh, ale nebude to text, bude tocelé číslo odkazující na odpovídající řádek v tabulce druhů knih. Celé to může vypadat nějak takto:

create table knihy (id int auto_increment, nazev varchar (50), druh id, primary key(id)); create table druhy (id int auto_increment, nazev varchar (20), max_doba_vypujcky tinyint,primary key (id));

Představme si teď následující data v obou tabulkách:

insert into druhy (nazev, max_doba_vypujcky) ; values ('detektivky',30),('odborná literatura',7); insert into knihy (nazev, druh) values ('Smrt na Nilu',1), ('Kdo chce zabít Zajíce?',1), ('Sto způsobů, jak shodit Windows',2),('Linux dokumentační projekt',2);

Vidíme, že tabulka druhů získala dva řádky (s ID č. 1 jsou to detektivky a s ID č. 2 pak odborná literatura) atabulka knih 4 řádky (2 detektivky a 2 svazky odborné literatury). Jak to teď ale spojit?

Nejjednodušší spojení

Nejjednodušší způsob spojení je vyjmenovat v příkazu SELECT obě tabulky. Pokud chcete, můžete si jakorozcvičku zkusit spustit následující příkaz (je to syntakticky správně):

SELECT * FROM knihy, druhy;

Vyjmenováním více než jedné tabulky v příkazu SELECT způsobíme, že MySQL vrátí sadu, v níž budouvšechny kombinace řádků z obou (případně ze všech) tabulek. Ta nám většinou bude k ničemu, protože nászajímají pouze řádky související. Jak ale víme, lze výslednou množinu omezit pomocí klauzule WHERE.Mnohem užitečnější tedy bude omezit data na taková, kde druh z tabulky knih souvisí s druhem v tabulcedruhů, takto:

select * from knihy, druhy where knihy.druh = druhy.id;

A tomu se v databázové hantýrce právě říká spojení. Pokud si to zkusíte, zjistíte, že dotaz vrátil sice data z oboutabulek, ale jen taková, která spolu opravdu souhlasí. Takto tedy můžeme jednoduše vracet data z více tabulek.K tomu si dovolím ještě několik postřehů:

1. Použití SELECT * vrátí všechny sloupce ze všech tabulek. Je dobré na to myslet, většinou je taková sadazbytečně široká.

2. Je možné vrátit data z jedné tabulky pomocí syntaxe SELECT [název tabulky].* a přesto využít spojení.V praxi by se to dalo udělat třeba v případě, kdy byste si přáli získat seznam knih, které mají zadán druh.

Page 63: MySQL Obsah

3. V případě podobných konstrukcí se dá předpokládat, že zařazení všech sloupců do výsledného dotazubude zbytečné. V našem případě například sloupec knihy.druh obsahuje stejné údaje jako druhy.id (abyne, vždyť to byla podmínka). Minimálně jeden z těchto sloupců lze ve výsledné sadě vynechat, možná ioba.

4. Při spojování tabulek se můžeme dostat do situace, kdy ve výsledné množině budeme mít dva či vícesloupců se stejným názvem. Například my máme dva sloupce s názvem id a dva sloupce s názvemnazev. Tomu byste se měli pokud možno vyhýbat. Ačkoli sestavení takové sady záznamů není žádnýproblém pro MySQL, může mít se zpracováním takových dat problém aplikace, která je požaduje. Tétomezní situaci se vyhnete vynecháním duplicitnách sloupců nebo použitím aliasů sloupců.

Výše uvedené zásady bychom mohli demostrovat přepsaným dotazem. Lepší verze by tedy byla:

select knihy.id, knihy.nazev, druhy.nazev as druh, max_doba_vypujcky from knihy, druhy where knihy.druh = druhy.id;

Všimněte si, že sloupec nazev z tabulky druhů jsem nazval druh a že jsem počet vrácených sloupců omezil.Většina správně napsaných aplikací nebude mít problém s takovou sadou záznamů.

Příště uvidíme, že MySQL, stejně jako řada dalších databází má i jiný, častěji používaný a výkonnější způsobzápisu spojení. Je to důležité téma, takže se máte na co těšit.

Page 64: MySQL Obsah

MySQL (21) - klauzule JOIN

Dnes si ukážeme, jak lze efektivně v MySQL spojit tabulky.

20.5.2005 06:00 | Petr Zajíc | přečteno 21672×

Komerční sdělení: Pořádáme Kurzy MySQL

V předchozím díle seriálu jsme si ukázali, jak lze jednoduše spojit tabulky pomocí jejich vyjmenování v příkazuSELECT a šikovně napsané klauzule WHERE. Není to však jediný způsob, jak něco takového provést, a není toani moc často používané. Dnes si ukážeme, jak to celé dělat efektivněji. Nejprve ovšem zase trocha teorie.

Typy spojení

Vnitřní spojení

Situaci, kterou jsme popisovali v minulém díle se v databázovém světě říká vnitřní spojení (anglicky inner join).Připomeňme si, že šlo o úlohu, kde se měly vybrat knihy a jejich druhy (žánry) v aplikaci představující fiktivníevidenci knihovny:

select knihy.id, knihy.nazev, druhy.nazev as druh, max_doba_vypujcky from knihy, druhy where knihy.druh = druhy.id;

Toto spojení je nazýváno vnitřní, protože jsou zobrazena pouze data, která si v obou tabulkách přesněodpovídají. Jinými slovy, knihy bez uvedeného žánru se ve výsledné sadě záznamů nikdy neobjeví, protožepodmínka where to zkrátka neumožňuje. Vnitřní spojení se dá jinak (a používá se to mnohem častěji) přepsat vMySQL následujícícm způsobem:

select knihy.id, knihy.nazev, druhy.nazev as druh, max_doba_vypujcky from knihy inner join druhy on knihy.druh = druhy.id;

Pozn.: Klíčové slovo inner se smí vynechat, takže se často setkáte se zápisem from [název tabuky] join [názevtabulky].

Jestliže by dotaz vyžadoval jak spojení tabulek, tak i nějakou omezující podmínku (případně řazení), klauzuleFROM ... INNER bude v dotazu jako první, potom následuje podmínka WHERE a nakonec řazení. To bychomsi měli jistě ukázat na nějakém příkladu:

select knihy.id, knihy.nazev, druhy.nazev as druh, max_doba_vypujcky from knihy inner join druhy on knihy.druh = druhy.id where druhy.nazev='detektivky' order by knihy.nazev;

Vnitřní spojení se používají všude tam, kde potřebujeme mít data omezená na záznamy totožné v oboutabulkách. Co však, jestliže by v našem příkladu nějaká kniha neměla zadaný žánr, a my bychom ji přesto chtělive výsledné sadě záznamů mít? Zkusme třeba do naší knihovničky vložit následující data:

insert into knihy (nazev) values ('kniha bez žánru');

Page 65: MySQL Obsah

Pro zopakování - tato kniha má zadán pouze název, takže MySQL do dalších polí v tomto záznamu doplnívýchozí hodnoty. V tabulce knih existují ještě další dvě pole - "id" a "druh". Do pole "id" doplní databázovýstroj nejbližší vyšší číslo (nejspíš pětku, protože zatím jsme měli 4 knihy), a do pole "druh" dá hodnotu NULL,protože jsme toto pole neurčili a hodnoty NULL v tomto sloupci smí být.

V takovém případě bychom museli při zobrazování sáhnout po trochu jiné konstrukci.

Vnější spojení

Nejprve si můžete zkusit použít trik z minulého dílu; nakonec ale zjistíte, že na úlohy tohoto typu to zkrátkanestačí. Například následující příkaz nebude fungovat tak, jak bychom potřebovali:

select knihy.id, knihy.nazev, druhy.nazev as druh, max_doba_vypujcky from knihy, druhy where knihy.druh = druhy.id or knihy.druh is null;

Abychom zahrnuli všechny knihy s jejich žánry a zároveň knihy, které žádný žánr nemají, k tomu máme vMySQL klauzuli LEFT JOIN (případně RIGHT JOIN). Napsat by se to dalo asi takto:

select knihy.id, knihy.nazev, druhy.nazev as druh, max_doba_vypujcky from knihy left join druhy on knihy.druh = druhy.id;

Všimněte si, že od původního příkazu s JOIN se tento liší pouze uvedením slova LEFT. Toto kouzelné slovíčkomá za následek, že se zahrnou všechna data z tabulky knih, a z tabulky druhů (žánrů) se zahrnou pouzesouvisející data. Ve sloupcích, v nichž "párová" data v související tabulce nejsou budou vloženy hodnotyNULL.

Vnější spojení mohou být "levá" nebo "pravá". Funkčně se ničím neliší. Mohli bychom tedy náš dotaz přepsatdo této podoby (a vrátil by totéž):

select knihy.id, knihy.nazev, druhy.nazev as druh, max_doba_vypujcky from druhy right join knihy on knihy.druh = druhy.id;

De facto bychom si vystačili buď jen s levým, nebo jen s pravým spojením. Ale nezapomeňme, že pomocíklauzule JOIN lze spojit více než dvě tabulky. Pak může být možnost použít "levé" nebo "pravé" spojení knezaplacení, neb můžeme tabulky vyjmenovávat v pořadí, v jakém se nám to hodí.

Vícenásobná spojení

Jak již jsme uvedli, lze spojit více než dvě tabulky. Přitom není nutné, aby byly všechny tabulky spojeny pomocívnitřního (nebo vnějšího spojení). Je například možné spojit dvě tabulky pomocí vnitřního spojení a třetípřipojit pomocí spojení vnějšího. Mohlo by to vypadat nějak takto:

select hlavicka_faktury.*, polozky_faktury.*, zakaznik.nazev from hlavicky_faktury inner join polozky_faktury on hlavicka_fatkury.id =polozky_faktury.hlavicka left join zakaznik on faktura.zakaznik = zakaznik.id;

V minulosti toho bylo hodně napsáno o tom, v jakém pořadí se mají jednotlivé spojované tabulky v příkazuuvádět. V dobách databázového pravěku totiž vykonával stroj spojení tupě zleva doprava. V poslední době je tojedno - DBMS mají takzvané optimizátory, které v naprosté většině případů dokáží spolehlivě odhadnout, vjakém pořadí tabulky spojit, aby byl výsledek poskytnut volající aplikaci co možná nejrychleji.

Význam spojeníUvědomme si, že relační databáze jsou na spojování šikovně navržených tabulek postaveny. Je tedy nesmírnědůležité dobře si osvojit syntaxi spojení a pokud možno se naučit psát příslušný kód z hlavy. Vizuální nástroje,

Page 66: MySQL Obsah

které umožňují modelovat spojení pomocí klikání myší bez znalostí odpovídajícího kódu jsou sice poměrněproduktivní, ale často si takový databázový programátor zvykne a zpohodlní. Má-li potom odladit nějaký dotazBEZ grafických nástrojů, je to problém.

O dalších věcech souvisejících se spojeními budeme mluvit v příštím díle našeho seriálu.

MySQL (22) - tipy a triky ke spojování tabulek

Netradiční zápisy spojení a úvaha nad rychlostí spojování tabulek - to je téma dnešního dílu seriálu o MySQL.

27.5.2005 09:00 | Petr Zajíc | přečteno 14912×

Komerční sdělení: Pořádáme Kurzy MySQL

Dnes si rozebereme některé věci, které se týkají spojování tabulek a které byste měli znát. Nebo takové, o nichžbyste měli alespoň tušit, že existují. Spojování tabulek je totiž tak v databázovém světě tak důležité, že se bezněj v naprosté většině aplikací zkrátka neobejdete.

Exotická spojení

Na těchto typech spojení je exotické to, že je většina vývojářů nebo projektů téměř nepoužívají. Na jednu stranuse nepoužívají proto, že k tomu není důvod, na druhou stranu je dobré o nich vědět. Takže, která spojení tojsou?

CROSS JOIN

CROSS JOIN spojí tabulky tak, že výsledkem je jejich kartézský součin. To znamená, že pro každý řádek zjedné tabulky je ve výsledné sadě záznamů vytvořena kombinace se všemi řádky z tabulky druhé. Má-li tedyprvní tabulka 5 řádků a druhá 2 řadky, bude ve výsledné množině řádků deset. CROSS JOIN tabulky knih adruhů bychom mohli zapsat takto:

select * from knihy cross join druhy;

Třebaže se to nezdá, s tímto příkazem jsme se již v seriálu setkali, a to v jiné formě v díle o základechspojování. On je totiž předchozí příklad ekvivalentní zápisu

select * from knihy, druhy;

a abychom byli politicky korektní, je rovněž významem roven zápisu

select * from knihy join druhy;

Sady vrácené pomocí CROSS JOIN bývají málokdy tak smysluplné, aby je šlo v reálných aplikacích nějakpoužít. Typickou chybou pro začátečníky v oblasti spojování tabulek je vytvoření příkazu CROSS JOIN anásledné "vyzobávání" potřebných záznamů pomocí klauzule WHERE nebo pomocí procházení výsledné sadyzáznamů. V praxi bývá většinou na místě použití INNER JOIN nebo LEFT JOIN.

Jako obecná zásada tedy může sloužit tvrzení, že používáte-li CROSS JOIN, pak nejspíš máte pomalédatabázové aplikace, špatný návrh struktury databáze nebo obojí.

Page 67: MySQL Obsah

NATURAL JOIN

Takže, nejprve definice: NATURAL JOIN (a NATURAL LEFT JOIN) je roven takovému příkazu JOIN (aLEFT JOIN), kde jsou použity všechny sloupce z obou tabulek, které se stejně jmenují. Tahle věcička patří ktěm, které se rozhodnete milovat nebo nenávidě, ale nic mezi tím. NATURAL JOIN se pochopitelně dá vždypřepsat jako odpovídající JOIN. Uveďme ale příklad, jak by takové spojení mohlo vypadat:

select * from knihy natural join druhy;

Pokud si to zkoušíte, zjistíte, že tento dotaz nevrátí pro naše tabulky žádná data. Proč? Podívejte se na strukturutabulek! Která pole se jmenují stejně? ID a název - a neexistuje záznam, v němž by byly v našem příkladushodné. Přiznám se, že patřím k těm, kdo NATURAL JOIN moc v lásce nemají. Pokud byste chtěli vědět proč,tady jsou moje důvody:

Z pohledu na zápis spojení pomocí NATURAL JOIN nepoznám, co dělá

Již fungující příkaz mohu elegantně zbořit tím, že do tabulky někdy v budoucnosti přidám nějaká pole(které bude shodou okolností existovat i v druhé tabulce)

Nevyhovuje to mým konvencím pro tvorbu tabulek. Například všechny primární klíče pojmenovávámid, a tím se vlastně ochuzuji o možnost NATURAL JOIN použít

Pozn.: Ten poslední bod je samozřejmě vyvratitelný. Nic by mi nebránilo nazvat si v tabulce druhů sloupec sprimárním klíčem třebas druh_id. Kdybych pak v tabulce knih rovněž odkazující sloupec nazval druh_id,NATURAL JOIN by se dal použít a určitá koncepce pojmenování tabulek by taky zůstala. Nicméně, zvyk ježelezná košile.

Uvědomme si, že NATURAL JOIN použije pro spojení všechna shodná pole. O něco elegantnější je následujícíkonstrukce.

JOIN ... USING

Toto rozšíření funguje tak, že sice rovněž spojuje pomocí shodně nazvaných polí v obou tabulkách, aleumožňuje nám tato pole vyjmenovat. Kdybychom v našem příkladu měli skutečně pole zastupující žánr knihynazváno druh_id, mohli bychom příkaz

select * from knihy join druhy on knihy.druh_id = druhy.druh_id;

přepsat použitím JOIN ... USING na

select * from knihy join druhy using (druh_id);

Jak vidíte, tím padají všechny moje argumenty ohledně nepoužitelnosti NATURAL JOIN, protože tento zápisspojení je celkem přehledný a dá se použít. Nicméně, stále to vyžaduje mít odpovídající pole ve spojovanýchtabulkách nazvána stejně. Pochopitelně, že lze rovněž použít zápis LEFT JOIN ... USING a RIGHT JOIN ...USING.

Rychlost spojení

Page 68: MySQL Obsah

Zaznamenal jsem některé dotazy v diskusi nebo e-mailech, které souvisely s výkonem spojení. Pokusím se teďna ně odpovědět.

Je rozdíl mezi LEFT JOIN a RIGHT JOIN v rychlosti?

Ne, manuál k mysql na stránce o optimalizaci spojení tvrdí, že "RIGHT JOIN je imlementováno analogicky kLEFT JOIN s tím, že role obou tabulek jsou prohozeny". Nemusíte se tedy bát. Skutečně není nutné vyměňovatv zápisu spojení tabulky jen proto, abychom dosáhli zvýšení rychlosti.

Musím spojit více tabulek. Nebude to pomalé?

V naprosté většině případů bude spojení více tabulek stejně to nejrychlejší možné řešení. Ostatní možnosti(například, uložení jednoho spojení do dočasné tabulky a její použití při dalším spojení) budou až řádověpomalejší.

Čeho bych se měl vyvarovat při spojování tabulek? Co naopak použít?

První věcí, kterou je třeba zmínit jsou indexy. V seriálu o nich bude teprve řeč, takže vydržte. Měli byste zvážitpoužití indexu pro spojení, protože toto spojení pak může být mnohem rychlejší. Druhá věc - a tu můžeme uvésthned - měli byste se pokud možno vyhýbat použití čehokoli jiného kromě názvu sloupců v definici spojení.Například následující spojení je sice syntakticky správné a MySQL jej provede.

select * from zamestnanec join pozice on zamestnanec.pozice = pozice.id+3;

Protože však je součástí spojovací podmínky výraz (pozice.id+3), nemůže nebohá databáze provést žádnouoptimalizaci a bude zřejmě při sestavování spojení muset procházet tabulkou "pozice".

Page 69: MySQL Obsah

MySQL (23) - relace 1:N a N:N

MySQL (23) - Co znamenají zkratky 1:N a N:N? Jak souvisejí sepsaním spojení a proč by nestačilo mít jen jeden typ spojení? Tovšechno se dozvíte v dnešním díle seriálu o MySQL.

3.6.2005 07:00 | Petr Zajíc | přečteno 13282×

Komerční sdělení: Pořádáme Kurzy MySQL

Zatím jsme v seriálu rozebírali taková spojení, při nichž šlo o dvě tabulky. Napsal jsem ale rovněž, žeprincipielně lze spojit i více tabulek. Ačkoli to nepředstavuje žádný syntaktický zádrhel, pro začátečníky voblasti databází bývá někdy problém pochopit logiku takových spojení. Proto se jim dnes budeme trochuvěnovat.

Spojení 1:N

Toto spojení jsme vlastně již probrali. Tajemnou zkratkou "1:N" se v databázovém světě rozumí spojení, kdejeden záznam v "hlavní" tabulce obsahuje teoreticky libovolný počet odpovídajících záznamů v "podřízené"tabulce. (Teoreticky libovolný počet zahrnuje rovněž nulu). Připomeňme také, že k vyjádření takového spojeníse používá:

klauzule LEFT JOIN (nebo RIGHT JOIN) v případě, kdy chceme zobrazit všechny řádky z "hlavní"tabulky bez ohledu na to, zda existují nějaké řádky v "podřízené" tabulce

klauzule INNER JOIN v případě, kdy chceme zobrazit pouze řádky v "hlavní" tabulce, které mají nějakésouvisející záznamy v tabulce "podřízené"

V praxi existuje celá řada situací, na níž lze toto schéma uplatnit. Pro osvěžení si některá připomeňme:

Jedna faktura může mít celou řadu položek ("hlavní" tabulka obsahuje záhlaví faktury, "podřízená"obsahuje položky)

Jedna síť může obsahovat řadu počítačů ("hlavní" tabulka obsahuje seznam sítí, "podřízená" obsahujeseznam počítačů v těchto sítích)

Jeden zaměstnanec se může starat o řadu zákazníků ("hlavní" tabulka obsahuje seznam zaměstnanců,"podřízená" obsahuje seznam zákazníků)

Celá situace se dá poměrně snadno znázornit graficky. Na obrázku níže můžete vidět, jak by vyladalo spojenímezi tabulkou faktur a jejich položek.

Page 70: MySQL Obsah

Kdybychom něco takového chtěli zapsat pomocí SQL, nebude to problém:

select * from faktury join polozky on faktury.id = polozky.faktura;

Spojení N:N

Co je špatného na modelu 1:N, že potřebujeme vymyšlet něco dalšího? Na modelu samotném není špatného nic.Problém spočívá v tom, že pro reálný svět tento model zkrátka nepostačuje. Vraťme se na chvíli k našíimaginární databázové aplikaci, která má mapovat provoz v knihovně. Jak byste zmapovali proces půjčováníknih? Je pravda, že jeden čtenář si může půjčit více knih, ALE zároveň je pravda, že více čtenářů si může půjčitstejnou knihu (dejme tomu v různém období). Vztah mezi knihami a čtenáři tedy není 1:N, ale N:N.

Realizovat něco takového pomocí dvou tabulek v reálné databázi většinou nejde. Takový vztah se obyčejněprogramuje pomocí další, třetí tabulky, která je spojena s oběma původními tabulkami. S každou tabulkou mávztah 1:N a celé to dokáže simulovat spojení N:N. Protože se to asi dá jen těžko představit, posloužím zasemalým obrázkem:

Je dobré si "prostřední" tabulku nějak smysluplně nazvat, i když to někdy nebude tak úplně jednoduché. Mybychom si ji mohli nazvat například "výpůjčky". Z toho je krásně vidět, jak je relace N:N "rozbita" na dvě relace1:N. Platí totiž:

mnoho různých čtenářů si může půjčit mnoho různých knih (N:N)

jedna kniha může být půjčena mnohokrát (1:N mezi knihami a výpůjčkami)

jeden čtenář může přijít do knihovny vícekrát za život a něco si půjčit (1:N mezi čtenáři a výpůjčkami)

V praxi to často bývá tak, že "prostřední" tabulka neslouží pouze jako technický prostředek k realizaci spojeníN:N, ale že obsahuje i nějaké smysluplné informace. Například si dokážu představit, že by tabulka výpůjčekdocela dobře mohla obsahovat datum půjčení a datum vrácení každé publikace. To totiž nepatří logicky ani dotabulky knih, ani do tabulky čtenářů.

Pozn.: Vidíte mimochodem, jak nesmírně je toto řešení pružné? Umožňuje například postihnout situaci, kdyčtenář nevrátí všechny knihy, které má půjčené ve stejném termínu. Protože pro každou kombinaci kniha-čtenářexistuje řádek v tabulce výpůjček, lze to pohodlně zapsat.

V praxi bychom tedy mohli pomocí výše uvedené průpravy například sestavit seznam právě vypůjčených knih:

Page 71: MySQL Obsah

select knihy.nazev, ctenari.prijmeni from knihy join vypujcky on knihy.id = vypujcky.kniha join ctenari on vypujcky.ctenar = ctenari.id where vypujcky.vracenodne is null;

Poznámky ke spojením

Zejména spojení N:N vyžadují určitou představivost ze strany programátora. Během let, kdy jsem programovaldatabázové aplikace, jsem si sestavil několik tipů, které se vám možná také budou hodit:

Změnit relaci 1:N na N:N v pozdější fázi vývoje může být docela problém. Je lepší pečlivě si promysletnávrh databáze, než ji začnete tvořit.

Mnoho spojení N:N samozřejmě znamená zvýšení obemu dat v databázi a zároveň snížení výkonu.Umožňuje však ukládat data pružně a do určité míry reagovat na změny v logice uložení dat. Výhody anevýhody jsou jak už to bývá protichůdné, takže je třeba pečlivě vybírat.

Jestliže nevíte, zda bude mezi dvěma tabulkami vztah 1:N nebo N:N, stop! Je to důležité a obyčejně je totřeba hned promyslet. Leckdy se problém dá převést z počítačové řeči do jazyka, jimž mluví zákazník(třeba čeština ;-)))) a zeptat se.

Hotová katastrofa vznikne, když se programátor snaží pomocí 1:N a N:N relací popsat procesy, jejichžtoku dostatečně nerozumí (může se jednat například o aplikaci skladového hospodářství se složitýmzpůsobem kompletace výrobků). Nezřídka je pak nutné celý návrh zahodit a začít znovu, pozor na to.

Jestliže máte duplicitní údaje ve dvou tabulkách, které spolu jsou v relaci 1:N, možná že měly být vrelaci N:N. Možná je čas to předělat, i když to bude složité. Do budoucna to může ušetřit čas, výkon anáklady.

Page 72: MySQL Obsah

MySQL (24) - Seskupujeme záznamy

Mít spoustu dat je hezká věc, ale občas bychom spíše potřebovali udělat z nich nějaký "výcuc". O tom je dnešnídíl seriálu o MySQL.

10.6.2005 06:00 | Petr Zajíc | přečteno 13492×

Komerční sdělení: Pořádáme Kurzy MySQL

Již víme, že tabulky se v dotazech dají spojovat. Dosud jsme ale pracovali způsobem, při němž se vždy vevýsledku dotazu zobrazily všechny (nebo vybrané) řádky z jedné či více tabulek. To může pro základní práci sdatabází sice stačit, ale většinou je to málo. Pojďme se dnes začít zabývat seskupováním záznamů.

Seskupování záznamů

Abychom byli od začátku přesní - seskupování záznamů je něco jiného než spojování tabulek. Při spojovánítabulek totiž pracujete se dvěma nebo více tabulkami s cílem najít záznamy, které spolu vzájemně souvisejí.(Exaktně řečeno lze spojit tabulku i samu se sebou, je to však speciální případ a probereme to pozdějisamostatně). Seskupování naproti tomu je proces, který probíhá s cílem zjistit něco o skupině nějaksouvisejících záznamů. "Skupina nějak souvisejících záznamů" přitom může být docela dobře v jediné tabulce.V praxi bychom mohli najít mnoho případů seskupování:

Aplikace vyhodnocující přístup k internetovým stránkám bude chtít vědět, kolik přístupů bylzaznamenáno v jednotlivých dnes provozu webu

Aplikace pro fakturaci bude chtít zjistit, jaká je celková cena bez DPH, DPH a cena s daní po sečtenívšech položek faktury

Aplikace pro statistiku v meteorologii bude chtít vědět, jaká byla průměrná teplota pro dnešní den vněkolika předcházejících desetiletích

Krásný příklad - budete chtít zjistit z databáze zaměstnanců, kdo má vyšší plat, než je průměr ve vašífirmě.

Představme si například následující tabulku, která by mohla vzniknout jako záznam z nějakého toho logunávštěvnosti webu. Ukládá datum návštěvy, operační systém uživatele, jeho prohlížeč, stránku, kterou navštívila čas, který tím strávil:

create table logtable (datum datetime, system varchar(20), prohlizec varchar(20), stranka varchar(20), doba_prohlizeni int); insert into logtable (datum, system, prohlizec, stranka, doba_prohlizeni) values ('20050609132500','windows','ie6','index.php',5); insert into logtable (datum, system, prohlizec, stranka, doba_prohlizeni) values ('20050609132510','windows','ie6','data.php',7); insert into logtable (datum, system, prohlizec, stranka, doba_prohlizeni) values ('20050609132740','linux','firefox','index.php',9); insert into logtable (datum, system, prohlizec, stranka, doba_prohlizeni) values ('20050609132810','linux','firefox','formular.php',35); insert into logtable (datum, system, prohlizec, stranka, doba_prohlizeni)

Page 73: MySQL Obsah

values ('20050609132810','unix','opera','index.php',6); insert into logtable (datum, system, prohlizec, stranka, doba_prohlizeni) values ('20050609132850','linux','firefox','data.php',15); insert into logtable (datum, system, prohlizec, stranka, doba_prohlizeni) values ('20050609132930','unix','opera','data.php',18); insert into logtable (datum, system, prohlizec, stranka, doba_prohlizeni) values ('20050610082500','linux','opera','index.php',44); insert into logtable (datum, system, prohlizec, stranka, doba_prohlizeni) values ('20050610091106','unix','firefox','formular.php',20);

Pozn.: Omlouvám se za délku, ale pokud si to budete chtít vyzkoušet, nějaká ta data je při testech seskupovánízáznamů třeba mít po ruce.

Seskupování záznamů probíhá tak, že se za příkaz SELECT uvede klauzule GROUP BY [název pole,[názevpole...]], která přikáže serveru data před jejich vrácením seskupit. V nejjednodušším případě to může vypadatnějak takto:

select * from logtable group by system;

Pokud si to zkoušíte, asi nejste z výsledku příliš nadšeni. MySQL totiž vybere z celé tabulky vždy první záznamo systému, který tu ještě nebyl, a ten vrátí. Ve výsledku tedy bude jeden řádek s linuxem, jeden s unixem a jedens windows. Ze seskupování se ale dá vyzískat mnohem víc, když se použijí

Agregační funkce

Agregační funkce umožňují "něco" vypočítat z řádků, které se právě seskupují. Přestože těchto funkcí existujecelá řada, v praxi pro většinu běžných úloh typicky stačí znát pouze dvě z nich:

Agregační funkce COUNT, která zjistí počet právě seskupovaných řádků

Agregační funkce SUM, která zjistí součet položek v právě seskupovaných řádcích

Obě teď můžeme předvést na příkladu. Pomocí agregační funkce COUNT můžeme z protokolu například zjistit,kolik přístupů zaznamenala ta která stránka:

select stranka, count(*) from logtable group by stranka;

A pomocí SUM můžeme třeba vypátrat, kolik času na jednotlivých stránkách naši návštěvníci tráví:

select stranka, sum(doba_prohlizeni) from logtable group by stranka;

K agregačním funkcím se váže celá řada postřehů a zásad, které je dobře znát. Tak například za klauzulíGROUP BY nemusí být uveden jeden sloupec, ale může jich být hned několik. Není to takový nesmysl, jak byse mohlo na první pohled zdát. Můžeme třebas náš příkad s funkcí COUNT chtít rozšířit tak, aby vracel početshlédnutí stránky podle stránky a prohlížeče, jímž se na tuto stránku přistupovalo. V tom případě bude vrácenpočet přístupů pro každou kombinaci stránky a prohlížeče:

select stranka, prohlizec, count(*) from logtable group by stranka, prohlizec;

Dále, nic nám nebrání sestavit dotaz, v němž bude jak klauzule WHERE, tak i GROUP BY (ve skutečnosti je tocelkem častý případ). Jestliže nás bude zajímat jen chování uživatelů Firexofu, můžeme předchozí příkladpřepsat použitím:

Page 74: MySQL Obsah

select stranka, prohlizec, count(*) from logtable where prohlizec = 'firefox' group bystranka, prohlizec;

Konečně, jednou seskupené řádky lze řadit. Uvědomme si, že řazení probíhá až PO seskupení záznamů. To mádva praktické důsledky:

1. Klauzule ORDER BY je v příkazu SELECT vždy až na posledním místě. Logicky to odpovídá pořadí, vněmž dotaz bude zpracováván. Takže, z nám známých rozšíření příkazu SQL je zatím pořadí toto:SELECT ... FROM ... JOIN ... WHERE ... GROUP BY ... ORDER BY. Začátečníkovi to sice můžepřipadat poněkud náročné na zapamatování, ale je to intuitivní.

2. Jelikož probíhá řazení až nakonec, můžeme řadit podle výsledku agregační funkce! Nebyl by tedyproblém seřadit například stránky sestupně podle doby, kterou na nich uživatelé tráví. Ovšem pozor,sytaxe, která vás v této souvislosti asi napadne nejdřív, nefunguje:

select stranka, sum(doba_prohlizeni) from logtable group by stranka order by sum(doba_prohlizeni) desc;

Důvod je prostý - MySQL nesmí mít v klauzuli ORDER BY výraz. Řešení jsou dvě, buď se dá použít číslořazeného sloupce, nebo si výraz SUM (doba_prohlizeni) nazvat aliasem. Oba dotazy níže již projdou a dělajítotéž:

select stranka, sum(doba_prohlizeni) as doba from logtable group by stranka order by dobadesc; select stranka, sum(doba_prohlizeni) from logtable group by stranka order by 2 desc;

V příštím díle se můžete těšit na další informace ohledně seskupování záznamů.

Page 75: MySQL Obsah

MySQL (25) - hrátky se seskupenými záznamy

Jak vytřídit již jednou seskupené záznamy? O tom je dnešní díl seriálu MySQL. Dozvíte se třeba, jak vypočítatprůměrné platy ve firmě.

17.6.2005 09:00 | Petr Zajíc | přečteno 9955×

Komerční sdělení: Pořádáme Kurzy MySQL

V předchozím díle jsme rozebrali seskupování záznamů. Dnes se na toto téma ještě podíváme, protože minulejsem vám zdaleka o této věci neřekl všechno. Co dalšího tedy můžeme uvést o MySQL, příkazu SELECT aseskupování položek?

Jiný příklad na seskupování

Zatím neumíme vybírat seskupené záznamy. Připomeňme si z minulého dílu myšlenku, že při seskupovánízáznamů můžeme použít klauzuli WHERE pro výběr záznamů, které se mají vzít v úvahu. To znamená, že ještěpředtím, než je cokoli seskupeno, jsou vybrány jen odpovídající záznamy. Protože jsme si minule pohrávali smyšlenkou sestavit dotaz, který by vybral pracovníky s nadprůměrným platem, pojďme to nyní udělat. Mějmenapříklad následující tabulku:

create table pracovnik (jmeno varchar(50), oddeleni varchar(20), plat int); insert into pracovnik (jmeno, oddeleni, plat) values ('Jarda', 'marketing', 14000); insert into pracovnik (jmeno, oddeleni, plat) values ('Pepa', 'marketing', 16000); insert into pracovnik (jmeno, oddeleni, plat) values ('Honza', 'marketing', 18000); insert into pracovnik (jmeno, oddeleni, plat) values ('Jana', 'výroba', 10500); insert into pracovnik (jmeno, oddeleni, plat) values ('Kamil', 'výroba', 12500); insert into pracovnik (jmeno, oddeleni, plat) values ('Petr', 'výroba', 13500);

Na první pohled sice z této tabulky vidíme, že lidé v marketingu mají větší peníze než lidé ve výrobě, ale tonebylo naším cílem. S tím, co již umíme, můžeme pomocí agregačních funkcí vypočítat průměrný plat ve firmě.V nejjednodušším případě třeba takto:

select sum(plat)/count(*) from pracovnik;

Z tohoto dotazu byste mohli být docela překvapení, protože neobsahuje vůbec žádnou klauzuli GROUP BY.Mám k němu několik postřehů, které se v praxi určitě budou nejdednou hodit:

1. Agregační funkce lze použít i bez klauzule GROUP BY. V takovém případě je za "skupinu" považovánacelá tabulka.

2. Při výpočtu, v němž dělíme počtem řádků musíme být opatrní. Snadno se můžeme dostat k chybám typudělení nulou.

3. Při výpočtu průměrných hodnot lze použít agregační funkci AVG (průměr), díky čemuž se vyhnemepoužití SUM a COUNT.

Náš dotaz by tedy šel mnohem elegantněji a se stejnými výsledky přepsat jako:

Page 76: MySQL Obsah

select avg(plat) from pracovnik;

Jenomže pro nás by teď bylo mnohem přesnější znám průměrný plat v jednotlivých odděleních. K tomu zcelajistě může posloužit dvojice dotazů s WHERE, takže při použití obou výše popsaných variant dostáváme něcove smyslu:

select avg(plat) from pracovnik where oddeleni='marketing'; select avg(plat) from pracovnik where oddeleni='výroba'; případně select sum(plat)/count(*) from pracovnik where oddeleni='marketing'; select sum(plat)/count(*) from pracovnik where oddeleni='výroba';

ale tento přístup má dvě podstatné nevýhody. Jednak je závislý na tom, že známe názvy oddělení a jednak přivyšším počtu oddělení je potřeba psát řadu dotazů. Jak asi tušíte, tohle není to pravé ořechové, takže použijemeagregační funkci a sestavíme dotaz ve smyslu:

select oddeleni, avg(plat) from pracovnik group by oddeleni;

Tím tedy víme, jaký je průměrný plat v každém oddělení, a tento dotaz bude fungovat bez ohledu na početoddělení a bez ohledu na počet pracovníků v nich.

Klauzule HAVING

Kdybychom chtěli vypsat seznam všech oddělení, kde průměrný plat je vyšší než průměrný plat v celé firmě,znalosti, které zatím máme nám nestačí. My totiž potřebujeme

1. nejprve zjistit průměrný plat na oddělení (což již umíme)

2. pak z těchto průměrných platů vybrat ty, které jsou nadprůměrné vzhledem k celé firmě. Nezapomeňme,že seznam oddělení nemusí obsahovat jen dvě položky, ale že jich může být mnohem víc

Takže, jak to celé provést? Existuje klauzule příkazu SELECT, která seskupené záznamy vytřídí. Je toHAVING. Náš příklad by tedy šel zapsat takto:

select oddeleni, avg(plat) from pracovnik group by oddeleni having avg(plat)>(select avg(plat) from pracovnik);

Všimněte si dvou věcí - jednak nám tento příkaz vybral již seskupené záznamy. V klauzuli HAVING tedymůžete bez obav používat agregační funkce. Respektive měli byste, protože není-li v klauzuli HAVING použitaagregační funkce, dá se přepsat s použitím WHERE. A za druhé, dnes poprvé jsme použili v příkazu SQLtakzvaný poddotaz - "vnořený" dotaz, který nějak souvisí s "hlavním" dotazem. O poddotazech ještě bude řeč;tady byl uveden proto, že počítal průměrný plat v celé firmě.

Pozn.: Vybrat z každého oddělení jen pracovníky s nadprůměrným platem (vzhledem k oddělení) lze sice také,ale tento dotaz je zatím příliš složitý, než abychom jej tady uváděli. Takže vydržte, ještě k tomu dojde.

Rozšíření ROLLUP

Page 77: MySQL Obsah

Když počítáte součty, může se Vám občas hodit dotaz, který vrací kromě součtů i totály, tedy celkový součetvšech mezisoučtů. Mějme například dotaz, který na základě dat z minulého dílu počítá dobu strávenou najednotlivých stránkách podle prohlížečů:

select prohlizec, sum(doba_prohlizeni) from logtable group by prohlizec;

Malou modifikací dosáhneme toho, že kromě řádků s jednotlivými prohlížeči bude ve výsledné sadě záznamů icelkový součet:

select prohlizec, sum(doba_prohlizeni) from logtable group by prohlizec with rollup;

není to však tak užitečné, jak by se na první pohled mohlo zdát. Jednak toto rozšíření funguje až od verze 4.1.1databáze MySQL. Ve volající aplikaci navíc budete muset tento řádek s celkovými součty nějak zpracovat. Akonečně, mnoho aplikací a nástrojů pro zobrazování dat (reporty, například) má stejně vlastní nástroje provytváření celkových součtů.

Shrnutí

Příště již opustíme popis příkazu SELECT. Jak sami vidíte, je to velmi složitý a komplikovaný příkaz, kterýnám sice umožňuje z databáze vybrat prakticky cokoli, na druhou stranu je však náročný na zapamatování.Jednotlivé klauzule tohoto příkazu tedy fungují v tomto pořadí:

SELECT

FROM

JOIN

WHERE

GROUP BY

HAVING

ORDER BY

I nadále budeme v seriálu průběžně používat příkaz SELECT. Je to jediná cesta, jak jej dostat do krve. Koneckonců, vybírání záznamů z databáze je tou nejčastější činností, která vás při práci s DBMS čeká.

Page 78: MySQL Obsah

MySQL (26) - Poddotazy

Jak je to s těmi poddotazy v MySQL? Umí je nebo neumí?

24.6.2005 07:00 | Petr Zajíc | přečteno 12223×

Komerční sdělení: Pořádáme Kurzy MySQL

Minule jsem poprvé v tomto seriálu použil techniku, které se v odborné terminologii říká poddotaz. Kpoddotazům se váže poměrně oblíbený mýtus, a to sice ten, že je MySQL neumí. Tábor zastánců MySQL paktvrdil, že poddotazy se dají při programování obejít, tábor odpůrců této databáze se zase naopak nechal slyšet, žeto nejde a že MySQL je tím pádem naprosto nepoužitelná databáze. Dnes si ukážeme, jak je to doopravdy - copoddotazy jsou, k čemu slouží a jak je v MySQL efektivně používat.

Poddotaz je když...

Termínem "poddotaz" je v SQL míněn platný "vnitřní" dotaz, který je součástí nějakého většího, "vnějšího"dotazu. Anglicky se označuje pojmem subquery, a můžeme rovněž slýchat označení vnořený dotaz.Zavzpomínáme-li na minulý díl, byl tam uveden tento poddotaz (v textu příkazu SQL jsem jej označil červeně).

select oddeleni, avg(plat) from pracovnik group by oddeleni having avg(plat)>(select avg(plat) from pracovnik);

Jak vlastně vzniklo tvrzení, že MySQL nepodporuje poddotazy? Obyčejná databáze skutečně poddotazynepodporuje, tak tomu skutečně dřív bývalo, že ani MySQL poddotazy neměla. Ale pak se pár chytrých hlavdalo dohromady a řekli: Dost! A není náhodou, že těch pár chytrých hlav se sešlo v MySQL! Víte, co toznamená? To znamená, že jsme zase o krok před nimi!

Takže teď vážně: MySQL podporuje poddotazy od verze 4.1 (což je podle některých správců "poměrněnedávno" a tuto verzi na svých systémech ještě nemusejí mít). Pro některé čtenáře to tedy bude spíše pohled dobudoucnosti, než že by mohli poddotazy hned začít využívat. Dřívější verze MySQL (což zahrnuje řady 4.0 avšechny "trojkové") práci s poddotazy v plném slova smyslu skutečně neuměly.

Poddotazy mají některé výhody, o nichž byste měli vědět (a díky nimž se používají). Mezi nejvýznamnější znich patří:

Čitelnost. Pokud luštíte existující dotaz a pokoušíte si představit, k čemu asi slouží, bude zápis spoddotazy většinou dosti názorný.

Strukturovanost. "Vnitřní" dotaz můžete otestovat a odladit dříve než jej učiníte součástí "vnějšího"dotazu.

Relativní jednoduchost. Poddotaz můžete použít leckde a jak ještě uvidíme, jsou poměrně flexibilní apřitom snadné na psaní.

Page 79: MySQL Obsah

Každá mince má dvě strany, a proto i poddotazy mají svoje nevýhody. Podotýkám, že tyto nevýhody se týkajíhlavně špatně napsaných poddotazů, ale měli byste o nich vědět i v případě, že se chystáte psát dobré poddotazy.

Dotaz s poddotazy může pomalý, pekelně pomalý. Uvědomte si totiž, že někdy milé databázi nezbydenic rychlejšího, než tupě provést poddotaz, nějak si zapamatovat jeho výsledky, ty použít ve vnějšímdotazu a pak vrátit data. (Normálně se MySQL pokusí dotaz před jeho provedením optimalizovat, abybyl proveden co nejrychleji. U poddotazů je velká šance, že optimalizaci nepůjde použít).

Dotaz s poddotazy může být někdy trochu nevyzpytatelný. Když se například zapletete s hodnotamiNULL, může s tím být docela legrace.

Použití poddotazů

BETWEEN a IN

Typické použití poddotazů je ve spojení s predikáty BETWEEN a IN. Ty byly již zmíněny v díle o filtrovánídat. Zejména predikát IN je častým "terčem" poddotazů. Funguje to následovně: nejprve připomenu příklad zdílu o filtrování dat:

select * from lidi where mesto in ('Praha', 'Brno', 'Ostrava');

Všimněte si, že v tomto příkladu žádný poddotaz není a že hodnoty měst jsou zadány "natvrdo". Pokud bychomseznam měst měli uložen v samostatné tabulce, můžeme dotaz přepsat na:

select * from lidi where mesto in (select mesto from mesta);

Výhoda je jasná - jestliže se změní tabulka měst, druhý dotaz bude i nadále fungovat. Ten první by se ale muselpo každé změně seznamu měst přepsat. V poddotazu můžeme používat prakticky všechny věci, které jsme senaučili u příkazu SELECT. Nic nám tedy nebrání vybrat jen lidi z měst nad 100000 obyvatel:

select * from lidi where mesto in (select mesto from mesta where obyvatel > 100000);

Jednu věc byste ale vědět měli - poddotaz použitý v souvislosti s predikátem IN musí vracet jen jeden sloupec.Takže, následující syntaxe je špatná, protože poddotaz vrací dva sloupce a nebohý hlavní dotaz netuší, který znich má pro porovnání použít:

select * from lidi where mesto in (select mesto, poloha from mesta);

Poddotazy lze používat mnoha dalšími způsoby. V souvislosti s tím mě napadá, že je třeba zmínit se ospeciálním operátoru - EXISTS.

Poddotazy a EXISTS

EXISTS funguje tak, že vrátí logickou hodnotu TRUE, pokud následující poddotaz obsahuje nějaké řádky.Pokud poddotaz žádné řádky nevrátí, EXISTS vrací FALSE. Vše bude asi nejlepší osvětlit na nějakém příkladu.Dejme tomu, že chceme vybrat všechna města, v nichž máme nějaké záznamy o obyvatelích:

select * from mesta where exists (select * from lidi where lidi.mesto=mesta.mesto);

Česky řečeno vrátí tento dotaz jen taková města, v nichž máme nějaké obyvatele. Na tomto typu poddotazu simůžete všimnout zajímavé věci - a to sice že poddotaz se "odvolává" na data v hlavím dotazu. To je možné. Veskutečnosti je to pro funkci EXISTS naprosto typické. Poddotazům tohoto typu se říká korelační (anglickycorrelated).

Page 80: MySQL Obsah

Jak jsme v příkladech viděli, poddotaz může být v klauzuli HAVING a v klauzuli WHERE. Ve skutečnostimůže být v příkazu prakticky kdekoli. Poddotaz může být dokonce i v jiném poddotazu! S poddotazy se budemev dalších dílech seriálu sektávat průběžně, takže se s nejobvyklejšími konstrukcemi poddotazů ještě seznámíte.

Poddotazy versus spojení

V souvislosti s poddotazy byste měli vědět, že některé z nich lze přepsat na spojení. Spojení bývá obecněrychlejší. Následující dva dotazy jsou tedy funkčně totožné, jeden však používá poddotaz a druhý spojení.

select * from lidi where mesto in (select mesto from mesta); select lidi.* from lidi join mesta on lidi.mesto= mesta.mesto;

V dobách, kdy MySQL nepodporovala poddotazy byl přepis na spojení jedinou možností, jak se s podobnýmiúlohami vypořádat. Nezapomeňme však, že některé poddotazy na spojení zkrátka přepsat nejdou, a tudíž je lzesmysluplně provést jen na verzích MySQL 4.1 a novějších. Pěkný rozbor této problematiky je v manuálu kMySQL.

Page 81: MySQL Obsah

MySQL (27) - Složitější dotazy

Jak napsat některé specifické dotazy? Dnes o vyhledávání duplicitních položek a chybějících záznamů pomocíjazyka SQL.

1.7.2005 06:00 | Petr Zajíc | přečteno 12963×

Komerční sdělení: Pořádáme Kurzy MySQL

Tím, jak jsme se postupně seznámili s jednotlivými příkazy jazyka SQL pro výběrové dotazy, otevřel se přednámi svět databázových dat dokořán. Většina pojednání o SQL, která se mi dostala do rukou v tomto bodě popispříkazu SELECT končí. To je škoda, protože sice jsme si ukázali na mnoho věcí z teorie, stále nám však chybípotřebná praxe.

Při dotazování pomocí SQL se běžně setkáváme s úlohami, které nejsou na první pohled zase až takjednoduché. Jak byste například provedli dotaz, který vrátí chybějící data v jedné tabulce ve srovnání s jinoutabulkou? Co dotaz na duplicitní položky? Umíte napsat dotaz, který vrátí nejvyšší hodnoty v několika různýchkategoriích? Co dotaz vracející jako součást sady záznamů číslování řádků, nebo takový, co umí vracetprůběžné součty? Dost mi vadí, že nemám takové náročnější příklady hned po ruce, když je potřebuji. Pokusímse to napravit; v seriálu teď několik takových věcí popíšu. Máte se na co těšit - pokud vím, nebyly tytoinformace na českých webech v podobné formě a rozsahu dosud uveřejněny.

Chybějící data

S tímto dotazem jsme se již setkali a je poměrně běžný. Zadání je jednoduché - máme dvě tabulky, kteréobsahují minimálně jeden shodný sloupec (typicky jsou to tabulky v relaci 1:N) a cílem je zjistit, které údaje zprvní tabulky se vůbec neobjevují v tabulce druhé. Mějme třeba knihovnu a dvě tabulky - čtenáře a výpůjčky.Cílem bude zjistit, kdo ze čtenářů v knihovně ještě nikdy nic nepůjčil. Tabulka čtenářů by mohla být:

create table ctenari (ctenar varchar(20)); insert into ctenari (ctenar) values ('Petr'), ('Karel'), ('Pavel'), ('Josef'); insert into ctenari (ctenar) values ('Petra'), ('Jana'), ('Veronika'), ('Lenka');

a výpůjčky by mohly vypadat takto:

create table vypujcky (datum datetime, ctenar varchar(20)); insert into vypujcky (datum, ctenar) values ('20050520','Petra'); insert into vypujcky (datum, ctenar) values ('20050528','Petra'); insert into vypujcky (datum, ctenar) values ('20050522','Jana'); insert into vypujcky (datum, ctenar) values ('20050615','Veronika'); insert into vypujcky (datum, ctenar) values ('20050528','Lenka');

Jak vidíte, kluci vůbec nečtou. Jak sestavit dotaz, který by to odhalil?

Řešení se spojením

Jedno dobré řešení je spojit obě tabulky levým spojením a výsledný dotaz filtrovat podle vypujcky.ctenar.Jestliže tam bude hodnota null, jde o čtenáře, který si nikdy nic nepůjčil - a toho právě hledáme.

select ctenari.* from ctenari left join vypujcky on ctenari.ctenar = vypujcky.ctenarwhere vypujcky.ctenar is null;

Page 82: MySQL Obsah

Toto řešení bude vracet výsledky velmi rychle a tudíž se používá velmi často.

Řešení s poddotazem

Existuje však další možnost, a to poddotaz. Odpovídalo by to českému "vyber všechny čtenáře, kteří nejsouobsaženi v tabulce výpůjček". Zapsáno v SQL by to bylo takto:

select ctenari.* from ctenari where ctenar not in (select ctenar from vypujcky);

Kromě toho, že se takto zapsaný dotaz dobře čte, má vlastně jen samé nevýhody. Předně - nebude ve většiněpřípadů dost rychlý, a to zejména tehdy, když se budou obě tabulky zvětšovat. Málo zřejmý je ale druhý,mnohem závažnější problém. Pokud by totiž v tabulce výpůjček existoval byť jen jeden záznam s hodnotouNULL ve sloupci ctenar, celé to přestane fungovat úplně. Důvodem je skutečnost, že nelze porovat dvě hodnotyNULL ani hodnotu NULL s jinou známou hodnotou (výsledkem je vždy hodnota NULL). Problémnamodelujete takto:

insert into vypujcky (datum, ctenar) values (now(), NULL); select ctenari.* from ctenari where ctenar not in (select ctenar from vypujcky);

Není to tak hrozné - situace má východisko. Pokud byste na řešení s poddotazem trvali, musíte v něm omezitvýběr na ty řádky, kde je zadán nějaký čtenář v tabulce výpůjček, takto:

select ctenari.* from ctenari where ctenar not in (select ctenar from vypujcky wherectenar is not null);

Jelikož řešení se spojením podobnými neduhy netrpí, doporučuji používat ten první přístup.

Pozn.: Příklad byl zjednodušen. V reálné aplikaci bychom pravděpodobně v tabulce výpůjček měli ještě dalšípole, a čtenáři by zřejmě byli identifikováni čislem, ne křestním jménem. Na principu to však nic nemění.

Duplicitní položky

Na stejných datech můžeme demonstrovat i další obvyklou úlohu - a to výběr položek, které se v dané tabulcevyskytují vícekrát než jednou. Mohli bychom chtít třeba vědět, kdo má více než jednu výpůjčku. Naštěstí i tadyje řešení celkem prosté. Spočívá v použití klauzule HAVING poté, co tabulku výpůjček seskupíme podlesloupce čtenář, nějak takto:

select ctenar from vypujcky group by ctenar having count(*) >=2;

Není v tom žádná magie. Tabulku jsme seskupili podle pole "čtenář" a zajímají nás jen ti, kteří byli v knihovnědvakrát (nebo častěji). Dotaz však není tak podrobný, jak by mohl být. Může se stát, že nás zajímají nejenčtenáři, kteří byli v knihovně častěji než jednou, ale i ostatní data (neboli, v našem případě kdy konkrétně byli vknihovně). Tady musíte být opatrní, protože snadno lze podlehnout léčce a myslet si, že rozšíření prvníhodotazu ve smyslu:

select * from vypujcky group by ctenar having count(*) >=2;

zařídí to, co potřebujeme. Kdepak! Tento dotaz vrátí stejný počet záznamů jako dotaz předchozí s tím, že budeuvedeno vždy jen jedno datum výpůjčky. Čili, musíme na to jinak.

Page 83: MySQL Obsah

Pozn.: Abych byl upřímný, zazlívám MySQL, že dotaz výše jde vůbec provést. V některých DBMS skončípodobný pokus chybovým hlášením ve smyslu tom, že sloupec vypujcky.datum nelze do výsledné sady záznamůzahrnout, neb není v klauzuli GROUP BY. Obecně byste se měli hvězdičkové konvenci vyhýbat vždy, kdyžpracujete se seskupováním záznamů.

Řešením je použít ten první dotaz jako poddotaz, nějak takto:

select * from vypujcky where ctenar in (select ctenar from vypujcky group by ctenar having count(*) >=2);

Tento kód bude fungovat ve všech DBMS a je syntakticky čistý. V rozporu s tím, co tvrdí někteří vývojáři lzetento poddotaz přepsat poměrně jednoduše na spojení:

select vypujcky.* from vypujcky join (select ctenar from vypujcky group by ctenar having count(*) >=2) pravidelni_ctenari on vypujcky.ctenar=pravidelni_ctenari.ctenar;

Je ale pravda, že specielně v tomto případě nebude rychlostní užitek ze spojení tak výrazný. Důvod je prostý -poddotazem nebyla skutečná tabulka, ale výsledek výpočtu. Tabulka pravidelni_ctenari tedy v databázineexistuje a MySQL ji musí v obou případech dopočítat.

Page 84: MySQL Obsah

MySQL (28) - Dotazy pro pokročilé

Dnes o tom, jak vrátit sadu záznamů s očíslovanými řádky. Uvidíte, jak se dá vtipně využít spojení tabulky sesebou samou.

8.7.2005 08:00 | Petr Zajíc | přečteno 10998×

Komerční sdělení: Pořádáme Kurzy MySQL

Minule jsme načali látku o pokročilých technikách sestavování SQL dotazů tím, že jsme si ukázali, jak se dásestavit dotaz na duplicitní položky a dotaz na chybějící záznamy. Dnes budeme v rozboru náročnějších dotazůpokračovat. Ukážeme si, co může vzniknout za problémy, když se rozhodnete vracet pořadová čísla záznamů.

"Očíslované" záznamy

Čas od času je třeba vrátit sadu záznamů, která obsahuje jako součást vracených dat i pořadové číslo záznamu.Může to být potřeba například při sestavování výsledkových listin v nějakém soutěžním klání, jako podklad protvorbu kalendářů a podobně. Mějme třeba jako data tabulku:

create table zamestnanci (jmeno varchar(20), plat integer); insert into zamestnanci (jmeno, plat) values ('Pepa', 10000); insert into zamestnanci (jmeno, plat) values ('Míša', 9500); insert into zamestnanci (jmeno, plat) values ('Jarda', 12500); insert into zamestnanci (jmeno, plat) values ('Jana', 13200); insert into zamestnanci (jmeno, plat) values ('Big boss', 16500);

a chtějme vrátit lidi podle jejich platů (nejbohatší nejvýše) s tím, že seznam bude očíslován. Jak na to? Existujeněkolik řešení.

Řešení s dočasnou tabulkou

První, co by někoho mohlo napadnout je, že k tabulce by se mohlo přidat automaticky číslované pole, a pak jiprostě vrátit i s tímto polem:

alter table zamestnanci add id int not null auto_increment primary key; select * from zamestnanci;

Tento přístup má však mnoho omezení, v praxi většinou takových, že se to nedá použít vůbec:

Každá tabulka smí mít jen jedno automaticky číslované pole

Odmazáním záznamů vznikne v číslené řadě "díra", kterou MySQL nezaplňuje

Toto číslování funguje jen pro celou tabulku, pokud budeme chtít data seřadit nebo vybrat jen některá, jenám tento postup víceméně nanic.

Page 85: MySQL Obsah

Ačkoli by se zdálo, že se tím nemá cenu déle zabývat, může mít tato technika vracení "očíslovaných záznamů"své zastánce, zejména pokud ji trochu upravíme. MySQL totiž může fungovat takto:

1. Vytvoříme si sadu záznamů, která nás zajímá

2. Tu umístíme do dočasné tabulky

3. K dočasné tabulce přidáme automaticky číslované pole

4. Pak z ní vybereme data a ta vrátíme volající aplikaci

Celé to předveďme na příkladu. Budeme chtít vrátit seznam zaměstnanců s tím, že budou seřazeni podle platu(sestupně) a očíslováni. Řešení?

create temporary table tmp_zamestnanci like zamestnanci; alter table tmp_zamestnanci add id int not null auto_increment primary key; insert into tmp_zamestnanci (jmeno, plat) select jmeno, plat from zamestnanci order byplat desc; select * from tmp_zamestnanci;

Toto řešení samozřejmě předpokládá, že v původní tabulce neexistovalo pole id. Pokud by existovalo, je druhýřádek z příkazu výše zbytečný. Tahle metoda je občas cenná, protože na jednu stranu sice přesypává kvantačísel, na stranu druhou však může i tak být dost rychlá. Druhé řešení, které vám předvedu, totiž trpí poměrněvýžnými výkonostními problémy.

Řešení s poddotazem

Tohle řešení nepoužívá dočasnou tabulku, ale poddotaz. A to poddotaz korelační, tedy takový, kde se data zvnitřního dotazu vztahují k dotazu vnějšímu. Nejprve jej předvedu:

select zamestnanci.*, (select count(*) from zamestnanci as pocitadlo where pocitadlo.plat>=zamestnanci.plat) as poradi from zamestnanci order by plat desc;

a teď vysvětlím - vnořený poddotaz prostě vrátí počet všech zaměstnanců, kteří mají stejný nebo vyšší plat nežaktuálně zpracovávaný zaměstnanec. Což znamená, že de facto vrátí počet zaměstnanců majících vyšší plat nežzpracovávaný záznam. Jak už to na tom světě bývá, i tohle řešení má háček, a to ten, že když by měli dvapracovníci stejný plat, vrátí jim poddotaz stejné pořadí. Což je logické - v takovém případě totiž existuje "stejnýpočet kolegů, majících stejný či vyšší plat".

Jak z toho ven? Je tu jeden způsob - a to ten, že si "vypůjčíme" ještě nějaké další pole pro řazení. V našempřípadě bychom například mohli řadit jednak sestupně podle platu, a jednak jména podle abecedy. To všechnoproto, abychom měli zajištěno pevné pořadí i v rámci skupiny se stejným platem. Dotaz, fungující dobře i prozáznamy s více lidmi se stejným platem by pak mohl vypadat takto (důležité pasáže jsem zvýraznil):

select zamestnanci.*, (select count(*) from zamestnanci as pocitadlo where pocitadlo.plat>zamestnanci.plat or (pocitadlo.plat=zamestnanci.plat andpocitadlo.jmeno<=zamestnanci.jmeno)) as poradi from zamestnanci order by plat desc,jmeno;

Když si poddotaz přečtete a zamyslíte se nad ním, je to opět logické. Vrací totiž:

Počet lidí majících vyšší plat než aktuální zaměstnanec, plus

Page 86: MySQL Obsah

Počet lidí majících sice stejný plat, ale příjmení, které je dříve v abecedě

Pochopitelně, poddotaz by nefungoval správně, kdyby řazení v hlavním dotazu bylo jiné.

Pozn.: Vnímavý čtenář může namítnout, že v reále lze mít dva lidi jak se stejným jménem, tak i se stejnýmplatem. Ono se to ve skutečnosti většinou ještě řadí podle nějakého jedinečného identifikátoru řádku (například,podle automaticky číslovaného pole), takže tento problém nenastává.

Řešení se spojením

Pokud jste se rozhodli přepsat výše uvedený poddotaz na spojení, mám pro vás dobrou zprávu - jde to. Člověkmusí pouze dát pozor na to, že v hlavním dotazu je pak nutné použít klauzuli GROUP BY, neb agregačnífunkce COUNT(*) musí počítat pouze s počty "předcházejících" zaměstnanců pro konkrétního pracovníka.Mohlo by to tedy dopadnout nějak takto:

select zamestnanci.*, count(*) from zamestnanci join zamestnanci as pocitadlo onpocitadlo.plat > zamestnanci.plat or (pocitadlo.plat = zamestnanci.plat andpocitadlo.jmeno <= zamestnanci.jmeno) group by zamestnanci.jmeno, zamestnanci.plat orderby zamestnanci.plat desc, zamestnanci.jmeno;

Závěr

Jak vidíte, vracet jako součást dat i pořadová čísla řádků není až tak úplně jednoduché. Někteří programátořiproto volí jiný přístup - nechají data sestavit bez čísel řádků a ve volající aplikaci pak zpracovávají data pojednotlivých záznamech. Aplikace sama si vytvoří a spravuje jakýsi čítač, s nímž se pak manipuluje. Řešení,které jsem předvedl, však může být mnohem elegantnější, protože udržuje aplikační logiku v databázi a nemá jiroztříštěnu mezi databázi a aplikaci.

Co si vyberete záleží pochopitelně na konkrétní situaci. Pokud budete číslovat větší počet záznamů, udělejte sinějaké testy rychlosti - jednotlivé metody zde uvedené se mohou mít až řádově odlišný čas provádění!

Page 87: MySQL Obsah

MySQL (29) - Vracení nejvyšších záznamů

Dnes se podíváme, jak řešit poměrně častou úlohu - vracení nejvyšších záznamů z nějaké množiny dat.

15.7.2005 08:00 | Petr Zajíc | přečteno 9089×

Komerční sdělení: Pořádáme Kurzy MySQL

S látkou z mnulého dílu úzce souvisí poměrně časta potřeba různých aplikací - a tou je vracení jednoho či více"maximálních" záznamů z nějaké množiny. Může se jednat o nejvyšší teplotu, nejvyšší plat nebo cokoliměřitelného. Abychom ale neměli všechny příklady stejné, ukážu vám, že se to může týkat i třeba řazeníkalendářních dat. Začněme hned s daty, protože jakékoli další vysvětlování je myslím zbytečné.

Vracení nejvyšších N záznamů

Zadání může být takové - máte tabulku zákazníků a s kažým zákazníkem sepisujete dodavatelsko -odběratelskou smlouvu. V tabulce budete chtít mít vždy zákazníka, a datum uzavření této smlouvy. Pojďmevyjít z následujících dat:

create table smlouvy (zakaznik varchar (50), datum date); insert into smlouvy (zakaznik, datum) values ('První stavební','20050410'); insert into smlouvy (zakaznik, datum) values ('První stavební','20050512'); insert into smlouvy (zakaznik, datum) values ('První stavební','20050615'); insert into smlouvy (zakaznik, datum) values ('Tunel, s.r.o.','20041205'); insert into smlouvy (zakaznik, datum) values ('Tunel, s.r.o.','20050512'); insert into smlouvy (zakaznik, datum) values ('Tunel, s.r.o.','20050518'); insert into smlouvy (zakaznik, datum) values ('Linuxman','20050301'); insert into smlouvy (zakaznik, datum) values ('Linuxman','20050401'); insert into smlouvy (zakaznik, datum) values ('Linuxman','20050501');

Klauzule LIMIT

Především budeme chtít vybrat jeden záznam, ten s nejvyšším datem. To půjde dobře pomocí rozšíření LIMITpříkazu SQL. Takže, naposledy uzavřenou smlouvu zjistíme lehce takto:

select * from smlouvy order by datum desc limit 1;

K tomu bych ale přece jen měl pár poznámek: Především, MySQL nepodporuje syntaxi s klíčovým slovemTOP, kterou možná znáte z jiných databázových systémů. Takže, tohle v MySQL NEBUDE fungovat:

select TOP 1 * from smlouvy order by datum desc;

Za druhé, rozšíření LIMIT je mnohem pružnější než TOP, protože umožňuje zadat "počáteční" řádek a rovněžpočet řádků, které mají následovat. Čehož pomocí TOP v jiných DBMS dosáhnout nejde. Takže, chcete-li saduzáznamů počínaje druhým nejvyšším datem a obsahující čtyři řádky v sadě, zkuste něco jako:

select * from smlouvy order by datum desc limit 2,4;

Page 88: MySQL Obsah

Za třetí, prakticky vždy se rozšíření LIMIT používá v souvislosti s kaluzulí ORDER BY, protože v praxivětšinou nemá smysl vybírat podmnožinu podle pořadí řádků z neseřazené sady záznamů. A konečně za čtvrté -klauzule LIMIT může být pro začátečníky ošidná, protože:

1. Ač se to nezdá, "LIMIT x" nemusí vrátit právě x záznamů. Jestliže je například výsledná sada záznamůprázdná, skončí příkaz prázdným výsledkem a nedojde přitom k žádné chybě.

2. "LIMIT x" může sice vrátit x záznamů, ale nebudou to všechny záznamy, které jste si možná mysleli. Vnašem případě jsou třebas 12.5.2005 uzavřeny dvě smlouvy, které se mají "dělit" o třetí místo v pořadípodle data uzavření, příkaz s LIMIT 3 však vrátí VŽDY jen určený počet záznamů. Řečeno jinak -jestliže by všechny smlouvy byly uzavřeny tentýž den, LIMIT 3 vypíše jen tři z nich. Na to je třeba dávatpozor při sestavování různých žebříčků, protože byste mohli na někoho zapomenout.

Agregační funkce MAX

Jak asi očekáváte, vrací agregační funkce MAX() záznam s nejvyšší hodnotou v dané skupině (nebo v celé sadě,pokud chybí klauzule GROUP BY). Takže, nejvyšší datum dostaneme takto:

select max(datum) from smlouvy;

Pokud bychom chtěli celý řádek (tedy jak datum, tak i odpovídajícího zákazníka), nemůžeme bohužel napsat:

select zakaznik, max(datum) from smlouvy;

Protože mixování seskupených a nesekupených záznamů je logicky nesmyslné. Můžeme ale dotazpřeformulovat takto:

select zakaznik, max(datum) from smlouvy group by zakaznik;

což je syntaxe, která projde a zobrazí u každého zákazníka datum naposledy uzavřené smlouvy.

Složitější příklad

Možná si říkáte, že možnost zobrazit nejvyšší datum pro každého zákazníka pomocí postupu popsaného výše jedocela jednoduchá a zároveň velmi užitečná. Bohužel, praxe je trochu jiná. Většinou totiž tabulka obsahuje ještějiné, neseskupitelné údaje, a ty bude třeba zpracovat. Mějme následující, lehce zmodifikovanou sadu záznamů,která kromě zákazníka a data sepsání bude ještě uvádět číslo smlouvy:

truncate table smlouvy; alter table smlouvy add column cislosmlouvy int; insert into smlouvy (zakaznik, datum, cislosmlouvy) values ('Prvnístavební','20050410',10); insert into smlouvy (zakaznik, datum, cislosmlouvy) values ('Prvnístavební','20050512',15); insert into smlouvy (zakaznik, datum, cislosmlouvy) values ('Prvnístavební','20050615',16); insert into smlouvy (zakaznik, datum, cislosmlouvy) values ('Tunel,s.r.o.','20041205',18); insert into smlouvy (zakaznik, datum, cislosmlouvy) values ('Tunel,s.r.o.','20050512',25); insert into smlouvy (zakaznik, datum, cislosmlouvy) values ('Tunel,s.r.o.','20050518',30); insert into smlouvy (zakaznik, datum, cislosmlouvy) values ('Linuxman','20050301',31); insert into smlouvy (zakaznik, datum, cislosmlouvy) values ('Linuxman','20050401',32); insert into smlouvy (zakaznik, datum, cislosmlouvy) values ('Linuxman','20050501',17);

Zadání bude: Vybrat pro každého zákazníka jeho název a číslo smlouvy s nejvyšším datem uzavření.Samozřejmě nepomůže dotaz:

Page 89: MySQL Obsah

select zakaznik, max(datum), cislosmlouvy from smlouvy group by zakaznik;

a nesprávné výsledky vrátí rovněž

select zakaznik, max(datum), max(cislosmlouvy) from smlouvy group by zakaznik;

Proč? Protože první dotaz vybírá číslo smlouvy, na které "právě natrefí", zatímco druhý dotaz vrací nejvyššíčíslo smlouvy pro daného zákazníka. Ani jeden dotaz však nevrací číslo smlouvy záznamu, který má prodaného zákazníka nejvyšší datum. Řešením je využít spojení ve smyslu:

select smlouvy.zakaznik, smlouvy.cislosmlouvy from smlouvy join (select zakaznik, max(datum) as datum from smlouvy group by zakaznik) as nejvyssi on smlouvy.zakaznik =nejvyssi.zakaznik and smlouvy.datum = nejvyssi.datum;

Neboli - využijeme data vrácená prostým výběrem maximálních hodnot a spojíme je znovu s tou samoutabulkou pro dohledání zbývajících údajů. Jak lze vidět, i s tabulkou obsahující tři sloupce si lze docela vyhrát.

V dalším díle se podíváme na jiný obvyklý problém, který může být na první pohled těžké pomocí jazyka SQLvyřešit, a tím bude vracení průběžných součtů.

Page 90: MySQL Obsah

MySQL (30) - průběžné součty

Jak vznést dotaz třeba na zůstatky na běžném účtu? A lze použít vícenásobných spojení téže tabulky i kaktualizaci dat?

22.7.2005 06:00 | Petr Zajíc | přečteno 7264×

Komerční sdělení: Pořádáme Kurzy MySQL

Poslední ze "záhad" jazyka SQL, kterou bych se v tomto seriálu rád zabýval, je vracení tzv. průběžných součtů(running totals). Ty si můžete představit jako například zůstatky peněz na běžném účtu nebo jako zůstatky zbožípři pohybu ve skladu. Jak uvidíme, opět se něco takového dá provést pomocí spojení tabulky se sebousamotnou.

Dotaz na průběžné součty

Vyjděme z příkladu se zůstatky na běžném účtu. Mějme například následující tabulku s pohyby na účtu a tatodata:

create table ucet (datum date, castka decimal (10,2)); insert into ucet (datum, castka) values ('20050101', 5000); insert into ucet (datum, castka) values ('20050110', -2700); insert into ucet (datum, castka) values ('20050111', -1500); insert into ucet (datum, castka) values ('20050120', 2200);

Sestavme nyní něco jako "výpis z účtu", tedy dotaz, který vrátí všechny pohyby i s jejich aktuálními zůstatky!Pokud zavzpomínáte na díl seriálu o číslování záznamů, bude i teď postup velmi podobný. Stačí šikovně spojittabulku samu se sebou pomocí poddotazu:

select ucet.datum, ucet.castka, (select sum(vypocet.castka) from ucet as vypocet where vypocet.datum <= ucet.datum) from ucet order by datum;

Všimněte si, že tohle je jeden z mála příkladů, kdy poddotaz logicky smí obsahovat klauzuli "sum" bezodpovídající kaluzule "group by". To proto, že součet bez definování skupiny sečte všechna data v danémsloupci dotazu, což je přesně to, co potřebujeme. Jak jsme již v tomto seriálu uvedli, drtivá většina poddotazůjde přepsat na spojení, tohle nevyjímaje. Takže, pokud jste spíše milovníky spojení, nebo pokud se ve vašempřípadě spojení prokáže být rychlejší, můžete to napsat takto:

select ucet.datum, ucet.castka, sum(vypocet.castka) from ucet join ucet as vypocet on ucet.datum>=vypocet.datum group by ucet.datum, ucet.castka order by ucet.datum;

V tomto spojení se nevyskytují legrácky typu "klauzule SELECT v klauzuli JOIN" a podobné. Je to vlastněvelmi čtivý dotaz, když se na něj podíváte. Jsou však oba uvedené dotazy v pořádku? Na první pohled jistě ano(i když se v reálné aplikaci jistě budou lišit rychlostí provádění). Co však, když v jeden den proběhne víceoperací najednou? Pojďme přidat následující řádek do tabulky!

insert into ucet (datum, castka) values ('20050110', -500);

Page 91: MySQL Obsah

Pokud si dotazy vyzkoušíte teď, zjistíte, že pro oba (teoreticky pro všechny) záznamy ze dne 10.1.2005 vracejístejný mezisoučet. To je z hlediska, z něhož jsme dotazy psali naprosto logické, protože pro každý den zjišťujístav teprve po sečtení všech záznamů. Abychom to obešli, musíme jednotlivé záznamy od sebe nějak rozlišit asčítat tyto rozlišené záznamy. V praxi to nejspíš nebude žádný velký problém, protože tabulka, jako je tato, budemít téměř jistě nějaký klíč, třeba automaticky číslované řádky. Takže sem s ním!

alter table ucet add id int not null auto_increment primary key;

A přepišme naše dotazy tak, aby vzaly číslování řádků v úvahu. Ten první by mohl vypadat asi následovně:

select ucet.datum, ucet.castka, (select sum(vypocet.castka) from ucet as vypocet where vypocet.datum <= ucet.datum and vypocet.id <= ucet.id) from ucet order by datum;

a ten druhý takhle nějak:

select ucet.datum, ucet.castka, sum(vypocet.castka) from ucet join ucet as vypocet on ucet.datum>=vypocet.datum and ucet.id >= vypocet.id group by ucet.datum, ucet.castka order by ucet.datum;

Tím, že se údaje rozliší, již nehrozí, že by se provedl mezisoučet pro více než jeden řádek.

Pozn.:Člověk někdy podlehne dojmu, že by stačilo odlišit od sebe jednotlivé záznamy například podle znaménkanebo podle částky, a že by se k tomu nemuselo volat na pomoc automatické číslování. Jenomže není to tak.Kdybychom odlišovali částky podle znaménka, seskupily by se nám součty pro všechny příjmy a výdaje za den,ale opět by nebyly rozlišeny jednotlivé pohyby. Kdybychom seskupovali podle částky, mohl by vzniknout stejnýproblém v případě, když by v jeden den přišly nebo odešly dvě platby ve stejné výši.

A co akční dotazy?

Mohla by vzniknout otázka, zda se dají triky nastíněné v několika předchozích dílech seriálu použít rovněž kúpravě dat, nejen k jejich vybírání. To je dobrá otázka. Například, daly by se využít zkušenosti z tohoto dílu kzapsání zůstatků na účtu do samostatného sloupce? Mějme tedy sloupec zachycující zůstatek:

alter table ucet add column zustatek decimal (10,2);

Do něj se dají celkem elegantně přepsat zůstatky pouhou úpravou výběrového dotazu na akční:

update ucet join (select ucet.id, sum(vypocet.castka) as zustatek from ucet join ucet as vypocet on ucet.datum>=vypocet.datum and ucet.id >= vypocet.id group by ucet.id) vypocet on ucet.id = vypocet.id set ucet.zustatek = vypocet.zustatek;

Přiznám se ale, že se tato technika moc často nevyužívá a že ji příliš v lásce nemám. Důvod je velmijednoduchý - v praxi to nemá moc velký smysl. Kdybyste totiž chtěli na sloupec zůstatků spoléhat, musíte jejpřepočítat po každé změně tabulky - a to při větším množství záznamů může docela trvat.

Na druhou stranu se tato technika uchovávání výsledků výpočtů používá celkem často u "statických" snímkůdat, která pak slouží pro nějaké analýzy či rozhodování. Tam to potom funguje zhruba tak, že:

1. Z "ostrých" dat se pořídí kopie

Page 92: MySQL Obsah

2. Na ní se provedou výpočty a uloží se pomocné hodnoty na odpovídající místa (například, jak jsme viděli,hodnoty zůstatků do vlastního sloupce)

3. Výsledek se předloží člověku (nebo programu), který s tím pak pracuje jako s daty "jen pro čtení"

4. Po ukončení analýz se data zničí (nejsou již nejspíš aktuální)

5. V "ostré" databázi se mezitím vesele zapisuje dál.

To proto, že někdy je třeba vyhodnotit miliony záznamů - ostrý systém by to mohlo zatěžovat, ale malánepřesnost způsobéná tím, že máme kopii "pouze včerejších" dat nemusí vadit.

Page 93: MySQL Obsah

MySQL (31) - Indexy

Co to je, k čemu je to dobré a jak to funguje. Indexy v databázích a jejich tvorba v MySQL.

29.7.2005 07:00 | Petr Zajíc | přečteno 10262×

Komerční sdělení: Pořádáme Kurzy MySQL

Původně jsem se v dalším pokračování článku chtěl věnovat něčemu trochu jinému, ale dotazy čtenářů měpřesvědčily, že je čas podívat se na způsob, jakým se v MySQL pracuje s indexy. Protože ale někteří možnáneví, k čemu indexy v databází přesně slouží, začněmě nějakou tou teorií.

Co jsou indexy

Suchá definice praví, že index je pomocná datová struktura, která určuje pozici dat v tabulce na základě jejichhodnoty. Je to definice jak se patří, což znamená, že si pod ní většina lidí nepředstaví zhola nic ;-). Pojďme si topřirovnat k situaci z reálného světa. Představte si obrovskou knihovnu, do níž si přijdete půjčit nějakou tu detektivku. Kdyby knihy v knihovně nebyly nijak srovnány (neboli "indexovány"), nezbylo by vám nic jiného,než vzít do ruky každou knihu a podívat se, zda je to ta, kterou jste si chtěli půjčit. V podstatě ve stejné situacije databáze, když má vybrat data z tabulky, na níž není definován žádný index - musí zkrátka celou tabulkouprojít.

Jiná situace nastane, když budou knížky v knihovně srovnány, seřazeny. To vám potom může knihovnice říct,že "detektivky jsou vzadu vpravo", a vám zůstane na procházení mnohem méně knih. To je právě index -všimněte si, že určuje pozici dat ("vzadu vpravo") na základě jejich hodnoty ("detektivky"). V databázi sloužíindexy v podstatě ke stejné věci - k urychlení hledání mezi mnoha záznamy.

Z toho, co bylo řečeno, by se mohlo na první pohled zdát, že indexy by měly být v databázi skoro všude - vždyťje to dobrá věc. Jako ale všechno na světě, i indexy mají svou druhou stranu mince. Jakou? Vraťme se keznázornění s knihovnou. Když knihovna získá nové výtisky, musí je správně zařadit - detektivky na své místo atak dále - a to je mnohem pomalejší, než kdyby se knížky "házely na jednu hromadu" nebo by se dávaly do polictak, jak přijdou. Úplně stejné je to v databázích - pro akční dotazy (INSERT, UPDATE a DELETE) platí, žeindexy tyto operace obecně zpomalují.

Vícesloupcové indexy

V databázi není nutné mít index jen na jednom sloupci. Když se opět vrátím ke knihovně, může to být napříkladtak, že "detektivky jsou vzadu vpravo" a zároveň "detektivky zahraničních autorů jsou v polici nahoře". Vtakovém případě máme vlasně index na dvou hodnotách najednou, na "detektivkách" a "zemi původu". I vdatabázích se běžně pracuje s indexy, které pokrývají data ve více sloupcích - a říká se jim podle tohovícesloupcové indexy. Samozřejmě, že vícesloupcové indexy mají reálný význam pouze v případě, kdyvyhledáváme data pomocí hodnot v indexovaných sloupcích.

Page 94: MySQL Obsah

Více indexů na tabulce

Je třeba si rovněž uvědomit, že ve světě databází není problém mít více indexů na jedné tabulce - zapředpokladu, že se týkají jiných sloupců. Tady již analogie s knihovnou pokulhává, ale přesto to můžemeznázornit. Knihovnice může mít k dispozici katalog všech detektivek s jejich umístěním (bez ohledu na to, zdapocházejí z pera našich autorů nebo ze zahraničí), a zároveň může mít jiný katalog všech zahraničních knih vknihovně (bez ohledu na to, zda se jedná o detektivku nebo cokoli jiného). Podobně v tabulce můžete mít jedenindex na poli příjmení a úplně jiný index na poli rodné číslo.

Indexy a MySQL

Moderní databázové systémy - MySQL nevyjímaje - fungují tak, že index můžete vytvořit při definici tabulky(nebo i později) a databáze se pak o tento index stará. Když říkám "stará", tak to v praxi znamená dvě věci:

1. Databáze index udržuje platný. Při změně indexovaných dat se změní i příslušný index nebo indexy.Což, pochopitelně, stojí nějaký ten čas.

2. Databáze při požadavku na vrácení nebo úpravu dat rozhodne, zda je rychlejší použít pro tuto operaciindex nebo procházení tabulkou. Pokud dojde k závěru, že je to rychlejší, použije hledání dat pomocíindexů podobně, jako knihovnice, když vám hledá konkrétní publikaci podle nějakého katalogu.

V MySQL existují celkem čtyři typy indexů. Jsou to:

1. Ordinální indexy - to je jiný výraz pro klasický index tak, jak jsem jej popisoval.

2. Jedinečné indexy - indexy, které kromě své klasické funkce hlídají i to, aby se žádná z hodnot vindexovaném sloupci neopakovala. Nebo, aby se v případě vícesloupcového indexu neopakovalakombinace hodnot v indexovaných sloupcích. Na jedné tabulce smí být definováno více jedinečnýchindexů.

3. Primární klíč - primární klíč je jedinečný index na poli, v němž je každá hodnota jedinečná a žádnáhodnota není neznámá (NULL). Každá tabulka smí mít nejvýše jeden primární klíč.

4. Fulltextový index - slouží k prohledávání fulltextu a budeme o něm mluvit později v tomto seriálu.

Definovat index při založení tabulky můžete pomocí následující syntaxe:

create table knihy (nazev varchar (50), zanr varchar(50), index (zanr));

Máte-li existující tabulku, můžete do ní index přidat takto (v příkladu předpokládáme, že existuje tabulka knihale bez indexu):

alter table knihy add index (zanr);

Tyto příkazy způsobí, že od nynějška začne databáze udržovat index všech hodnot na sloupci "žánr", a to dokudindex neodstraníme. Pokud bychom toužili zbavit tabulku břímě indexu, poslouží nám k tomu syntaxe vesmyslu:

Page 95: MySQL Obsah

alter table knihy drop index zanr;

Tyto operace lze provést bez ohledu na to, zda a jaká data tabulka obsahuje. S existujícími daty se v žádnémpřípadě nic nestane.

Pozn.: Pozor na ty závorky. V prvním případě jsou, ve druhém nikoli. Tady se programátoři MySQL mocnevyznamenali, dodnes se mi to plete. Naštěstí se indexy neruší tak často, aby mi to stálo za zapamatování.

Obdobně jako ordinální index lze v tabulce definovat i unikátní (neboli jedinečný) index - pouze je třeba mysletna to, že se definuje klíčovým slovem UNIQUE namísto INDEX. Vytvoření probíhá takto:

create table knihy (nazev varchar (50), zanr varchar(50), unique (zanr));

přidání unikátního indexu do již existující tabulky takhle:

alter table knihy add unique (zanr);

Ale pozor - odstranění unikátního indexu probíhá stejně jako odstranění ordinálního indexu, takže ne DROPUNIQUE, ale DROP INDEX. U unikátních indexů je třeba pamatovat ještě na jednu věc - pokud se pokusímedefinovat unikátní index na sloupci, který již obsahuje data, a tento sloupec navíc obsahuje duplicitní údaje,příkaz pro vytvoření unikátního indexu selže. Na prázdné tabulce pochopitelně příkaz uspěje, protože taneobsahuje žádná data, natož nějaké duplicity.

V dalším díle seriálu se podíváme na primární klíče. Také si porovnáme výkon výběrových a aktualizačníchdotazů při použití indexů a bez nich, takže se máte na co těšit.

Page 96: MySQL Obsah

MySQL (32) - ještě k indexům

Jak je to v MySQL s primárními klíči? A jak rychlé či pomalé je pracovat s tabulkami, na nichž je nějaký tenindex? O tom je řeč v dnešním díle seriálu.

5.8.2005 07:00 | Petr Zajíc | přečteno 7323×

Komerční sdělení: Pořádáme Kurzy MySQL

V dnešním díle dokončíme rozbor toho, co pro MySQL znamenají indexy a podíváme se na slíbené testyrychlosti. Uvidíte, že použití indexů v praxi může výrazně zrychlit některé operace, jiné však může naopakvýrazně zpomalit.

Primární klíče

Z indexů nám zbývá podívat se na primární klíče. Připomenu z definice, že primární klíč je jedinečný klíč nasloupci, jež nesmí obsahovat hodnoty null a jež smí být v každé tabulce maximálně jeden. V praxi se téměř vždyk vytvoření primárního klíče používá sloupec s automatickým číslováním, protože tam jsou neprázdné hodnotyzajištěny již z principu. Takové pole vytvoříte pomocí příkazu ve stylu:

CREATE TABLE cislovani (id INT AUTO_INCREMENT, PRIMARY KEY (id));

Tato technika již byla v seriálu rozebrána, a to v díle Tipy ke tvrobě tabulek. Je ale třeba si uvědomit, žezatímco pole typu AUTO_INCREMENT musí být v MySQL definováno jako primární klíč, primárním klíčemNEMUSÍ být vždy automaticky číslované pole. Jestliže jste schopni zajistit unikátnost ve sloupci jinýmiprostředky než pomocí automatického číslování, můžete to udělat.

Pozn.: Praxe je ovšem taková, že sloupce zahrnuté v primárním klíči vetšinou pouze odlišují řádky, a nenesoužádnou jinou informaci, která se váže k datům. Proto většinou kombinace primárního klíče a automatickyčíslovaného pole bohatě postačí a není třeba vymýšlet nic jiného.

Rychlost operací s indexy

Abyste měli alespoň nějakou představu o tom, jak indexy zrychlují nebo zpomalují určité databázové operace, aaby seriál nebyl jen samá teorie, rozhodl jsem se udělat takový primitivní rychlostní test. Test spočívá v tom, žejsem si připravil soubor s určitým kvantem informací a ten se pokusím dostat do databáze. Budu přitom měřit,jak dlouho bude taková operace trvat - a na základě toho uvidíte, jak a co vlastě všechno indexy ovlivňují.

Aby byl test jednoduchý, připravil jsem si tabulku jen s jedním jediným sloupcem - bude do něj ukládáno celéčíslo. Pokud si něco takového chcete vyzkoušet, zadejte příkaz ve smyslu:

create table cisla (cislo int);

Page 97: MySQL Obsah

Následně jsem si připravil soubor s náhodnými čísly. Abych co nejméně ovlivnil výsledky měření, nepoužiljsem k tomu MySQL, ale nechal jsem si vygenerovat soubor obsahující jeden milión náhodných čísel pomocíkraťoučkého programu v jazyce Java

import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.Random; public class Rand { public static void main(String[] args) { Random generator = new Random(); StringBuffer buffer=new StringBuffer(); FileOutputStream fout; String separator = System.getProperty("line.separator"); int i; for (i=0;i<1000000;i++){ buffer.append(generator.nextInt()); buffer.append(separator); } try { fout = new FileOutputStream ("cisla"); new PrintStream(fout).print(buffer.toString()); fout.close(); } catch (IOException e){} } }

Pozn.: K tvorbě souboru s náhodnými čísly můžete samozřejmě použít jakýkoli programovací jazyk, kterýzvládá použití generátoru náhodných čísel a zápis do souboru. Původně jsem plánoval, že bych pro testovacíúčely svůj soubor s daty zveřejnil, ale byl by moc veliký. I přesto, že jsem jej zkoušel komprimovat.

Hromadné vkládání záznamů

MySQL obsahuje příkaz, pomocí něhož lze nahrát data z textového souboru do databáze. Protože jsme jej ještěv seriálu nerozebírali, zmíním se jen letmo o tom, že

load data infile './cisla' into table cisla;

nahraje obsah souboru cisla do naší právě vytvořené tabulky. To za předpokladu, že soubor je umístěn vadresáři, v němž má MySQL data pro právě používanou databázi a že jsme právě přepnuti v databázi, ježobsahuje tabulku cisla. Tento příkaz jsem změřil, výsledky jsou v tabulce níže. Postupoval jsem přitom tak, žejsem vytvořil pět souborů s náhodnými daty a vkládal je postupně jeden za druhým. Jestliže tabulku cislavyprázdníme a k poli cislo přidáme index,

truncate table cisla; alter table cisla add index (cislo);

a zkusíme příkaz pro vložení záznamů opakovat, zjistíme, že trvá déle, mnohem déle. Opět jsem celou akciopakoval pětkrát s tím, že jsem vložil první až pátou sadu s milionem náhodných čísel. Výsledky (které opětmáte v tabulce) poukazují na fakt, že přebudování indexů pochopitelně něco stojí.

Co kdybychom ale šli na celou věci jinak? Co kdybychom

1. Existující index zrušili,

2. Hromadně vložili data,

Page 98: MySQL Obsah

3. A následně znovu přidali k tabulce index?

Vložení dat v takovém případě bude trvat v podstatě konstatní dobu. Jak ale vidíme, zrušení a znovuvytvořeníindexu je až řádově rychlejší než jeho udržování během operace hromadného vkládání záznamů - a ten rozdíl jetím markantnější, čím více dat je v podkladové tabulce.

Vložení (bezindexu)

Vložení (sindexem)

Vložení s přebudováním indexuDROP

INDEXLOADDATA

ADDINDEX

CELKEM

První milionzáznamů

0,64 s 2,84 s 0,01 s 0,64 s 2,52 s 3,17 s

Další milion(celkem 2 mil.)

0,64 s 12,41 s 0,30 s 0,64 s 5,16 s 6,10 s

Další milion(celkem 3 mil.)

0,64 s 25,64 s 0,53 s 0,64 s 8,30 s 9,47 s

Další milion(celkem 4 mil.)

0,66 s 125,23 s 0,78 s 0,64 s 10,66 s 12,08 s

Další milion(celkem 5 mil.)

0,64 s 261,77 s 1,05 s 0,64 s 13,52 s 15,21 s

Výběr záznamů

Když už máme tak pěknou sadu dat, můžeme si ještě ukázat, jak indexy plní svůj původní význam - tedydohledávat data podle jejich hodnoty. Pokud máte na tabulce index, zrušte jej a zkuste si spustit následujícídotaz:

select * from cisla where cislo > 2000000000;

Na mém stroji tento dotaz trvá asi 1,45 s a to proto, že databáze musí tuto tabulku projít (data v tabulce totižnejsou nikterak seřazena - vždyť jsou to náhodná čísla). Stejný dotaz s použitím indexu však trvá pouhých 0,85s. protože databáze díky indexu ví, kde má hodnoty větší než dvě miliardy ve výsledné sadě záznamů hledat.

Závěr

Tyto rychlostní testy samozřejmě je třeba brát s jistou rezervou. Především proto, že neodrážejí skutečnéoperace, s nimiž se budete při práci s databází setkávat v praxi. Dále proto, že jsme měřili pouze rychlostprovedení dotazu, a ne již takové věci, jako je zatížení procesoru, spotřeba paměti a tak dále. Konečně, měřeníprobíhalo na mé pracovní stanici, kde bylo zároveň spuštěno několik dalších programů, takže výsledky budouzcela jistě nepřesné.

Nicméně, mohli jste si udělat představu o tom, jak indexy urychlují (či zpomalují) jednotlivé databázovéoperace.

Page 99: MySQL Obsah

MySQL (33) - Příkaz UNION

Tabulky všech zemí, spojte se! Nebojte, staré časy se nevrací, to jen v dnešním díle seriálu o MySQL bude řeč ospojování pomocí příkazu UNION.

12.8.2005 08:00 | Petr Zajíc | přečteno 9725×

Komerční sdělení: Pořádáme Kurzy MySQL

... aneb tabulky všech zemí, spojte se. Dnes bude řeč o technice spojování více sad záznamů do jedné, chcete-lisi to nějak představit. Může se jednat například o situaci, kdy budete chtít spojit současná data s historickýmizáznamy a podobně. Leč jako vždy, nejprve trocha teorie.

Příkaz UNION

Příkaz pro spojení dvou sad v jednu v MySQL dlouho chyběl. K nelibosti vývojářů, kteří na tuto techniku bylizvyklí z jiných DBMS. Od verze 4.0.0 je však tato funkce k dispozici. Jde o to, že se výsledky jednoho příkazuSELECT spojí s výsledky jiného příkazu, takže to naoko vypadá, jako by ani nepocházely z více zdrojů. Mohloby to vypadat nějak takto:

select id, nazev, autor from knihy union select id, nazev, autor from stare_knihy

Platí přitom, že obě "zdrojové" sady záznamů musejí mít především stejný počet polí. Takže, následující příkazskončí chybou "The used SELECT statements have a different number of columns":

select id, nazev, autor from knihy union select id, nazev from stare_knihy

protože se pokoušíme spojit sadu s třemi sloupci s jinou sadou, která má sloupce pouze dva. Aby to nebylo ažtak jednoduchá, tak navíc platí, že spojované sloupce by měly mít stejný datový typ. Pokusíte-li se spojit dvěsady záznamů a sloupce nebudou mít stejný datový typ, operace UNION selže.

Abych nemluvil pouze o omezeních - JE možné spojit dvě sady záznamů, kde v každé z nich se spojovaná polejinak jmenují (samozřejmě za předpokladuů uvedených výše). To znamená, že následující příkaz by mohl projít:

select id, nazev, autor from knihy union select stare_id, stary_nazev, stary_autor fromstare_knihy

Nabízí se otázka - jak se v takovém případě budou jmenovat sloupce výsledné sady záznamů? Odpověď jejednoduchá - budou se jmenovat tak, jak se jmenují sloupce první sady. V našem případě tedy id, nazev a autor.

Sloupce v příkazu SELECT nemusíte vyjmenovávat, můžete použít hvězdičkovou konvenci. Takže, i toto můžebýt platný UNION, pokud mají tabulky stejnou strukturu:

select * from knihy union select * from stare_knihy

Page 100: MySQL Obsah

Před tímto přístupem bych Vás však měl spíše varovat, než abych Vám jej doporučoval. Problém je v tom, žestačí změnit strukturu libovolné z oněch dovu tabulek a celé to přestane pracovat. Takže zásada - při použitípříkazu UNION více než kdy jindy vyjmenovávejte jednotlivé sloupce.

Doposud jsem mluvil pouze o spojování dvou tabulek. Příkazem UNIOIN však můžete spojit praktickylibovolný počet sad, takže se klíčové slovo UNION smí opakovat.

Problémy a omezení

Duplicity a UNION

Existuje jeden problém, s nímž se začátečníci používající příkaz UNION někdy potýkají, a tím problémem je, žeUNION jako výchozí chování odstraňuje duplicitní řádky z výsledné sady záznamů. A to bez ohledu na to, zdaduplicita pochází z jedné tabulky, nebo z různých tabulek. Toto chování Vám za prvé může vadit, a za druhé(logicky) zabere nějaký čas. Chcete-li se obojímu vyhnout, použijte namísto příkazu UNION příkaz UNIONALL.

select id, nazev, autor from knihy union all select id, nazev, autor from stare_knihy

V takovém případě máte jednak jistotu, že duplicitní řádky budou vráceny, a jednak dobrý pocit, že příkazproběhne o nějakou tu milisekundu rychleji než při použití "klasického" příkazu UNION. A většinou je to to, copotřebujete.

UNION a řazení záznamů

Výsledky vrácené příkazem UNION lze řadit tak, jako lze řadit každou jinou sadu záznamů, tedy pomocíklauzule ORDER BY v závěru příkazu. Mějme však na paměti, že tento příkaz nejprve spojí obě (či všechny)záznamy a teprve pak to celé seřadí. To je většinou to, co očekáváme. Pokud byste chtěli nejprve řadit a pakspojovat, mám pro Vás dobrou zprávu - i to MySQL umí. Podívejte se do manuálu, je to tam popsáno.

Pozn.: Za svou praxi jsem to ale ještě nepotřeboval, takže to berte spíše jako perličku než jako něco, co bysteměli doopravdy znát.

Použití

Spojení aktuální a archivní tabulky

Čas od času je k vidění technika, kdy se data zapsaná do nějaké tabulky po čase rozdělí - "čerstvá" data zůstávajív aktuální tabulce, "stará" data jsou pak v tabulce archivní. Pokud má archiv stejnou strukturu jako "živá"tabulka a potřebujeme data z obou, je UNION (resp. UNION ALL) to pravé ořechové pro náš dotaz. Tatotechnika bývá k vidění zejména u tabulek, které jsou velké a často modifikované na konci (napříkad se můžejednat o časově závislá statistická data).

Tvorba virtuální tabulky

Někdy potřebujeme (například do poddotazu a podobně) sestavit a použít virtuální, neexistující tabulku s vícenež jedním řádkem. V takovém případě může být mnohem rychlejší než vytvářet dočasnou tabulku použít něcojako:

Page 101: MySQL Obsah

select 1 as cislo union select 2 union select 3 union select 4 union select 5

(tabulka může mít samozřejmě i více než jeden sloupec). Jelikož MySQL s takovou "sadou" zachází jako skaždou jinou, může to nejen hodit, ale může to být rovněž velmi rychlé řešení.

Vzdáleně související data

Termínem "vzdáleně související data" mám na mysli taková data, která je obtížné nebo nemožné spojit pomocírelací. Může se jednat o data pro nějaký složitý kombinovaný report, o data obsahující jak podrobnosti tak isouhrny a podobně. I tady může být použití UNION namístě. Obyčejně se v takovém případě ještě dělá to, že sejeden sloupec vyhradí na identifikaci původní tabulky, protože to může být potřeba. Mám ny mysli něco jako:

select id, cas, 'vysledky' as tabulka from vysledky union all select id, cas, 'rekordy'as tabulka from rekordy

Jistě existují i další, specifičtější příklady použití UNION. Pokud o nějakém víte a chcete se s námi o nějpodělit, napište to do diskuse pod článkem.

Page 102: MySQL Obsah

MySQL (34) - větvení kódu a pivotní tabulky

Znát podmíněné příkazy v MySQL může přijít vhod. Zejména na šílenosti typu pivotních tabulek a souhrnů.Což je dnešní téma seriálu MySQL.

19.8.2005 07:00 | Petr Zajíc | přečteno 7886×

Komerční sdělení: Pořádáme Kurzy MySQL

Situaci, kdy je potřeba provést nebo neprovést určitý úsek kódu v závislosti na splnění podmínky budete znátspíše z "klasických" programovacích jazyků. Jak ale uvidíme v dnešním díle seriálu o MySQL, jde to použít i vdotazech, a leckdy to má docela opodstatnění. Tak či tak, znát příkazy pro rozbočení kódu může být docelaužitečné.

Větvení kódu v MySQL

Především je dobře si uvědomit, kdy se asi budou podobné hrátky s příkazy používat. Bude to v situacích, kdechceme vrátit (či změnit) data v závislosti na nějaké podmínce - nejčastěji v závislosti na datech jiných. Taknám například jeden a tentýž dotaz může vrátit různá data na základě toho, jaká hodnota je uvedena ve sloupci apodobně. Pro některé typy dotazů je to nepostradatelné.

Příkaz IF

Příkaz IF je obdobou ternárního operátoru, jaký známe z většiny programovacích jazyků. Obsahuje tři části.Vyhodnotí se podmínka (1. část), jestliže je splněna, je vrácen jako výsledek výraz ve druhé části, jestliže ne jevrácen výraz ve třetí části. Mohlo by to vypadat nějak takto:

select jmeno, if (plat>15000,'nadprůměrný','podprůměrný') as plat from pracovnik

V případě jednoduchých rozhodování tento příkaz přes svoji úspornost jistě postačí. Může to ušetřit následnézpracování "řádek po řádku" v nějaké aplikaci, která bude tato data konzumovat. Samozřejmě, že podobnoukonstrukci lze použít nejen v příkazu SELECT, ale třeba i v UPDATE.

Příkaz IFNULL

Zvláštním případem jednoduchého větvení budiž příkaz IFNULL. Ten má dva argumenty. Pokud ten první jerovnen hodnotě NULL, je vrácen druhý, jinak první. To se často hodí v případě, kdy sloupec smí obsahovathodnoty NULL, ale my je v daném případě chceme nahradit nějakou jinou hodnotou. Kdyby směl sloupec platobsahovat hodnoty NULL a my je chtěli nahradit nulou, šli bychom na to takto:

SELECT jmeno, IFNULL(plat,0) AS plat FROM pracovnik

Page 103: MySQL Obsah

Což je mimochodem rovnocenné zápisu

SELECT jmeno, IF(plat is null,0,plat) AS plat FROM pracovnik

Co k tomu dodat? Snad jen že existuje i funkce NULLIF, která funguje poněkud jinak a v praxi se téměřnepoužívá. Její popis byste našli v manuálu k MySQL. Ano, a ještě to, že některé DBMS mají funkci IFNULLnazvánu ISNULL, takže se mi to neustále plete.

Příkaz CASE

Case umí větvit kód na více částí a navíc má dvě syntaktické formy. Tudíž je nejsložitější z uvedených příkazůpro větvení. Zase toho ale nejvíc umí a poměrně často se používá. První forma je tzv. "rozhodovací" a vypadátakto:

SELECT JMENO, CASE WHEN PLAT < 12000 THEN 'málo' WHEN PLAT > 12000 AND PLAT < 15000 THEN 'středně' WHEN PLAT > 15000 THEN 'ujde to' END as PLAT FROM pracovnik

Druhá, "prohledávací" pak vypadá nějak takhle

SELECT JMENO, CASE STATUS WHEN 1 THEN 'zaměstnán' WHEN 2 THEN 'propuštěn' WHEN 3 THEN 've zkušební době' ELSE 'neznámý' END from pracovnik

Jak vidíte, její typické použití je právě ve spojení s "překladem" jednoduchých "stavových" informací na jejichsrozumitelné protějšky.

Praxe

Pro použití těchto konstrukcí v praxi bych měl několik tipů, které se Vám možná budou hodit. Především - snástroji pro větvení kódu je třeba zacházet opatrně. Mějte na paměti, že použití mnoha (zejména vnořených)konstrukcí CASE nebo IF může kód poněkud znepřehlednit. V příkladech "prohledávacího" typu CASE je navícmožné stavové informace uložit do samostatné tabulky a potom to spojit pomocí relace - odpadá tak nutnostúpravy v kódu v případě, kdy by se přidávala nová větev (nový stav).

Ještě jeden tip z praxe - kdekoli je to možné, hodí se zdrojové kódy SQL obsahující větvení formátovat, abybyly hezky čitelné. Sám jsem se o to v příkladech výše snažil.

Pivotní tabulky

Pomocí příkazu CASE se lehce dají vytvořit pivotní tabulky, tedy takové pohledy na data, které shrnují"řádkové" výsledky do sloupců. Než bych to dlouhosáhle vysvětloval, raději to předvedu na příkladu. Mějmetabulku vystavených faktur

create table faktury (datum date, castka decimal(10,2)); insert into faktury (datum, castka) values('20040101', 2200); insert into faktury (datum, castka) values('20040201', 2600);

Page 104: MySQL Obsah

insert into faktury (datum, castka) values('20040301', 2500); insert into faktury (datum, castka) values('20040501', 3800); insert into faktury (datum, castka) values('20040701', 4200); insert into faktury (datum, castka) values('20040806', 2100); insert into faktury (datum, castka) values('20040901', 2300); insert into faktury (datum, castka) values('20040906', 2800); insert into faktury (datum, castka) values('20041001', 3100); insert into faktury (datum, castka) values('20050101', 4000); insert into faktury (datum, castka) values('20050201', 5000); insert into faktury (datum, castka) values('20050301', 5500); insert into faktury (datum, castka) values('20050501', 4200); insert into faktury (datum, castka) values('20050701', 4800); insert into faktury (datum, castka) values('20050806', 6100); insert into faktury (datum, castka) values('20050901', 3200); insert into faktury (datum, castka) values('20050906', 2200); insert into faktury (datum, castka) values('20051001', 8500);

a šéfa. Ten jednoho krásného dne přijde s tím, že chce výsledky ve formě tabulky, kde každý řádek budeobsahovat data za jeden rok a sloupce budou obsahovat součty pohybů za jednotlivé měsíce. Tento požadavekse v mnoha obměnách opakuje v nejrůznějších aplikacích, takže následující postup se docela vylatí znát. Dotazbude vypadat nějak takto:

select rok, sum(case when mesic=1 then castka else 0 end) as 'leden', sum(case when mesic=2 then castka else 0 end) as 'únor', sum(case when mesic=3 then castka else 0 end) as 'březen', sum(case when mesic=4 then castka else 0 end) as 'duben', sum(case when mesic=5 then castka else 0 end) as 'květen', sum(case when mesic=6 then castka else 0 end) as 'červen', sum(case when mesic=7 then castka else 0 end) as 'červenec', sum(case when mesic=8 then castka else 0 end) as 'srpen', sum(case when mesic=9 then castka else 0 end) as 'září', sum(case when mesic=10 then castka else 0 end) as 'říjen', sum(case when mesic=11 then castka else 0 end) as 'listopad', sum(case when mesic=12 then castka else 0 end) as 'prosinec' from ( select year(datum) as rok, month(datum) as mesic, sum(castka) as castka from faktury group by year(datum), month(datum) ) as soucty group by rok

Všimněte si, že data za jednotlivé měsíce jsou nejprve sloučena v poddotazu, a ten je ve "vnějším" dotazupoužit jako zdroj. Výhoda tohoto přístupu je jasná - dotaz seskupí data pro libovolný počet let a navíc v jednomměsíci může být libovolný počet pohybů (včetně žádného). Jen je ten kód trochu nudný na psaní.

Page 105: MySQL Obsah

MySQL (35) - vestavěné funkce

Pojďme se dnes souhrnně podívat na funkce, které máte v MySQL při psaní kódu SQL k dispozici.

26.8.2005 07:00 | Petr Zajíc | přečteno 9638×

Komerční sdělení: Pořádáme Kurzy MySQL

Napsat tento díl seriálu nebylo jednoduché. Články popisující funkce nějakého databázového produktu sevětšinou smrsknou buď na nezáživné opisování manuálu, nebo na nepřehlednou změť různých příkladů. Vědomsi podobných úskalí pokusil jsem se sepsat v tomto článku jen funkce, které byste opravdu mohli potřebovat ana zbytek věcí odkážu čtenáře do manuálu.

Vestavěné funkce

Na co funkce použijete? Nemám to ověřené, ale asi nejčastěji pro operace nad vracenými sloupci v příkazuSELECT. Uvědomte si, že část příkazu SELECT počínaje FROM je nepovinná, a tudíž si některé funkcemůžete v MySQL vyzkoušet, aniž byste vůbec měli v databázi nějakou tabulku! Všechny následující příkladyjsou syntakticky platné:

select 1+2; select avg (plat) from (select 10000 as plat union select 20000 as plat union select16000 as plat) platy; select concat('Linux','soft');

Funkce, které budete používat lze alespoň zhruba rozdělit do skupin. S některými jsme se navíc seznámili vtomto seriálu průběžně, takže to pro někoho bude již opakování. V zásadě tedy existují následující skupinyfunkcí:

Funkce pro práci s řetězciFunkce Příklad Vrátí Kdy použítLCASE, LOWER,UCASE, UPPER

LCASE('NA mAlá') 'na malá' například při vyhledávání nezávislémna velikosti písmen

LEFT, RIGHT LEFT('Linuxsoft',5) 'Linux' ukládání dat omezené délky nebojejich vracení, práce s prefixy čisuffixy

LTRIM, RTRIM,TRIM

TRIM(' Linuxsoft ') 'Linuxsoft'

Odstranění mezer, formátování; TRIMtoho však umí více

LENGTH LENGTH('MySQL') 5 Práce s řetězci, zejm. ve spojení sLEFT a RIGHT

Page 106: MySQL Obsah

SUBSTRING SUBSTRING('okolo',2,3)

'kol' Extrakce obsahu řetězce

Na těchto funkcích není nic zvláštního, používají se víceméně stejně v mnoha programovacích jazycích i SQLdialektech, a tak vám snadnou přejdou do krve. MySQL nabízí ještě celou řadu dalších funkcí pro řetězce, ježmůžete najít v manuálu.

Funkce pro zpracování číselFunkce Příklad Vrát

íKdy použít

Základníaritmetika (+,-,*,/)

SELECT2+3*4

14 Na každém kroku ;-)

Celočíselné dělení SELECT 10DIV 4

2 Např. čísla mezi 100000 - 199999 mají SELECTCISLO DIV 100000 rovno jedné

CEIL, FLOOR,ROUND

SELECT CEIL(10.5)

11 Zaokrouhlování. Převod reálných čísel na celá

RAND RAND() ??? Tvorba náhodných čísel. Rovněž sad náhodných čísel.Také výběr náhodných dat, viz manuál.

Nevyjmenoval jsem goniometrické funkce a některé speciální. Opět platí, že si je lze najít v odpovídající částimanuálu. Matematické funkce budete samozřejmě využívat dost často. S tím, že provádění základních operací(sčítání, násobení) na serveru může být mnoem rychlejší, než dělat to potom při procházení výsledné množinyzáznamů řádek po řádku.

Funkce pro datum a čas

Je dost možné, že zjistíte, že MySQL je poměrně dobře vybavená funkcemi pro zpracování data a času. Tak čitak, následující tabulka vám některé častěji používané funkce předvede.

Funkce Příklad Vrátí Kdy použítCURDATE() SELECT CURDATE() čas

provedeníNapříklad chcete-lisledovat čas pořízenízáznamu

DATE_ADD SELECT DATE_ADD('20040227',INTERVAL 3 DAY)

1. březen2004

Pro sčítáníkalendářních dat.Respektuje přechodnéroky, takže vždypoužívejte tuto funkcinamísto odvozování aručních přepočtů

DATEDIFF SELECT DATEDIFF('20040301','20040227')

3 Zjištění rozdílu mezikalendářními daty.Pouor, vrací narozdílod jiných DBMSpouze rozdíl ve dnech.

Page 107: MySQL Obsah

YEAR(),MONTH(),DAY()

SELECT DAY('20050502') 2 "Vytáhne" informace očásti kalendářníhodata. Analogickéfunkce existují i pročas. Obyčejně jevhodnější použítkonstrukci BETWEENdatum1 AND datum2než extrahovat měsíc arok

DATE_FORMAT SELECT DATE_FORMAT(CURDATE(), '%d.%m.%y')

něco jako25.08.05

Různě formátovanédatum. Na jednustranu pomůžerespektovat národníspecifika, na stranudruhou ztěžujelokalizaci. Používattedy s rozvahou.

Agregační funkce

Většinu agregačních funkcí jsme již poznali. Mezi agregační funkce MySQL patří SUM, AVG, COUNT, MIN,MAX a některé další. Jejich popis je opět obsažen v manuálu, těchto pět by však pro běžnou práci mělo stačit.

Jiné

Je dobré vědět, že o některých funkcích jsem se nezmínil. Patří mezi ně funkce informační, šifrovací a funkcepro práci s regulárními výrazy. Také funkce pro fulltextové vyhledávání tvoří zajímavou kapitolu MySQL. Oněkterých těchto rysech se zmíníme v seriálu jindy, protože nepochybně vydají na samostatný díl.

Když vestavěné nestačí

MySQL, stejně jako řada jiných DBMS umožňuje napsat vlastní funkce a volat je z kódu jazyka SQL v případě,že vám vestavěné funkce nestačí (nebo je dokážete napsat rychleji). Postup, jak takovou funkci sestavit azačlenit do serveru je popsán v manuálu k MySQL. Zajímalo by mě, jestli se někdo z čtenářů dostal do situace,kdy mu vestavěné funce nestačily a napsal si vlastní (podělte se s námi v diskusi). Přestože psaní vlastníchfunkcí může být zábavné, nezapomínejte na to, že tím ztížíte proces distribuce projektu - kromě MySQL se budemuset na cílový server nainstalovat i nová funkce.

Page 108: MySQL Obsah

MySQL (36) - Regulární výrazy

Když se sestavovala osnova tohoto seriálu, vyžádali si čtenáři zvláštní díl na regulární výrazy. Nuže, toto jeston.

2.9.2005 07:00 | Petr Zajíc | přečteno 7573×

Komerční sdělení: Pořádáme Kurzy MySQL

Jedním z největších překvapení při mém přechodu na Linux kdysi bylo, s jakou silou a razancí se všudepoužívají regulární výrazy. Upřímně mě to nadchlo, protože je to elegantní, rychlé a výkonné řešení. Ne snad žeby regulární výrazy byly vždy "to nej" nebo že by byly samospasitelné - ale přinejmenším se vyplatí o nichvědět. Pronikly i do MySQL, a právě o tom bude dnešní článek.

Regulární výrazy

Pokud byste dostatečně nevěděli, co to regulární výrazy jsou, pak vězte, že se jedná o nástroje pro vyhledávánítextu (případně jeho nahrazování) pomocí důmyslných pravidel a zástupných znaků. Než bych se pokoušel onějakou vzletnou a nicneříkající definici, poskytnu raději dychtivým čtenářům několik odkazů, které je zasvětí apřejdu rovnou k myšlenkám, týkajícím se MySQL. Takže, o regulárních výrazech se můžete něco málodozvědět:

Ve wikipedii

V seriálu, který kdysi vycházel na root.cz

U nás třeba v "sesterském" seriálu o PostgreSQL

Rovněž o nás v souvisejícím díle série o PHP

MySQL a regulární výrazy

V MySQL jsou regulární výrazy zastoupeny de facto jedinou funkcí, a to REGEXP. Opravdoví znalci namítnou,že existuje ještě funkce NOT REGEXP (což je pravda), a funkce RLIKE a NOT RLIKE (ty jsou alesysnonymem funkcí REGEXP a NOT REGEXP). Zapište si za uši, že MySQL má pouze nástroje provyhledávání podle regulárních výrazů, nikoli však odpovídající nástroje pro změnu dat. Nic takového, jako jenapříklad PHP funkce ereg_replace v MySQL nenajdete.

Page 109: MySQL Obsah

Abych nebyl jen negativní - pro účely vyhledávání může být REGEXP poměrně užitečný. Z tabulkyzaměstnanců:

create table pracovnik (prijmeni varchar(20), jmeno varchar(15)); insert into pracovnik (prijmeni, jmeno) values ('Zajíc','Petr'); insert into pracovnik (prijmeni, jmeno) values ('Zajícová','Veronika'); insert into pracovnik (prijmeni, jmeno) values ('Novák','Josef'); insert into pracovnik (prijmeni, jmeno) values ('Procházka','Karel'); insert into pracovnik (prijmeni, jmeno) values ('Horáková','Jana'); insert into pracovnik (prijmeni, jmeno) values ('Nováková','Marie');

můžete například vybírat podle sloupce prijmeni s pomocí regexp lidi, jejichž příjmení obsahuje písmeno "a"takto:

select * from pracovnik where prijmeni regexp 'a';

Lidi, jejichž příjmení končí na "ová" zase můžete najít pomocí následujícího kódu (Novák tam nebude, protoženekončí na "ová"):

select * from pracovnik where prijmeni regexp 'ová$';

Nebo lidi, jejichž příjmení začíná na "Z" a končí na "c" zjistíte takhle:

select * from pracovnik where prijmeni regexp '^Z.+c$';

Jak to obejít

Přestože jsou regulární výrazy mnohem mocnější než to, co jsem předvedl, dají se leckdy přepsat pomocíoperátoru LIKE a tak se jim můžete úplně vyhnout. Uvádím to proto, že pro mnohé z nás je syntaxe LIKEdaleko pochopitelnější než regulární výrazy. V porovnání LIKE existují pouze dva zástupné znaky - "%"(procento) zastupuje libovolné množství znaků (včetně žádného) a "_" (podtržítko) zastupuje právě jeden znak.Dotazy výše by se tedy v tomto případě daly všechny přepsat:

select * from pracovnik where prijmeni like '%a%'; select * from pracovnik where prijmeni like '%ová'; select * from pracovnik where prijmeni like 'Z%c';

Pozn.: Není to tak úplně přesné. Výraz "zc" by v posledním případě s použitím LIKE prošel, ale s použitímregexp nikoli (neobsahuje mezi "z" a "c" žádné další znaky, ale měl by). Z toho je vidět, že regulární výrazyjesou mnohem mocnější než like a také to, že při přepisu regexp na like je třeba dávat si pozor.

Rychlost zpracování regulárních výrazů

Panuje názor, že provedení regulárního výrazu je mnohem pomalejší než porovnání pomocí LIKE. Něcotakového je logické, protože regulární výrazy jsou mnohem komplikovanější než prosté porovnání sezástupnými znaky. Abych Vám pomohl udělat si představu o tom, jaký je to rozdíl, a abych vás naučil testovatdobu provádění funkcí v MySQL, představím Vám v tomto díle seriálu ještě informační funkci BENCHMARK.

MySQL funkce BENCHMARK je sama o sobě k ničemu, protože vrací vždy nulu. Slouží pouze k tomu, abyzopakovala předaný příkaz s předaným počtem opakování. Co nás opravdu zajímá je fakt, jak dlouho takováakce bude trvat. Jelikož mysql vrací dobu potřebnou k vykonání posledního příkazu, můžeme pomocíBENCHMARK spustit x-krát danou funkci a změřit, jak dlouho to celé bude trvat. Takže milionkrát spustímtest s LIKE:

SELECT BENCHMARK(1000000,'Zajic' LIKE 'Z%c');

a milionkrát spustím test s regexp:

Page 110: MySQL Obsah

SELECT BENCHMARK(1000000,'Zajic' regexp '^Z.+c$');

a výsledek? Průměr ze tří testů ukázal, že milionkrát porovnání pomocí LIKE trvalo 0,5 vteřiny, kdežtomilionkrát porovnání pomocí regexp trvalo 1,5 vteřiny. Můžeme tedy prohlásit, že v tomto případě bylo použitíregulárních výrazů zhruba třikrát pomalejší.

Pozn.: Testy tohoto typu by se však neměly brát jako dogma. Nezapomínejte, že stěží budete porovnávat vreálné aplikaci milionkrát za sebou regulární výraz. V praxi zřejmě rozdíl ve výkonu LIKE vůči REGEXP vůbecnepocítíte. Měli byste však vědět, že je to pomalejší a že pomocí funkce BENCHMARK to lze změřit.

Page 111: MySQL Obsah

MySQL (37) - použití fulltextového vyhledávání

MySQL (37) - MySQL umí vyhledávat fulltextem. Co to je, k čemu topoužít a na co dát pozor se dozvíte v dnešním díle seriálu.

9.9.2005 07:00 | Petr Zajíc | přečteno 10968×

Komerční sdělení: Pořádáme Kurzy MySQL

Nástroji, které se dají použít pro fulltextové vyhledávání se jednotlivé databázové systémy liší, někdy dostipodstatně. V případě MySQL mám pro Vás dobrou zprávu - tato databáze umí používat fulltext a jde jí tocelkem dobře. Fulltextové vyhledávání bude námětem dnešního článku. Protože (zejména při spolupráciMySQL, nějakého skriptovacího jazyka a webu) se Vám tato funkce může velice hodit, rozebereme si jipoměrně podrobně, hned ve dvou dílech. Nejprve však mi dovolte nastínit něco teorie.

Fulltextové vyhledávání

Podle definice je fulltext "metoda vyhledávání textu uvnitř dokumentů". Jako klasický příklad se uvádí situace,kdy máte k dispozici sadu textů (možná umístěných v síti internet, na disku a podobně) s různými tématy ajediný cíl - najít text, který se bude zabývat vyhledávaným slovem, slovním spojením nebo frází. Většina definicjedním dechem dodává, že v databázích se k realizaci fulltextového vyhledávání používá speciální typ indexu.

Typickou fulltextovou funkci tedy "nakrmíte" seznamem prohledávaných textů a hledaným výrazem.Výsledkem je (nejčastěji) číslo, kterému se říká relevance (český ekvivalent závažnost nebo váha se vodborných kruzích moc neujal) a které uvádí pravděpodobnost, že prohledávaný článek obsahuje to, po čemjsme pátrali. Velice častým výstupem je potom seřazení výsledků sestupně podle relevance (tedynejpravděpodobnější výsledky nejvýše).

Fulltextové vyhledávání plní trochu komplexnější úlohu než funkce pro práci s textem vyhledávající jedenřetězec v jiném (v MySQL představované třeba řetězcovou funkcí INSTR). Fulltext totiž umí při vyhledávánízohlednit četnost vyhledáváných slov v daném textu, jejich vzájemnou vzdálenost a podobně. Existují dokoncenástroje pro jemné doladění prohledávání - třeba příkaz pro "umělé" snížení relevance některého z hledanýchslov.

Fulltext a MySQL

To, co jsme uvedli v definici platí i pro MySQL - s jistými omezeními. Měli byste ale vědět, že v praxi anisebelepší fulltext není všemocný. Pokud se budete pohybovat v česko-slovenských vodách, měli byste vědět, žev souvislosti s použitím fulltextu v MySQL můžete pěkně narazit na:

Page 112: MySQL Obsah

diakritiku. Ne snad, že by si fulltextové vyhledávání s diakritikou neumělo poradit. Spíše ale budeteprohledávat texty (například diskuse k článkům), v nichž někdo diakritiku používá a někdo ne. Slovokočička tak nebude vůbec odpovídat slovu kocicka.

skloňování. Slovo kočička nebude MySQL považovat za stejné jako výraz kočiček, takže v tomtopřípadě obdržíte při vyhledávání takové výsledky, jako by se jednalo o dvě naprosto různá slova.

Pozn.: V této souvislosti je zajímavé vědět, že existují fulltextové vyhledávače, které skloňování umí. Ne však vMySQL; takové nástroje patří mezi velmi pokročilé a používají se především u internetových vyhledávačů. Aještě doplním, že technologie za většinou vyhledávačů je mnohem komplexnější, než aby obsahovala "pouhý"fulltext.

Při používání fulltextu v MySQL byste měli vědět o dalších omezeních, které je nutné vzít v úvahu. Patří mezině:

1. Fulltextové vyhledávání lze (celkem logicky) používat pouze u sloupců obsahujících řetězce (tedyCHAR, VARCHAR nebo TEXT)

2. Fulltextové vyhledávání nerozlišuje velikost znaků. To však lze obejít tím, že je sloupec definován sklíčovým slovem BINARY - pak je brána v úvahu i velikost písmen.

3. Fulltextové vyhledávání lze použít u MySQL pouze tehdy, pokud jsou prohledávané tabulky typuMyISAM. O typech MySQL tabulek jsme ještě v tomto seriálu nehovořili, takže vám jen poskytnu linkna oficiální dokumentaci a nechám to na jindy.

4. To, že daná tabulka má "umět" fulltextové vyhledávání lze určit již při její definici, nebo kdykolipozději. Vzhledem k tomu, že MySQL používá pro zajištění fulltextového prohledávání tabulek index,platí pravidlo, které jsme již rozebírali - při hromadném nahrávání dat se vyplatí případný index zrušit,nahrát všechna data a pak jej znovu vytvořit. Je to mnohem rychlejší než plnit masivně daty tabulku,která už nějaký fulltextový index obsahuje.

5. Jelikož je fulltext realizován indexem, můžete v MySQL touto metodou prohledávat více sloupcůnajednou (pomocí indexu vytvořeného na více sloupcích).

6. Jelikož je fulltext realizován indexem, můžete mít v jediné tabulce i více fulltextových indexů. To semůže hodit - jednou budete chtít vyhledávat například podle textu článku, jindy i podle jména autora čiperexu.

7. Jelikož je fulltext realizován indexem, nemůžete v MySQL bohužel fulltextem vyhledávat datapocházející z více než jedné tabulky. To může nasazení fulltextu pro některé projekty zhola znemožnit,protože existující data mohou být ve více souvisejících tabulkách.

Aby těch omezení nebylo málo, platí pro práci s fulltextem v MySQL i další "pravidla hry".

Page 113: MySQL Obsah

1. Fulltextové vyhledávání funguje smysluplně pouze pro větší počet záznamů. Tabulku s jednímzáznamem nelze smysluplně fulltextovat.

2. Slova kratší než 4 písmena jsou z fulltextového vyhledávání vypuštěna. Takže, výraz pes si fulltextověnevyhledáte. (U verze databáze 4.0 nebo vyšší lze ovšem minimální délku slova pro zahrnutí do fulltextunastavit)

3. Existuje seznam tzv. "stop slov", která jsou často používána a která jsou z vyhledávání vyloučena. Patřímezi ně například anglický člen the. Seznam lze upravit.

4. Dále, existuje pravidlo "padesátiprocentního prahu". To stanoví, že slova, která se vyskytují ve více než50% prohledávaných záznamů jsou z fulltextování vyloučena. To lze "vypnout" přepsáním zdrojovéhokódu MySQL a rekompilací nebo obejít pomocí alternativní metody práce s fulltextem

5. Konečně, verze MySQL 4.0.1 a vyšší obsahují tzv. BOOLEAN MODE fulltext, který umožňujemnohem pokročilejší práci s fulltextem a který vám rozhodně příště předvedu.

Vytvoření fulltextového indexu

Mějme v MySQL tabulku obsahující sloupce CHAR, VARCHAR nebo TEXT. Klasicky se fulltextovévyhledávání předvádí na fragmentu nějakého webového redakčního systému - je to sice poněkud otřepané, aletypické, takže se toho budu rovněž držet.

create table clanky (nazev varchar (50), zneni text);

Na této tabulce můžete vytvořit fulltextový index takto:

alter table clanky add fulltext (zneni);

a/nebo, pokud bychom byli dychtivi vyhledávání rovněž v názvech článků, lze definovat jiný fulltext

alter table clanky add fulltext (nazev, zneni);

Oba fulltextové indexy mohou existovat na tabulce současně. Dost to zpomalí aktualizaci tabulky, ale umožní tovyhledávat výrazy jak v článku, tak v kombinaci článek + název.

Pozn.: Hořekování nad pomalostí změny dat v tabulkách však leckdy nemá u fulltextových vyhledávání valnývýznam. Často se touto metodou zpracovávají data, která se mění jen jednou nebo zřídka (jako třeba právěčlánky v databázi redakčního systému) a právě u nich je ztráta času při vložení záznamů snesitelná.

Tento díl seriálu byl jen teoretický (pro někoho možná až příliš). Nicméně příští díl bude nabit praktickýmiukázkami vyhledávání, takže se máte na co těšit. Ukážeme si, jak vyhledávat fulltextově v rozsáhlých datech -ještě prozradím, že to budou opravdu data "ze života", takže doufám, že to bude pro čtenáře přínosné.

Page 114: MySQL Obsah

MySQL (38) - Fulltext a praxe

Příklady na použití fulltextu v MySQL.

16.9.2005 07:00 | Petr Zajíc | přečteno 10631×

Komerční sdělení: Pořádáme Kurzy MySQL

V tomto díle seriálu nebude žádná teorie. Opravdu. Slibuji.

Testovací data

Fulltextové vyhledávání se nejlépe zkouší na nějakých smysluplných datech, a k tomu nejlépe, když jich je"větší než malé množství". Mějme tedy následující tabulku:

create table clanky (id int not null auto_increment, cislo int, zneni text, primary key(id));

s následujícím fulltextem

alter table clanky add fulltext (zneni);

Najít smysluplná data na internetu také není problém, já jsem tabulku naplnil údaji ze sesterského seriálu o PHPtímto triviálním PHP skriptem:

<?php $idclanku=Array(1=>171,172,173,176,177,178,179,180,181,183, 188,192,199,204,205,206,212,217,229,234, 252,257,264,269,270,274,292,296,297,303, 310,321,325,328,329,336,337,344,345,357, 361,366,368,369,375,408,414,420,422,425, 430,436,440,443,444,457,459,462,467,475, 484,488,492,502,504,514,517,523,524,538, 543,545,551,556,557,564,567,572,574,580, 587,588,609,613,617,623,626,629,635,636, 642,644,646,651,657,658,663,666,670,674 ); function textclanku($clanek){ global $idclanku; $id=$idclanku[$clanek]; $url="http://www.linuxsoft.cz/article.php?id_article=$id"; ob_start(); readfile ($url); $textclanku = ob_get_contents(); ob_end_clean(); $textzacatku="<h2><img src=\"img/sipka1.png\" width=\"15\" height=\"15\"alt=\"&gt;\">";

Page 115: MySQL Obsah

$textkonce="<div class=\"links\">"; $zacatek=strpos($textclanku,$textzacatku); $konec=strpos($textclanku,$textkonce); return substr($textclanku,$zacatek,($konec-$zacatek)); } mysql_connect("localhost","root","") or die (mysql_error()); mysql_select_db("test"); mysql_query("SET NAMES 'utf8'"); for ($i=1; $i<=count($idclanku);$i++) { $sql="insert into clanky (cislo, zneni) values (".$idclanku[$i].",'".mysql_escape_string(textclanku($i))."')"; mysql_query($sql)or die (mysql_error()); } ?>

Pozn.: Pokud zrovna neholdujete PHP, nezoufejte. Je to jen na okraj. Tento skriptík definuje stočlenné polehodnot, jehož každý člen obsahuje identifikátor článku ze seriálu o PHP na našem serveru. Toto stočlenné poleje postupně procházeno, jednotlivé články se stahují a ukládají se do tabulky, kterou jsme vytvořili. Zabývaljsem se tím jen proto, abych získal pro fulltextové vyhledávání nějaká smysluplná data.

Vyhledáváme!

Takže, teď již máme opravdu vše pro vyhledávání fulltextem. K tomu slouží v MySQL funkce MATCH. Jejínejjednodušší použití je následující:

select * from clanky where match (zneni) against ('substr');

Tento kód vybere ze seznamu článků ty, které obsahují hledanou frázi - substr (to je jedna z funkcí jazyka PHP).Přestože to z příkazu přímo nevyplývá, tento příkaz vrátí výsledky sestupně podle relevance. To totiž funkceMATCH v klauzuli WHERE bez uvedení implicitního řazení udělá vždy. Přestože je relevance pouze hodnotasloužící k porovnávání, můžeme ji do výsledků zahrnout - to by potom mohlo vypadat nějak takto:

select *, match (zneni) against ('substr') from clanky where match (zneni) against('substr');

Pozn.: Mohlo by se zdát, že to zatíže server, protože ten bude muset provést řazení dvakrát. Nicméně není totak, podle dokumentace optimalizátor dotazů tuto situaci rozpozná a fulltextové prohledávání provede pouzejednou.

Stejně tak by nebyl problém vyžádat si povinné seřazení položek - třeba podle relevance vzestupně. Sice by toznamenalo, že nejpravděpodobnější výsledky budou vráceny až naposled, ale syntakticky je to možné.Odpovídající příkaz by byl:

select *, match (zneni) against ('substr') from clanky where match (zneni) against('substr') order by match (zneni) against ('substr');

Všimněte si rovněž, že příkaz

select * from clanky where match (zneni) against ('PHP');

žádné řádky nevrátí. Uplatní se zde pravidlo padesátiprocentního prahu, protože fráze "PHP" se objevuje vevětšině článků a je tudíž vyhodnocena jako nepoužitelná. Všechny příklady jsem dosud uváděl s tím, že hledanáfráze obsahovala jen jedno slovo - to pro jednoduchost. Ve skutečnosti je spíše typické hledat slovní spojení.Takže, vypadalo by to nějak takto:

select * from clanky where match (zneni) against ('PHP ve spolupráci s apache');

Page 116: MySQL Obsah

Právě v tom je síla fulltextu - naprogramování něčeho podobného "ručně" by vám nejspíš zabralo hodně času aúsilí. K tomuto příkladu bych ještě připomněl, že slova "ve" a "a" budou z fulltextového vyhledávání vypuštěna,protože jsou příliš krátká.

Boolean mode

To není všechno. MySQL umožňuje ještě mnohem pokročilejší techniky fulltextového prohledávání. Databázilze přikázat:

Která slova v hledaném textu musejí být

Která slova v hledaném textu nesmějí být

Která slova budou při vyhledávání mít větší (nebo menší) relevanci než tu, kterou by jim přiřadil počítač

Která slovní spojení musejí být obsažena doslovně

Některé další funkce pro zpřesnění vyhledávání.

Ke všemu tomu se dostanete prostřednictvím rozšíření funkce MATCH - IN BOOLEAN MODE. Osvětlím tona pár příkladech:

select * from clanky where match (zneni) against ('+server -apache' IN BOOLEAN MODE);

najde články, které obsahují frázi server, ale neobsahují frázi apache. Kdybychom chtěli, aby byly nalezenyvšechny články obsahující výraz databáze s tím, že výraz MySQL by byl pro nás méně relevantní (ale vyloženěby nám nevadil), můžeme použít následující syntaxi:

select * from clanky where match (zneni) against ('+databáze <MySQL' IN BOOLEAN MODE);

Na stránkách manuálu se můžete dočíst i o dalších zběsilých formách tohoto způsobu vyhledávání - lzenapříklad použít závorky a tak dále.

Poznámky

Měli byste vědět, že vyhledávání "IN BOOLEAN MODE" má některá zajímavá omezení. Patří mezi ně:

Pravidlo padesátiprocentního prahu se nepoužívá

Výsledky nejsou automaticky řazeny sestupně podle relevance

Může fungovat i bez existence odpovídajícícho FULLTEXT indexu, ale je to dosti pomalé

Existuje v databázi až od verze 4.0.1

Page 117: MySQL Obsah

K technice použití fulltextu v MySQL bych obecně uvedl následující - pokud již máte data v MySQL (třeba vtom redakčním systému), může pro vás použití fulltextu znamenat výhru - jeho nasazení a správa budou vpodstatě bezbolestné. Pokud to ale není váš případ, lze najít mnohem obecnější fulltextové systémy - napříkladLucene. Vzájemné porovnání fulltextových technologií není vůbec jednoduchá věc a rozhodně to nenípředmětem našeho seriálu, ale je dobré mít na paměti, že MySQL není jediný systém, který něco podobnéhoumožňuje.

MySQL (39) - typy tabulek v MySQL

Databáze MySQL disponuje několika typy tabulek. Jaké typy to jsou, k čemu slouží a kdy je použít se dozvíte vtomto a v dalším díle našeho seriálu.

23.9.2005 08:00 | Petr Zajíc | přečteno 6516×

Komerční sdělení: Pořádáme Kurzy MySQL

Databázový systém MySQL má poměrně výjimečné postavení na trhu s obdobnými produkty - a to v tom, žeumožňuje mít data fyzicky uložena hned v několika typech tabulek. Dnes některé z nich prozkoumáme - aukážeme si, kdy který typ použít.

Typy tabulek v MySQL

Dodnes neumím říct, zda je tato vlastnost pro MySQL přínosem nebo prokletím, ale fakt je, že data v MySQLlze uložit minimálně do sedmi rozdílných typů tabulek. Každý z typů má vlastní výhody a nevýhody. V praxi sevšak běžně používají pouze dva typy tabulek - o těch ostatních se tedy zmíním spíše pro zajímavost. Typtabulky se dá zadat při jejím vytvoření jako (nepovinné) rozšíření příkazu CREATE TABLE. Například tabulkutypu MyISAM (co to je se dozvíte za chvíli) vytvoříte pomocí následujícího definičního příkazu:

create table tabulka (id int, nazev varchar(10)) engine = myisam;

MySQL povoluje rovněž změnu typu již existující tabulky. Se zachováním struktury i dat můžete tedy našitabulku změnit třeba na typ INNODB (co to je se dozvíte v dalším díle seriálu) takto:

alter table tabulka engine = innodb;

Pozn.: Místo klíčového slova ENGINE pro určení typu tabulky se rovněž můžete setkat s klíčovým slovem TYPE.Jsou to ekvivalenty.

V jedné databázi můžete mít tabulky více typů. Asi se ptáte, jaký typ tabulky vytvoří databázový stroj vpřípadě, že jej implicitně nezadáte. V tom případě bude použit výchozí typ tabulky. Ten je nastaven "z výroby",případně jej lze změnit v konfiguraci serveru MySQL. Pojďme se teď podívat na jednotlivé typy tabulekpodrobněji.

Page 118: MySQL Obsah

Typ ISAM

ISAM je historicky nejstarší typ tabulky, který se v MySQL používal od počátku. Samotný název ISAM jezkratka - indexed sequential access method, česky metoda indexovaného sekvenčního přístupu. V současné doběje tento typ považován za zastaralý a ve verzi 5.0 databáze MySQL již nebude k dispozici. Zastaralý je proto, žeindexy k tabulce byly ukládány v tomto typu tabulek nekomprimovaně a práce s nimi byla relativně pomalá.

Typ MyISAM

Tabulky typu MyISAM se používají dosud - a je to asi nejčastější (a rovněž výchozí) typ tabulek v databáziMySQL. Oproti ISAM mají tu podstatnou výhodu, že indexy u těchto typů tabulek jsou komprimovány, zabírajítudíž méně místa a systém provede příkazy SELECT na těchto tabulkách s menší spotřebou systémovýchzdrojů, než kdyby se jednalo o tabulky ISAM. Komprimování indexů taky něco stojí, takže provádění akčníchdotazů nad těmito tabulkami spotřebuje více času procesoru; tato nevýhoda je však při výkonech dnešníchprocesorů poměrně zanedbatelná.

Platí, že byste měli používat tabulky typu myISAM kdykoli si nejste jisti, jaký typ použít. Rovněž platí, žetabulky typu MyISAM vám dovolí využít co nejvíce z funkčnosti MySQL, například nad nimi lze provádětfulltextové vyhledávání. Tabulky MyISAM jsou rovněž velmi rychlé. Na druhou stranu tabulky MyISAM (aniISAM) neumožňují transakční zpracování. O transakcích budeme v seriálu mluvit později, takže jen naznačím,o co se jedná: v případě selhání systému uprostřed příkazu (nebo skupiny příkazů) může u těchto tabulek dojítbuď k porušení struktury, nebo k situaci, kdy tabulka obsahuje nekonzistentní data.

Tabulky MERGE

Jsou velmi zvláštní. Merge tabulka je virtuální tabulka nad dvěma nebo více tabulkami MyISAM, které majístejnou strukturu (to znamená stejný název, typ a počet sloupců a stejné indexy). Proč by něco takového mohlobýt potřeba? Především pro velmi velké tabulky. U nich by mohlo buď dojít k tomu, že bude vyčerpán limit provelikost souboru daný operačním systémem, nebo k tomu, že bude vyčerpáno místo na jednotce, na níž sedatabázový soubor nachází. Jelikož MERGE může spojovat tabulky umístěné fyzicky na více jednotkách, tentoproblém u nich odpadá.

Jak vytvořit MERGE tabulku? Začněme tím, že budeme mít dvě shodné tabulky (druhou jsem vytvořilkopírováním první):

create table log2004 (rok smallint, datum datetime); create table log2005 like log2004;

Obě tabulky naplníme nějakými daty:

insert into log2004 values (2004,'2004-01-01'); insert into log2004 values (2004,'2004-02-01'); insert into log2004 values (2004,'2004-12-29'); insert into log2005 values (2005,'2005-06-30'); insert into log2005 values (2005,'2005-08-12'); insert into log2005 values (2005,'2005-09-16');

a teď to nejzajímavější - vytvoříme "obalovací" tabulku typu MERGE, která nám umožní pohlížet na tyto dvětabulky jako na jednu:

create table log (rok smallint, datum datetime) engine=merge union=(log2004,log2005);

Od této chvíle naše virtuální tabulka žije. Co s ní lze dělat? Například je možné z ní vybírat záznamy - takžetento příkaz vrátí data z obou "původních" tabulek:

Page 119: MySQL Obsah

select * from log order by datum desc;

Do takto definované tabulky typu MERGE však bohužel nelze vkládat záznamy, takže příkaz v následujícímstylu by skončil chybou:

insert into log (rok, datum) values (2005,'2005-09-22');

To je logické, protože databázový stroj neví, do které z podkladových tabulek by měl záznam přijít a MERGEtabulka žádná "vlastní" data nemá. Od verze 4.0 MySQL však lze definovat MERGE tabulku s rozšířenímspecifikujícím, kam se mají vkládat nové záznamy. Pokud to uděláte, budou příkazy INSERT směřovány dospecifikované podkladové tabulky:

create table log (rok smallint, datum datetime) engine=merge union=(log2004,log2005)insert_method=last;

Při práci s MERGE tabulkami je dobré vědět, že

potřeba MERGE tabulek se dá obejít pomocí příkazu UNION

smazáním MERGE tabulky se neodstraní podkladové tabulky

v jedné MERGE tabulce mohou být více než dvě podkladové tabulky (teoreticky až 128)

jedna podkladová tabulka může být členem více MERGE tabulek zároveň

na podkladové tabulce můžete provádět změny v datech

na MERGE tabulkách nemůžete provádět FULLTEXT

To, zda bude použití MERGE tabulky rychlejší či nikoli je předem nepředvídatelné a je třeba si to řádněodzkoušet. V určitých situacích to může být pomalejší.

V praxi se s tabulkami MERGE nejspíš nesetkáte, protože objem dat zpracovávaných u typické MySQLdatabáze je (zejména u webových aplikací) realtivně malý. S čím se však rozhodně setkáte jsou typy tabulekumožňující transakční zpracování - a o těch budeme mluvit v dalším díle našeho seriálu.

Page 120: MySQL Obsah

MySQL (40) - další typy tabulek

MySQL nabízí několik typů tabulek pro uložení dat. Některé jsme vzpomenuli minule, na jiné dojde řada dnes.

30.9.2005 08:00 | Petr Zajíc | přečteno 6354×

Komerční sdělení: Pořádáme Kurzy MySQL

V tomto díle seriálu budeme pokračovat ve výčtu a rozboru těch typů tabulek, které MySQL nabízí.

Tabulky umožňující transakce

MySQL nabízí dva typy tabulek, které umožňují transakční zpracování. O transakcích ještě v seriálu řeč nebyla,ale na teorii se můžete podívat do "sesterského" seriálu o PostgreSQL. Teorie databázových transakcí je totižpro všechny databáze vlastně stejná. U transakcí jde o to, že jeden nebo více příkazů pro databázi může býtpovažováno za logický celek a jako takový mohou být potvrzeny nebo zamítnuty. Následující dva typy tabulekpodporují transakce:

InnoDB

Aby mohla MySQL podporovat InnoDB, musí být zkompilována s jejich podporou. To je od verze 4.0 MySQLjiž samozřejmé. Tabulky InnoDB používají při zpracování dat techniku zamykání dat na úrovni řádků. Hodí sepro prostředí, kde je vysoký podíl akčních dotazů vůči výběrovým (tedy, často se data mění a méně častovybírají). Technologii InnoDB vyvinula finská firma Innobase Oy.

Tabulky InnoDB nejsou na databázovém serveru uloženy v jednotlivých souborech. Spíše jsou v prostorutabulek, který je navenek reprezentován jako jediný soubor (typicky ibdata1) v adresáři data vaší instalaceMySQL.

Pokud budete chtít založit tabulku typu InnoDB, použijte definiční příkaz ve stylu:

create table tabulka (id int, nazev varchar(30)) type=innodb;

InnoDB je možné doladit pomocí celé řady konfiguračních voleb a spustit s celou řadou parametrů. Nebudemeje tady do podrobna rozebírat, pouze připomenu zásady, kterými byste se při ladění výkonu InnoDB měli řídit:

Page 121: MySQL Obsah

Všechny případné testy dělejte na podobném objemu dat, jaký bude používat reálný systém.

Jestliže půjde o hodně zatěžovaný systém, je třeba simulovat pečlivě i zátěž - například zapisováním datdo tabulky z více klientů najednou a podobně.

Máme funkci BENCHMARK

InnoDB tabulky lze v dotazech spojovat s tabulkami jiných typů - MyISAM například - ale můžete tímpřijít o výhodu transakcí

Je rovněž dobré vědět, že tabulky InnoDB mají svá omezení. Nemůžete na nich například provádět fulltextovévyhledávání. Kompletní seznam omezení tabulek tohoto typu najdete v dokumentaci k MySQL.

BDB

Rovněž tabulky typu BDB podporují transakce. BDB je zkratka z "Berkeley database" a jedná se o databázi,původně vyvinutou na University of California ve městě Berkeley. Teď se o vývoj BDB stará firma Sleepycatsoftware. O použití jádra BDB v MySQL platí zhruba to, co bylo řečeno o InnoDB - totiž že se hodí pro serverys vysokým podílem akčních dotazů oproti výběrovým. Přestože je BDB sama o sobě vyspělý produkt, rozhranímezi MySQL a BDB je stále ve fázi intenzivního vývoje a proto by tento typ tabulek měl být nasazován opatrně.

Tabulku typu BDB založíte použitím následujícího definičního příkazu:

create table tabulka (id int, nazev varchar(30)) type=bdb;

Manuál k MySQL obsahuje volby, s nimiž je možné upravit chování tabulek typu BDB a omezení, které BDBtabulky mají.

Upřímně řečeno nechápu, proč se MySQL zabývá souběžnou podporou InnoDB a BDB, když jejich filozofie jetak podobná. Pokud byste někdo měl nějaké zkušenosti nebo srovnání výhod a nevýhod tabulek BDB oprotiInnoDB, můžete přispět do diskuse pod článkem.

Méně časté typy tabulek

S tabulkami, které jsme až dosud probrali se můežte setkávat relativně často. Zejména to platí o typechMyISAM a InnoDB. Existují však i další, exotické typy tabulek. Kráce je shrňme.

Memory

Tabulky typu MEMORY (synonymum je HEAP) existují pouze v paměti počítače. Abych byl přesný dodám, žev paměti jsou jen data, definice tabulky je uložena na disku. To znamená, že při restartu serveru je obsahtabulek HEAP ztracen. Asi si říkáte, k čemu taková vymoženost vůbec je - ale tabulky MEMORY mohou mítsvé opodstatnění.

Page 122: MySQL Obsah

Především, díky tomu, že jsou celé v paměti, může být práce s HEAP tabulkami velmi rychlá. Pak je třeba vzít vúvahu, že tabulky typu HEAP mohou být ideálními kandidáty na dočasné (temporary) tabulky. A konečně jetřeba vědět, že HEAP tabulku lze vytovřit jako kopii existující "trvalé" tabulky takto:

create table tabulka_v_pameti type=memory select * from tabulka_na_disku;

Také tyto tabulky mají svá specifika a omezení, o nichž byste si mohli přečíst v manuálu.

Federated

Tento naprosto nový typ tabulek lze použít až od verze 5.0.3 MySQL. Funguje tak, že definice tabulky určípouze její strukturu, data jsou umístěna na vzdáleném serveru a při dotazu na tuto tabulku jsou přenesena po sítina požádání. U tabulek typu FEDERATED je při definici tabulky třeba zadat informace sloužící k připojení kevzdálenému serveru:

create table tabulka (id int, nazev varchar(30)) connection='mysql://jmeno:[email protected]:3306/database/tablename';

Myšlenka je to zajímavá. Nicméně než se něco takového rozšíří, je třeba mít na paměti následující věci:

Definice vytvářené tabulky musí odpovídat definici vzdálené tabulky

Výkon takových tabulek bude notnou měrou záviset na rychlosti spojení mezi servery

Součástí definice tabulky jsou připojovací informace ke vzdálenému serveru. Pozor na bezpečnost.

CSV

Jak asi tušíte, tento typ tabulek ukládá data oddělené čárkami do textového souboru. Je to méně obvyklý způsob,funguje od verze 4.1.4 a musí se při kompilaci MySQL povolit (ve výchozím stavu není k dispozici a není kdispozici ani u typických binárních distribucí). CSV má více nevýhod - například takto uložená data nelzeindexovat.

Závěr

Takový počet typů tabulek u jednoho produktu vás možná překvapil (a to jsem některé exotické typy vynechal).Nic si z toho nedělejte, v praxi se používají většinou pouze dva. MyISAM na data, z nichž se často vybírápomocí SELECT a InnoDB na data, která se často mění. Je to sice zjednodušující, ale pro orientaci by to mělostačit.

Page 123: MySQL Obsah

MySQL (41) - Transakce

Pojďme se začít věnovat transakcím; téma je bezpochyby na více dílů, takže dnes to bude spíše jen takový úvod.

7.10.2005 08:00 | Petr Zajíc | přečteno 8951×

Komerční sdělení: Pořádáme Kurzy MySQL

Transakce jsou v souvislosti s databázemi často skloňovaným tématem. Není divu - většina databázovýchsystému se ohání schopnosti "transakčního zpracování", optimalizací pro "souběžný běh transakcí" a kdoví, čímvším ještě. Pojďme se v dnešním díle seriálu podívat na to, co to transakce vlastně jsou, co naopak nejsou a jakvlastně vevnitř fungují.

Něco teorie

O transakcích toho bylo napsáno mnoho - a netýká se to jen databází. Podle Akademického slovníku cizích slovje trasakce ve výpočetní technice "činnost jedné položky dat zahrnující vstup položky dat do počítače, vlastnízpracování položky a výstup výsledku zpracování". To nám pro databázové pojetí transakcí moc nevyhovuje,proto bychom to potřebovali lehce předefinovat. Mnohem lepší je tato definice: "Transakční zpracování jeobecný koncept, jehož cílem je zajistit integritu jakéhokoliv dynamického systému v rámci přechodu z jednohokonzistentního stavu do druhého". Jedním dechem můžeme dodat, že "konzistentním stavem" z hlediskadatabázového systému může být stav, kdy máme v pořádku data.

Transakce a aplikační logika

Z hlediska reálného světa databází půjde při trasakcích o jedno - možnost provést sadu nějakých databázovýchoperací jako jeden funkční celek. To velmi často odpovídá situacím, se kterými se můeže setkat v aplikacích.Představme si prodej ve velkoobchodě: zákazník si objedná zboží, je mu vystaven doklad, zboží je odečteno zestavu ve skladu a jsou přijaty peníze. V databázi něco takového může znamenat následující činnosti:

1. Je přijata objednávka a zapsána do deníku objednávek

2. Je vystavena faktura či prodejka (a zapsána do odpovídající agendy)

3. Ze skladových karet zboží je odečten odpovídající počet kusů

4. Do pokladny je přičtena částa za uvedené zboží.

Page 124: MySQL Obsah

To celé by se s trochou nadsázky dalo považovat za transakci. Kdyby se měly odpovídající příkazy provést vdatabázi, asi chápete, že je třeba provést je všechny najednou. Není možné přestat v bodě 2 nebo 3 a peníze zaprodané zboží někam schovat. Na druhé straně se může stát, že aplikace dojde při provádění transakce k bodučíslo 3 a zjistí, že požadované zboží na skladě není. V tom případě musí být celá transakce zrušena, a to včetněbodů 1) a 2). Můžeme tedy říci, že z hlediska databází lze transakci považovat za jeden nebo více příkazů, kterélze jako celek buď potvrdit, nebo zrušit. Protože to je činnost často související s aplikační logikou, setkáváme ses tím, že aplikační logika může být realizována pomocí transakcí.

Nesmíme rovněž zapomínat na to, že náš velkoobchod má možná více pokladen a že si zboží v jedné chvílimůže objednávat více lidí - ano, v jednom DBMS může probíhat více transakcí najednou.

Co transakce nejsou

Je třeba rovněž vědět, co transakce nejsou. Zejména proto, že si to mnoho lidí plete. Pokusím se tedy vyvrátitněkteré mýty, které jsem v této souvislosti slyšel.

Transakce jsou způsob, jak zajistit práci více uživatelů najednou - To je dvojsečné tvrzení. Správnépoužití transakcí sice může zajistit, že s nějakým databázovým systémem může pracovat více uživatelů,na druhé straně však špatné použití transakcí může práci více uživatelů zcela znemožnit. Transakce tedypráci více uživatelů nezajišťují, spíše ji umožňují - za určitých okolností.

Trasakce chrání databázi před selháním - Naprostý nesmysl. Jestliže selže pevný disk, na němž jeuložená databáze, je úplně jedno, zda umožňovala transakce či nikoli - data jsou v tomto případě vždyztracena.

Transakce jsou příliš pomalé - Je stejné jako říci, že auta jsou pomalá. Závisí tedy na okolnostech.Někdy mohou transakce operace zrychlit, jindy zpomalit. Opět to závisí na okolnostech a stav, kdy jeoperaci kvůli transakci pomalejší nemusí nutně znamenat chybu.

Transakce udělají v databázi pořádek - Je-li správný návrh databáze, dá se v ní vyznat. Jestliže není,je třeba tu databázi předělat, a ne nasazovat transakce. V takovém případě povedou transakce spíše květším zmatkům.

Co musí transakce umět

Transakce musí, jak jsme si již ukázali, být nedělitelné (atomické). V praxi to znamená, že navenek se musejíjevit jako jediná operace. Jestliže se transakce dokončí, musejí být zapsány všechny změny, jestliže ne, musejíbýt všechny změny zrušeny. V této souvislosti se sluší poznamenat, že:

Převážná část transakcí končí jejich potvrzením a databázové systémy bývají většinou na tento scénářoptimalizovány.

Transakce může selhat vlivem vyšší moci (například, během provádění transakce vypadne napájení). I vtakovém případě musí být transakční systém schopen transakci dokončit nebo stornovat (ale nic mezitím).

Page 125: MySQL Obsah

Transakce může být odvolána (před jejím dokončením) i na přání klienta, to znamená například na přáníuživatele.

Dále, transakce musejí být konzistentní. To znamená, že databáze se nikdy navenek nesmí jevit jako v nějakémpřechodném stavu. Jestliže například nějaká součást transakce mění data, nesmí být jinému uživateli (nebo jinétransakci) k dispozici část změněných dat a část nezměněných dat. Uvědomte si, že tato vlastnost transakcízávisí do jisté míry na vás - lze ji totiž ovlivnit dobrým návrzem databáze.

Transakce navíc musejí být izolované. Zajistit něco takového v praxi znamená, že jedna probíhající transakcenesmí ovlivnit transakci jinou. Vzhledem k tomu, že teoreticky může v jednom čase probíhat na stejných datechvíce transakcí, asi tušíte, že uhlídat něco takového není žádná legrace - a máte pravdu. Jediný "jistý" způsob jevšechny transakce hezky řadit do fronty a provádět je tak, jak na ně přijde řada. Protože to je velmi pomalé, vpraxi se většinou lze uchýlit ke kompromisu a izolovanost nepožadovat tak striktně. Proto existují takzvanéúrovně izolace, které v přijatelné míře slevují z této zásady ve prospěch rychlosti zpracování.

Konečně, transakce musejí být trvalé. V praxi to znamená, že při potvrzení transakce dojde k zápisu dat asystém je opět považován za konzistentní (o to pořece šlo, ne?). Je třeba si uvědomit, že potvrzení transakcemůže pro databázový systém znamenat dost práce, přestože to uživatel většinou nevnímá.

Jak se to dělá

Třebaže princip vnitřního fungování transakcí většinou není potřeba detailně znát, je docela zajímavý. Většinauživatelů si totiž myslí, že každá transakce je do databáze zapsána až v okamžiku jejího potvrzení, ale tak tomunení. Transakce jsou zapisovány do databáze okamžitě, a spolu s tím si databáze někde uchovává seznam krokůpotřebných k potvrzení (nebo zrušení) dané transakce.

To lze v podstatě dělat dvěma způsoby. Jedním z nich je takzvaná multigenerační architektura. Tento způsobzpracování transakcí spočívá v tom, že každá změna je zapsána do databáze spolu s čísem verze. Trochu se topodobá způsobu, jakým systému pro správu kódu uchovávají verze rozpracovaných projektů. Asi nejlepší českýčlánek na toto téma si můžete přečíst na serveru IBPhoenix. Není divu, protože tento server je spjat s databázíFirebird, která multigenerační architekturu používá.

Druhý způsob (který používá i MySQL) spočívá v tom, že server si udržuje takzvaný transakční protokol, což jeseznam všech transakcí a jejich kroků. Ten lze využít k odvolání nebo potvrzení transakce. Je nutné se zmínit otom, že součástí filozofie tohoto přístupu jsou takzvané zámky, které slouží jako mechanizmus k zajištěníizolovanosti dat.

Který způsob realizace transakcí je lepší? To se, jak už to bývá, nedá jednoznačně určit. Jak systém protokolů,tak i multigenerační architektura prošly během let vývojem a mají za sebou kus cesty. MySQL, jako většinadatabází, používá systém s protokolem. Příště si ukážeme, jak se transakce v MySQL realizují.

Page 126: MySQL Obsah

MySQL (42) - ještě k transakcím

Dnes si ukážeme nějaké praktické příklady transakcí.

14.10.2005 06:00 | Petr Zajíc | přečteno 7444×

Komerční sdělení: Pořádáme Kurzy MySQL

Dnes se budu snažit o přiblížení toho, jak by měly transakce fungovat v praxi. Takže se můžete těšit na nějakýten příklad.

Příklady na transakce

Každý se snaží při uvádění příkladů na transakce použít převod peněz z účtu na účet. Je to tak otřepané, že tosnad ani víc otřepat nejde; takže se vydáme trochu jinou cestou - a budeme přitom postupovat od jednoduchýchpříkladů ke složitějším. Jak jsme již uvedli v některém z minulých dílů, v MySQL jsou tabulky podporoványpouze pro některé typy tabulek - konkrétně pro InnoDB a BDB. Častější je použití InnoDB, takže budeme vpříkladech používat tabulky tohoto typu. V souvislosti s transakcemi si pravděpodobně budete chtít zapamatovatpříkazy, které je řídí:

Příkaz VýznamSTARTTRANSACTION

Zahájí neboli odstartuje transakci. Veškeré příkazy zadané později jsousoučástí transakce a navenek se tedy budou jevit jako jediný příkaz.

COMMIT Aktuální transakce je potvrzena. Změny jsou zapsány do databáze a jsouuvolněny systémové prostředky, které si transakce vyžádala.

ROLLBACK Aktuální transakce je zamítnuta. Všechny provedené změny jsou zrušeny adatabáze se vrátí do stavu, v němž byla před zahájením transakce.

Pojďme si to celé ukázat na příkladu. Dejme tomu, že pracujete ve firmě, kde se rozhodnout rapidně zvýšitplaty. Půjde se na to tak, že lidem, kteří měli méně než 15000,-Kč bude přidáno 2000,- Kč a následně budevšem zvýšen plat o 10% (hezká představa, že?). Pochopitelně, že to celé zrealizujeme pomocí transakce. Proč?Taková transakce nám zajistí, že:

1. Během celé operace nebude s platy moci hýbat nikdo jiný. Uvědomte si, že ve víceuživatelskýchsystémech by se to klidně mohlo stát.

2. Celá operace se provede (nebo se celá neprovede). Asi byste zrovna nechtěli být na řadě, když bychudáku serveru někdo vypnul proud právě ve chvíli, kdy se chystá aktualizovat váš plat.

Page 127: MySQL Obsah

3. Navíc, představte si, že byste byli na místě člověka, který to má dát do pořádku poté, co se polovinazáznamů zaktualizovala a druhá polovina nikoli.

Vytvořme tedy nějakou tabulku:

create table platy (zamestnanec varchar(50), plat int) type=innodb;

naplňme ji daty:

insert into platy values ('Jarda',12000); insert into platy values ('Pepa',15000); insert into platy values ('Petr',14000); insert into platy values ('Pavel',10000); insert into platy values ('Šárka',16000); insert into platy values ('Monika',13000);

a zkusme to celé provést. Půjdeme na to takto:

start transaction;update platy set plat=plat+2000 where plat < 15000;update platy set plat=plat*1.1; commit;

Za zmínku stojí, že kdyby se pokusil během naší transakce o úpravu dat někdo jiný, byl by odmítnut. To lzelehce ověřit, pokud si zkusíte dva paralelně běžící klienty (nejlépe asi v konzoli):

klient 1 klient 2 Popisstart transaction Spustí transakciupdate platy setplat=plat+2000 whereplat < 15000;

Transakce změnila tabulku, ale ještě nevíme, zda se topotvrdí nebo odvolá

update platyset plat=plat

Tento příkaz nemůže být ihned proveden, protože data jsoublokována předchozí transakcí. Na vykonání nějakou dobučeká a pokud je tato doba vyčerpána, skončí chybou "lockwait timeout exceeded"

update platy setplat=plat*1.1;

(čeká) Transakce opět změnila tabulku; stále nevíme, zda se topotvrdí či nikoli

commit; (čeká) Transakce je dokončena, změny jsou zapsány a tabulka jevolná.

proveden! Pokud transakce byla dokončena dostatečně včas, přicházína řadu příkaz z klienta č. 2 (pokud ne, je zahozen)

Automatické transakce

Je třeba si uvědomit, že při zadávání příkazů do tabulek InnoDB nebo BDB je vždy spuštěna transakce. Možnáse vám to nezdá, ale při zadání příkazu:

select * from cosi;

Provede databáze ve skutečnosti toto:

start transaction; select * from cosi; commit;

Page 128: MySQL Obsah

To proto, že transakce bez zadaného příkazu start transaction jsou automaticky dokončovány. Někdy by Vám alemohlo vyhovovat spíše to, že zadáte sadu příkazu a sami je potvrdíte pomocí COMMIT. Něco takového se dánastavit pomocí konfigurační volby autocommit:

SET AUTOCOMMIT=0;

Pozor ale, není to volba databáze, nybrž jednotlivého spojení. Pokud bude spojení ukončeno, přejde databázezpět do režimu automaticky dokončovaných transakcí. V této souvislosti je rovněž dobré si uvědomit, žeexistují příkazy, které vždy dokončují transakci (bez ohledu na to, zda jsou úspěšné či nikoli). Jinými slovy, natěchto příkazech nelze vykonat ROLLBACK. Patří mezi ně převážně příkazy pro definici struktur, jako jsou:

CREATE DATABASE

CREATE TABLE

CREATE INDEX

ALTER ...

DROP ...

TRUNCATE

Proto byste se použití těchto příkazů v transakcích měli spíše vyhýbat.

Page 129: MySQL Obsah

MySQL (43) - Uložené procedury

Jak je na tom MySQL s uloženými procedurami? Nová verze je umí, takže se ta to pojďme podívat.

21.10.2005 07:00 | Petr Zajíc | přečteno 9897×

Komerční sdělení: Pořádáme Kurzy MySQL

Uložené procedury jsou jednou z věcí, kterou se liší "malé" databáze od "velkých" a spousta lidí si myslí, žeMySQL nic takového nepodporuje. To byla pravda až do čtyřkových verzí MySQL; od verze 5.0 jsou uloženéprocedury normálně ve výbavě tohoto databázového systému. Takže pozor, všechno co dnes budu popisovatplatí až od verze 5.0 databáze. A pokud si to budete chtít vyzkoušet, měli byste si "pětku" nainstalovat.

Uložené procedury

Nejprve malá poznámka k instalaci MySQL 5. V době psaní tohoto článku existuje ke stažení release candidate5.0.13 MySQL. Release candidate verze nejsou připraveny pro ostré nasazení a proto byste je měli instalovatpouze ke zkušebním účelům. Instalace pětky by nicméně měla být velmi podobná jako u předchozích verzí,takže by měly jít využít poznatky z dílů o instalaci (první, druhý). Je potřeba rovněž zmínit se o tom, žesoučasná existence více MySQL serverů na jednom stroji vyžaduje trochu konfigurace, takže pokud se chystáteněco takového udělat, ujistěte se, že to zvládnete. Například je důležité, aby každý z více současně existujícíchserverů naslouchal na jiném portu, takže do příslušného konfiguračního souboru (my.cnf na Linuxu, my.ini naWindows) bude zapotřebí napsat něco jako:

[client] port=3306 # nebo jiný pro druhý server [mysqld] port=3306 # nebo jiný pro druhý server

Více o konfiguračních souborech se dočtete zde, nyní ale zpět k uloženým procedurám.

Definice

Uložená procedura je sada příkazů SQL, které jsou:

Page 130: MySQL Obsah

Uložené na serveru

Zkompilované pro rychlejší použití

Proč se k něčemu takovému tvůrci DBMS a jejich uživatelé vůbec uchylují? Jedním důvodem je fakt, že některédatabázové operace se neustále opakují. Pokud je taková databázová operace provedena jako dávka na serveru,nemusejí se jednotlivé příkazy (kterých klidně mohou být desítky) vypisovat pokaždé, když je chcete provést.Hodně vzdáleně se to může podobat filozofii maker ve vašem (doufám) oblíbeném OpenOffice.org writeru -takže je to jednoduché, protože sada příkazů je provedena najednou.

Dalším dobrým důvodem pro zavedení uložených procedur je jistá unifikace požadavků od jednotlivýchklientů. Jestliže chce několik databázových klientů vykonávat stejnou (nebo hodně podobnou) práci, bude proně příjemné zjištění, že něco takového již server "umí" díky uložené proceduře, kterou má k dispozici.

Uložené procedury rovněž mohou podstatným způsobem ulehčovat správu databázových aplikací. Mějme jakopříklad server, který ukládá a zpracovává data. Pokud to celé poběží pomocí uložených procedur, mohou seshodným způsobem vůči databázi chovat klienti pocházející z nejrůznějšího prostředí - desktopová aplikacenapsaná v Javě, webový klient v PHP nebo třebas vzdálený server, který s tím "naším" komunikuje. Jestliže jepotřeba uloženou proceduru upravit (nebo opravit), může se to udělat na jednom místě a tato změna je ihnedpoužitelný pro všechny aplikace, které s databází komunikují.

Dalším významným rysem uložených procedur je to, že přispívají k zabezpečení serveru (respektive mohou todělat, pokud jsou dobře napsány). Když mluvíme o bezpečnosti v souvislosti s uloženými procedurami, můžememít na mysli dvě věci:

1. Procedury mohou být v databázových systémech nastaveny tak, že je smí spouštět pouze někdo

2. Procedury mohou samy kontrolovat počet, typ, velikost a některé jiné charakteristiky parametrů, jež jsoujim posílány. To je v praxi velmi významné, protože to umožňuje vyhnout se fenoménu SQL injection.

Je ale zajímavé, že ani jeden z uvedených argumentů není pro nasazení uložených procedur ten nejvýznamnější.Zdaleka nejdůležitějším argumentem pro nasazení uložených procedur na server bývá to, že jsou obecněschopny běžet rychleji, než kdyby se příslušný kód vykonával příkaz po příkazu z klientské aplikace. Důvodemje fakt, že uložené procedury, jak jsme již uvedli, jsou na serveru zkompilovány.

Zkompilování uložené procedury neznamená, že je tato procedura převedena do spustitelné, binární formy, anito, že je uložena do samostatného souboru. Zkompilováním je myšleno to, že server si pro uloženou proceduruvytvoří a spravuje tzv. prováděcí plán. Díky tomu je subsystém serveru zvaný optimalizátor obvykle schopennajít nejrychlejší způsob, jak uloženou proceduru provést, a potom tento způsob opakovaně používat přijednotlivých voláních této uložené procedury.

Co mohou dělat

Zjednodušeně se dá říci, že uložené procedury mohou dělat většinu z toho, co "běžné" příkazy. Mezi nejčastějšíčinnosti, které taková uložená procedura vykonává, patří zejména:

Page 131: MySQL Obsah

Vybírání dat

Vkládání, aktualizace, odstraňování dat

Vytváření, používání a rušení dočasných tabulek

Matematické a statistické výpočty

Uložené procedury a MySQL

MySQL, jak jsme již uvedli, umožňuje tvorbu uložených procedur od verze 5.0. Každá uložená procedura je vMySQL s konkrétní databází, takže kdybyste toto databázi odstranili, přijdete rovněž o definici uloženéprocedury.

Uložené procedury se obecně vytvářejí příkazem CREATE PROCEDURE. Pojďme si dnes na úvod vytvořitalespoň tu nejjednodušší uloženou proceduru, abyste viděli, jak to celé funguje. Mějme tedy v MySQL 5následující tabulku:

create table software (id int, nazev varchar(50));

s následující sadou dat:

insert into software (id, nazev) values (1, 'Firefox'); insert into software (id, nazev) values (2, 'Mozilla'); insert into software (id, nazev) values (3, 'OpenOffice.org');

Uloženou proceduru, která vrátí všechny záznamy z této tabulky pak můžeme vytvořit pomocí následujícíhokódu:

create procedure sp_VratSoftware() begin select * from software; end

A zavolat pomocí příkazu:

call sp_VratSoftware()

K tomu by se slušelo říci pár postřehů:

1. Tohle je sice jeden z nejjednodušších způsobů, jak vytvořit a použít uloženou proceduru, neplatí však oněm, že bude rychlejší než prosté volání SELECT. To platí až o složitějších procedurách.

2. Uložené procedury mohou mít parametry, k nimž se dostaneme. Tahle je ale nemá. Přesto se při definicimusejí použít prázdné závorky.

3. Již jednou vytvořenou proceduru lze volat pomocí příkazu CALL. I zde je potřeba použít závorky

4. Tělo procedury je uloženo mezi klíčovými slovy BEGIN a END

Page 132: MySQL Obsah

Asi vás napadá, jak takovou proceduru napsat pomocí řádkového klienta, když tělo procedury obsahuje středník.Odřádkování v takovém případě způsobí odeslání neúplné definice, příkaz skončí chybou a procedura nebudevytvořena. Naštěstí lze v řádkovém klientovi změnit sekvenci znaků ukončujících příkaz za něco jiného než jestředník. Provedete to takto:

delimiter //

K uloženým procedurám se toho dá říci ještě mnoho. A protože ucelený materiál v češtině k tomuto tématuzatím chybí, můžete se těšit na další informace v příštích dílech našeho seriálu.

MySQL (44) - parametry uložených procedur

MySQL, procedury a jejich uložené parametry.

28.10.2005 08:00 | Petr Zajíc | přečteno 6517×

Komerční sdělení: Pořádáme Kurzy MySQL

Uložené procedury v jakékoli databázi by měly je pramalý význam, kdyby se jim nedaly posílat parametry. Myse dnes podíváme na to, jak se to dělá, jaké to má výhody a taky nezapomeneme na nějaké typické scénáře, kdyse parametry uložených procedur používají.

Aktuálně

Třebaže to nesouvisí jen s uloženými procedurami, dovolím si připomenout, že v době psaní tohoto článku vyšlaOSTRÁ verze MySQL 5.0. Takže stahujte, čtěte co je nového nebo upgradujte stávající verzi na novou.

Pozn.: Nemůžete však čekat, že se MySQL 5 objeví zakrátko na všech systémech, k nimž snad máte přístup.Administrátoři bývají s nasazováním nových verzí opatrní a nechávají uběhnout několik verzí, než nasadí novouřadu produktu na "svůj" server. Asi vědí proč.

Parametry uložených procedur

Podobně jako funkce v programovacích jazycích, mohou i uložené procedury v MySQL přebírat parametry.Možná si ještě vzpomínáte na proceduru z minulého dílu:

create procedure sp_VratSoftware() begin select * from software; end

Moc užitečná nám skutečně není, protože vždy vrátí celou tabulku. Možná byste ale chtěli vrátit jen jeden jedinýřádek - vybraný například podle identifikátoru. Se vstupním parametrem je to hračka:

Page 133: MySQL Obsah

delimiter $$ create procedure sp_vratradek (radek int) begin select * from software where id = radek; end $$ delimiter ;

Jak vidíte, je vstupní parametr předán v závorkách za názvem procedury. Každý ze vstupních parametrů uloženéprocedury musí mít specifikovaný typ. Když říkám každý, znamená to, že vstupních parametrů může být i více.V takovém případě jsou odděleny čárkou. To hezky dokresluje následující příklad:

delimiter $$ create procedure sp_vratradky (od int, do int) begin select * from software where id between od and do; end $$ delimiter ;

Volání procedur s parametry

Rovněž velmi jednoduché je uloženou proceduru s parametry zavolat. Naši proceduru s jedním parametrembychom zavolali takto:

call sp_vratradek(1)

A tu druhou, se dvěma parametry pomocí něčeho jako:

call sp_vratradek(10, 20)

Je potřeba si uvědomit, že MySQL testuje počet předaných parametrů, takže si musíte při volání uloženéprocedury být jisti, že jste zadali právě tolik parametrů, kolik jich procedura skutečně má (!) a ne méně ani více.K mojí velké nelibosti však zároveň musím dodat, že MySQL netestuje typ předaných parametrů, takženásledující příkaz:

call sp_vratradek('Tohle přece není číslo');

mi funguje tak, že vstupní parametr je zkonvertován na číslo a příkaz je proveden (s jedním warning). Mnohemraději bych viděl to, že příkaz skončí chybou, protože pokus o předání řetězce namísto čísla signalizuje obvyklenějaký problém a nemělo by to být v tichosti ignorováno.

Vynechání parametru

Přestože jsem o pár řádků výše tvrdil, že parametry nemůžete vynechat, lze je "skoro" vynechat, pokud namístonich dosadíte hodnotu NULL. Při psaní procedury s tím však musíte počítat a sestavit logiku tak, aby hodnotaNULL dělala to, co chcete. Například volání

call sp_vratradek(NULL);

bude sice syntakticky správně, ale procedura v takovém případě nikdy nic nevrátí (jedna hodnota NULL senikdy nemůže rovnat ničemu jinému včetně jiné hodnoty NULL). Možná je to to, co byste zamýšleli, možná ne.Je třeba na to při návrhu procedury myslet.

Typické použití vstupních parametrů

Jak jsme již viděli, vstupní parametr může být použit pro podmínku WHERE příkazu SELECT. To je dostitypické. Stejně tak jej lze použít v klauzuli ORDER BY k nastavení sloupce, podle něhož se bude řadit:

delimiter $$ create procedure sp_vratradkypodle(sloupec int)

Page 134: MySQL Obsah

begin select * from software order by sloupec; end $$ delimiter ;

To už tak typické není, protože o této možnosti někteří programátoři neví. Připomeňme, že to celé můžefungovat díky tomu, že klauzule ORDER BY přijímá číslo sloupce jako parametr. Procedury tohoto typu bývajíideálními kandidáty na řazení tabulek při klepnutí na záhlaví, protože obyčejně není problém zjistit si pořadovéčíslo sloupce, na nějž se kliklo.

Pozn.: Má to i nevýhody. Při pokusu seřadit výsledek pomocí neexistujícího sloupce celý dotaz selže, takžepozor na to.

Další obvyklou technikou je použít uloženou proceduru na vkládání dat do nějaké tabulky. Ilustruje tonásledující příklad:

delimiter $$ create procedure sp_vlozradek(id int, nazev varchar(50)) begin insert into software (id, nazev) values (id, nazev); end $$ delimiter ;

Jakou to má výhodu oproti prostému příkazu INSERT? Především, při opakovaném spuštění bude tento příkazrychlejší než prostá sada INSERTů. Podle mých zkušeností o 25-30%. A navíc, časem se můžeme rozhodnout,že při vložení nového řádku chceme udělat ještě něco jiného (protokolovat, například) a není problém to doprocedury dopsat.

Mnohem širší uplatnění uložených procedur však souvisí s faktem, že mohou obsahovat určitou logiku -podmínky, smyčky, lokální proměnné a tak dále. O těchto věcech bude řeč v dalším díle našeho seriálu.

Page 135: MySQL Obsah

MySQL (45) - větvení kódu uložených procedur

... aneb kterak v uložených procedurách MySQL využít podmínky a smyčky.

4.11.2005 06:00 | Petr Zajíc | přečteno 6560×

Komerční sdělení: Pořádáme Kurzy MySQL

Samozřejmě, že uložené procedury nemusejí obsahovat jen sadu příkazů, které se budou sekvenčně provádět odjednoho k druhému. Mohou obsahovat určité příkazy pro větvení kódu, jako jsou smyčky nebo podmínky. Todnes prozkoumáme; takové věci totiž dělají z uložených procedur docela užitečné pomocníky. Alespoň vněkterých situacích.

Řízení toku

Prakticky jakýkoli programovací jazyk má nějaké ty příkazy pro řízení toku programu. Patří sem nejrůznějšípodmínkové konstrukce, smyčky, odskoky na návěští a podobně. Jazyk pro uložené procedury v MySQL máněco podobného, i když je to jen slabý odvar toho, co možná znáte z jazyků jako C nebo JAVA.

Nicméně programování uložených procedur může bý pro ná mnohem jednodušší, jestliže takové konstrukceznáme; já se dnes zaměřím na ty nejpoužívanější z nich, a to jsou podmínky a smyčky.

Podmíněné provádění kódu

Podmínky jsou asi nejčastější používanou konstrukcí pro větvení kódu, alespoň v procedurách. Umožňují námprovést nebo neprovést jistou část kódu na základě splnění nebo nesplnění podmínky. Ilustrujme to najednoduchém příkladu. Vytvoříme si tabulku obsahující protokolování návštěv na našem serveru:

create table log (datum datetime, ip varchar (15));

a naplníme ji nějakými hypotetickými daty (jsou to samozřejmě jen příklady)

insert into log values ('20051103072516', '10.1.1.0'); insert into log values ('20051103081525', '10.1.1.2'); insert into log values ('20051103074838', '192.168.36.3');

Page 136: MySQL Obsah

insert into log values ('20051103091319', '10.0.0.9'); insert into log values ('20051103073859', '127.0.0.1'); insert into log values ('20051103072518', '65.50.48.206');

Jak napsat uloženou proceduru, která vrátí všechny záznamy z této tabulky, nebo jen prvních pět? S použitímpodmínky je to hračka:

create procedure sp_showlog (jennejnovejsich5 boolean) begin if jennejnovejsich5=1 then select * from log order by datum desc limit 5; else select * from log order by datum desc; end if; end

Jak vidíte, je to celkem snadno pochopitelné. Fantazii se meze nekladou, namísto logické hodnoty obsahujícíúdaj o tom, zda chceme vrátit prvních pět záznamů nebo rovnou všechny může vstupní parametr obsahovatpřímo údaj o tom, kolik řádků chceme vrátit a podobně. Vracení různých sad záznamů na základě hodnotparametrů je dosti častým příkladem použití podmínek uvnitř těla procedur.

Nejsme však vázáni pouze na takové použití. Tatáž uložená procedura může jednou provádět vložení záznamů ajindy jeho aktualizaci. Ukažme to opět na příkladu:

create procedure sp_vlozneboaktualizuj (radek int, novynazev varchar(50)) begin if exists(select * from software where id = radek) then update software set nazev = novynazev where id = radek; else insert into software (id, nazev) values (radek, novynazev); end if; end

Tato procedura vykonává dosti fikanou úlohu - buď řádek najde a aktualizuje, nebo jej vloží. Něco takovéhobyste pomocí kódu na straně klienta zcela jistě neudělali tak jednoduše jako zde pomocí uložené procedury.Můžete si zkusit tuto procedutu spusti dvakrát:

call sp_vlozneboaktualizuj(10,'test'); call sp_vlozneboaktualizuj(10,'žádný test');

a uvidíte, že řádek je poprvé vložen a podruhé zaktualizován. Procedury tohoto typu můžete v praxi vidětnapříklad při ukládání konfiguračních hodnot do databáze - buď již záznam s kofigurací existuje a je použit,nebo neexistuje a je vytvořen.

Smyčky s podmínkou

Se smyčkami se sice v uložených procedurách nesetkáváme zdaleka tak často jako s podmínkami, ale je dobré onich něco vědět. Smyčky nám umožňují provádět opakovaně nějaký kód dokud platí podmínka (to jsou smyčkys podmínkou na začátku) nebo tak dlouho, dokud po provedení smyčky podmínka neplatí (to jsou smyčky spodmínku na konci). V uložených procedurách se nejspíš setkáte se smyčkami s podmínku na začátku. Jejichvýsledky se často ukládají do dočasných tabulek a později se využívají jako výstup nebo se dále zpracovávají.

Ukažme si opět něco takového na příkladu. Dejme tomu, že budete potřebovat (snad pro nějakou kalendářovouaplikaci) tabulku obsahující 30 následujících dnů. Se znalostí podmínek, dočasných tabulek a uloženýchprocedur na to můžete jít nějak takhle:

create procedure spkalendar() begin declare den date; set den = curdate();

Page 137: MySQL Obsah

create temporary table dny (datum date); while den < (curdate() + interval 30 day) do insert into dny (datum) values (den); set den = den + interval 1 day; end while; select datum from dny; end

Všimněte si, jak to celé funguje. Nejprve je vytvořena prázdná dočasná tabulka a je zjištěno dnešní datum. Pakje ve smyčce WHILE přičteno postupně 30 dnů a výsledky jsou průběžně ukládány do dočasné tabulky.Nakonec je obsah této dočasné tabulky vrácen jako výsledek.

Jistěže MySQL podporuje i smyčky s podmínku na konci; jejich použití však zdaleka není tak časté; možnáproto, že taková smyčka se vždy minimálně jednou provede.

MySQL (46) - Triggery

"Po mém zásahu zůstane v databázi spoušť" aneb co jsou to triggery.

11.11.2005 07:00 | Petr Zajíc | přečteno 9976×

Komerční sdělení: Pořádáme Kurzy MySQL

Další žádanou vymožeností, která přibyla do verze 5 databázového stroje MySQL jsou triggery. Dnes sepodíváme na to, co to přesně triggery jsou a k čemu jsou v databázovém světě dobré. Bude to spíše teoreticképovídání s tím, že věci specifické pro MySQL budou soustředěny do následujícího článku.

Triggery

Především - existuje krásné české slovo, jímž se dá přeložit anglické trigger - a to je spoušť. Moc se ale neujalo.Možná proto, že zní tak nepořádně. Představte si třeba větu "po mojí úpravě kódu zůstala v databázi pěknáspoušť". Protože tohle by asi většina uživatelů slyšet nechtěla, budu používat spíš původní, anglické slovotrigger.

Suchá definice pak praví, že trigger je uložená procedura, která se spouští v souvislosti s provedením nějakéhoakčního dotazu na tabulce. Pokud tuto definici trochu rozpitváme, dostaneme z ní následující informace:

Trigger je "uložená procedura", to znamená, že uvnitř triggeru lze provádět většinu věcí, které umíuložené procedury. V triggeru lze mít například smyčku, podmínku, lokální proměnnou, matematickývýpočet a podobně.

Spouští se "v souvislosti" s akčním dotazem. To v praxi znamená, že se trigger může spustit buďpředtím, než je úprava dat provedena, nebo poté, co jsou změny v datech zapsány do databáze. Některédatabáze umožňují pouze triggery před uložením dat, ale většina (včetně MySQL) má k dispozici obatypy.

Page 138: MySQL Obsah

"Akční dotaz" znamená, že trigger lze spustit při vkládání dat, při jejich aktualizaci nebo přiodstraňování dat z databáze. Rovněž z toho vyplývá, že trigger nelze v žádném případě spustit příkazemSELECT.

"na tabulce" - každý trigger patří právě jedné tabulce. Ačkoli samozřejmě může existovat tabulka beztriggeru, není možné, aby existoval trigger nezávisle na tabulce. V některých DBMS může být vícetriggerů stejného typu na jedné tabulce a lze dokonce určit pořadí, v němž budou spuštěny. V MySQLvšak některé z těchto věcí nejsou možné.

Čím se liší od uložených procedur

Triggery mají sice stejnou syntaxi jako uložené procedury, přesto se od nich v lecčems liší. Tak předevšímtriggerům není možné předávat žádné vstupní parametry. To znamená, že trigger nemá žádné informace o tom,jak by měl být prováděn, které by se daly "zvenčí" přepínat za chodu. Triggery navíc narozdíl od uloženýchprocedur nemohou vracet sadu záznamů. A navíc, databázové systémy mívají některá omezení a příkazy, kterése v triggerech nesmějí objevit. Pro MySQL platí, že se v triggeru nesmí objevit přinejmenším tyto příkazy:

Příkazy ALTER (ALTER TABLE, ALTER DATABASE a tak dále)

Příkazy pro řízení transakcí (START TRANSACTION, ROLLBACK, COMMIT)

Volání procedur (CALL)

Příkazy pro nastavování práv (GRANT, REVOKE)

a některé další příkazy

Na druhou stranu mají triggery oproti uloženým procedurám něco navíc; mají totiž "vevnitř" přístup k datům,která se právě mění. To například znamená, že trigger, který se spouští před aktualizací nějaké tabulky mápřístup k hodnotám těch řádků, které se snažíme změnit. Také to znamená, že v triggeru můžete provést nějakérozhodnutí v závislosti na datech, která má tento trigger změnit.

Jak se používají

Triggery se v tabulkách používají z několika důvodů. Ty mohou souviset s konzistencí dat, s jejich správou aúdržbou nebo s tím, jak a kdy bude databáze komunikovat se svým okolím. Abyste měli určitou představu,nastíním některé typičtější scénáře:

1. Konzistence dat: Trigger může provést výpočet a na základě toho povolit nebo nepovolit změnu dat vdatabázi. Například v tabulce skladových zásob může být trigger, který zakáže vyskladnit zboží vpřípadě, že bychom se tím dostali do záporného stavu zboží. Trigger může zakázat smazání zákazníka zdatabáze v případě, kdy má u nás nějaký dluh a podobně.

Page 139: MySQL Obsah

2. Protokolování změn: Trigger může evidovat kdo, kdy a jak měnil data. Lze tak dohledat pracovníka,který zadal špatné údaje nebo zjistit, v kolik hodin došlo k navstupování včerejší uzávěrky.

3. Verzování dat: Díky triggerům lze snadno naprogramovat aplikaci tak, aby jedna tabulka udržovalahistorii změn tabulky jiné. To lze s úspěchem použít třeba jako bezpečnostní mechanismus. (Pouze námtím databáze dost naroste).

4. Zasílání zpráv světu: Trigger může spustit nějaký externí program nebo proces. Poněkud otřepanýpříklad praví, že při změně ceny akcií rozešle databáze e-maily obchodníkům; jistě si ale dokážetepředstavit i jiné využití.

Typický scénář použití triggerů je tedy takový:

1. Databáze zachytí požadavek na změnu dat - dejme tomu na aktualizaci dat v tabulce.

2. DMBS zjistí, zda je pro tuto tabulku definován trigger, který se má provést před aktualizací záznamů.Pokud ano, provede jej.

3. Jestliže trigger aktualizaci nezrušil, zapíší se data do tabulky.

4. DMBS zjistí, zda je pro tuto tabulku definován trigger, který se má provést po aktualizací záznamů.Pokud ano, provede jej.

5. Dokončeno. Systémové prostředky použité pro zápis dat jsou vráceny systému a čeká se na dalšípožadavek.

Aplikační logika v databázi

Poněkud kontroverzním tématem je použití triggerů jako centrálního bodu pro vytvoření či správu aplikačnílogiky. Zastánci tohoto přístupu tvrdí, že pomocí triggerů se v dnešní době ná naprogramovat prakticky cokoliva výsledek pak mohou používat všechny aplikace sdílející danou databázi; odpůrci zase tvrdí, že databáze byměla sloužit jako úložiště dat a pro správu aplikační logiky by měly sloužit aplikační servery.

Jak už to bývá, pravda je někde uprostřed. O tom, kolik toho budou zajišťovat triggery budete muset nakonecrozhodnout ve svých aplikacích sami.

Na co dát pozor

Přestože triggery jsou ve spoustě situací velmi přínosné, měli byste vědět, že jsou s nimi spojena určitá úskalí.Především - každý trigger zabere nějakou dobu. Pokud budete mít triggerů více a/nebo pokud budou provádětčasově dlouhé operace, můžete si snížit dobu odezvy databáze na akční dotazy. Rovněž triggery se obtížně ladí.Klasický akční dotaz změní data a skončí; trigger může data modifikovat, uložit jinam nebo operaci zakázat.Díky tomu bývá občas velmi obtížné zjistit, co se vlastně v databázi děje - a to je tím palčivější, čím vícetriggerů máte a čím složitější akce provádějí.

Page 140: MySQL Obsah

MySQL (47) - Triggery a praxe

S prstem na spoušti spouštíme spouště, aneb MySQL, triggery a praxe.

25.11.2005 06:00 | Petr Zajíc | přečteno 9072×

Komerční sdělení: Pořádáme Kurzy MySQL

V minulém dílu jsme si řekli dost o teorii triggerů, takže je čas podívat se na to, jak je můžeme v MySQL použítv praxi. Na jednu stranu to bude trochu smutné čtení, protože MySQL triggery zdaleka neumějí to, co triggerytřebas ve Firebirdu. Na druhou stranu je ale i tak život se spouštěmi veselejší než bez nich.

Triggery v praxi

Uvedli jsme, že triggery mohou přispívat k bezpečnosti dat a že jedním z příkladů může být "bezpečné" mazánířádků v tabulce. Bezpečné proto, že záznam není vymazán úplně, ale data jsou přesunuta do jiné tabulky, takžeje později lze dohledat. Pokud tedy budeme mít následující tabulku:

create table bezpecna (id int not null auto_increment, jmeno varchar( 50 ) not null, platdecimal(12,4) not null, primary key (id)) type = myisam;

S testovacími daty:

insert into bezpecna (jmeno, plat) values ('Jarda', 12000); insert into bezpecna (jmeno, plat) values ('Pepa', 13000); insert into bezpecna (jmeno, plat) values ('Franta', 14000); insert into bezpecna (jmeno, plat) values ('Honza', 10000); insert into bezpecna (jmeno, plat) values ('Anička', 11500);

Page 141: MySQL Obsah

můžeme chtít místo mazání z této tabulky data přesunout do "záložní" tabulky s tím, že si zároveňpoznamenáme, kdo a kdy ta původní data promazával. Něco takového zcela určitě můžeme svěřit triggeru.Vytvoříme si tabulku, která bude obsahovat data z původní tabulky a ještě údaj o "mazajícím" uživateli a čase,kdy se řádky odstraňovaly:

create table bezpecna_zaloha like bezpecna; alter table bezpecna_zaloha add column cas_odstraneni datetime; alter table bezpecna_zaloha add column uzivatel varchar (128);

a konečně, vytvoříme trigger, který při odstraňování dat ta původní data uchová v tabulkce bezpecna_zaloha:

create trigger trSaveRows before delete on bezpecna for each row begin insert into bezpecna_zaloha(id, jmeno, plat, cas_odstraneni, uzivatel) values (old.id, old.jmeno, old.plat, now(), user()); end;

Jaký je význam toho všeho? Výsledek spočívá v tom, že když se nyní pokusíte odstranit nějaká ta data z tabulkybezpecna, tak... vyzkoušejte postupně tyto příkazy:

delete from bezpecna where id > 2; select * from bezpecna; select * from bezpecna_zaloha;

Jak vidíte, smazaná data se objeví v tabulkce bezpecna_zaloha. K tomu všemu bude jistě vhodné uvést párpoznámek:

1. Trigger se tvoří pomocí příkazu CREATE TRIGGER.

2. Jméno triggeru musí být pro danou databázi jedinečné. To znamená, že nelze mít dva shodněpojmenované triggery ani na dvou různých tabulkách. Zvykl jsem si názvy triggerů začínat písmeny tr,abych je na první pohled odlišil od jiných objektů v databázi (jako jsou uložené procedury).

3. U každého triggeru musí být uvedeno, před nebo po jaké akci je spuštěn. Možnosti jsou BEFOREINSERT, BEFORE UPDATE, BEFORE DELETE, AFTER INSERT, AFTER UPDATE, AFTERDELETE. V MySQL navíc platí omezení, že pro každou z vyjmenovaných akcí smí existovat nejvýšejeden trigger. To mě trochu mrzí, protože v praxi někdy bývá zapotřebí provést více souvisejících akcí anejpřehlednější by bylo umístit tyto akce do samostatných triggerů. Aby těch omezení nebylo málo,neumožňuje MySQL definovat jeden trigger pro dvě akce najednou, což je v jiných databázích obvyklé.

4. Každý trigger musí souviset právě s jednou tabulkou. V našem případě souvisí s tabulkou bezpecna.Mimochodem - jestliže je tabulka odstraněna, jsou odstraněny i všechny související triggery.

5. Tělo spouště v MySQL začíná klauzulí FOR EACH ROW a ta značí, že následující akce bude provedenatolikrát, kolik je řádků ovlivněných akčním dotazem. Většinou předem nevíte, kolik řádků budeovlivněno, takže byste neměli spoléhat na to, zda a kolikrát bude tělo triggeru provedeno.

Page 142: MySQL Obsah

6. Jak jsem uvedl již v minulém díle seriálu, triggery mají přístup k měněným datům. Ten je reprezentovánvirtuálními tabulkami old a new. Jejich význam je ten, že tabulka old obsahuje původní data (ta, která semají mazat pomocí DELETE nebo ta, která se upravují pomocí UPDATE) a tabulka new obsahujekonečná data (ta, která se vkládají pomocí INSERT nebo ta, která budou v tabulce po provedeníUPDATE). My jsme v příkladu právě toho využili a data "schovali" do jiné tabulky.

7. Konečně, v triggeru lze využít i vestavěných funkcí. My jsme použili jednu funkci vracející současný časa další vracející právě aktivního uživatele. Díky tomu máme kompletní přehled o tom, kdo a kdy dataměnil.

K příkladu ještě jedno varování: Trigger se NESPUSTÍ při použití příkazu TRUNCATE TABLE. To neníchyba, ale vlastnost DMBS, takže pokud se spoléháte na nějakou akci, která se spustí při odstraňování dat ztabulky, buďte opatrní. Při použití DELETE FROM TABLE se však trigger spustí a zpracuje všechny řádky,které ještě v nebohé tabulce zbývají.

Triggery jako kontrola dat

Další typickou činností triggerů je kontrola měněných dat. Mělo by tedy jít například napsat trigger, který donaší tabulky zakáže vkládat platy vyšší než 30000,- Kč. Vypadal by nějak takhle:

create trigger trMaxPlat before insert on bezpecna for each row begin if new.plat>30000 then /*něco, co akci zruší*/; end if; end;

Bohužel, v době psaní tohoto článku je prakticky nemožné vyhodit nějakou smysluplnou chybu z triggeru, a tojejich použití pro kontrolu dat téměř znemožňuje. Pro informaci se můžete podívat do diskuse k tomuto tématu.Manuál doporučuje pro takový případ "uměle" vytvořit například chybu porušení primárního klíče, podle mě jeto však jen chabá náplast. Problém je reportován do buglistu (sem a sem), tak uvidíme, co s tím bude vývojářskýtým dělat.

Page 143: MySQL Obsah

MySQL (48) - UDF

Uživatelsky definované funkce jsou dalším rysem databáze MySQL, kterému se dnes podíváme na zoubek.

2.12.2005 06:00 | Petr Zajíc | přečteno 5871×

Komerční sdělení: Pořádáme Kurzy MySQL

Protože jsme se v tomto seriálu již začali věnovat novým rysům MySQL 5.0, jako jsou uložené procedury aspouště, slušelo by se rovněž zmínit se o uživatelsky definovaných funkcích. Ty byly totiž rovněž přidány vposlední době - a i s nimi je databázový život mnohem jednodušší. Pojďme se tedy podívat, co nám v tomtoohledu může MySQL nabídnout.

Uživatelsky definované funkce

Jak jste asi pochopili, uživatelsky definovaná funkce je taková, kterou si můžete sami napsat. V tomto ohledu byz hlediska MySQL mohlo dojít k určitému matení pojmů, v tomto systému si totiž můžete napsat vlastní funkcidvěma způsoby:

1. Jednak můžete rozšířit databázový systém napsáním rutiny v jazycích C či C++ a tuto rutinu pakzaregistrovat pro použití na serveru,

Page 144: MySQL Obsah

2. a jednak můžete (od verze 5.0.3) vytvářet uživatelsky definované funkce pomocí příkazu SQL -CREATE FUNCTION.

My se dnes budeme bavit pouze o tom druhém způsobu, a sice o vytváření funkcí pomocí příkazu CREATEFUNCTION. Tyto funkce se v mnohém podobají uloženým procedurám - například v tom, že mohou požadovatvstupní parametry nebo v tom, že jsou svázány s konkrétní databází. Než bych to dlouze vysvětloval, radějiposloužím nějakým názorným příkladem. Je to odpověď na otázku, kterou často dostávám e-mailem: zda a jakse dá zajistit, aby MySQL vracela české datumy s textovým označením měsíce.

My na to půjdeme tak, že si vytvoříme funkci, která podle pořadového čísla měsíce "natvrdo" vrátí jehotextovou reprezentaci (ve druhém pádě). Jak bude tato funkce vypadat? Nějak takhle:

delimiter $$ create function mesicslovy (mesic tinyint) returns varchar (9) begin return case mesic when 1 then 'ledna' when 2 then 'února' when 3 then 'března' when 4 then 'dubna' when 5 then 'května' when 6 then 'června' when 7 then 'července' when 8 then 'srpna' when 9 then 'září' when 10 then 'října' when 11 then 'listopadu' when 12 then 'prosince' end; end $$ delimiter ;

Jak vidíte, je tvorba uživatelských funkcí v MySQL velmi prostá. Je ale přitom třeba mít na paměti následujícízásady:

1. Funkce se vytváří pomocí klauzule CREATE FUNCTION.

2. Funkce může (ale pochopitelně nemusí) přijímat vstupní parametry. Těch může být jedna a více - ale jetřeba určit jejich typ.

3. Dále je třeba určit, jaký datový typ bude naše milá funkce vracet. To se provede pomocí klíčového slovaRETURNS. Pozor, na konci je S.

4. Pak následuje tělo funkce, ohraničené pomocí bloku BEGIN a END tak, jako je tomu u uloženýchprocedur. Všimněte si, že v našem případě je tělo funkce tvořeno jediným příkazem; samozřejmě to nenípodmínka.

5. Tělo funkce musí obsahovat klíčové slovo RETURN (bez S), které vrátí výsledek.

Page 145: MySQL Obsah

Volání funkce

Takto vytvořená funkce je pochopitelně k ničemu, pokud ji nebudeme z kódu volat. Pro volání uživatelemvytvořených funkcí přitom platí jednoduché pravidlo: volají se stejně jako funkce vestavěné. Jinými slovysystém se chová tak, jako by v něm naše drahá funkce byla odjakživa. Pokud tedy napíšete:

select mesicslovy(5);

Dostanete kýžený výsledek ("května"). Samozřejmě, že jedna funkce může volat funkci jinou:

delimiter $$ create function ceskedatum (datum date) returns varchar (18) begin return CONCAT( day(datum), '. ', mesicslovy (month(datum)), ' ', year(datum) ); end $$ delimiter ;

Můžete si to vyzkoušet: Stačí zavolat něco ve smyslu:

select ceskedatum(now());

a hned obdržíte hezkou českou reprezentaci data přímo z MySQL. Výhoda je jasná - pokud bude databázivyužívat více různých klientů - možná napsaných v různých programovacích jazycích - všichni můžou těžit ztéto funkce uložené na serveru. A ještě jedna poznámka: při testech jsem si všiml, že MySQL standardněpřetypovává vstupní parametry funkcí na ten datový typ, který funkce očekává. Prakticky to znamená, ženásledující příkaz PROJDE:

select ceskedatum('2005-12-24');

Funkce očekávala datum, ale dostala řetězec. Ten se pokusila převést na datum, což se povedlo a tak se celýpříkaz v tichosti dokončil. Nejsem si tak úplně jistý, jestli je to dobře nebo špatně, ale pohodlné to každopádněje.

Použití funkcí

Přestože se funkcemi dá ošetřit leccos, měli byste je v MySQL používat spíše střízlivě. Do určité verze MySQLnesměly funkce obsahovat odkazy na tabulky, a i v současné době mají jistá omezení. "Správná" databázováfunkce by tedy měla být krátká, měla by řešit pouze jeden problém a to problém související s daty. Pěknýmpříkladem mohou být právě funkce sloužící k formátování výstupu.

Page 146: MySQL Obsah

MySQL (49) - pohledy

Žádné pozdravy z dovolené, nýbrž virtuální tabulky a práce s nimi. To nás čeká v dnešním dílu seriálu oMySQL.

9.12.2005 06:00 | Petr Zajíc | přečteno 6911×

Komerční sdělení: Pořádáme Kurzy MySQL

Motto: Každý velký systém má časem tendenci být nepřehledný.

Asi to znáte sami. Internet obsahuje spoustu míst, na něž byste se chtěli vrátit, souborový systém obsahujedesítky programů, které čas od času spouštíte a databáze obsahují kvanta dat v mnoha tabulkách. Ta věc máspolečné řešení - v prohlížeči máte záložky, na ploše zástupce a v databázi? V databázi jsou pohledy. Dnes budeřeč o pohledech v MySQL - co to je, jak to funguje a kdy něco takového použít.

Databáze rostou

Page 147: MySQL Obsah

Možná máte nějaký malý projekt používající databázi; snad na webu. Často se stává, že takový systém obsahujerelativně málo tabulek - třeba kolem deseti. Větší systémy však mají běžně několik desítek tabulek - a opravduvelké jich mají stovky a tisíce. Takže časem se bude každý, kdo s něčím tak velkým pracuje potýkat nejen smnožstvím dat v tabulkách, ale i s počtem tabulek jako takových.

Řešením mohou být pohledy (anglicky views). Pohled je virtuální databázová struktura, která může obsahovatdata z nula až více tabulek. Nebo chcete-li obdobnou definici, pak pohledy jsou "statické dotazy, s nimiž lzepracovat, jako by to byly tabulky". To znamená, že z nich lze především vybírat data (k čemuž slouží nejčastěji),a někdy do nich lze i data vkládat. Databázové systémy by se bez pohledů obešly - podobně, jako byste se naploše obešli bez zástupců nebo v prohlížeči bez záložek. Ale práce s nimi může být mnohem pohodlnější.

Pohledy v MySQL

MySQL má pohledy jako další "trhák" pětkové řady - jsou k dispozici od verze 5.0 a je to velmi žádaná funkcedatabáze. Přestože jsem uvedl, že pohledy byly vynalezeny jako prostředek, jak se vyznat v tabulkách, mají ještěcelou řadu výhod:

Mohou sloužit jako jiné pojmenování tabulek

Mohou z tabulky vybrat jen určité řádky (nebo sloupce)

Pohledy mohou obsahovat výrazy (jako jsou vestavěné funkce MySQL nebo uživatelsky definovanéfunkce).

Mohou spojovat data z více tabulek

A konečně, pohledy se mohou odkazovat na další pohledy

Jak se pohled vytváří? Velmi jednoduše, a sytaxe v tomto případě stojí za to, abyste se ji naučili zpaměti.Syntaxe je totiž de facto shodná se syntaxí příkazu SELECT s tím, že to celé je pojmenováno. Mějme tedynapříklad tabulku:

create table pracovnici (id int not null auto_increment , prijmeni varchar(50) not null , zamestnanod date not null , zamestnando date null , vek tinyint not null , primary key ( id )) type = myisam ;

s daty:

insert into pracovnici (prijmeni, vek, zamestnanod, zamestnando) values ('Novák',38,'2004-02-01',NULL), ('Horák',23,'2005-01-01','2005-11-30'), ('Votočková',28,'2004-11-01',NULL), ('Bízová',26,'2005-03-01','2005-10-30'), ('Přikryl',39,'2005-12-01',NULL);

Nejjednodušší pohled, vytvořený "nad" touto tabulkou by potom mohl vypadat nějak takto:

create view vwPracovnici as select * from pracovnici;

Page 148: MySQL Obsah

Od tohoto okamžiku můžete pohled použít jako tabulku, ve smyslu:

select * from vwPracovnici;

Ovšem, jak jsme uvedli, lze vytvořit i pohled s funkcemi. Takže, následující ukázky jsou všechny v pořádku:

create view vwPrumernyVek as select avg(vek) as prumer from pracovnici;

Vrátí průměrný věk (výsledek bude obsahovat vždy jen jeden řádek). Neboli pohled může obsahovat agregačnífunkci.

create view vwDobaNeurcita as select * from pracovnici where zamestnando is null;

Vrátí pracovníky, kteří nemají v tabulce údaj o datu ukončení pracovního poměru a jsou zaměstnáni na dobuneurčitou (za předpokladu, že to tak chápeme, údaj zamestnando by taky mohl znamenat datum vyhazovu).Neboli pohled může obsahovat podmínku.

create view vwSeznamLidi as select prijmeni from pracovnici order by prijmeni;

Vrátí prostě jen seřazený seznam jmen. Ukázka je zde proto, abyste si uvědomili, že dotaz nemusí vracet ztabulky všechny sloupce a že může obsahovat řazení. To v některých DBMS není tak samozřejmé a jinde todokonce vůbec nejde. Uvádět daší příklady pohledů asi nebude příliš přínosné - jen dodejme, že pohledy mohourovněž vracet data z více tabulek spojených pomocí LEFT JOIN nebo INNER JOIN.

Praxe

Všeho moc škodí. Pokud budete mít na ploše osmdesát zástupců, zřejmě ztratí svou původní funkci - rychlenajít a spustit program. Stejně tak pokud budete mít v databázi příliš mnoho dotazů, nejspíš se mezi nimiztratíte. Nezapomeťe, že když budete v aplikaci mít výběr z dotazu a ne z tabulky, tak si tím vytvoříte mnohemméně čitelný kód. Následující postřehy by Vám tedy mohly přijít vhod:

Používejte pohledy, pokud

si tím subjektivně zjednodušíte práci

se stejný dotaz opakuje

vám to usnadní psaní vícenásobných spojení

potřebujete mít v dotazu SELECT nějaké výrazy

Nepoužívejte pohledy, pokud

se dotazy, které by byly v definici pohledů nebudou opakovat

jich už máte v databázi spoustu a místo hledání existujícího si "pro jistotu" vytvoříte nový

Page 149: MySQL Obsah

"vrstvíte" dotaz na dotaz a nejste schopni poznat, z jaké tabulky vlastně data pocházejí

MySQL (50) - Pohledy podruhé

K pohledům se vracíme ještě jednou; tentokrát si ukážeme jejich roli při abstrakci datové vrstvy.

16.12.2005 06:00 | Petr Zajíc | přečteno 5217×

Komerční sdělení: Pořádáme Kurzy MySQL

Také dnes se budeme v našem seriálu věnovat pohledům. Podíváme se na to, jak nám mohou usnadnit život vkonkrétních případech. Trochu mě k napsání tohoto dílu seriálu vedla diskuze v minulém díle, kde jste si přálivíce příkladů na pohledy. A také jste chtěli vědět, jak mohou pohledy pomoci v situacích, kdy potřebujemeurčitou mezivrstvu, abstrakci mezi aplikací a databází.

Svět se mění a my s ním

Page 150: MySQL Obsah

Tento otřepaný slogan se dá použít samozřejmě taky na databáze. Je přirozenou podstatou věci, že v naprostévětšině databází bude docházet k výměně dat, většinou dost časté. Co je ale potřeba zároveň říci je to, že měnitse budou rovněž požadavky uživatelů na data, která mají databáze poskytovat okolnímu světu. Přičemž za"uživatele" je v této souvislosti potřeba považovat kohokoli, kdo má s daty něco do činění – od programátora pomanagera.

Uveďme si proto postupně několik příkladů, z nichž – jak alespoň doufám – vynikne síla použití pohledů jakomezivrstvy. Věřím, že další příklady si pak budete moci vymyslet a aplikovat sami.

Mějme třeba tabulku obsahující osobní data nějaké té skupiny lidí:

create table lidi (jmeno varchar (20), narozendne date);

S následujícícmi daty:

insert into lidi (jmeno, narozendne) values ('Jarda', '19700101'); insert into lidi (jmeno, narozendne) values ('Jana', '19751231'); insert into lidi (jmeno, narozendne) values ('Petr', '19801010');

Z ní budete chtít vytáhnout jméno člověka a jeho věk. S pomocí pohledů na to můžete jít nějak takhle:

create view vwVek as select jmeno, year(now())-year(narozendne) as vek from lidi;

Data z pohledu pak zabudujete do jedné či více aplikací, sestavíte potřebný kód (možná v PHP či v jinémprogramovacím jazyce) a je to. Takže ve finále máte:

1. Tabulku lidi obsahující data

2. Aplikaci, která z této tabulky čerpá, a

3. Pohled, který toto čerpání zajišťuje.

Pozn.: Někteří programátoři si v této souvislosti zvykli označovat pohledy používané v jednotlivých aplikacích(nebo částech projektu) nějakým prefixem. Takže by to mohlo vypadat ve stylu vw_Personalistika_vek nebopodobně. Já jsem zastáncem krátkých jmen pohledů, ale jisté je jedno: zaveďte si systém, a toho se pak držte.

Jednoho dne se ale zjistí, že dotaz je sémanticky špatný. Když se někdo narodí na silvestra, hned následující denmu už pohled vrátí jeden rok věku, stejně jako člověku, který se narodil téhož roku, jenomže na nový rok. Takženezbude, než milý pohled lehce přepsat ve stylu:

select jmeno, case when dayofyear(now())>=dayofyear(narozendne) then year(now())-year(narozendne) else year(now())-year(narozendne)-1 end as vek from lidi

Teď už bude program porovnávat nejen letošní rok s rokem narození člověka, ale bude se rovněž zabývatzbylou částí data. (Hrátky s daty nejsou námětem tohoto článku, takže příklad vezměte s rezervou). Co se ale vtomto případě stane s naším projektem?

Page 151: MySQL Obsah

1. Tabulka obsahující data zůstala nezměněna

2. Aplikace, která z této tabulky čerpá zůstala rovněž nedotčena

3. Změnil se jen a pouze pohled, který zprostředkovává spojení mezi aplikací a daty.

Z toho všeho je jasně vidět, že vhodným použitím pohledů si můžeme ušetřit mnoho práce při sestavováníprakticky jakéhokoli databázového projektu.

Role pohledů při změně struktury dat

Možná namítnete, že předchozí příklad nebyl zase až tak přesvědčivý. Že šlo o chybu na straně logiky aplikace,kvůli níž by se tak jako tak muselo něco předělat, a že by se tomu všemu dalo vyhnout vhodným uplatněnímzlatého pravidla "Dvakrát měř, jednou řež". To může být pravda, existuje však řada dalších příčin, kvůli nimžbudete muset nakonec sáhnout na pohledy. Jednou z častých je změna struktury databáze.

Ideální databáze nikdy nemění svou strukturu; ale to je v praxi k vidění málokdy. Často to bývá tak, že zrůzných důvodů bývá nutné strukturu tabulek měnit. Schválně ukážu učebnicový příklad. Máte tabulku, kterázachycuje výdej položek ze skladu:

create table pohyb (zbozi varchar(50), datum datetime, odebral varchar(20));

s daty

insert into pohyb (zbozi, datum, odebral) values ('Šrouby', '20051201','HřebíkFrantišek'); insert into pohyb (zbozi, datum, odebral) values ('Matice', '20051202','Matičný Karel'); insert into pohyb (zbozi, datum, odebral) values ('Podložky', '20051202','HřebíkFrantišek'); insert into pohyb (zbozi, datum, odebral) values ('Podložky', '20051202','PodložnýJosef');

a pohled, v němž si budete přát zachytit pohyby seřazené podle data a odběratele:

create view vwPohyb as select datum, odebral, zbozi from pohyb order by datum, odebral;

časem ale zjistíte, že bude praktické mít pro odběratele vlastní tabulku:

create table odberatele (id int not null auto_increment, jmeno varchar(20) not null,primary key (id)); insert into odberatele (jmeno) select distinct odebral from pohyb; alter table pohyb add odberatelid int; update pohyb join odberatele on pohyb.odebral = odberatele.jmeno set pohyb.odberatelid =odberatele.id; alter table pohyb drop column odebral;

Pozn.: Koho to zajímá, pro toho dodáme, že tento postup je součástí procesu, jemuž se říká normalizacedatabáze a který by se měl udělat předtím, než se databáze skutečně naplní a pustí do ostrého provozu. Rovněžzde uvedený příklad je školácký – žádný zkušený databázový expert by nenavrhl tabulku pohyb tak špatně. Berteto ale jako příklad věci, která se v té či oné podobně v praxi stává.

Page 152: MySQL Obsah

Co se ale stalo s naším pohledem? Ten přestal fungovat, protože pole odebral se v naší databázi již nevyskytuje.Naštěstí je pomoc snadná, pohled lze upravit:

alter view vwPohyb as select pohyb.datum, pohyb.zbozi, odberatele.jmeno as odebral from pohyb join odberatele on pohyb.odberatelid = odberatele.id order by pohyb.datum, odberatele.jmeno;

Protože má tento pohled stejnou logiku jako předchozí, aplikace, která z něj těží opět může zůstat beze změny.Existuje ještě celá řada situací v nichž může být dobrý nápad použít pohledy - a v aplikacích se odkazovat na ně– namísto prostého výběru dat z tabulek. Jednou z nich může být potřeba specifického řazení, které jsme již vtomto seriálu probírali. Pohledy tedy mají své místo nejen jako zkratky k datům, ale i jako abstrakční vrstva„vřazená“ mezi aplikace a data. Největším problémem pak často zůstává donutit se důsledně používat pohledynamísto přímých dotazů do tabulek, ale to už je otázka disciplíny nebo interních pravidel pro psaní kódu.

MySQL (51) - Metadata

Dnes se podíváme na to, jak nám práci s databází MySQL může usnadnit systémový katalog. Řeč tedy bude ometadatech.

23.12.2005 06:00 | Petr Zajíc | přečteno 4640×

Komerční sdělení: Pořádáme Kurzy MySQL

Když jsme v seriálu probírali ty důležité změny, které přináší MySQL 5.0, přece jen jsme něco vynechali.Hovořili jsme o uložených procedurách, spouštích, uživatelsky definovaných funkcích a pohledech. "Pětka" mávšak ještě další významnou novinku, a tou je systémový katalog.

Page 153: MySQL Obsah

Definice

Pro systémový katalog se běžně používá několik vzájemně se překrývajících termínů. Proto v této souvislostimůžete slyšet výrazy jako databázová metadata (database metadata), datový slovník (data dictionary) nebosystémový katalog (system catalog). Pokaždé se však jedná o to samé - metadata popisují strukturu samotnédatabáze. Proto se pojem metadata vysvětluje jako "data o datech".

Celá myšlenka metadat spočívá v tom, že údaje o jednotlivých databázích, tabulkách, sloupcích, indexech,uložených procedurách a tak dále jsou uloženy na jednom místě. Asi už tušíte kde - jsou uložena v samostatnédatabázi. Tato logika implementující sama sebe má svoji výhodu - uvědomte si, že mezi databázemi, tabulkamia sloupci jsou vlastně relační vztahy. Není tedy nic jednoduššího, než na uložení metadat použít stejný způsobjako na uložení samotných dat.

Myšlenka metadat pochopitelně není nová a MySQL není jediná databáze, která obsahuje systémový katalog.Ve skutečnosti téměř každá soudobá databáze nějaký ten katalog obsahuje. Koho to zajímá, pro toho můžemeuvést, že informační schéma je rovněž součástí SQL standardu ANSI/ISO SQL:2003.

Katalog v MySQL

Už jsme uvedli, že katalog je reprezentován databází. A v MySQL je touto databází information_schema.Protože je systémový katalog v MySQL až od verze 5.0, je pochopitelně i tato databáze přítomna až od verze5.0. Krátký pohled na tuto databázi nám objasní, co všechno obsahuje:

informace o znakových sadách a způsobech řazení

informace o jednotlivých sloupcích tabulek databází

informace o klíčích a indexech

informace o uložených procedurách

seznam databází na daném serveru

seznam tabulek v těchto databázích

informace o triggerech

informace o pohledech

seznam uživatelů a jejich oprávnění

Page 154: MySQL Obsah

Jak to funguje

Celý katalog si pochopitelně databázový server obhospodařuje sám. To znamená, že informační bude žít svýmvlastním životem, aniž byste se o ni museli nějakým způsobem starat. V praxi to vypadá tak, že když provedetenějaký ten definiční příkaz (dejme tomu CREATE TABLE), tak se v databázi nejen vytvoří potřebná tabulka,ale rovněž se do katalogu zapíší všechna metadata.

Manuál k MySQL podrobně popisuje, jaká je struktura jednotlivých tabulek v informační databázi a rovněžposkytuje příklady toho, jak tyto informace smysluplně použít. My se za chvíli podíváme na některé prakticképříklady.

Důležitá věc: Informační databáze slouží pouze k prohlížení, nemůžete do ní zapisovat. Všechny změny vdatabázi je tedy potřeba dělat pomocí definičních příkazů. Stojí rovněž za zmínku, že některé tabulky vinformační databázi fyzicky neexistují, jsou pouze virtuální. Jak bystrý čtenář usoudí, je pro ně použit typtabulky MEMORY. Přístup do systémového katalogu rovněž může být upraven pomocí oprávnění uživatelů.

Použití

Protože jsou metadata v tabulkách, lze s nimi pracovat pomocí příkazu SELECT. To znamená, že je můžemeseskupovat, třídit, spojovat, filtrovat a podobně. Jestliže tedy budu chtít znát názvy všech tabulek v databázitest, mohu použít něco ve smyslu:

select * from tables where table_schema = 'test'

V praxi používám systémový katalog na několik věcí. Především, je třeba si uvědomit, že katalog obsahujezdrojový kód všech uložených procedur a pohledů, takže pokud jsem někde ztratil zdrojový kód procedury, nenínic jednoduššího než přepnout se do informační databáze a napsat:

select routine_name, routine_definition from routines;

A kódy procedur jsou na světě. Druhá věc, na níž metadata používám je zjišťování údajů o sloupcích. Taknapříklad sloupec typu varchar má zcela jistě definovánu nějakou maximální délku řetězce, kterou do něj lzeuložit. Tuto délku asi budete chtít znát pro případnou kontrolu, zda uživatel nezadal více dat, než je zdrávo.Kýžený údaj se dozvíte takto (použil jsem zjišťování údajů o tabulce z minulého dílu seriálu):

select column_name, character_maximum_length from columns where table_name = 'lidi' and data_type='varchar';

Pozn.: Tohle má mnoho využití. Ve webových formulářích například často budete sbírat údaje od uživatelů spomocí prvků typu TEXT nebo TEXTAREA. Pokud se mají údaje uložit do databáze, bude jen žádoucízkontrolovat jejich délku.

A třetí věc, na níž používám metadata je tvorba "automatických" kusů kódu. Obecně se dá říci, že databázovýsoftware trpí častým opakováním kódu. Vybíráte data z rozevíracích seznamů, zobrazujete tabulky na základěsad záznamů a tak dále. Používané kódy se často podobají jeden druhému jako vejce vejci, a rozdíl bývá jen vtextech dotazů získávajících data. Do aplikace však většinou není třeba nic "natvrdo" zadávat - postačí páršikovných dotazů na metadata a univerzální rozhraní pro zobrazení prakticky čehokoliv je na světě.

Metadata se dají pužít i k mnoha dalším věcem. Můžete například snadno zjistit, která tabulka ve vaší databázimá nejvíce sloupců nebo která nemá primární klíč. Platí samozřejmě, že výhody systémového katalogu jsou tímzřejmější, čím větší databázi máte. Nic se nesmí přehánět; pokud vaše databáze obsahuje dvě tabulky, nejspíš sebez služeb katalogu obejdete.

Page 155: MySQL Obsah

MySQL 4

V MySQL 4 sice katalog není k dispozici, ale částečně jej nahrazuje sada příkazů show. Tak napříkladinformace o sloupcích tabulky lidi můžete zobrazit pomocí něčeho jako:

show full columns from lidi;

Není to sice zdaleka tak pružné jako použití systémového katalogu, ale v mnoha případech to bohatě postačí.

Závěr

Katalog je v MySQL až od verze 5.0. Což znamená, že až dosud se vývojáři museli obejít bez něj a byli taknuceni používat příkazy SHOW TABLES, SHOW DATABASES a podobně. Protože dotazy na metadatanebývají stežejními částmi aplikací, pravděpodobně se příkazy SHOW nebudou s nástupem "pětky" masivněpředělávat; spíše při vývoji nových věcí bude možné použít namísto toho katalog. Neboli - nakládání s metadatyje třeba znát, ale svět na tom nestojí.

MySQL (52) - A co zálohování?

... není to tak jednoduché, jak jste čekali. Nebo snad ano?

30.12.2005 06:00 | Petr Zajíc | přečteno 6206×

Komerční sdělení: Pořádáme Kurzy MySQL

Page 156: MySQL Obsah

Již jsme se podívali na zoubek všem podstatným změnám, které přináší pětková verze databáze MySQL. Takžese teď s klidným svědomím můžeme věnovat zase trochu obecněji platným tématům. Jinými slovy, unásledujících dílů seriálu si přijdou na své i uživatelé starších verzí MySQL. Řeč dnes bude o zálohování; aprotože toto téma si to zaslouží, bude to spíše teoretický rozbor toho proč, co, kdy, kdo a jak má (může)zálohovat. Jak uvidíme, celé téma je dost rozsáhlé.

Zálohování dat

Je naprosto samozřejmé, že dříve či později narazíte při práci s libovolnou databází na problém zálohování dat.Typická databázová aplikace ukládá drtivou většinu svých dat (ne-li všechna) právě do databáze a přijít o němůže znamenat naprostou katastrofu. Problém se nevyhýbá ani MySQL - i zde se bude muset zálohování nějakřešit. Dnešní zamyšlení nám ale má pomoci uvědomit si, že různé aspekty zálohování vyžadují různý přístup aže ne vždy rozumíme pod výrazem zálohování totéž.

Proč zálohovat

Tato zdánlivě jednoduchá otázka má více odpovědí. Zálohovat můžete:

1. Abyste nepřišli o data, nebo abyste přišli o co nejméně dat. V případě poruchy hardware pak můžeteobnovit data z nějaké zálohy.

2. Abyste mohli čelit útokům - jestliže se někdo pokusí databázi změnit nebo odstranit, vždy máte "bodnávratu", data, která můžete nahradit.

3. Proto, že databázi chcete chcete zkopírovat nebo přesunout na jiný stroj nebo systém. To může býtpotřeba z nejrůznějších důvodů - vývojem počínaje a výměnou hardware konče.

4. Jako součást dokumentace - technická zpráva k projektu může například obsahovat popis databáze nebovzorek nějakých dat. Taková (třeba i malá) sada dat může sloužit k testování či proto, aby se v projektuvyznali i jiní.

Jistě by se našly i další důvody. Uvádím to celé proto, abyste si uvědomili, že potřeba zálohování můžepramenit z kdečeho a postupy se pak mohou lišit.

Co zálohovat

"Zálohování databáze" je široký pojem, možná až moc. V zásadě můžete zálohovat:

1. Strukturu databáze (tedy definici jednotlivých sloupců tabulek)

2. Samotná data

3. Strukturu a data

Page 157: MySQL Obsah

4. Část dat (jen související tabulky apod.)

5. Celou databázi (včetně existujících indexů a podobně)

6. Celý server (více databází)

Mezi jednotlivými body jsou jemné kvalitativní rozdíly. Není například pravda, že zálohovat "strukturu a data"znamená zálohovat "celou databázi". Kromě dat totiž databáze může obsahovat i například indexy - a ty můžetea nemusíte chtít uchovat. Připomeňme si, že indexy se dají podle potřeby rušit a vytvářet relativně nezávisle nadatech. Rovněž můžete a nemusíte chtít zachovat definici uživatelsky definovaných funkcí, uložených procedur,spouští a pohledů.

Kdy zálohovat

Třebaže se Vám to možná bude zdát zvláštní, tak vězte, že tohle je jedna z nejtěžších otázek při správě databází.Na jednu stranu budou existovat (relativně) bezcenná data, která možná nebudete chtít zálohovat nikdy. Mám namysli třeba staré přístupové protokoly. Na druhou stranu existují data tak cenná, že byste je chtěli zálohovattéměř po každé operaci. Protože zálohování může nepříznivě ovlivnit výkon systému, souběžnost práce sdatabází a může zabrat docela dost místa na disku, je v praxi běžně k vidění kompromis mezi oběma extrémy.Ten kompromis může být následující:

výkon a souběžnost - aby zálohování mělo co nejmenší dopad na výkon systému, provádí se v době, kdyje databáze nejméně zatěžována (například v noci). Někdy je jednoduché určit, kdy je zatížení nejmenší,jindy je to rébus; takže uvedenou zásadu nelze chápat striktně.

místo na disku - toto se řeší dvěma způsoby. Jednak tím, že se zálohy umisťují na různá místa či zařízení(CD/DVD disky, jiný oddíl HDD a podobně) a jednak tím, že existují plné a inkrementální zálohy

Kdo zálohuje?

I to je na pováženou. Zálohovat samozřejmě může:

1. Uživatel systému nebo aplikace

2. Správce systému (např. správce serveru)

3. Počítač pomocí nějakých naplánovaných úloh (cron) či při splnění nějaké podmínky (čas od poslednízálohy, velikost dat a podobně)

Protože sám vyvíjím databázové aplikace, dovolte, abych tu nastínil jednu zásadu: Ponechat zálohování nauživateli je cesta k maléru. Průměrný uživatel zkrátka data zálohovat nebude, a pokud ano tak jen proto, že vminulosti již o nějaká ta data přišel. To samozřejmě neznamená, že bychom uživatelům neměli umožnitzálohování provést; spíše to znamená, že bychom se na to neměli v žádném případě spolehnout.

Page 158: MySQL Obsah

Správce serveru naproti tomu většinou data zálohovat bude, zejména pokud je provoz databázového serverusoučástí placených služeb. V případě hostingu s databází bude například jistě v zájmu providera, aby vaše dataochránil jak před zneužitím, tak i před ztrátou. Pokud si databázový server spravujete sami, asi taky budete chtítdata nějakým způsobem ochránit.

Konečně, existuje celá řada více či méně povedených nástrojů a utilit pro zálohování dat, které mohou fungovatbez zásahu uživatele, a které navíc mohou mít jednu či více z následujících schopností:

komprimace záloh

odesílání záloh "někam" (FTP, SSH apod.)

vytváření protokolů o zálohování

notifikace pro případ selhání systému zálohování

spolupráce více zálohovacích systémů nebo zařízení

uživatelské rozhraní pro konfiguraci

Jak zálohovat

Tomu se budeme podrobně věnovat příště. Teď je potřeba říci, že dostupné prostředky se pochopitelně budoulišit případ od případu. Jestliže jste správcem serveru s právy superuživatele, máte samozřejmě k dispozicimnohem více možností než pokud máte na témže serveru hosting s jednou databází. Rovněž je třeba rozlišovatpodle množství zálohovaných dat: pokud databáze denně přijme deset řádků do dvou tabulek, bude zálohovánízcela jistě jednodušší než pro databázi s desítkami tisíc změn denně.

Doufám, že jsem Vás přesvědčil, že zálohování se nedá odbýt jedním řádkem kódu a že je potřeba tyto věciznát. Pokud ano, můžete se těšit na další díl seriálu, který bude zaměřen již více na praxi.

MySQL (53) - SELECT INTO OUTFILE

Jak tedy zálohovat data v MySQL? Pomocí příkazu SELECT!

6.1.2006 06:00 | Petr Zajíc | přečteno 7159×

Komerční sdělení: Pořádáme Kurzy MySQL

Page 159: MySQL Obsah

Pojďme se dnes podívat na to, jak jednoduše se pomocí MySQL dají zálohovat data z jedné nebo více tabulek.Jak uvidíte, může s tím být docela zábava. Již minule jsme hovořili o tom, že jednotlivé metody zálohování semohou lišit - dnes uvidíte, že je to skutečně pravda, i když budeme mluvit jen o jedné z nich.

SELECT INTO OUTFILE

Klasický příkaz SELECT obsahuje velmi milé rozšíření, které nám umožní přímo vyexportovat vybraná data dotextového souboru. Místo toho, abyste napsali příkaz ve stylu:

select * from lidi;

napíšete prostě

select * from lidi into outfile 'lidi.txt';

a výsledná množina dat se vloží do nového souboru. Je to velmi jednoduchá a prostá myšlenka, kteránevyžaduje další znalosti. Stačí umět používat příkaz SELECT.

Výhody příkazu SELECT INTO OUTFILE

Výhod tohoto přístupu k zálohování je několik, pojďme si projít ty hlavní:

1. Můžete si vybrat, které tabulky budete chtít zálohovat.

2. Můžete si (vyjmenováním sloupců v příkazu SELECT) vybrat jen určité sloupce tabulky.

3. Můžete si (použitím klauzule WHERE) vybrat jen určité řádky

4. Výslednou množinu můžete seřadit.

5. Přestože se to nepoužívá příliš často, lze takto zálohovat spojení dvou či více tabulek (tedy saduzáznamů vzniklou použitím LEFT JOIN, RIGHT JOIN či INNER JOIN)

6. Celý příkaz je velmi jednoduchý na naučení a intuitivní.

7. Výsledný soubor je čitelný člověkem

8. Protože je výsledný soubor textový, bývá snadné jej komprimovat a obvykle rovněž kompresní poměrbývá velmi solidní.

9. Proces zálohování pomocí tohoto příkazu je dosti rychlý

Export můžete jemně ovlivnit použitím několika voleb, které formátují výstup. Uvádím je v tabulce:

Page 160: MySQL Obsah

Volba VýznamFIELDS ESCAPED BY Escapování znaků. Například NULL je zapsáno jako \N, pokud je

escape znakem obrácené lomítkoFIELDS ENCLOSED BY Umožňuje zvolit znak, který bude uzavírat data (např. uvozovka)FIELDS OPTIONALLYENCLOSED BY

Umožňuje zvolit znak, který bude uzavírat data (např. uvozovka),ovšem pouze textová. Čísla zůstanou neobklopena ;-)

FIELDS TERMINATED BY Znak sloužící k oddělení polí, typicky středník nebo tabelátor.LINES TERMINATED BY Znak sloužící k oddělení řádků (záznamů). Typicky systémový znak

konce řádku.

Pokud si nechcete tyto volby pamatovat, pak vězte, že nemusíte. K prostému zazálohování postačí výchozíhodnoty všech voleb. Zejména, pokud budete chtít data opět obnovit pomocí nástrojů MySQL. Je ale dobrévědět o těchto přepínačích; zejména pracujete-li pod více operačními systémy. Ve Windows je například dobrédefinovat konec řádku jako \r\n, aby byl výsledný soubor vidět v textových editorech, které jsou tam k dispozici.

Pozn.: Nic Vám samozřejmě nebrání zálohovat data v jednom operačním systému a obnovit je v jiném.Komplementární příkaz LOAD DATA INFILE má k dispozici volby, pomocí nichž se vyrovná třeba snesystémovými oddělovači řádků.

Nevýhody příkazu SELECT INTO OUTFILE

Jak asi tušíte, příkaz SELECT INTO OUTFILE má rovněž nějaké ty nevýhody. Jednou drobnou nevýhodoumůže být fakt, že textový soubor po vytvoření neobsahuje záhlaví sloupců. To je sice možná trochu nepříjemné,ale nikoli neřešitelné. Můžete totiž exportní příkaz upravit ve smyslu:

select 'jmeno','narozen dne' union all select jmeno, narozendne from lidi into outfile'lidi2.txt';

Připomeňme, že příkaz UNION umožňuje spojit data z více tabulek. V našem případě byla první "tabulka" jenvirtuální a obsahovala názvy polí. MySQL přitom ani nevadí, že spojovaná data nejsou téhož typu, takže tentopříkaz můžete bez obav použít. Další drobnou nevýhodou příkazu je fakt, že se nedá přesně určit, kam budoudata zapsána v případě, že neuvedete absolutní cestu. Mám zkušenost, že to závisí na verzi MySQL a napoužívané distribuci, takže je třeba být opatrný, pokud se chcete na výchozí chování systému spolehnout. Jábych preferoval jistější způsob - a to vždy uvádět absolutní cestu k exportovanému souboru.

A teď ty největší nevýhody. Všechny podstatné nějakým způsobem souvisejí se zabezpečením.

Soubor vzniklý pomocí SELECT INTO OUTFILE je uložen vždy na databázovém serveru. Když se nadtím zamyslíte tak je to samozřejmé; uvádím to jen proto, abyste neočekávali, že bude vytvořena zálohana nějakém klientském, vzdáleném počítači.

Soubor, který vznikne pomocí SELECT INTO OUTFILE musí být nový. Jinými slovy, tento příkaz senikdy nepokusí přepsat existující soubor, a to bez ohledu na to, kdo a kdy původní soubor vytvořil.Neuděláte tedy ani dvakrát stejný soubor. To je určitý bezpečnostní prvek, který zabraňuje MySQLpřepsat (ať už neúmyslně nebo cíleně) existující soubory v systému. Pokud chcete využívat tento příkaz,musíte se tedy ujistit, že cílový soubor neexistuje.

Abyste mohli příkaz SELECT INTO OUTFILE provést, musíte mít příslušná databázová práva

Page 161: MySQL Obsah

K databázovým právům - MySQL kontroluje, kdo smí nebo nesmí v operačním systému vytvářet soubory. Cožse přesně týká příkazu SELECT INTO OUTFILE. Pokud budete chtít zjistit aktuální stav oprávnění pro zápis dosouborů, můžete to provést dotazem na metadata (od verze 5.0) nějak takto:

select * from user_privileges where privilege_type = 'FILE';

Špatná zpráva pro uživatele MySQL na hostinzích je ta, že většinou mít potřebná práva nebudete - a to je docelaškoda. Tento způsob zálohování patří totiž k těm rychlejším a pružnějším. Ale pokračujme ještě dalšímiomezeními:

Pokud je soubor úspěšně vytvořen, je čitelný komukoliv. To je něco, co Vám může vadit a nemusí. Alepříčina je zase zcela jasná; uvědomte si, že soubor vytváří databázový stroj, a ten běží pod nějakýmúčtem. Pokud by vytvořené soubory nezpřístupnil ostatním, asi byste zálohu nemohli číst ani vy. Téměřurčitě totiž budete přihášeni pod jiným uživatelským účtem, než pod nímž běží databáze apravděpodobně nebudete ani členem téže skupiny.

A abychom byli přesní - soubor je potřeba vytvořit v takovém adresáři, do něhož máte odpovídajícípráva (například domovský adresář), aby se vám nestalo, že databáze sice export provede, ale vy se kněmu nedostanete.

Poslední nevýhoda tohoto způsobu zálohování dat je ta, že budete mít pouze data - nezálohují se tímtedy indexy, pohledy, spouště, uložené procedury a tak dále.

Závěr

Pokud máte přístup k systému, na němž MySQL běží a pokud se chcete zabývat zálohováním jen nějakých dat,pak je pro Vás jistě SELECT INTO OUTFILE dobrou volbou. V opačném případě však nejspíš kvůlibezpečnostním omezením systému nebudete moci tento přístup použít a je potřeba jít na to jinak. Jak, touvidíme v dalším díle našeho seriálu.

MySQL (54) - zálohování MySQL z webu

Ať chceme nebo ne, většinou se MySQL používá ve spojení s weby. Jak zálohovat data v tomto případě?

13.1.2006 06:00 | Petr Zajíc | přečteno 7105×

Komerční sdělení: Pořádáme Kurzy MySQL

Page 162: MySQL Obsah

Je na čase zaměřit se na zálohovací potřeby těch uživatelů, kteří pracují s MySQL na webech. Ne snad, že by tobyla nějaká zvláštní skupina databázových guru, ale kombinace webu a MySQL je pro mnoho prezentací prostětypická. Takže, jak mohou zálohovat data z MySQL majitelé prezentací či internetových obchodů? Jak vidíme,je jejich prostředí pro běh MySQL specifické. Pojďme se tedy podívat, s čím lze počítat.

Prostředí

Typické hostingové prostředí, v němž je provozována MySQL na webu, vypadá nějak takto:

Webový server běhá na Linuxu

K dispozici je nějaký skriptovací jazyk, snad PHP

MySQL běhá na stejném serveru jako web, nebo na serveru v místní LAN

Uživatel prezentace má k dispozici typicky jednu databázi MySQL

Uživatel nesmí do databáze přistupovat vzdáleně, t.j. z cizí IP adresy

Uživatel nemá přístup k systému (nemá systémový účet)

Uživatel nemůže provádět příkaz SELECT ... INTO OUTFILE

Uživatel však má k dispozici jeden nebo více adresářů, do nichž může zapisovat; často i mimo kořenovýadresář svojí prezentace

Dále je typické, že na stejném databázovém serveru jsou umístěny databáze mnoha jiných uživatelů a žewebový server obhospodařovává požadavky několika webů. Skutečností tedy je, že v takovém prostředí spíševíce věcí nesmíte než můžete. Přesto i tady máte určité možnosti, jak smysluplně zálohovat.

PhpMyAdmin

O tomto webovém nástroji na správu databáze MySQL máme na našem webu seriál od Michala Čihaře. Vnaprosté většině případů se Vám podaří tento nástroj nainstalovat a nakonfigurovat bez komplikací, protoženemá žádné zvláštní požadavky na systém (požaduje vlastně jen webový server, PHP a databázi MySQL). Jerovněž možné, že jej budete mít na serveru již k dispozici přímo od hostingové společnosti.

Příjemnou vlastností PhpMyAdminu je to, že umí exportovat data z MySQL do několika nejběžnějších formátů- a Vy tak můžete databázi zálohovat. Mezi formáty, do nichž můžete data zazálohovat, a které jsou z tohotohlediska zajímavé patří:

Page 163: MySQL Obsah

1. Textové soubory oddělené čárkou nebo středníkem. Data jsou pak v souboru uspořádána podobně, jakokdybyste je exportovali pomocí SELECT INTO OUTFILE.

2. Příkazy SQL. Vznikne sice poněkud větší soubor, ale ten bude obsahovat přímo sadu příkazů INSERTs tím, že spuštěním tohoto souboru proti cílové databázi dojde k obnově dat.

3. Soubory Microsoft Excel. Pro zarytého linuxáka je třeba dodat, že soubor půjde otevřít pomocíOpenOffice.org Calcu, pro všechny pak to, že dávám přednost spíše textovým souborům pro zálohování.

4. Soubory Microsoft Word. Z hlediska zálohování se moc nehodí, neb případná obnova dat z takovéhosouboru by nebyla příliš triviální.

PHPMyAdmin má sice skvělé možnosti, ale někdy jej buď nemůžeme použít, nebo potřebujeme něco vlastního- třeba zálohovat jen kus tabulky. V tom případě nám nezbyde než si zálohovací proceduru napsat sami. Pokudse do toho budete chtít pustit, možná zjistíte, že bude užitečné prostudovat nějaký kus hotového kódu. UPHPMyAdmina si tak například můžete prohlédnout skript export.php, a rovněž všechny skripty ve složcelibraries/export. Možná zjistíte, že se tam najde něco užitečného i pro Vás.

Vlastní skript

Úmyslně nechci zabíhat do tajů skriptovacích jazyků, takže jen stručně. Pokud máte k dispozici adresář s právyzápisu a nějaký ten skriptovací jazyk, můžete si zálohování napsat sami. Struktura skriptu přitom bude velmijednoduchá, zejména pokud budete chtít zálohovat do textových souborů. Pro většinu jazyků (PHP, Python,Perl) bude postup dosti podobný. Může to (psáno v pseudojazyce) vypadat nějak takto:

otevřít spojení na databázi vytvořit textový soubor vybrat data z tabulky dokud jsou k dispozici další data { načíst řádek dat procházet sloupce a { data ze sloupce zkonvertovat na text zkonvertovaná data uložit do souboru uložit do souboru oddělovač polí } uložit do souboru znak konce řádku } zavřít vytvořený soubor zavřít spojení na databázi nahlásit úspěch

Pozn.: Jak se připojit k MySQL z několika nejběžnějších skriptovacích a programovacích jazyků si budeme vtomto seriálu ještě ukazovat.

Můžete při sestavování něčeho podobného nějak narazit? Vlastně ani ne, pokud si dáte pozor na následujícívěci:

Cokoliv co není text (čísla, data, logické hodnoty) by se mělo zkonvertovat na text. Stanovte si nebopřevezměte nějaká pravidla (například pro konverzi kalendářních dat, logických hodnot nebodesetinných čísel).

Ujistěte se, že skript má dost času doběhnout do konce

Page 164: MySQL Obsah

Ujistěte se, že nepřepisujete stále týž soubor se záložními daty (anebo že to děláte, ale nevadí vám to)

Pokud chcete uchovávat více záloh, nějak si je rozlište (asi bych volil datum jako součást názvusouboru)

Můžete si pohrát z komprimací záloh; textové soubory půjdou nejspíš zkomrimovat s dost dobrýmpoměrem.

Plánování záloh

Nemusí Vám vždy vyhovovat ruční spouštění záloh. Možná budete požadovat, aby byl Vámi napsaný skriptprováděn v zadaném čase automaticky. K tomu slouží nástroj cron obsažený snad v každém UNIX-Likesystému. Cron zřejmě nebudete moci na webhostingu nastavovat sami, ale možná budete moci požádat správceserveru, aby Vám nějaký ten skript přidal do existujících automaticky spouštěných úloh, snad jednou denně.

Pokud Vám však ani to nestačí, je třeba vědět, že existuje ještě pružnější cesta. Když se nad tím zamyslíte, jezálohovací skript sekvencí příkazů jako každý jiný. To znamená, že když máte skripthttp://www.nejakyserver.cz/zalohujdata.php, můžete si jej spustit z libovolného prohlížeče na světě a můžetetak svoje cenná data zazálohovat. Pokud například vlastníte v libovolném systému, do něhož máte přístupnějaký textový prohlížeč, můžete napsat příkaz ve stylu:

links http://www.nejakyserver.cz/zalohujdata.php

A skript se na vzdáleném systému provede. "Juknutí" na server můžete naplánovat třeba pomocí nějakého cronuna systému, k němuž máte přístup.

Příště si ukážeme, jak na zálohování dat v situaci, kdy máte plný přístup na server, na němž MySQL běží.

MySQL (55) - zálohování MySQL z pohledu správce

Správce databázového serveru má větší možnosti, ale i větší zodpovědnost. Jak se tedy postavit k zálohovánídat?

20.1.2006 06:00 | Petr Zajíc | přečteno 7578×

Komerční sdělení: Pořádáme Kurzy MySQL

Jak asi tušíte, dnes se zaměříme na zálohování MySQL databází z pohledu správce systému. Budeme tedyuvažovat o situacích, kdy máme daný server na starosti a můžeme, když je to potřeba, pracovat jakosuperuživatel. Jak uvidíme, i zde je více možností zálohování.

Page 165: MySQL Obsah

Příkaz BACKUP TABLE

Superuživatel samozřejmě může využít všechny možnosti, o nichž jsme hovořili v předchozích dvou dílechseriálu. Rovněž může použít některé další nástroje. Patří mezi ně příkaz BACKUP TABLE, který slouží kzálohování jediné tabulky. Jeho syntaxe je následující:

BACKUP TABLE [názevtabulky] TO '/cesta/k/zaloze'

A upřímně řečeno, používám jej dost nerad. Tento příkaz má následující výhody:

Umožňuje elegantně pořídit kopii jediné tabulky

Je principielně dosti rychlý

Dá se velmi snadno zapamatovat

Ale rovněž následující nezanedbatelné nevýhody:

Při zápisu do cílového adresáře jste omezeni právy systému (tato nevýhoda pochopitelně není prosuperuživatele podstatná)

Funguje to jen s tabulkami typu MyISAM.

Příkaz je v dokumentaci označen jako zastaralý.

Neumožňuje přepsat existující data

A konečně - situace, v níž byste chtěli zálohovat jedinou tabulku je z hlediska správy serveru poměrněvzácná.

Jak to funguje? Jednoduše. Na serveru jsou pro každou tabulku typu MyISAM vyhrazeny až tři soubory:

Soubor Obsahuje*.frm Definice tabulky MyISAM. Jsou zde uloženy typy a velikosti jednotlivých sloupců tabulky.*.MYD

Samotná data pro tabulku.

*.MYI Indexy pro danou tabulku

Pozn.: Seznam není vyčerpávající. V MySQL 5 může napříkad existovat soubor *.TRG s definicí triggerů prodanou tabulku, ale to teď není podstatné.

Page 166: MySQL Obsah

Když přijde příkaz pro zálohování pomocí BACKUP TABLE, databáze se postará aby do dané tabulky nemohlnikdo zapisovat a pak prostě vykopíruje soubory frm a MYD do cílového adresáře. Indexy se nekopírují, neboťje lze z obnovených dat poměrně snadno zrekonstruovat. Jak vidíme, není tedy za příkazem BACKUP TABLEžádná velká alchymie.

Příkaz mysqldump

Tento užitečný příkaz vytvoří zálohu dat tak, že sestaví SQL příkazy, které povedou k vytvoření dané tabukynebo tabulek. Příkad:

mysqldump -u root test lidi > ~/lidi.sql

Povede k tomu, že bude vytvořen v domovském adresáři soubor lidi.sql se zhruba následujícím obsahem:

-- MySQL dump 10.10 -- -- Host: localhost Database: test -- ------------------------------------------------------ <zkráceno> -- -- Table structure for table `lidi` -- DROP TABLE IF EXISTS `lidi`; CREATE TABLE `lidi` ( `jmeno` varchar(20) collate utf8_czech_ci default NULL, `narozendne` date default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci; -- -- Dumping data for table `lidi` -- LOCK TABLES `lidi` WRITE; INSERT INTO `lidi` VALUES ('Jarda','1970-01-01'),('Jana','1975-12-31'),('Petr','1980-10-10'); <zkráceno> UNLOCK TABLES;

Je tedy vytvořena jak definice tabulky, tak i data. Příkaz mysqldump má poměrně hodně přepínačů, s nimižbude dobré se seznámit, pokud to myslíte s tímto příkazem vážně a dá se použít i na jiné typy tabulek nežMyISAM. Osobně ho mám docela rád, protože produkuje výstup, který je člověku čitelný, textový a který se dározumně zkomprimovat. Lze se také zmínit o tom, že vygenerované příkazy se mohou náramně hodit přiexportu struktury a dat na jiný typ DBMS.

Skript mysqlhotcopy

Ten mám rád ze všech nejméně. Nejdřív ale, co to dělá. Funguje v podstatě tak jako BACKUP TABLE s tímrozdílem, že může zálohovat více tabulek nebo i více databází. Rovněž se v dokumentaci praví že je rychlejšínež BACKUP TABLE a není označen jako zastaralý.

Teď něco nevýhod:

Skript je v PERLu, což znamená, že musíte být schopni spouštět perlové skripty, aby to fungovalo.

Page 167: MySQL Obsah

Skript vyžaduje závislosti: Data::Dumper a některé další. Většinou je budete v systému mít.

Není obecně přítomen ve Windows distribucích MySQL

Neříkám, že mysqlhotcopy nemáte používat nebo že to nebude fungovat, ale raději bych zálohování svěřilodzkoušenému binárnímu programu než skriptu (je to věc názoru, nekamenujte mě v diskuzi).

Závěr

Zdaleka jsme nevyčerpali všechny možnosti zálohování. V praxi bude zvolená strategie nejspíš nějakoukombinací uvedených způsobů. Přitom, když se budete rozhodovat co a jak zálohovat, Vám mohou pomocinásledující otázky:

Co by se stalo, kdybych právě o tato data přišel?

Jak často by se měla právě tato databáze či tabulka zálohovat?

Kolik (historicky) záloh těchto dat budu potřebovat?

Jaký způsob zálohování bude nejrychlejší/nejvýkonnější/nejbezpečnější

Jak vidíte, je toho dost. Cílem bylo seznámit Vás s nejběžnějšími technikami zálohování s tím, že svoji cestu simusí najít každý sám.

MySQL (56) - Obnova zálohovaných dat

Umět data zazálohovat je sice záslužné, mnohem důležitější však je, aby šla správně obnovit. Dnes si ukážeme,jak na to.

27.1.2006 06:00 | Petr Zajíc | přečteno 6086×

Komerční sdělení: Pořádáme Kurzy MySQL

Page 168: MySQL Obsah

Protože jsme poslední tři díly seriálu věnovali zálohování dat, nebude na škodu zmínit se rovněž o opačnémprocesu - obnově dat. Zvládneme to v jednom díle, protože většina zásad a postupů, které jsme probrali přizálohování dat platí úměrně i pro jejich obnovu.

Obecně k obnově dat

Nejprve mi však dovolte něco "otcovských" rad k obnově dat. Obecně zřejmě budete obnovovat data ve dvoutypických scénářích:

1. Protože jste zálohovali data na vývojovém systému a nyní je obnovujete pro "ostrý" provoz. Napříkladvyvíjíte webovou apikaci s databázovým backendem a nyní nahráváte konfigurační data na ostrý server.

2. Protože jste přišli o nějaká data vlivem výpadku, havárie či útoku a potřebujete systém co nejdříve dostatzpátky "na nohy".

K prvnímu bodu není příliš co dodat - obnova dat bude tak jako tak provedena prakticky ihned a jestliže neníněco v pořádku, projeví se to okamžitě. Ke druhému bodu bych však přispěl dobrou radou: Vyzkoušejte si, jestlivám obnova jde dat tak, jak jste předpokládali ještě dříve, než budete data skutečně potřebovat obnovit!Přestože se to zdá samozřejmé, často se na to zapomíná. Několik potřehů z praxe snad pomůže zdůraznit, jakmoc je to potřeba:

Obnovu dat při havárii budete skoro vždy dělat v časovém presu. Jestliže budete schopni provést torychle, je to plus.

Při obnově dat budete pravděpodobně zápasit s větším množstvím záloh. Je třeba vybrat správná data -pořádkumilovnost se v tomto případě vyplácí.

Obnova dat bude muset být kompletní. Z argumentů typu "sklad máte v pořádku, ale databázi uživatelůse bohužel nepovedlo obnovit" asi zákazník příliš nadšený nebude.

Obnova dat je většinou (narozdíl od záloh) neplánovaná akce. Podle zákona schválnosti potřebaobnovit data nastane v době, kdy se Vám to nejméně hodí.

Je tedy potřeba si udělat "cvičný poplach" (klidně si nějakou tu havárii nasimulujte) a ověřit si, zda obnova datdělá opravdu to, co má. A to bez ohledu na použitou metodu. Mluvím o tom schválně dříve, než budu rozebíratjednotlivé varianty obnovy, protože to je opravdu důležitá koncepční otázka.

Obnova z textových souborů

Uvedli jsme, že lze zálohovat data pomocí příkazu SELECT INTO OUTFILE. Komplementární příkaz proobnovu dat je LOAD DATA INFILE. Platí pro něj stejná omezení jako pro SELECT INTO OUTFILE s jednoupodstatnou výjimkou - za určitých okolností lze pomocí rozšíření LOAD DATA LOCAL INFILE nahrávat dotabulky data ležící jinde než na serveru.

Page 169: MySQL Obsah

Pozn.: Lidé si to často pletou - takže pro upřesnění: pokud máte 1) PC doma, na němž vyvíjíte web, 2) PC nawebhostingu, na němž web běží a 3) PC na webhostingu, na němž běží databáze, pak platí, že pomocí LOADDATA INFILE můžete nahrávat soubory ležící na PC3, pomocí LOAD DATA LOCAL INFILE soubory umístěnéna PC2, ale soubory z PC1 pomocí LOAD DATA INFILE nemůžete nahrát skoro nikdy. Důvodem je, že budetemít stěží povoleno manipulovat s databází z domácí IP adresy.

To celé však může být zákázáno - a na webech často je zakázán celý příkaz LOAD DATA INFILE. To je škoda,protože příkaz sám o sobě je dosti rychlý. Uveďme si příkad, jak může záloha a obnova dat probíhat:

select * from lidi into outfile 'lidi.txt'; load data infile 'lidi.txt' into table lidi;

Jak vidíte, je to poměrně přímočaré. I když těžko zapamatovatelné, protože člověk by instinktivně čekal vnahrávacím příkazu klíčové slovo INSERT.

Obnova dat na webu

Pokud zálohujete z webu (viz tento díl seriálu), můžete pro obnovu dat použít PhpMyAdmin stejně jako prozálohování. Je to dosti jednoduché, pokud máte k dispozici soubor s jednotlivými příkazy pro databázi. Prostěpřepnete v PhpMyAdminu do okna SQL a vložíte do něj jednotlivé příkazy. Toto okno umí zpracovat i vícepříkazů, pokud jsou odděleny středníky, a umí soubor s instrukcemi uploadovat pomocí formuláře i zevzdáleného stroje.

Pozn.: PhpMyadmin je naprogramován v PHP. Tudíž při uploadování souborů můžete narazit na omezeníwebserveru a/nebo PHP týkající se maximální velikosti dat odesílaných pomocí formuláře nebo maximálnívelikosti uploadovaného souboru. Takže čas od času bude potřeba rozdělit si obnovovaná data na více dílů.Naštěstí to není takový problém, protože soubory jsou textové.

Jestliže jste prováděli zálohu "ručně" pomocí skriptu vlastní provenience, můžete stejným způsobem provést iobnovu dat. Pokusím se opět o ilustraci v pseudojazyce:

otevřít spojení na databázi otevřít textový soubor dokud jsou k dispozici další řádky souboru { načíst řádek dat rozdělit na sloupce procházet sloupce a { data z textu pospojovat } z pospojovaných dat vytvořit příkaz INSERT provést INSERT } zavřít textový soubor zavřít spojení na databázi nahlásit úspěch

Přitom Vás může potkat spousta nepříjemností. Nastíním ty hlavní:

Nikde není řečeno, že nebudete kromě dat muset obnovit rovněž strukturu, Takže může přijít ke slovupříkaz CREATE TABLE.

Musíte se postarat, aby textová data byla převedena na "správné" datové typy - například na kalendářnídata.

Page 170: MySQL Obsah

Musíte zjistit, zda vám vadí či nevadí dílčí neúspěchy importu a musíte se podle toho zařídit. Někdy lzepár neobnovených řádků lhostejně ignorovat, zatímco jindy díky tomu musíme celý import prohlásit zaneúspěšný.

Konečně, je třeba nějak odkontrolovat, zda se obnovilo to, co jsme chtěli.

Obecně platí, že napsat kvalitní skript na obnovu dat je o něco náročnější než napsat skript na zálohu. Adoufám, že po přečtení prvního oddílu článku vás ani nenapadne sestavovat obnovovací skript až ve chvíli, kdyjej budete potřebovat!

Obnova dat z pohledu správce serveru

Opakem příkazu BACKUP TABLE, o němž byla řeč je příkaz RESTORE TABLE. Má stejné nectnosti jakojeho kolega; mezi největšími připomeňme, že funguje jen pro tabulky MyISAM.

Příkaz mysqldump nemá žádného bratříčka mysqlrestore. Je tomu tak proto, že obnovu dat můžeme provéstpomocí řádkového klienta mysql. Bude o něm ještě podrobněji v seriálu řeč, teď jen poznamenejme, že tentoprogram má mezi spoustou jiných voleb rovněž možnost načíst požadované instrukce ze souboru - což je přesněten soubor, který nám vznikl pomocí mysqldump. Pokud chcete něco podobného vyzkoušet, v řádkovémklientovi mysql se poohlédněte po příkazu source.

Ani mysqlhotcopy nemá bratříčka. Chcete-li obnovit zálohu vytvořenou pomocí mysqlhotcopy, nezbyde nežnahradit soubory v adresáři aplikace ručně.

Závěr

Techniky, které jsme pro zálohu a obnovu dat použili, zdaleka nejsou jediné. Existuje například možnost použítk obnovení dat databáze binární protokol aktualizací. V běžné praxi se však mnohem častěji setkáváme spíše sřešeními, které jsem popisoval. Je nesmírně důležité testovat zálohy ještě předtím, než je budete potřebovat kobnově dat.

MySQL (57) - Ach, ta čeština

Podle mě musí existovat spojení mezi slovy "konverze" a "kontroverze". Máloco je totiž ve spojení s MySQLtak časté, jako dotazy ohledně češtiny a znakových sad vůbec. Rozeberme to.

3.2.2006 06:00 | Petr Zajíc | přečteno 9705×

Komerční sdělení: Pořádáme Kurzy MySQL

Page 171: MySQL Obsah

Dozrál čas věnovat se dotazům, které se v té či oné formě pravidleně objevují v mojí e-mailové schránce a kterése v souvislosti s MySQL tak či onak dotýkají znakových sad. Naše požehnaná mateřština disponuje celou řadouhlásek s háčky a čárkami, což programátorovi a správci databáze může pěkně zatopit. Postupně si ukážeme, žeporozumět tomu, jak se chová MySQL v takových situacích není zase až tak složité, pokud člověk vezme vúvahu všechny faktory. Leč postupně, nejprve trocha té nezbytné teorie.

MySQL, znakové sady a potíže s nimi

Řetězce v databázi mohou být uloženy v mnoha znakových sadách. MySQL tento pohled na věc velmi dobřepodporuje. Znaková sada zde může být specifikována pro celý server, pro jednu databázi, pro jednu tabulkunebo dokonce pro jediný sloupec. Nicméně je třeba pochopit celý mechanismus a správně ho uplatnit, aby tovšechno fungovalo k naší spokojenosti. Kdy se vlastně v souvislosti s MySQL a řetězci musíme zajímat oznakové sady? V několika hlavních situacích:

1. Při importu dat do databáze nebo při ukládání znakových dat sesbíraných pomocí nějaké klientskéaplikace

2. Při interní manipulaci s řetězci uvnitř MySQL

3. Při zobrazení dat "vně" databáze, prostě když je chceme vydolovat a použít

Lehce si to celé rozeberme, abychom pochopili, jak to všechno souvisí. Platí totiž zásada, že buď:

je dobré při manipulaci se znakovými sadami vybrat si jednu a té se držet, nebo

používat několik znakových sad a na správném místě provést konverzi mezi nimi pomocí nástrojů, kteréposkytuje MySQL nebo podkladový operační systém

Pozn.: Pro mě je "správný" ten první postup. Ke konverzím se uchyluji jen když je to nezbytné, třeba kdyžmusím spolupracovat s více oddělenými systémy s jiným kódováním.

Import nebo vstup dat

Nezřídka je nutné importovat data do MySQL z externích zdrojů, jak jsme o tom psali minule. Například pokudse jedná o import textových souborů - jsou uloženy ve správné znakové sadě? Pokud vaše distribuce používáUTF-8, pak budou textová data nejspíš v tomto kódování. Pokud máte něco jiného (jako je soubor pocházející zWindows), bude třeba na to myslet již před importem.

Pozn.: Situace, kdy se naimportují data v neodpovídající znakové sadě je zejména u začátečníků poměrně častá.Obyčejně je mnohem účinnější provést import znovu, než se snažit o opravu existujících dat uvitř databáze.

Page 172: MySQL Obsah

Manipulace s daty

Třebaže se to nezdá, je i tady zapotřebí mít se na pozoru. Především je MySQL hodně flexibilní, takže v jednédatabázi, i dokonce v jediné tabulkce můžete mít data v několika znakových sadách. Takže, příkaz INSERTnebo UPDATE může s nabodeníčky krásně zamíchat, pokud si na to nedáte pozor. Další často opomíjenouskutečností je fakt, že v určitém kódování funguje rovněž klient, kterého používáte (jako je řádkový klient neboPHPMyAdmin). Pokyny, které databáze dostane tedy musejí přijít se správnou diakritikou, aby to celé mohlosmysluplně pracovat. Hezky je to vidět na příkazech SELECT:

select * from pracovnik where prijmeni = 'Žežulka' and obec = 'Středoplky'

To může být sice napsáno správně, a v databázi mohou odpovídající záznamy existovat, přesto však někdynedostaneme to, co potřebujeme. Důvodem může být nešťastná konverze, kterou klient provede předtím, neždatabáze pokyn obdrží. Může vzniknout jen těžko dohledatelná chyba nebo mohou být nalezeny záznamy, kteréjsme nechtěli.

Výstup dat

Vlastně to hezky souvisí s oběma předchozími problémy: Nějaký konzument dat (desktopová aplikace, webovástránka nebo cokoli jiného) požaduje znaková data a databáze mu je pošle. Zobrazí se na výstupu to, co jsmepotřebovali? To bude opět záviset na více faktorech. Především je nutné, aby klient dokázal o data správněpožádat, a potom také to, aby je správně předložil uživateli.

V případě webových aplikací bude nejspíš výstupem nějaká HTML stránka, která ovšem rovněž používákódování. Takže, může vzniknout několik problémů, které spolu souvisejí. Postupně si v tomto seriáluukážeme, jak se celý ten zašmodrchanec dá rozplést.

Řazení dat

Abych předešel případným dotazům, řeknu to rovnou: řazení znakových dat sice souvisí se znakovými sadami,ale není to totéž. V databázi můžeme například mít znaková data v UTF-8 a požadujeme jejich české řazení,stejně tak ale pro UTF-8 data můžeme chtít řazení anglické nebo německé. Tomuto tématu se budeme věnovatpozději, teď jen zásada: Nastavení znakové sady pro databázi není totéž co nastavení způsobu řazení dat.

Lehký úvod do problematiky

Jak vidíte, je toho dost a jistě nám tato látka vystačí na více dílů seriálu. Obecně lze říci, že MySQL podporujevíce znakových sad, přičemž záleží na nastavení při kompilaci, které budou k dispozici. Seznam dostupnýchznakových sad můžete zobrazit příkazem

SHOW CHARACTER SET;

a seznam dostupných řazení pak pomocí příkazu

SHOW COLLATION;

Pozn.: Nelekněte se. Moje výchozí instalace MySQL "pětky" obsahuje 36 znakových sad a 124 vestavěnýchzpůsobů řazení dat, takže je toho opravdu dost. V praxi však budete používat většinou jen zlomek toho, co je veskutečnosti k dispozici.

Page 173: MySQL Obsah

My se příště podíváme na praktický příklad, jak se se znakovými sadami vypořádat v situacích, které jsemnastínil. Dopředu prozradím, že budu doporučovat používání UTF-8 podobně, jako to děláme tady na serverupři psaní stránek. Rovněž naznačím, co Vás může potkat za problémy a jak se s nimi vypořádat; a pokusím sezodpovědět nejčastější dotazy, které mi v té souvislosti chodí.

A ještě něco: Příště udělám trochu ústupek a použiju příklady psané v PHP, přestože jsem si předsevzal, že se vtomto seriálu budu snažit věnovat pouze databázi bez vazby na konkrétní programovací jazyky. Důvod je prostý- většina lidí takto MySQL používá a problémy se mohou prolínat, takže zahrnu do vysvětlování i PHP.

MySQL (58) - čeština v praxi

Příliš žluťoučcí koně - prostě hrátky s nabodeníčky stokrát jinak a pokaždé s MySQL.

10.2.2006 06:00 | Petr Zajíc | přečteno 13397×

Komerční sdělení: Pořádáme Kurzy MySQL

Teorie bylo minule až dost, takže vzhůru na praktické uplatnění vědomostí o MySQL a znakových sadách.

Page 174: MySQL Obsah

Definice sloupce tabulky

Především je třeba vědět, že při definici tabulky lze v MySQL určit znakovou sadu a řazení pro každý sloupeczvlášť. V jediné tabulce tedy můžete mít sloupce s různým kódováním znaků. Příkaz, který to zajistí lze napsatnějak takto:

CREATE TABLE cestina ( win VARCHAR(50) CHARACTER SET cp1250 COLLATE cp1250_czech_cs, latin VARCHAR(50) CHARACTER SET latin2 COLLATE latin2_czech_cs, utf VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_czech_ci ) TYPE = MYISAM ;

Samozřejmě, že v reálné aplikaci to většinou nebudete potřebovat. Tam často postačí definovat znakovou sadupro celou tabulku, a tato znaková sada je pak použita pro všechny sloupce obsahující řetězce.

CREATE TABLE cestina_cela ( text1 VARCHAR( 50 ) NOT NULL , text2 VARCHAR( 50 ) NOT NULL , text3 VARCHAR( 50 ) NOT NULL ) TYPE = MYISAM CHARACTER SET utf8 COLLATE utf8_czech_ci;

Leč zpátky k prvnímu příkladu. Pokud se nyní do tabulky cestina pokusíte zapsat data následujícím příkazem:

insert into cestina (win, latin, utf) values ('Příliš žluťoučký kůň pěl ďábelskéódy','Příliš žluťoučký kůň pěl ďábelské ódy','Příliš žluťoučký kůň pěl ďábelské ódy');

Skončíte na 99% chybovým hlášením "Data too long for column 'win' at row 1", nebo něčím hodně podobným.Než se to pokusím vysvětlit, je třeba uvést, že:

V příkladech předpokládám použití řádkového klienta mysql. Pokud byste použili napříkladPhpMyAdmin tak nejspíš k žádné chybě nedojde, protože aplikace se pokusí kódování nějak vyřešit (anejspíš uspěje). To nám momentálně VADÍ, protože to ztěžuje pochopení našeho problému. Při použitířádkového klienta máme naopak jistotu, že do databáze dorazí přesně to, co jsme napsali.

Chybová hláška je v tomto případě naprosto zavádějící. Ve skutečnosti je problém v tom, že klient aserver vzájemně "nepochopili" svoje znakové sady.

Client character set

Jakou znakovou sadu tedy vlastně používá řádkový klient mysql, když "mluví" s databází? A vůbec - nějakouznakovou sadu přece musí používat jakýkoli klient, řádkovým počínaje a třeba PHP skriptem konče, takže jak toje? Odpověď je jednoduchá - server PŘEDPOKLÁDÁ, že klient bude posílat data v určité znakové sadě! Ta jedána systémovou proměnnou character_set_client a je předkonfigurována při instalaci.

Pozn.: Což je pro neznalé hotové neštěstí, neb až do verze 4.1 byla výchozí latin1 - něco, co našincům mocvyhovovat nebude. Naštěstí se zdá, že většina instalací "pětek" má přednastavenou utf8.

To, jakou znakovou sadu Váš server od klienta očekává si můžete ověřit následujícím dotazem:

SHOW VARIABLES LIKE 'character_set_client';

Page 175: MySQL Obsah

To byly špatné zprávy, teď něco dobrých. Bez ohledu na to, jaká je výchozí znaková sada si můžete poručit, žepro Vaše připojení budete používat specifickou sadu. To provedete pomocí veledůležitého příkazu SETNAMES. Jestliže tedy budu chtít ve zdraví provést příkaz INSERT INTO, jak je uveden výše, mohu na to jítnějak takhle:

set names cp1250; insert into cestina (win) values ('Příliš žluťoučký kůň pěl ďábelské ódy'); set names latin2; insert into cestina (latin) values ('Příliš žluťoučký kůň pěl ďábelské ódy'); set names utf8; insert into cestina (utf) values ('Příliš žluťoučký kůň pěl ďábelské ódy');

Důležité: Mají-li se data do databáze dostat ve správné znakové sadě, musí tedy platit ZÁROVEŇ tato dvěpravidla:

1. Sloupec, který má data pojmout musí být definován ve správné znakové sadě

2. Klient musí posílat příkazy na server ve znakové sadě, na níž se dohodli (což je výchozí znaková sadanebo znaková sada určená pomocí SET NAMES).

Pokud si příklady zkoušíte a zapsali jste cvičná data do tabulky, můžete je teď zkusit pomocí řádkového klientazobrazit:

a ejhle! Pokaždé se správně zobrazí jen ten sloupec, pro nějž je odpovídajícím způsobem nastavena znakovásada. Čímž se vlastně dostáváme k dalšímu tématu - a tím je spolupráce s PHP.

MySQL, znakové sady a PHP

Tady není moc co dodat. Je třeba si uvědomit, že z hlediska databáze je PHP klient jako každý jiný, a že je tudížnamístě specifikovat v našich ctěných skriptech rovněž odpovídající příkaz SET NAMES, nějak takhle:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Test znakových sad</title> </head> <body> <? mysql_connect("localhost","root"); mysql_select_db("test"); mysql_query("SET NAMES 'cp1250';"); //nebo 'latin2' nebo 'utf8' $vysledek=mysql_query("select * from cestina;"); while ($zaznam=MySQL_Fetch_Array($vysledek)): echo $zaznam["win"]."<BR>\n"; echo $zaznam["latin"]."<BR>\n"; echo $zaznam["utf"]."<BR>\n"; endwhile; ?> </BODY> </HTML>

Samozřejmě, že něco takového se musí udělat ještě předtím, než databáze vrátí data, jinak je to zbytečné. Pokudsi to chcete vyzkoušet, zjistíte, že pokaždé jsou správně zobrazena jen data v odpovídající znakové sadě, a žeostatní je "rozsypaný čaj".

Page 176: MySQL Obsah

A co importy?

Jestliže importujeme data do MySQL z textových souborů, je třeba navíc dbát na to, aby i vstupní soubor s datybyl ve správné znakové sadě. Jinak platí to, co jsme uvedli výše. Tedy:

1. Importovaný soubor musí být ve správné znakové sadě (UTF-8, například)

2. Klient mysql musí obdržet příkaz SET NAMES XXX

3. Data se musí ukládat do sloupce se správně nadefinovanou znakovou sadou.

Není to složité, když si uvědomíte, jak spolu jednotlivé věci souvisejí. Nepříjemné je, že musí být splněno vícepodmínek - a když nejsou, nevyjde to.

MySQL (59) - české řazení

Podívejme se dnes ještě na konverze textu a rovněž na způsob, jak zajistit české řazení v MySQL.

17.2.2006 06:00 | Petr Zajíc | přečteno 8144×

Komerční sdělení: Pořádáme Kurzy MySQL

Page 177: MySQL Obsah

Minulý díl seriálu vzbudil celkem dost ohlasů. Pojďme tedy nejprve lehce doplnit látku o konverzi textovýchsouborů mezi znakovými sadami a potom se věnujme českému řazení v MySQL.

Změna kódování souboru

Jak jsme uvedli, pokud chceme importovat znaková data do MySQL, musí nám souhlasit znaková sada vdefinici sloupce, do něhož data přijdou, znaková sada klienta, který import zajišťuje (jako je řádkový klientmysql) a znaková sada souboru, z něhož data čerpáme. Právě v tom posledním bodě se někdy můžete zaseknout,protože soubor je dodán v jiném kódování než potřebujete.

Iconv

Není třeba zoufat. Linuxoví guru nám přece odjakživa vtloukají do hlavy, že Linux se skládá z celé řady malýchprográmků, které dělají jednu věc (a dobře). Jedním z nich je utilita na převod kódování zvaná iconv. Jejípoužití je velmi intuitivní, takže to předvedu přímo na příkladu se vstupním souborem v UTF-8, který chcemedostat do ISO-8859-2:

iconv -f UTF-8 -t ISO8859-2 text_utf.txt -o text_latin2.txt

Volby jsou v tomto případě triviální - vstupní kódování, výstupní kódování, název souboru pro konverzi. Zaním je uveden přepínač -o přikazující programu přesměrovat výstup do souboru (ve výchozím stavupřesměrovává na standardní výstup, což je obrazovka, a to nám ve většině případů moc užitečné nebude). Zazmínku stojí už snad jen příkaz

iconv -l

který vypíše seznam všech dostupných kódování, která pro konverzi můžete použít. A pro našince potěší zpráva,že mezi nimi je jak ISO8859-2, tak UTF-8, tak WINDOWS-1250. Nebudete tedy ponecháni na holičkách, ať uždostanete svůj soubor v jakémkoli kódování. Protože s MySQL laborují dost často lidé kolem webových stránekje třeba se rovněž zmínit o tom, že PHP umí s iconv spolupracovat, takže můžete napsat něco jako:

iconv("UTF-8", "ISO-8859-2", $nejaky_retezec)

A jeden tip nakonec: Pokud nevíte, v jakém kódování je vstupní soubor, můžete použít klasický příkaz linuxufile, který se to pokusí zjistit. Opět malý příklad:

file text_utf.txt (výstup)text_utf.txt: UTF-8 Unicode text

Recode

Jako poněkud robustnější alternativu k iconv můžete použít program recode. Má podstatnou výhodu: Pracujepřímo s konvertovaným souborem. Uvědomte si ale, že to může být i nevýhoda. Další "drobností" je, že recodev systému po instalaci nemusíte mít, kdežto iconv tam nejspíše mít budete. Takže jenom dodám příklad:

recode ISO_8859-2..UTF-8 text_latin2.txt

a téma konverzí textových souborů můžeme opustit. Znovu bych doporučil důsledně používat UTF-8 všudetam, kde jen je to možné. Proto ho máme.

České řazení v MySQL

Page 178: MySQL Obsah

V dávných a dávných dobách byl docela problém donutit MySQL česky řadit. Jak nejspíš víte, je české řazenídost specifické. Máme písmena s čárkami, háčky a rovněž ch, které tvrdohlavě řadíme mezi h a i. Protohovoříme o tom, že české řazení je několikaprůchodové - prosté porovnání znaků nám leckdy k určení pořadízkrátka nestačí. Hezky je to rozebráno například tady. S tím vším se musí databáze nějak vypořádat.

Naštěstí doby temna skončily a současné verze MySQL řadí česky správně. Pochopitelně, že je třeba správnědefinovat typ sloupce a požadované řazení. Můžeme si to ukázat na příkladu. Vytvoříme tabulku s jednímsloupcem:

create table test_razeni(polozka varchar(50) character set utf8 collate utf8_czech_ci notnull);

Všimněte si, že je nutné specifikovat řazení pomocí klíčového slova collate. Tabulku teď naplníme nějakýmidaty:

insert into test_razeni (polozka) values ('auto'),('cihla'),('česnek'),('chleba'),('rum'),('ředkvička'),('zlato'),('židle'),('stůl'),('špička'),('dav'),('ďábel'),('ňouma'),('nestor');

a seřadíme pomocí order by:

select * from test_razeni order by polozka;

Jak můžete vidět, žádné nepříjemné překvapení se nekoná. Ch je na svém místě a slova s diakritickýmiznaménky rovněž. Poměrně málo známý je trik se specifikací COLLATE přímo v klauzuli ORDER BY. Můžetesi například předchozí sadu záznamů zkusit setřídit podle pravidel pro řazení unicode:

select * from test_razeni order by polozka collate utf8_general_ci;

Kdy něco takového použít? Vlastně asi nikdy. Vždy je totiž lepší zadat si výchozí způsob třídění pro danýsloupec nebo tabulku. Dokážu si nicméně představit třeba nějakou mezinárodní webovou aplikaci, kde by byldejme tomu seznam měst a uživatel by mohl dostat tento seznam setříděný podle svých národních zvyklostí.Uznávám ale, že je to dosti vykonstruovaný příklad, protože názvy měst se stejně většinou píší i třídí anglicky.

Ještě poznámka k webovým aplikacím. Autoři stránek se občas v minulosti pokoušeli implementovatněkolikaprůchodové české řazení přímo pomocí skriptů, jako je PHP. Pokud data pocházejí z databáze, mělo bytěmto pokusům zvolna odzvonit, protože obecně jakákoli databáze seřadí data rychleji než skript. Samozřejměpokud řazená data z databáze nepocházejí, pak asi nezbyde než se pokusit o implementaci vlastního řazení - aleje to úkol pro odvážné.

MySQL (60) - řádkový klient

Pojďme se dnes podívat na možnosti řádkového klienta, který je s MySQL dodáván.

24.2.2006 06:00 | Petr Zajíc | přečteno 5452×

Komerční sdělení: Pořádáme Kurzy MySQL

MySQL se dá ovládat různě. Pomocí frontendů jako je PhpMyAdmin, prostřednictvím internetového portálu,prostřednictvím desktopové aplikace a rovněž celou řadou administračních nástrojů. Dnes se zaměříme natextového klienta mysql, který, jak nejspíš zjistíte může být docela efektivní.

Page 179: MySQL Obsah

Řádkový klient mysql

Používat řádkového klienta může někomu připadat velmi středověké, protože grafických nástrojů na správuMySQL je na světě opravdu hodně. Nicméně, možná zjistíte, že umět pracovat se základními nástroji může býtvelké plus. Proč? Z několika dobrých důvodů:

Řádkový klient bude všude nebo skoro všude, narozdíl od grafických nadstaveb, které možná používáte

Řádkový klient může být velmi rychlý

Řádkový klient může být velmi efektivní

Při používání textových nástrojů pro správu databáze vypadá člověk jako pořádný borec.

Aby nedošlo k matení pojmů uveďme to, co jsme již zmínili v díle o instalaci mysql. Server mysql se jmenujemysqld, řádkový klient pak mysql. Dnes hovoříme o klientovi, takže pozor na to. Nejjednodušší použití klientaje prostě ho spustit:

mysql

V takovém případě se mysql klient pokusí přihlásit pod aktuálním uživatelem na místní server s prázdnýmheslem. Jak asi tušíte, to není příliš užitečné, protože to v mnoha případech nebude fungovat. Klidně se protonaučte z hlavy následující přepínače (jsou intuitivní):

Přepínač

Význam

-h Hostitel, k němuž se chceme připojit. Zadává se IP adresa nebo název stroje (místní systémmusí být schopen přeložit název stroje na adresu).

-u Název uživatele, pod nímž se chceme k mysql připojit. Pozor, nemusí souviset s názvemuživatele, který provádí příkaz mysql.

-p Heslo. Pokud se nezadá, počítač se na něj při přihlašování zeptá, což je mimochodemmnohem bezpečnější než ukládat heslo jako součást textového souboru.

-P Port. Hodí se, pokud na databázovém serveru běhá více instancí MySQL (například 4.x a5.x). Jinak je výchozím portem 3306 a většinou to vyhoví.

Ukázkové přihlášení by tedy mohlo vypadat nějak takto:

mysql -h 192.168.0.1 -u root -P 3306 -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 25 to server version: 4.1.10a-nt Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql>

Pozn.: Jak vidíte, z Linuxu se lze přihlásit na server běžíci na Windows. Jde to i naopak. Ve Windows bysteřádkového klienta našli pod názvem mysql.exe ve složce bin instalace MySQL serveru.

Page 180: MySQL Obsah

Řádkový klient se po přihlášení přepne do "naslouchacího" režimu a očekává Vaše příkazy. Můžete použítlibovolné SQL příkazy, které jste se naučili (SELECT, INSERT, CREATE TABLE a tak dále) plus některépříkazy pro ovládání řádkového klienta.

Zadávání SQL

Důležité: Na serveru může být více databází a před zadáváním příkazů je třeba se ujistit, že pracujete s tousprávnou. Mohou Vám pomoci následující příkazy:

show databases; use test;

První ukáže seznam dostupných databází, druhý pak přepne do konkrétní databáze. Příkazy se v mysql ukončujístředníky. Pokud příkaz neukončíte a odentrujete, mysql přejde na další řádek a trpělivě čeká na ukončenípříkazu. Dlouhé příkazy tak nemusíte vtěsnat na jediný řádek.

mysql> select 1 ->

Příkazy SELECT produkují data v tabulkové formě, akční příkazy pak uvádějí počet chyb, počet varování apočet řádků ovlivněných posledním dotazem. Při běžné práci je příjemným zjištěním fakt, že mysql podporujehistorii příkazů tak, jak jste zvyklí z příkazové řádky linuxu. To se hodí například při ladění výběrových dotazů.

Příkazy pro ovládání řádkového klienta

Fungování klienta si můžete nastavit k obrazu svému. Slouží k tomu sada vestavěných příkazů. Tu si nemusítepamatovat, neb ji lze zobrazit použitím vestavěného ;-)) příkazu help. Následující výpis je zkrácen:

mysql> help clear (\c) Clear command. connect (\r) Reconnect to the server. Optional arguments are db and host. delimiter (\d) Set query delimiter. edit (\e) Edit command with $EDITOR. ego (\G) Send command to mysql server, display result vertically. exit (\q) Exit mysql. Same as quit. go (\g) Send command to mysql server. help (\h) Display this help. nopager (\n) Disable pager, print to stdout. notee (\t) Don't write into outfile. pager (\P) Set PAGER [to_pager]. Print the query results via PAGER. print (\p) Print current command. prompt (\R) Change your mysql prompt. quit (\q) Quit mysql. rehash (\#) Rebuild completion hash. source (\.) Execute a SQL script file. Takes a file name as an argument. status (\s) Get status information from the server. system (\!) Execute a system shell command. tee (\T) Set outfile [to_outfile]. Append everything into given outfile. use (\u) Use another database. Takes database name as argument.

Praxe

Pro praktické využití řádkového klienta bych měl dva tipy. Předně, tohle je přesně ten typ software, který senaučíte ovládat prostě tím, že ho budete používat. Nemá smysl biflovat se jedlotlivé příkazy nebo přepínače, snimiž může být řádkový klient spouštěn. Člověku to přejde do krve po několikátém použití. A druhý tip: Mezipříkazy klienta je i source (viz výše). Ten slouží k převzetí následujících příkazů ze souboru.

Page 181: MySQL Obsah

Za domácí úkol si můžete vyzkoušet importování velkého souboru obsahujícího příkazy SQL nejprve přesPhpMyAdmin a potom přes řádkového klienta. Budete překvapeni, o kolik je import pomocí řádkového klientarychlejší. A to je důvod, proč jej k importům tak často používám.

MySQL (61) - Oprávnění

Máte právo nevypovídat, aneb jak fungují v MySQL oprávnění.

3.3.2006 06:00 | Petr Zajíc | přečteno 5956×

Komerční sdělení: Pořádáme Kurzy MySQL

Právě se v seriálu dostáváme k poměrně rozsáhlé oblasti správy databáze, a tou je oprávnění jednotlivýchuživatelů. MySQL obsahuje poměrně silný koncept oprávnění, a proto jej v několika dalších dílech podrobně

Page 182: MySQL Obsah

prozkoumáme. Kvalitně nastavená oprávnění mohou samozřejmě zvýšit bezpečnost serveru a naopak - přišpatně nastavených oprávněních můžete přijít o data nebo se - což je mnohdy ještě horší - údaje z databázemohou dostat do nepovolaných rukou.

Princip

Základní princip oprávnění, který MySQL používá je v zásadě totožný s většinou jiných databázových systémů.Funguje tak, že pokud chcete s databází pracovat, je třeba se nejprve identifikovat pomocí uživatelského jména.Toto uživatelské jméno je samozřejmě unikátní, takže se nemůže stát, že by dva uživatelé na jednomdatabázovém serveru měli stejné uživatelské jméno.

Pozn.: Na druhou stranu je možné, že se pod jedním uživatelským účtem vytvoří několik připojení k databázi. Tymají potom z hlediska oprávnění rovnocenné podmínky.

Dalším bezpečnostním prvkem je heslo. Tady už teoreticky je možné, aby dva různí uživatelé měli heslo stejné;i když v praxi to nastane zřídkakdy. Je rovněž teoreticky možné heslo nepoužívat, ale to podstatně snižujebezpečnost systému. Na základě kombinace uživatelského jména a hesla je rozumným způsobem zajištěno, žese přihlašuje opravdu ten, kdo heslo obdržel. I když s jistotou se to tvrdit nedá, heslo moho být zcizeno.

Následně se přihlášený uživatel pokusí vykonat na databázi nějaký příkaz - vybrat data, manipulovat s daty nebospravovat databázi. Před každým takovým příkazem jsou zkontrolována oprávnění a buď je akce povolena, neboje zakázána.

Uvedený přístup funguje obdobně u naprosté většiny databází. MySQL má ještě rozšíření v tom smyslu, že jakosoučást přihlašovacích informací může DBMS brát v úvahu počítač, z něhož se k databázi připojujete. Tak tedynapříklad uživatel "franta" může se svým heslem přistupovat k serveru z adresy 192.168.0.1, ale tentýž uživatelnemůže přistupovat ze stroje 192.168.0.2. Tím se možnosti zabezpečení dosti rozšiřují - lze například zakázatnebo povolit přístup k databázi z místní sítě nebo z internetu.

Na druhou stranu je dobré zmínit se o tom, že MySQL nepoužívá integrovaný systém přihlašování známýuživatelům Windows. Integrovaný (trusted) systém zjednodušeně funguje tak, že "když tě ověří systém, smíš ido databáze". MySQL pochopitelně nic takového nepodporuje, protože je multiplatformní a uvedený princip byfungoval pouze na Windows NT (2000, XP).

Rozlišení práv

V moderních databázových systémech samozřejmě nejde jen o to uživateli něco povolit nebo zakázat, ale jde i oto, jak jemné může takové nastavení být. Proto se dají oprávnění vymezit nejen pro celý server, ale i projednotlivé drobnější celky. MySQL nezůstává v tomto trendu pozadu, takže pro uživatele lze zajistit následujícívěci:

Přiřadit mu práva pro celý server

Přiřadit mu práva pro jednu nebo více databází (z mnoha existujících)

Page 183: MySQL Obsah

Přiřadit mu práva pro jednu nebo více tabulek v databázi (z mnoha existujících)

Přiřadit mu práva pro jeden sloupec v tabulce

Přiřadit mu práva vytvářet a používat pohledy (jen MySQL 5.x)

Přiřadit mu práva vytvářet, měnit nebo spouštět uložené procedury (jen MySQL 5.x)

O jaká práva se konkrétně jedná? Pokud jde o data, lze povolit nebo zakázat, že uživatel může:

Prohlížet (používat SELECT)

Vkládat (používat INSERT)

Upravovat (používat UPDATE)

Odstraňovat (používat DELETE)

V případě databází existují práva vytvářet či měnit tabulky, měnit sloupce v tabulkách či vytvářet dočasnétabulky. Existují práva pro správu, umožňující měnit práva ostatním uživatelům nebo měnit nastavení systému.Je toho hodně, ale je v tom systém. Idea je ta, že prostřednictvím kombinace práv by mělo být možné povolitnebo zakázat prakticky cokoli.

Databáze MySQL ukládá oprávnění - jak asi tušíte - do zvláštní, systémové databáze. Ta se jmenuje mysql a jevytvořena při instalaci serveru. Tato databáze obsahuje několik tabulek, které ukládají oprávnění uživatelů proglobání přístup, pro jednotlivé databáze, tabulky a sloupce. Jak uvidíme v příštím díle, oprávnění jsou z tabuleknačítána jako klasická data, což znamená, že přímou změnou těchto tabulek pomocí akčních dotazů můžemeoprávnění spravovat. Uvidíme ale také, že existuje sada příkazů SQL, která to udělá za nás s mnohem většímkomfortem.

Filozofie

Protože ve správě systému by měla vládnout tvrdá totalitní ruka administrátora, bude se nejspíš při přidělovánípráv pro databázi používat následující zásada: Co není povoleno, je zakázáno. Většina správců si tedy bude přátpoužít postup "povolit všem co nejméně" a "povolit více, jen pokud to nezbytně potřebují". Zní to tvrdě, aleúčinně se tak dá udržet v databázi pořádek.

V provozu tedy není časté, aby jednotlivý uživatel mohl dělat všechno. Existují spíše uživatelské účty pro prácis daty, uživatelské účty pro nastavování serveru a třeba uživatelské účty pro zálohování dat. Rovněž nebýváčasté, že by se více lidí přihlašovalo pod jedním uživatelským účtem. Naopak, každý má typicky svůj účet asvoje heslo.

Page 184: MySQL Obsah

Praxe

Běžný uživatel při práci s MySQL přiliš nenarazí na oprávnění. Důvodem je fakt, že v typické situaci bude mít(třeba na hostingu) k dispozici jednu databázi, a v ní bude moci provozovat jakoukoli myslitenou akci (obvyklekromě smazání databáze samotné). Uživatelé jsou tedy omezeni na "svoji" databázi a mohou v ní vytvářet aměnit tabulky, pracovat s daty a vytvářet pohledy, funkce a procedury. Zároveň většinou nemají přístup kekonfiguraci systému.

Tento přístup je léty ověřený a obvykle postačí pro webhosting. Spokojen bude jak uživatel, tak správce. Zcelajiná situace však nastane, když bude třeba používat více databází, více uživatelů pracujících se stejnými datynebo připojovat se z různých míst. Pak přijdou na řadu oprávnění - a leckdy bude pěkný hlavolam nastavit jetak, aby odpovídaly skutečným potřebám praxe.

Jinými slovy - pokud používáte MySQL pouze na webu a jako uživatelé, pravděpodobně se nemusítezáležitostmi kolem oprávnění příliš vzrušovat. Pokud jste správci nebo pokud potřebujete nastavit konkrétnísystém, pak se Vám bude líbit následující díl, který se bude nastavováním oprávnění zabývat prakticky.

MySQL (62) - Oprávnění podruhé

Jak zajistit, aby se nám k databázi připojovali jen správní lidé ze správného místa?

10.3.2006 06:00 | Petr Zajíc | přečteno 6055×

Komerční sdělení: Pořádáme Kurzy MySQL

Page 185: MySQL Obsah

Co můžeme udělat pro nastavení zabezpečení databáze MySQL v praxi a jak na to jít? O tom bude řeč vdnešním díle seriálu. Zpočátku se Vám možná bude zdát celá problematika dosti spletitá, ale nakonec zjistíte, žecelý systém je velmi logický a přehledný. Takže, vzhůru na věc!

Jak MySQL ukládá oprávnění

Veškerá oprávnění jsou v MySQL uložena ve zvláštní databázi, která se jmenuje mysql. V ní je pět tabulek,které s oprávněním tak či onak souvisejí. MySQL při požadavku na provedení nějaké operace tyto tabulkydotazuje, a podle výsledku se rozhodne, zda dané oprávnění přidělí či nikoli. Těmito pěti tabulkami jsou:

user

db

host

tables_priv

columns_priv

a v zásadě se dá říci, že se s jejich obsahem dá za určitých okolností manipulovat přímo. Abychom to celétrochu zjednodušili, vynecháme z dobrých důvodů tabulku host a budeme se věnovat zbylým čtyřem. Proexperimenty je dobré v tomto případě mít k dispozici testovací server s administrátorským přístupem.

MySQL provádí v podstatě dvojí ověřování. První se nazývá ověření při připojení a stanovuje kdo se odkud smínebo nesmí k našemu serveru připojit. Pokud to projde nastupuje druhá fáze, nazývaná ověření při požadavku.Ta poskytuje uživatelům ověřeným při připojení práva pro konkrétní akce na serveru (jako je třeba vkládání datdo tabulek).

Pozn.: V těchto dvou věcech je podstatný rozdíl. Je klidně možné nakonfigurovat správu uživatelů tak, aby seněkdo mohl připojit, ale potom nemohl provést prakticky žádnou myslitelnou akci na serveru.

Ověření při připojení

Tady platí, že pro ověření při připojení se používají údaje, které jsou uloženy v tabulce user. Pokud jstepřihlášen jako superuživatel, můžete si je prohlédnout pomocí

use mysql; select * from user;

nebo ještě stručněji - protože nás v tuto chvíli zajímají pouze tři pole - pomocí něčeho jako

select host, user, password from user;

Page 186: MySQL Obsah

Jak asi tušíte, ověření při připojení zjišťuje, zda daný uživatel se smí připojit z daného hostitele - a zda přitompoužil správné heslo. Pokud je všechno v pořádku, pustí MySQL uživatele dál. Pokud ne, skončíte připřihlašování chybou ve stylu:

ERROR 1045 (28000): Access denied for user 'xxx'@'host' (using password: NO)

Do tabulky user může superuživatel (nebo jiný uživatel, pokud má k tomu práva) zapisovat přímo. Můžete taknapříklad založit uživatele franta s heslem atnarf, který bude smět přistupovat k serveru z hostitele192.168.0.100. První, co Vás asi napadne je provést to pomocí INSERT prostě takto:

insert into user (user, host, password) values ('franta','192.168.0.100','atnarf');

To nebude fungovat! Důvodem je, že MySQL neukládá hesla ve sloupci password jako prostý text, ale -zjednodušeně řečeno - ukládá jejich hash. Ten lze vytovřit pomocí MySQL funkce PASSWORD, takževylepšená verze příkazu pro vložení do tabulky user by mohla znít nějak takto (nesprávně založeného uživatelejsem odstranil):

delete from user where user = 'franta' and host = '192.168.0.100' and password ='atnarf'; insert into user (user, host, password) values ('franta','192.168.0.100',password('atnarf'));

Jestliže si to vyzkoušíte, zjistíte pravděpodobně, že to zase nebude fungovat. Důvodem je tentokrátmechanismus, jakým MySQL obsluhuje mezipaměť. Je třeba přikázat databázi, aby nový obsah tabulky userzapsala na disk. To provedete pomocí příkazu flush:

flush privileges;

K čemu dojde? MySQL vyprázdní cache a znovunačte oprávnění. V našem případě i s nově založenýmuživatelem, který se od této chvíle smí se svým heslem připojit ze stroje 192.168.0.100.

K celému mechanismu bych si dovolil několik poznámek:

V tabulce user smíte mít jednoho uživatele vícekrát. Například budete chtít, aby se franta mohl připojit iz hostitele 10.0.0.5. Tudíž je jedině logické, že pro jednoho uživatele a dva hostitele budou v tabulceuser dva řádky. To není chyba

Ve výše popsaném případě smí mít tentýž uživatel přistupující k serveru z různých míst různá hesla. Jeto sice hezká funkce, ale moc se to nepoužívá. Důvodem je to, že by si uživatel musel na každém strojipamatovat jiné heslo, což může být poněkud náročné.

MySQL dovolí nechat políčko host prázdné. V zásadě to znamená, že daný hostitel se pak může připojitodkudkoli. Nedoporučuji to. Jednak to asi není to, co chcete, a jednak pak není jasné, zda jste hostitelepouze zapomněli specifikovat nebo zda má být prázdný.

MySQL dovolí nechat prázdné políčko pro heslo. Význam je takový, že heslo pak není pro spojenívůbec požadováno. To sice rovněž nelze doporučit, ale v praxi se to někdy používá, třeba pro lokálnípřístup.

Hostitele lze zadat mnoha způsoby, příklady jsou dostupné v dokumentaci. Já jsem si napříkladzapamatoval, že při připojení z místního PC lze zadat jako název hostitele localhost. Za určitýchpodmínek lze rovněž zadat více hostitelů - například jednu podsíť.

Page 187: MySQL Obsah

Pochopitelně nesmíte zadat stejnou kombinaci uživatele a hostitele do tabulky user vícekrát. Jednak je tologický nesmysl, a jednak je na tabulce user na sloupcích user a host primární klíč - a ten jak víte musíbýt unikátní.

Smíte zadat prázdný název uživatele. To má význam ten, že pak povolujete anonymní přihlášení. Moc seto nepoužívá. Lze samozřejmě povolit anonymní přihlášení pouze z určitých hostitelů pomocí prázdnéhojména a zadaného hostitele.

Příkaz GRANT

Prozradím rovnou, že přímá modifikace systémových tabulek s oprávněními není jediná možnost, jak tatooprávnění spravovat. Přesto je velmi rozumné vědět, že to můžete provést. Činnosti přidávání uživatelů všakmůžeme udělat mnohem jednodušeji pomocí vestavěného SQL příkazu GRANT. Než bych pracně vysvětloval,jak takový příkaz funguje uvedu příklad. Stejného efektu, kterého jsme předtím dosáhli ručním vyplněnímtabulky user lze pomocí GRANT dosáhnout takto:

GRANT USAGE ON *.* TO franta@'192.168.0.100' IDENTIFIED by 'atnarf';

Použití GRANT je mnohem pružnější než přímý zápis do tabulek s oprávněními nejméně z následujícíchdůvodů:

1. Jeho použití nevyžaduje FLUSH PRIVILEGES.

2. Heslo se nemusí hashovat pomocí PASSWORD.

3. Při změně formátu tabulek s oprávněními (jakože se to v případě MySQL občas stává) funguje příkazGRANT konzistentně.

4. Narozdíl od vkládání do tabulky pomocí INSERT lze GRANT bezpečně libovolněkrát opakovat.

5. V jednom příkazu GRANT lze vložit více uživatelů nebo více kombinací uživatel+hostitel.

6. Jak uvidíme příště - GRANT může ovlivňovat data ve více tabulkách, takže je mnohem rychlejší nežzadávání několika příkazů INSERT

Bude dobré si říci, že svoje oprávnění (a leckdy i oprávnění ostatních) můžete zkontrolovat příkazem SHOWGRANTS:

show grants; show grants for 'franta'@'192.168.0.100';

Tím jsme zhruba dokončili ověřování při připojení a příště se podíváme na to, jak zajistit a spravovat oprávněnípři požadavku.

Page 188: MySQL Obsah

MySQL (63) - jemné nastavení práv

Potřetí a naposledy se budeme v MySQL zabývat právy; tentokrát jejich jemným nastavením.

17.3.2006 06:00 | Petr Zajíc | přečteno 5384×

Komerční sdělení: Pořádáme Kurzy MySQL

Page 189: MySQL Obsah

Při našem rozboru oprávnění MySQL jsme se dostali k přihlášení uživatelů. Už tedy umíme zakázat nebopovolit nějakému uživateli z nějakého stroje přihlásit se k našemu serveru. To je sice moc hezké, ale nestačí to.

MySQL a oprávnění při požadavku

Lidé se k MySQL nepřihlašují proto, aby byli spojeni s databázovým serverem. Přihlašují se proto, že chtějí seserverem něco dělat, tvořit strukturu databáze nebo pracovat s daty. Takže, když si lehce zopakujeme látku zminulého dílu a založíme uživatele franta, který se smí na server připojit z místního stroje:

grant usage on *.* to franta@'localhost' identified by 'atnarf';

A přihlásíme se jako tento uživatel, zjistíme, že kromě přihlášení nemůžeme se serverem dělat vůbec nic. Nelzepoužít žádnou databázi ani žádnou vytvořit. Uživatel prostě nemá jiná než přihlašovací práva.

Pozn.: Nemusí to být tak úplně pravda. V závislosti na konfiguraci serveru může mít náš nový uživatelimplicitně přístup do databáze test. Proč to je, to uvidíme za chvíli.

Přidělení globálních práv

Odpovědí na tento problém je nahlédnutí do tabulky user. Sice jsem Vám to minule zatajil, ale tato tabulkaobsahuje i další pole kromě host, user a password. Ta jsou určena právě pro přidělování globálních práv, takženapříklad pole select_priv povoluje či zakazuje našemu Frantovi číst databázová data (k čemu slouží insert_priva další jistě vysvětlovat nemusím). Můžete si to vyzkoušet. Zadáte následující příkazy:

update user set select_priv='Y' where user='franta' and host='localhost'; flush privileges;

Od této chvíle náš Franta může klidně brouzdat databázemi a vybírat data pomocí příkazu SELECT. O něcopohodlněji by se dalo podobné věci dosáhnout jedním příkazem GRANT. Předvedu:

grant select on *.* to franta@'localhost' identified by 'atnarf';

Neboli: Příkaz grant může zajišťovat nejen oprávnění při připojení, ale i oprávnění při požadavku. Jednotlivýchoprávnění při požadavku je asi pětadvacet a nebudu je zde rozepisovat, k tomu slouží manuál. Důležité je rověžvědět, že v jednom příkazu GRANT lze oprávnění kombinovat, takže našemu uživateli bychom mohli napříkladpovolit plnou manipulaci s daty v existujících tabulkách pomocí následujícího příkazu GRANT:

grant select, insert, update, delete on *.* to franta@'localhost' identified by 'atnarf';

Což, jak už nejspíš tušíte, zaktualizuje související políčka v tabulce user.

Problém s globálními právy

Největší problém s globálními právy spočívá v tom, že jsou příliš přebujelá. Je třeba si uvědomit, že pokud taktopráva přidělíme, tak uživatel může přistupovat k datům ve všech databázích na serveru, A TO VČETNĚDATABÁZÍ, které vzniknou v budoucnu!!! Takový systém je dost nepředvídatelný, zejména pokud by sejednalo o server, v němž má každý uživatel data v jedné databázi. Taková konfigurace je obvyklá například nahostinzích. Proto se globální práva uživatelům v typických scénářích až na malé výjimky neposkytují. Čímž sedostáváme k další otázce, a tou je odebrání práv.

Page 190: MySQL Obsah

Odebrání práv

Odebrání práv funguje analogicky k jeho přidělování. Související sloupce v tabulce user se nasaví na N (tedynepovoleno), nebo lze využít protipólu příkazu GRANT, a tím je REVOKE. Protože má podobnou syntaxi jakoGRANT, tak to pouze předvedu:

revoke select, insert, delete, update on *.* from 'franta'@'localhost';

Pozn.: Pozor na syntaxi. Správně je "GRANT ... TO" a "REVOKE ... FROM". Ať se Vám to neplete. REVOKErovněž nikdy neodstraní záznam z tabulky user, takže pokud budete chtít uživateli znemožnit i samotnépřihlášení na server, tak musíte sáhnout po ručním promazávání tabulky user.

Práva k jednotlivým databázím

V praxi se skutečně nejčastěji používá tento způsob, kdy:

1. Uživatelé jsou v tabulce user zapsáni pouze proto, aby se mohli přihlásit k serveru jako takovému ažádná globální práva jim nejsou poskytnuta

2. Uživatelům jsou pak povolena pouze práva pro konkrétní databázi.

Předveďme, jak to celé funguje, pokud budeme chtít uživateli franta povolit přístup do nově vzniklé databázefranta z lokálního počítače. Nejprve pomocí ručního zápisu do tabulek oprávnění:

delete from user where user = 'franta' and host='localhost'; insert into user (user, host, password) values ('franta', 'localhost', password('atnarf')); create database franta; insert into db (host, db, user, Select_priv, Insert_priv, Update_priv, Delete_priv,Create_priv, Drop_priv, References_priv, Index_priv, Alter_priv, Create_tmp_table_priv, Lock_tables_priv,Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv, Execute_priv) values ('localhost', 'franta', 'franta', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y','Y', 'Y', 'Y', 'Y', 'Y'); flush privileges;

Je to trochu delší příklad, takže co jsme vlastně provedli: Nejdřív jsme odstranili a znovu vložili uživatele frantado tabulky user. Byl to nejrychlejší způsob, jak se ujistit, že nebude mít žádná globální oprávnění. Následnějsme vytvořili databázi franta, a konečně jsme zápisem do tabulky db (to děláme nyní poprvé) přidělili uživatelifranta všechna práva k této nově vzniklé databázi.

Všimněte si, že franta nemá práva k žádné jiné databázi na serveru. Tento způsob přidělování se používá právěna hostinzích. A ještě pro úplnost dodejme, že to celé lze postatně zkrátit použitím GRANT, v tomto smyslu:

create database franta; grant all on franta.* to 'franta'@'localhost' identified by 'atnarf';

Z výroby však může být nastaveno, že jednotliví uživatelé mohou přistupovat k databázi test. Pokud se chcetepodívat, jak je na tom vaše instalace serveru, stačí se zeptat:

select * from db where db='test';

Závěr

Page 191: MySQL Obsah

V popisu přidělování práv bychom mohli podobným způsobem pokračovat a ukázat si, jak se přidělují práva kjednotlivým tabulkám a sloupcům. Protože však je to podobné a protože se to tak často nepoužívá, odpustíme sito. Rovněž je zajímavé "právo přidělovat práva", které umožňuje jiným uživatelům přidělit práva, která sámmám. MySQL navíc disponuje možnostmi přidělovat práva na základě toho, zda a jak je spojení k databázizašifrované.

Pokud se budete chtít stát v MySQL bezpečnostními experty, pravděpodobně Vám informace zde uvedené stačitnebudou. Ale jestliže chcete celému mechanizmu pouze rozumnět, nebo jestliže chcete nastavit párjednodušších bezpečnostních pravidel, tak byste tu měli najít, co potřebujete.

MySQL (64) - nad dotazy čtenářů

Dnes trochu netradičně. Neboli, co se urodilo v mojí e-mailové schráce od doby, kdy začal vycházet seriál oMySQL.

24.3.2006 06:00 | Petr Zajíc | přečteno 5877×

Page 192: MySQL Obsah

Komerční sdělení: Pořádáme Kurzy MySQL

Dnešní díl bude tak trochu mimo zavedené pořadí. Pokusím se totiž reagovat na řadu e-mailů a otázek, které seseriálu týkají a které stojí za to zodpovědět v samostatném článku. Budou to dotazy organizační, technické arovněž nějaké autorsko-právní.

Ještě než se pustím do zodpovídání konkrétních věcí, chtěl bych všechny, kdo mi v souvislosti se seriálem oMySQL píší pochválit. Dotazy - a musím říct, že tentokrát naprosto všechny - jsou velmi inteligentní afundované. Může to být tím, že s databázemi pracují chytří lidé, může to také znamenat, že čtenáři linuxsoftujsou ti nejlepší možní, každopádně jsem skutečně za rok, kdy seriál vychází nezaznamenal žádný hloupý,sprostý nebo arogantní příspěvek. Takže teď vzhůru k tomu, na co se ptáte.

Organizační věci

Seriál vychází jednou týdně; zatím to vypadá, že není důvod nějak to měnit. Redakce má filozofii vydávat jedenčlánek denně, a protože MySQL není středobodem vesmíru (ani linuxu), přijde nám to jako dobrý kompromismezi extrémy. Počet dílů seriálu není předem určen, teoreticky se může vyšplhat až k nějaké stovce dílů, alenebudeme to záměrně prodlužovat.

Pokud v seriálu nějaké informace postrádáte, zkuste se svěřit v diskusi pod libovolným článkem. Diskusesamozřejmě pravidelně čtu a podle možností v nich odpovídám. Na seriál mám osnovu, nicméně je možné, žejsem něčemu věnoval málo prostoru nebo že jsem něco vynechal. MySQL je obrovské téma a budu jen rád,když mi dáte vědět, na co bych se ještě mohl zaměřit.

Pár dotazů přišlo k tomu, nakolik by seriál měl nebo neměl korespondovat s oficiální dokumentací k MySQL.Odpověď je ta, že manuál a seriál jsou dvě různé věci. Mám vcelku odpor k článkům, které jsou de factopouhým překladem dokumentace; takže se usilovně snažím psát spíš z vlastní hlavy, než že bych překládaloriginální "návod k použití". V seriálu ale existuje řada odkazů na originální dokumentaci. Vím, že odkazuji naanglické stránky, ale pokud to s programováním a databázemi myslíte vážně, pak jistě alespoň trochu anglickyumíte.

Někdy chce vědět tazatel hodně věcí. Tady bych doporučil školení k MySQL, které linuxsoft pořádá a na kteréje upoutávka v záhlaví každého článku ze série. Jako autor neorganizuji žádná školení k MySQL (a i kdyby ano,nebylo by fér dělat si tady reklamu). Rovněž Vám většinou nebudu schopen zodpovědět dotazy, které vyžadujíspoustu času nebo které by znamenaly nějak výrazně se podílet na Vašich projektech.

Technické dotazy

Tady jsem vybral nejčastější dotazy technického směru - tedy na použití MySQL v praxi. Některé z nich jsou dojisté míry zodpovězeny v souvisejících dílech seriálu, takže někdy stačí jen číst v souvislostech. O jiných jsemmoc nemluvil, takže to teď napravím.

Dá se řadit podle rozdílu hodnot ve dvou sloupcích?

Ano, klauzule ORDER BY podporuje výrazy. Například tohle projde:

Page 193: MySQL Obsah

create table rozdil(jedna int, dva int); insert into rozdil (jedna, dva) values (10,5); insert into rozdil (jedna, dva) values (5,1); insert into rozdil (jedna, dva) values (7,3); insert into rozdil (jedna, dva) values (8,8); insert into rozdil (jedna, dva) values (100,1); select * from rozdil order by jedna-dva;

Pozn.: Krajně opatrní však musíte být při řazení podle podílu sloupců. Pozor totiž na dělení nulou - to byneprošlo.

Operace s daty/časem, rozdíl mezi daty, jak na to?

Tady vyjímečně dobře zafunguje originální manuál. Záznamy ne starší než 3 měsíce například z tabulkypohodlně vyberete stylem:

SELECT * FROM tabulka WHERE DATE_SUB(CURDATE(),INTERVAL 3 MONTH) <= Datum;

Vícenásobné spojení s tou samou tabulkou (častý dotaz!)

V podstatě jde o to, jak v dotazu použít vícekrát odkaz na stejnou tabulku. Máte třeba seznam zaměstnanců aseznam úkolů. V seznamu úkolů je uvedeno kdo daný úkol zadal a komu ho zadal. Obě informace jsou ve forměcizího klíče do tabulky zaměstnanců. Příklad:

create table lidi (id int, prijmeni varchar(50)); insert into lidi (id, prijmeni) values (1, 'Novák'); insert into lidi (id, prijmeni) values (2, 'Horák'); insert into lidi (id, prijmeni) values (3, 'Procházka'); insert into lidi (id, prijmeni) values (4, 'Jandera'); insert into lidi (id, prijmeni) values (5, 'Holý'); insert into lidi (id, prijmeni) values (6, 'Holík'); insert into lidi (id, prijmeni) values (7, 'Pazdera'); create table ukoly (kdozadal int, komuzadal int, popis varchar (50)); insert into ukoly (kdozadal, komuzadal, popis) values (2,5,'Udělat seznam zákazníků'); insert into ukoly (kdozadal, komuzadal, popis) values (3,1,'Obtelefonovat dodavatele'); insert into ukoly (kdozadal, komuzadal, popis) values (4,2,'Vyřídit reklamaci'); insert into ukoly (kdozadal, komuzadal, popis) values (5,3,'Vyměnit uklizečku'); insert into ukoly (kdozadal, komuzadal, popis) values (1,4,'Jít na oběd');

Řešení je v použití aliasů tabulky lidi a může vypadat nějak takto

select kdozadal.prijmeni, komuzadal.prijmeni, ukoly.popis from ukoly join lidi as kdozadal on ukoly.kdozadal = kdozadal.id join lidi as komuzadal on ukoly.komuzadal = komuzadal.id;

(klíčové prvky jsem zdůraznil kurzívou)

Jak ukládat do MySQL "stromová" data?

Úkol je jasný - máte například zaměstnance a podřízeného zaměstnance. Ti tvoří strukturu, která se můžerozšiřovat jak do šířky, tak do hloubky - tedy strom. Pracovat efektivně se stromy pomocí jazyka SQL jenáročné. Po zralé úvaze jsem se rozhodl to do seriálu NEDAT. Pár odkazů jinam: článek na root, špičkovýčlánek na abclinuxu.

Pozn.: Tip pro znalé - genealogické stromy jsou v MySQL díky rychlému LIKE velmi výkonné.

Page 194: MySQL Obsah

Ukládání dat do databáze pomocí PHP (častý dotaz!)

Otázka: Při ukládání dat pomocí PHP dojde k situaci, kdy po uložení a refreshi stránky se data vloží dvakrát. Tomi vadí. Neexistuje na to nějaký trik, jak tomu zabránit?

Odpověď: Ano, existuje trik. Spočívá v tom vědět, že na linuxsoftu máme seriál o PHP a že jeden z dílů to řeší.

Jak udělat dobrý návrh databáze

Bohužel tady řadu tazatelů moc nepotěším, ale upřímně řečeno funguje to takto:

1. Udělejte několik špatných návrhů databáze.

2. Zjistěte, proč byly špatné

3. Udělejte další návrhy databáze - ty budou dobré.

Jinými slovy: Přestože existují poučky o vývojových cyklech, normalizaci databází a tak dále, je třeba siuvědomit, že k dobrému návrhu databáze musíte mít selský rozum, špetku intuice a mraky zkušeností. Na něcotakového neexistuje e-mailová rada.

Existuje dobrá česká kniha o MySQL?

Znám celou řadu špatných českých knih o MySQL. Chtěl by někdo poradit nějakou dobrou? Jestliže ano, šup stím do diskuse!

Autorsko-právní záležitosti

Ještě jednou děkuji všem, komu se seriál líbí. Je třeba si uvědomit, že jakmile je článek napsán a uveřejněn,stává se majetkem redakce linuxsoftu. Tudíž já jako autor už s ním nemůžu dále disponovat. Není napříkladmožné, abych stejný článek uveřejnil někde jinde. V záležitostech kolem případného použití informací z článku- jako je jejich přetištění - byste se měli obrátit na redakci. Následuje seznam otázek, na které nemůžu dátsmysluplnou odpověď:

Vyjde seriál vcelku? Třeba jako PDF?

Vyjde seriál i v "papírové" podobě

Plánujete uveřejnění seriálu na CD/DVD apod?

Můžu část/celý seriál přetisknout do svých materiálů/zveřejnit na svém webu

Page 195: MySQL Obsah

Čistě pro úplnost dodávám - taky se na to někdo ptal - že informace z článku samozřejmě MŮŽETE použít vesvých projektech, databázích nebo výzkumech. K tomu seriál slouží a jsem rád, pokud si někdo díky čtenílinuxsoftu rozšíří obzory.

MySQL (65) - Ladíme server

Page 196: MySQL Obsah

Běh serveru lze ovlivnit mnoha parametry. Podíváme se na to, jak a kde se dají v MySQL nastavovat.

31.3.2006 06:00 | Petr Zajíc | přečteno 6388×

Komerční sdělení: Pořádáme Kurzy MySQL

Přiznám se, že napsat tenhle článek bylo pro mě jednou z nejtěžších věcí v celém seriálu o MySQL. Jde totiž otéma, které se dá pojmout velmi různě - o nastavení serveru. Člověk by mohl sklouznout k mnoha špatnýmmetodám, jak o něčem takovém napsat povídání. Mohl bych například podat suchopárný, nezáživný,vyčerpávající a nezapamatovatelný seznam konfiguračních voleb; mohl bych opsat originální dokumentaci nebobych se mohl vášnivě rozhovořit o tom, jak to dělám na "svých" instalacích MySQL a proč právě to je "tanejlepší" cesta.

Pokusil jsem se to všechno neudělat; a mám k tomu moc dobrý důvod. Nastavování serveru totiž není jakonastavování pračky. Databázový server může být používán mnoha způsoby a proto také musí být odlišněvyladěn. Proč? Není to snad tak, že server MySQL slouží jen jako úložiště dat? Ano a ne. Uvědomme si, žejeden a tentýž databázový server může být nastaven různě - a přece pokaždé "správně". Co tedy spolurozhodujeo tom, jak nastavit (kolega by řekl "vytunit") MySQL? Když se nad tím zamyslíte, mohou to být napříkladnásledující činitele (přičemž mnoho dalších jsem pro jednoduchost vynechal):

Na jakém hardware server poběží. Paměť, disky a procesor budou hrát klíčovou roli

Zda musíme mít zajištěnou nepřetržitou dostupnost nebo se smíme smířit s občasnými výpadky (třeba utestovacích serverů)

Jakým způsobem se s daty pracuje. Často se vkládá? Často se používá SELECT?

Kolik uživatelů bude k serveru připojeno. Kolik z nich bude chtít pracovat zároveň.

Jaký je objem dat. Kolik máme databází, kolik tabulek v nich a jak často se ty které tabulky používají.

Jaké máme typy tabulek.

Jaké máme indexy a jak často a hojně se využívají.

Zda se používají transakce.

Jak uvídíme, vzít to všechno v úvahu je silně nad rámec seriálu. Proto jsem se rozhodl popsat celé nastavení naněkolika málo příkladech a doufat, že vnímavý čtenář si odvodí odpovídající postupy i pro další proměnné avolby.

Nastavujeme MySQL

Page 197: MySQL Obsah

Není to zase tak složité. Pokud chcete v MySQL něco nastavit, potřebujete vlastně "jen":

Vědět, co hledáte

Vědět, kde a jak se to mění

Vědět, co to způsobí a vědět jak to ověřit

Vědět, jak se vrátit k původní konfiguraci pokud "to" nebude fungovat

Popíšu celé na příkladu. Zjistíme třeba, že řazení záznamů nám trvá neúměrně dlouho a že by bylo třeba sitrochu pohrát s nastavením výkonu pro příkaz ORDER BY. Pravda, příklad je trošku vyumělkovaný, alezáměrně jsem zvolil něco jednoduchého.

Vědět co hledáme

Neexistuje obecný návod; leda byste si každou z voleb pamatovali. Pokud budete chtít optimalizovat řazení dat,pravděpodobně se podíváte do manuálu a zjistíte, že výkon řazení může ovlivnit proměnná sort_buffer_size.Udává velikost bufferu, který si alokuje každé vlákno vykonávající řazení dat. S hodnotou si můžemesamozřejmě pohrát; přičemž je třeba vzít v úvahu, kolik paměti vlastně máme celkem pro server k dispozici akolik vláken nám (odhadem) bude zároveň potřebovat řadit data.

Pozn.: Údaj "kolik paměti máme pro server" je ošidný sám o sobě. Nezapomeňte, že v reálném světě nám můžena jednom stroji kromě MySQL běžet ještě řada služeb či programů a ty potřebují další paměť. Takže to berteopravdu jen jako příklad.

Vědět, kde a jak se to mění

Začněme tím, že si ukážeme, jak vlastně zjistit aktuální hodnotu konfiguračních voleb. To je jednoduché. Stačíse připojit k databázi a zadat příkaz:

show variables;

Cože? Že se v nich nemůžete vyznat? Jenom jsem Vás zkoušel. Moje instalace MySQL 5 obsahuje 209konfiguračních proměnných, takže v nich se opravdu špatně hledá. Mnohem lepší je

show variables like 'sort_buffer_size';

A hned vidíte, jak na tom jste. Když už jsme u příkazu SHOW VARIABLES, tak bych měl asi upřesnit, ženeobsahuje jen měnitelné, konfigurovatelné hodnoty. Obsahuje rovněž například informace o verzi serveru,kterou pochopitelně přepsat nemůžete. Změnit hodnotu proměnné - když to jde - můžete příkazem SET, nějaktakto:

set sort_buffer_size=1000000;

Zapamatujte si, že pokud to uděláte, bude nová hodnota platit ihned, ovšem pouze do ukončení aktuálníhospojení a pouze pro toto spojení. Jestliže vy nebo někdo jiný otevřete jiné spojení, bude v novém spojení opětpůvodní hodnota proměnné. Což je hezké, ale jak změnit hodnotu pro všechna připojení? Použitím klíčovéhoslova GLOBAL, nějak takto:

Page 198: MySQL Obsah

set global sort_buffer_size=1000000;

V tomto případě bude nová hodnota platit pro všechna od této chvíle vytvořená nová spojení až do restartuserveru. Z toho ovšem vyplývá, že pro spojení, které proměnnou nastavilo nová hodnota neplatí (pozor na to).

Pokud nám ani to nestačí a potřebujete proměnnou nastavit pro celý server a po každém spuštění, je třebazabrousit do konfiguračního souboru. Ten bude umístěn typicky v /etc/my.cnf (nebo jinde podle distribuce) abude mít formát jako ... ini soubor ve Windows. Takže změnu sort_buffer_size provedeme editací příslušnésekce:

[mysqld] ... sort_buffer_size=100K ...

Pozor, konfigurační hodnoty jsou načítány při startu serveru, tudíž při jejich změně bude nutné MySQLrestartovat. A ještě informace pro opravdové znalce: hodnoty konfiguračních voleb můžete povětšinou zadat přistartu serveru rovněž jako přepínače do příkazového řádku. Načítání voleb ze souboru mi však přijde mnohempřehlednější.

Jak to ověřit

Docela problém, protože většina voleb má na výkon relativně malý dopad. Dopad změny velikosti proměnnésort_buffer_size bychom mohli ověřit nějak takto:

set sort_buffer_size=100K; select * from obrovska_tabulka order by pole limit 1000,100; set sort_buffer_size=100M; select * from obrovska_tabulka order by pole limit 1000,100;

Čas potřebný ke zpracování výsledků by neměl být stejný, zejména pokud provedete více měření na reálnémprovozu.

Jak se vrátit k původní konfiguraci

Jak jste asi pochopili, občas bude mít význam vyzkoušet si změnu serverové proměnné pouze pro dané spojení.O návrat do původního stavu se pak vlastně nemusíme starat, protože po ukončení spojení se specifickénastavení ztratí. Jestliže nastavíte proměnnou pomocí set global, její hodnota se obnoví po restartu serveru napůvodní hodnoty. Pokud se chcete zabývat změnami konfiguračních souborů, je jasné, že bude třeba si jenejprve zálohovat. Pokud se něco pokazí, lze se vrátit k záloze. A ještě něco: do konfiguračních souborů lze psátpoznámky. Využijte toho, napište si třeba datum a čas změny, původní hodnotu proměnné nebo proč jste tukterou volbu měnili. Uvidíte, že to není zbytečná práce.

Protože sort_buffer_size byla použita opravdu jen jako příklad, podíváme se v dalším díle na to, které serverovéproměnné mohou ovlivnit naši konfiguraci opravdu podstatným způsobem a také si řekneme, jak zjišťovatstavové informace o právě běžící instanci serveru. Takže se máte na co těšit.

MySQL (66) - Ještě k ladění serveru

Page 199: MySQL Obsah

Ladění serveru MySQL na výkon je dost odborné téma. Dnes se podíváme alespoň na principy.

14.4.2006 06:00 | Petr Zajíc | přečteno 5334×

Komerční sdělení: Pořádáme Kurzy MySQL

Dnes budeme pokračovat v tématu "vylaďování" MySQL serveru tím, že si ukážeme, jak zjistit informace oběžícím serveru. Rovněž se podíváme na to, jak se dá výkon ovlivnit pomocí několika důležitých parametrů.

Zjišťování informací o běžícím serveru

Připomeňme, že v minulém díle jsme díky příkazu show variables mohli zjišťovat (a díky set měnit) hodnotykonfiguračních voleb. Jenomže to není při správě serveru vždy to, co potřebujeme. Často nás totiž ani taknezajímá, jak je na serveru co nastaveno, jako spíše to, jak se s tím v praxi chudák server vůbec popere.Přidejme potřebu chtít zjistit něco víc o serveru jako takovém - a máme tady příkaz show status. Jehonejjednodušší forma je - jak už asi tušíte - prostě ho bez skrupulí napsat.

show status;

Není na tom nic složitého; složité je nějak se ve výpisu vyznat. Proměnné jsou většinou pojmenovány intuitivně,někdy je však třeba zapátrat trochu v dokumentaci. Abyste si udělali představu, jak takový výpis vypadá,přikládám zkrácenou verzi z jednoho serveru, na který mám přístup (není to linuxsoft):

Aborted_clients 172Aborted_connects 61Bytes_received 1136057937Bytes_sent 1271897989Connections 327488Created_tmp_disk_tables 374068Created_tmp_tables 805247Created_tmp_files 7Delayed_insert_threads 0Delayed_writes 0Delayed_errors 0Flush_commands 1Key_blocks_used 15586Key_read_requests 274667326Key_reads 6716363Key_write_requests 1648257Key_writes 162455Max_used_connections 48Open_tables 64Open_files 125Open_streams 0Opened_tables 756017Select_full_join 73686Select_full_range_join 1418Select_range 64910Select_range_check 5349Select_scan 2096101Slow_queries 49Sort_range 210464Sort_rows 25126074Sort_scan 1704483Table_locks_immediate 9911663Table_locks_waited 4851Threads_cached 0Threads_created 327487Threads_connected 4Threads_running 2Uptime 67925

Page 200: MySQL Obsah

Co podstatného se dá vyčíst z tohoto seznamu? Především (a to je jedna z prvních věcí, na kterou byste se mělipodívat) server běží jen krátce, protože jeho uptime v sekundách je 67925, což je okolo 18 hodin. Takže pokudbyste jej chtěli ladit na výkon, bylo by asi lepší ještě nějakou dobu počkat a posbírat reprezetativnější statistiky.Dále, jak můžete vidět, tak během 18 hodin proběhlo otevření 756017 tabulek, došlo k 327488 spojením a takdále.

Optimalizace cache tabulek

Tento server (bohužel, neb se jedná o údaje z jakéhosi webhostingu, kde by tomu mohl někdo rozumět) mábídně nastavenu jednu ze základních výkonostních charakteristik, a tou je table_cache. Zjednodušeně řečenotato proměnná udává, kolik tabulek může maximálně MySQL udržovat v mezipaměti. Cachování tabulek vmezipaměti je přitom mnohem výkonnější než nejich načítání z disku. Abych mohl rozhodnout, zda jecachováno málo nebo hodně tabulek, je třeba vědět Uptime (v příkladu asi 18 hodin), Open_tables (v příkladu64) a potřebuji navíc znát hodnotu table_cache z nastavení (to jsme probírali v minulém díle):

show variables like 'table_cache';

(v mém případě ukazuje údaj 64 tabulek). A teď závěr: Protože je povoleno otevření maximálně 64 tabulek, 64je jich otevřeno, ale celkem jich již bylo otevřeno 756 tisíc, je server poddimenzovaný a je možné, že s nímbudou problémy. Obdobně by se daly porovnat další související údaje z konfigurace s údaji z provozu. PokudVás něco takového zajímá, mohu nasměrovat zejména na:

key_buffer_size, která optimalizuje čtení a zpracování indexů a souvisí s key_read_requests a key_reads

max_connections, která optimalizuje spojení a souvisí s max_used_connections

Tyto parametry jsou pro výkon serveru klíčové. Celá řada dalších nastavení dolaďuje spíše jemné výkonostnídetaily.

Všeho s mírou

Znamená to, co jsem uvedl výše, že byste měli ukamenovat svého webhostera poté, co zjistíte, že server neníoptimálně nastaven? V žádném případě. Informace, které jsem ukázal je nutné brát v širším kontextu. Napříkladpro zvýšení table_cache bude zcela jistě zapotřebí dostatek operační paměti, kterou ale server nemusí mít kdispozici. Zvýšení maximálního počtu spojení nemusí být nutné, protože správce databáze může mít k dispozicii starší statistiky (například ty, které získal před restartem serveru). Aktuální počet transakcí se může dost měnita tak dále.

Údaje z článku budete tedy potřebovat spíše v případě, kdy nastavujete server jakožto správci - a pak jistě časemzískáte cvik a cit pro vyváženost.

MySQL - (67)

Page 201: MySQL Obsah

MySQL a PHP nebo Java. Jde to dohromady? Jistě!

21.4.2006 06:00 | Petr Zajíc | přečteno 6756×

Komerční sdělení: Pořádáme Kurzy MySQL

Náš seriál o MySQL by zdaleka nebyl úplný, kdybychom si v něm nepředvedli, jak lze s daty v MySQLpracovat v několika různých programovacích jazycích. To dnes napravíme a ukážeme si, jak se připojit kdatabázi, jak vypsat data z tabulky a jak je do ní vložit - a to pomocí PHP a Javy.

Teorie

Když se to celé hodně zjednoduší (znalci teď prominou poněkud nepřesnou terminologii), dá se říci, že existujídva typy programovacích jazyků rozdělené podle toho, jak mohou pracovat s MySQL. Pro první platí, že majípodporu MySQL API vestavěnou přímo do jazyka a jejich typickým představitelem je PHP. Řečeno přesně -PHP může být zkompilováno s podporou MySQL a tudíž se pro spojení s databází a pro práci s ní volají funkce,které má jazyk "normálně" k dispozici.

Druhá filozofie pak spočívá v použití nějaké mezivrstvy, která stojí mezi programovacím jazykem na stranějedné a databází na straně druhé. Důvodem pro použití takové vrstvy je hlavně skutečnost, že vývojáře nebavilopsát odlišný kód pro různé databáze, takže se píše pro práci s databází stejný, unifikovaný kód a odlišnostijednotlivých databázových systémů se pak řeší v samostatné vrstvě. Typickými představiteli této filozofie budižnapříklad technologie ODBC pro Windows nebo technologie JDBC pro Javu.

Ještě pár poznámek pro upřesnění. Toto rozdělení je třeba chápat jako orientační. Například PHP se s MySQLklidně může spojovat pomocí datového zdroje ODBC, takže může spadat do obou typů. A další věc: technologiejako JDBC se sice tváří, že může pomocí stejného přístupu pracovat s různými datovými zdroji, v praxi všakvětšinou stejně narazíte na odlišnosti jednotlivých databází a kód musíte doladit.

Leč, vzhůru do praxe. Aby to bylo jednoduché, budeme chtít pracovat s následující tabulkou:

create table lidi (jmeno varchar (10), prijmeni varchar (20));insert into lidi (jmeno, prijmeni) values ('Jaroslav', 'Procházka');insert into lidi (jmeno, prijmeni) values ('Karel', 'Novák');insert into lidi (jmeno, prijmeni) values ('Jana', 'Sedláková');

Ukážeme si na:

1. Postup, jakým se dá k databázi připojit

2. Postup, jakým se dají získat data

3. A konečně, jak se dají data zapsat

Samozřejmě, že pro pořádnou práci s databází by to nestačilo. Je třeba ještě umět pomocí programovacíchjazyků vytvářet oprávnění, měnit strukturu databáze a tak dále. Ale pro ilustraci jistě bude stačit to, co uvedeme.

Page 202: MySQL Obsah

PHP

Připojení k databázi

Jelikož má PHP, jak jsme již uvedli vestavěnou podporu pro práci s MySQL, můžeme prostě použít funkci,která se připojuje k databázi. Bylo to rozepsáno v souvisejícím díle sesterského seriálu o PHP, takže jenpřipomenu, že ona funkce se jmenuje mysql_connect a že funguje zhruba takto:

<? $link = mysql_connect("localhost", "uzivatel", "heslo"); mysql_select_db("mojedb",$link);?>

Získání dat

Data v PHP můžeme z existujícího spojení získat pomocí funkce mysql_query (odkaz na seriál o PHP). Získanévýsledky lze procházet ve smyčce a něco s nimi dělat:

<? $vysledek=mysql_query("select jmeno, prijmeni from lidi"); while ($zaznam=MySQL_Fetch_Array($vysledek)): $jmeno = $zaznam["jmeno"]; // tady by se s výsledky pracovalo endwhile;?>

Manipulace s daty

PHP je relativně jednoduché. Proto se pro manipulaci s daty používá rovněž mysql_query.

<? $vysledek=mysql_query("insert into lidi (jmeno, prijmeni) values ('Petr','Zajíc')");?>

Java

Pro Javu bude prvním krokem získání JDBC driveru. Pro MySQL jich existuje poměrně dost, my použijeme tenod samotné MySQL. JDBC driver je třeba stáhnout a správně nainstalovat (to trochu přesahuje rámec našehoseriálu, tak se tomu věnovat nebudeme).

Připojení k databázi

Pro připojení k databázi je v Javě zapotřebí nejprve zinicializovat příslušný driver. Jeho název je pevně dán alze ho vyčíst z dokumentace. Například pro originální JDBC Connector z dílny MySQL je tocom.mysql.jdbc.Driver. Dále je nutné definovat připojení, a to tak, že se sestaví připojovací řetězec. Má rovněžpevně danou syntaxi (pro každý driver jinou, takže to, co vidíte níže nebude pro jiné DBMS fungovat) aspecifikuje umístění zdroje dat. Celé to může vypadat nějak takto:

try { Class.forName ("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnection ("jdbc:mysql://localhost/test?user=root");} catch (Exception e) { e.printStackTrace();}

Page 203: MySQL Obsah

Získání dat

Pokud máme k dispozici objekt Connection, můžeme na něm vykonat dotaz zhruba následujícím způsobem(data jsem pro porovnání s předchozím příkladem v PHP rovněž procházel ve smyčce):

ResultSet rs = con.createStatement().executeQuery("select jmeno, prijmeni from lidi");while(rs.next()){ String jmeno = (rs.getString(1)); //tady by se s výsledky pracovalo}

Za zmínku přitom stojí, že díky objektovosti Javy lze získat pomocí metod getXXX (getString, getDouble atd.)data z databáze již zkonvertovaná. Každopádně další práce se získanými daty jde nad rámec seriálu.

Manipulace s daty

Pokud budeme chtít provádět akční dotazy, lze využít metody executeUpdate objektu Statement. Je to poměrnějednoduché na pochopení a vypadá to zhruba takto:

con.createStatement().executeUpdate("insert into lidi (jmeno, prijmeni) values('Petr','Zajíc')");

To by mohlo na ukázku stačit. Zvídavý čtenář si asi bude chtít sám zjistit, co dělá objekt Statement a my mu vtom nebudeme bránit.

Závěr

Uvedené příklady z Vás samozřejmě neudělají mistry databázového programování v PHP nebo v Javě. Sloužíspíše jen jako jednoduchá ukázka toho, co je možné. Pokud budete chtít do problému proniknout hlouběji,budou se Vám hodit následující postřehy:

1. Prakticky jakákoli databázová operace může selhat. Robustní kód by měl ošetřovat chyby a nějak na něreagovat. To jsem v příkladech vynechal, pro praxi však to je naprosto nezbytné.

2. Jestliže se budete zabývat programováním hlouběji, nezbyde něž si pořídit a prostudovat dokumentaci kdanému jazyku a databázovému rozhraní.

3. Nevymýšlejte kolo. Spojení programovacích jazyků a databází je tu dlouho. Na práci, kterou chceteudělat existují jistě desítky příkladů, několik hotových řešení a pár frameworků. Hledejte.

Page 204: MySQL Obsah

MySQL (68) - Závěr

5.5.2006 06:00 | Petr Zajíc | přečteno 8270×

Komerční sdělení: Pořádáme Kurzy MySQL

MySQL v proudu času

MySQL za několik let vyrostla z malé databáze do středně velkého a solidně stabilního systému. Z nějakýchdůvodů si ji oblíbili správci webových serverů, a proto ji hojně najdete na webhostinzích. Ve skutečnosti je totak, že počet databází MySQL na webech bude až řádově vyšší než všechna ostatní nasazení dohromady.

Dodnes se mi nepodařilo přijít na to, proč zrovna MySQL je tak populární. Půjde ale nejspíš o směs módy,snadné správy a rychlosti, s jakou MySQL běhá. Také systém oprávnění založený na místě, z něhož se uživatelpřipojuje nahrává webovým řešením. Nesmíme samozřejmě zapomenout ani na lehkost, s níž spolupracujeMySQL s populárním PHP.

MySQL byla svého času kritizována za to, že nic neumí. To už není v kurzu, protože tato databáze disponuje jaktransakcemi, tak cizími klíči, tak i uloženými procedurami. Abych ale jen nechválil - i nadále se MySQL chováv některých věcech dost podivně. Například na způsob zápisu triggerů si stále nemůžu zvyknout.

Je také třeba počítat s tím, že MySQL se dost rychle vyvíjí. Vede to k častému vydávání nových verzí - ale tosamozřejmě neznamená, že každou novou verzi správce bude hned instalovat na server. Poměrně častá je taksituace, kdy na serverech dodnes běží MySQL 3.x, přestože již dávno existuje MySQL 4.x a 5.x.

MySQL a ti druzí

MySQL ovšem není jediná Free/OpenSource databáze. Z ostatních svého druhu bych jmenoval hlavně databázePostgreSQL a Firebird. Jistě byste chtěli vědět, jak na tom jsou tyto produkty při vzájemném srovnání. Něcotakového je však velmi ožehavé. Jednak neznám ostatní systémy úplně do detailu, a jednak má každý tohosvého favotira, jehož si bude hájit. Pokusím se alespoň nastínit některá kritéria.

Rozšířenost na webech - tady samozřejmě vede MySQL, následována PostgreSQL. Firebird je až úplně vzadua takhle z hlavy skutečně neznám jediný komerční hosting, který by nabízel podporu Firebirdu (samozřejmě toneznamená, že neexistují). Pro skriptovací jazyky však existují způsoby, jak se připojit ke každé z uvedenýchdatabází.

Rozšířenost jinde - pro ostatní řešení (desktopy, malé servery) překvapivě hodně lidí používá Firebird. Nadruhém místě pak je PostgreSQL a MySQL až na konci. Proč je to tak? Možná proto, že Firebird se velmijednoduše instaluje a má dokonce embedded verzi s velmi nízkými nároky na zavedení a správu.

Funkcionalita - tady vítězí jednoznačně PostgreSQL, následována Firebirdem a MySQL. Team lidí okoloPostgreSQL odvádí skutečně pozoruhodný kus práce a jejich databáze umí hodně z toho, co lze od moderníhosystému očekávat.

Page 205: MySQL Obsah

Pozn.: Veškerá zde uvedená srovnání byste měli brát jako informativní. Jednak je možné, že jsem subjektivní, ajednak se klidně může stát, že pořadí se změní, když tento článek budete číst za několik měsíců nebo let.

Co je však velmi nepravděpodobé: hypotéza, že by do světa těchto tří databází vstoupil někdo čtvrtý. Karty jsourozdány a myslím si, že srovnatelný produkt s MySQL, PostgreSQL a Firebirdem zkrátka hned tak neuvidíme.To ale nevadí, výběr ze tří dobrých produktů je myslím pro naše data právě tak dostatečný.

Mám se to učit?

Pokud již s nějakou databází pracujete, následující věty pro Vás nebudou ničím novým. V databázovém světětotiž platí, že člověk se neučí "sólo" vědomosti o jedné databázi, následně o další a tak dále. Spíše je to tak, žekaždý se nejprve naučí jakýsi základ. Můžete si jej klidně představit jako jazyk SQL. Následně se k tomutozákladu přidají jen věci, které má daná databáze odlišné. Má databáze jinak vyřešené zabezpečení? Správuuživatelů? Uložené procedury? Pak je na místě se to doučit. Jedná se ale spíš o drobnosti typu odlišné syntaxenež o nějak zásadní věci.

Jak se z tohoto úhlu dívat na MySQL? Pokud s žádnou databází nepracujete a chcete začít u MySQL, v podstatěnevím o ničem, co by Vám mohlo být na překážku. Tvorba tabulek, indexy, transakce - to všechno se můžetenaučit a pak to obdobným způsobem používat i v jiných DBMS.

Měli byste mít na paměti, že tvrzení o podobném přístupu k práci s jednotlivými databázemi neplatí pro uloženéprocedury. Skutečně neznám dva databázové systémy, které by měly společnou filozofii syntaxe kóduuložených procedur. To pro Vás může být určitým zklamáním, nicméně je to tak.

Závěr

V několika desítkách dílů jsme si prošli základy MySQL. Tato databáze je hojně používaná a jsem přesvcědčen,že ze světa jen tak nezmizí. Pokud Vám informace, které jsou v seriálu uvedené budou k něčemu dobré, budujen rád. Do seriálu se samozřejmě nevešlo všechno. Vynechal jsem některá pokročilá témata, jako napříkladreplikaci databází. I přesto věřím, že si zde každý najde ty svoje informace.

Petr Zajíc