Ar šo ierakstu vēlos sākt rakstu sēriju ar praktiskiem padomiem programmēšanā (jā — PPP nozīmē praktiski padomi programmēšanā). Tā kā ar programmēšanu nodarbojos katru dienu un ar to pelnu savu iztiku, tad agri vai vēlu, gribot vai negribot nākas saskarties ar vienu vai otru problēmu, kura ir diez gan specifiska un par kuru atrodamā informācija internetā ir nepietiekama vai nepietiekoši skaidra.
Tad lūk, pirmā šada veida problēma, kuru vēlos izpētīt, ir ierakstu kārtošana mysql datubāzē atbilstoši latviešu alfabētam. Sākšu ar pamatuzstādījumiem, lai visiem ir skaidrs, kas par situāciju. Lietoju pēdējo MySQL 5.1.x versiju, tabulām izmantoju utf-8 charset. Gadījumā, ja kāds bļaus, ka ir jau utf8_latvian_ci kolācija (translate.google.com vārdam collation kā tulkojumu piedāvāja “uzkožamie”, tāpēc palikšu pie angļu vārda latviskošanas), tad man jājautā jums, vai tā jums jebkad ir strādājusi pareizi? Problēma ar latviešu kolāciju ir tāda, ka tā uztver “a” un “ā” kā vienlīdzīgus. Bet mēs visi zinam ka “ā” seko aiz “a”. Rezultātā mysql atgrieztu ierakstus “ab”, “āa” sekojošā secībā: “āa”, “ab”.
Tagad, kad esam sapratuši, kur ir problēma, varam doties tālāk. Sākumā prasīju googlei, vai vēl kādam ir tāda problēma. Brīnumainā kārtā neatradu nevienu pašu, kuram tāda būtu. Atradu vēl vienu personu ar tādu pašu problēmu php.lv forumā, bet tur nekāda atbilde netika sniegta. Nedaudz sabrīnījos un nodomāju, ka jāuzprasa kādam no zināmajiem “ekspertiem”, vai šiem nav idejas. Lai gan visi bija ļoti atsaucīgi (paldies @sandis un Laacz par mēģinājumiem palīdzēt), problēmu atrisināt neizdevās. Tā nu es pāris dienas atļāvos atstāt šo problēmu novārtā, jo labākās idejas vienmēr nāk pēc laika, kad vismazāk tās gaidam.
Nesen atkal uznāca vēlme atrisināt šo problēmu. Vēl meklējumi, vēl sarakstes, bet nekā. Pagaidām bija skaidrs tikai viens: problēma ir tāda, ka kolāciju tabulās latviešu burti ir kā alias attiecīgajiem latīņu burtiem (tātad ar vienādu “svaru”). Pēdīgi nonācu pie secinājuma, ka būs jāliek pielāgota kolācija. Atkal meklējumi, atkal vilšanās.
Izmisums jau bija mani pārņēmis, kad beidzot uzdūros lapai, kura izmainīja manu dzīvi (vakaru). How to Add a Collation.
Tagad sākas interesantākais. Mēģināšu parādīt rezultātus uzskatāmi. Man ir tabula, kurā esmu savadījies vienkārši 2 burtus, kur pirmie burti ir alfabēta burti un otrais ir galvas jaukšanai, lai parādītu, kā atšķiras rezultāti.
Kvērijs ir vienkāršs:
SELECT * FROM test ORDER BY field ASC
un rezultāti tam ir sekojoši.
| Pirms | Pēc |
|---|---|
| āa | Aa |
| Āa | ab |
| Aa | AB |
| ab | āa |
| AB | Āa |
| ba | ba |
| ča | cb |
| ČA | CB |
| cb | ča |
| CB | ČA |
| Da | Da |
| ēa | eb |
| ĒA | EB |
| eb | ēa |
| EB | ĒA |
| f | f |
| ģa | gb |
| ĢA | GB |
| gb | ģa |
| GB | ĢA |
| … | … |
Domāju, ka atšķirību saskatāt.
Zinu, zinu … bļausiet, ka dzīvē tā nenotiek. Kļūdāties! Un panākt to var gaužām vienkārši.
- Sākumā atrodam /share/charsets/Index.xml failu (uz manas windows kastes to var atrast mysql instalācijas mapē.
- Atrodam rindiņu, kura sākas ar <charset name=”utf8″>
- Šeit mēs pieliksim savu kolāciju. Pēc izmaiņām tam būtu jāizskatās aptuveni šādi:
<charset name="utf8">
<family>Unicode</family>
<description>UTF-8 Unicode</description>
<alias>utf-8</alias><collation name="utf8_general_ci" id="33">
<flag>primary</flag>
<flag>compiled</flag>
</collation>
<collation name="utf8_reallatvian_ci" id="56">
<rules>
<reset>A</reset><p>\u0100</p>
<reset>a</reset><p>\u0101</p>
<reset>C</reset><p>\u010C</p>
<reset>c</reset><p>\u010D</p>
<reset>E</reset><p>\u0112</p>
<reset>e</reset><p>\u0113</p>
<reset>g</reset><p>\u0123</p>
<reset>G</reset><p>\u0122</p>
<reset>i</reset><p>\u012B</p>
<reset>I</reset><p>\u012A</p>
<reset>k</reset><p>\u0137</p>
<reset>K</reset><p>\u0136</p>
<reset>l</reset><p>\u013C</p>
<reset>L</reset><p>\u013B</p>
<reset>n</reset><p>\u0146</p>
<reset>N</reset><p>\u0145</p>
<reset>s</reset><p>\u0161</p>
<reset>S</reset><p>\u0160</p>
<reset>u</reset><p>\u016B</p>
<reset>U</reset><p>\u016A</p>
<reset>z</reset><p>\u017E</p>
<reset>Z</reset><p>\u017D</p>
</rules>
</collation>
<collation name="utf8_bin" id="83">
<flag>binary</flag>
<flag>compiled</flag>
</collation>
</charset> - Pārstartējam serveri
- Gatavs!
Tālāk viss ir vienkārši — vajadzīgajam laukam norādam “UTF-8″ charset un utf8_reallatvian_ci collation.
Pēdējās piezīmes
1) Es ieteicu likt kolāciju konkrētajam laukam un nevis visai tabulai, jo tā tomēr būs drošāk un jūs ietekmēsiet tikai vienu lauku un pārējā tabula uzvedīsies kā parasti.
2) Pārliecinieties, ka uz jūsu servera konkrētais kolācijas ID nav aizņemts (to var izdarīt ar vaicājumu “SHOW COLLATION WHERE Id = ‘xx’”). Ja ir, izvēlieties kādu citu no brīvajiem.
3) Varat kolācijai dot savu nosaukumu. Ja nepatīk “utf8_reallatvian_ci”, sauciet par “mana_mega_kruta_kolacija” manispēc.
4) Pielietojums šai metodei ir daudz plašāks kā es te esmu aprakstījis. Viens no tiem būtu jau prezentācijā pieminētais gadījums ar numuriem, kad mums vajag, lai MySQL ignorē attiecīgus simbolus. Man uzreiz iešāvās prātā variants par uzņēmumu nosaukumiem, kuros var būt pēdiņas. Vienkārši ieliekam ” (izmantojiet unicode apzīmējumu) iekš <s> taga (līdzīgi kā mēs likām latviešu burtus <p> tagā). Precīzas pamācības var izlasīt prezentācijā, kuru iemetu iepriekš. Noteikti katram būs savs pielietojums šai metodei.
Pievienotā vērtība rakstam (jeb ko vēl mēs ieguvām?)
1) Dažreiz risinājumi problēmām nav uzreiz acīmredzami, bet tas nenozīmē, ka atbilde ir sarežģīta. Vien to, ka neesam to vēl atraduši.
2) Ir iemesls, kāpēc mēs mācāmies. Jo vairāk mēs zinam, jo vairāk iespēju mums paveras. Ņemsim par piemēru augstāk aprakstīto problēmu. Iepriekš, ja man būtu jāatrisina problēma ar tekstiem, kuri var saturēt vai nesaturēt pēdiņas, es būtu taisījis vēl vienu lauku, kur vērtības glabātu bez pēdiņām. Bet tā būtu datu dublēšana. Tagad man atliek vien uztaisīt kolāciju, kurā pēdiņas nav svarīgas un es varu strādāt ar datubāzi neko nemainot kodā, bet rezultātu iegūstot tieši tādu, kādu vēlos. Jo plašākas ir mūsu zināšanas, jo efektīvāk varam risināt problēmas.
3) Uzrakstīt šādu rakstu prasa daudz vairāk laika nekā viens varētu domāt.
Papildināts
Saskāros ar vienu problēmu. Ja uz laukiem, kuriem ir uzliks šis charsets, izmanto LOWER() (un gan jau tas attiecas uz citām līdzīgām funkcijām), tad kvērijs neizpildās. Risinājums būtu izmantot šo kolāciju tikai kārtošanai (… ORDER BY field COLLATE utf8_reallatvian_ci ASC), bet pašu lauku atstāt kā utf8_general_ci vai utf8_latvian_ci.