Nedávno som pri tvorbe databázy miest a obcí, narazil na celkom zaujímavý problém so znakovou sadou. Na prvý pohľad je to veľmi jednoduché zadanie a väčšina programátorov si povie, že navrhnúť štruktúru databázy je práca na niekoľko minút.
Keďže išlo o české a slovenské mestá, ako zotriedenie pre databázu, tabuľky a stĺpce som zvolil utf8_slovak_ci. Názvy miest som importoval z rôznych zdrojov.
CREATE TABLE IF NOT EXISTS `tblCities` (
`id` int(11) NOT AUTO_INCREMENT,
`district_id` int(11) NOT ,
`title` varchar(50) COLLATE utf8_slovak_ci NOT ,
PRIMARY KEY (`id`),
KEY `district_id` (`district_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_slovak_ci AUTO_INCREMENT=1 ;
Spustil som import zo súborov a dáta som mal po niekoľkých sekundách v databáze.
Problém nastal až keď som databázu začal používať. Myslím, že každý z nás pozná slovenskú abecedu a ak si ju z 1. ročníka na základnej škole nepamätá, tak pre osvieženie:
a, á, ä, b, c, č, d, ď, dz, dž, e, é, f, g, h, ch, i, í, j, k, l, ĺ, ľ, m, n, ň, o, ó, ô, p, q, r, ŕ, s, š, t, ť, u, ú, v, w, x, y, ý, z, ž
http://sk.wikipedia.org/wiki/Slovenská_abeceda
Prečo som uviedol abecedu? Keď som podľa nej dal zotriediť všetky mestá v databáze pomocou dopytu:
SELECT * FROM `tblCities` ORDER BY `tblCities`.`title` ASC;
Zobrazil sa mi nasledovný výsledok:
id | district_id | title
-----+---------------+--------
1 | 6 | Ábelová
2 | 87 | Abertamy
3 | 9 | Cabov
4 | 55 | Čabalovce
Po prekontrolovaní aplikácie som sa pustil do hľadania v internete. Dopracoval som sa až k definícii znakovej sady, ktorú síce implementuje MySQL 6, ale chyba nie je odstránená.
http://www.collation-charts.org/mysql60/mysql604.utf8_slovak_ci.html
Podľa tabuľky sú z nejakého dôvodu akýmsi spôsobom zjednotené niektoré písmená. Neviem prísť na princíp, podľa ktorého sa zjednocovali. Možno by nám to vedel vysvetliť niekto, kto sa venuje gramatológii. Bohužial nikoho takého nepoznám a ani som nenašiel. Hovorím napríklad o písmenách „č“, „ď“, „ň“, ...
Zatiaľ čo spoluhlásky „c“ a „č“ sú oddelné a zotriedenie naozaj funguje správne, zvyšné spoluhlásky a takmer všetky samohlásky sú zjednotené. V praxi to znamená, že ak v dopyte uvediete napríklad písmeno „a“ alebo „á“, písmeno sa stále považuje za „a“ a podľa toho sa vám zobrazí výsledok.
SELECT * FROM `tblCities` WHERE `title` LIKE 'abe%'; Chyba – vráti 2 záznamy
SELECT * FROM `tblCities` WHERE `title` LIKE 'ábe%'; Chyba – vráti 2 záznamy
SELECT * FROM `tblCities` WHERE `title` LIKE 'cab%'; Správne – vráti 1 záznam
SELECT * FROM `tblCities` WHERE `title` LIKE 'čab%'; Správne – vráti 1 záznam
Kvôli tomuto pravidlu teda nefunguje správne ani zotriedenie (ORDER BY).
Na stránkach MySQL som našiel dvoch slovákov, ktori na túto chybu upozorňovali pred niekoľkými rokmi. Keďže MySQL priamo nezodpovedá za tvorbu znakovej sady, ich odpoveď bola, že to majú implementované správne a nič s tým nespravia, hľadal som ďalej.
Tvorcovia operačných systémov, databázových systémov a ďalší, používaju znakovú sadu definovanú organizáciou The Unicode Consortium (http://unicode.org/). Pred niekoľkými dňami (16.11.2012) vydali nový release jadra Unicode, v ktorom som našiel aj xml špecifikáciu pre slovenčinu. Problém v ňom stále pretrváva. Hľadal som na ich stránke, či už túto chybu niekto s nimi riešil, no nič také nemajú zverejnené. Preto som zaslal ich adresu podrobný popis tohto problému a čakám na ich odpoveď.
Keďže je riešenie tohto problému zatiaľ v nedohľadne, musím sa spoľahnúť na programovanie a dáta si pred zobrazením preusporiadať manuálne (späť k latin1_swedish_ci :-)).
Toto sa týka češtiny. Znaky, ktorých význam môže zmeniť nasledujúce písmeno (d, t, n, l) a samohlasky majú rovnakú hodnotu bez ohľadu na diakritiku. Dúfam, že som pomohol. Ak som napísal v prvom príspevku iný email, tak som sa pomýlil. Správny je v tomto. Reagovať