Forum » Programiranje » [MariaDB] Zakaj LENGTH za ne ASCII znake (npr. "é") vrača dolžino 2 (namesto 1)?
[MariaDB] Zakaj LENGTH za ne ASCII znake (npr. "é") vrača dolžino 2 (namesto 1)?
HotBurek ::
Dobro jutro.
Evo, novo dan, nov teden, in nov zanimiv izziv.
Setup je sledeč. Database je MariaDB (InnoDB). Tabela ima definiran stolpec "key" tipa VARCHAR(40), katerega COLLATE je utf8mb4_bin.
SQL query, ki ga poženem, je sledeč (v vednost, gre za helper query, da lažje vidim, kaj se dogaja):
Rezultat zgornjega query-ja je sledeč (Slo-Tech določenih črk (cirilica, grške črke) ne prikazije, in jih zamenja z "?" znakom):
Tu se postavljata dva vprašanja:
1. Zakaj SQL query, ki ima v pogoju SUBSTRING(`key`, 1, 4), vrača rezultate, kjer je string dolžine 2 ali 3 (in zanimivo, nobenega dolžine 1)?
Rad bi namreč, da vrne samo stringe, ki so (na oko) dolžine 4.
2. Zakaj funkcija LENGTH za ne ASCII znake upošteva, kot da je posamičen znak dolg 2?
Se pravi:
What the heck?
Kako doseč, da LENGTH izmeri dolžino string kot takega (na oko), ne pa kot število bajtov, potrebnih za zapis znaka, ki so za ne ASCII znake 2.
------------------------------------------------------------------------------------
UPDATE
Sem šel gledat na internete, če bom kaj našel na to temo. In sem.
Najprej sledeče:
LENGTH
In the default mode, when Oracle mode from MariaDB 10.3 is not set, the length is measured in bytes. In this case, a multi-byte character counts as multiple bytes.
Vir: https://mariadb.com/kb/en/length/
Za rešitev so na voljo dve opcije:
1. Uporaba funkcije CHAR_LENGTH v WHERE pogoju.
2. Nastavitve SET SQL_MODE=ORACLE, ki enači funkcijo LENGTH kot, da je CHAR_LENGTH.
Dokumentacija: https://mariadb.com/kb/en/sql_modeoracl...
Jaz sem uporabil prvo opcijo. Zdej dela tako, kot se gre.
Monday is the best day of the week.
Evo, novo dan, nov teden, in nov zanimiv izziv.
Setup je sledeč. Database je MariaDB (InnoDB). Tabela ima definiran stolpec "key" tipa VARCHAR(40), katerega COLLATE je utf8mb4_bin.
SQL query, ki ga poženem, je sledeč (v vednost, gre za helper query, da lažje vidim, kaj se dogaja):
SELECT main.`sub`, CONCAT('>', main.`sub`, '<') AS 'highlight', main.`length` FROM ( SELECT SUBSTRING(`key`, 1, 4) AS 'sub', LENGTH (SUBSTRING(`key`, 1, 4)) AS 'length' FROM `database_1`.`table_1` GROUP BY SUBSTRING(`key`, 1, 4) ) AS main GROUP BY main.`length`;
Rezultat zgornjega query-ja je sledeč (Slo-Tech določenih črk (cirilica, grške črke) ne prikazije, in jih zamenja z "?" znakom):
sub |highlight|length| ----+---------+------+ 00 |>00< | 2| 000 |>000< | 3| 00 0|>00 0< | 4| 00 ?|>00 ?< | 5| béžo|>béžo< | 6| a???|>a???< | 7| ????|>????< | 8|
Tu se postavljata dva vprašanja:
1. Zakaj SQL query, ki ima v pogoju SUBSTRING(`key`, 1, 4), vrača rezultate, kjer je string dolžine 2 ali 3 (in zanimivo, nobenega dolžine 1)?
Rad bi namreč, da vrne samo stringe, ki so (na oko) dolžine 4.
2. Zakaj funkcija LENGTH za ne ASCII znake upošteva, kot da je posamičen znak dolg 2?
Se pravi:
LENGTH ("e") = 1 LENGTH ("é") = 2
What the heck?
Kako doseč, da LENGTH izmeri dolžino string kot takega (na oko), ne pa kot število bajtov, potrebnih za zapis znaka, ki so za ne ASCII znake 2.
------------------------------------------------------------------------------------
UPDATE
Sem šel gledat na internete, če bom kaj našel na to temo. In sem.
Najprej sledeče:
LENGTH
In the default mode, when Oracle mode from MariaDB 10.3 is not set, the length is measured in bytes. In this case, a multi-byte character counts as multiple bytes.
Vir: https://mariadb.com/kb/en/length/
Za rešitev so na voljo dve opcije:
1. Uporaba funkcije CHAR_LENGTH v WHERE pogoju.
SELECT SUBSTRING(`key`, 1, 4) AS 'sub' FROM `database_1`.`table_1` WHERE CHAR_LENGTH (SUBSTRING(`key`, 1, 4)) = 4
2. Nastavitve SET SQL_MODE=ORACLE, ki enači funkcijo LENGTH kot, da je CHAR_LENGTH.
Dokumentacija: https://mariadb.com/kb/en/sql_modeoracl...
Jaz sem uporabil prvo opcijo. Zdej dela tako, kot se gre.
Monday is the best day of the week.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
- spremenilo: HotBurek ()
mr_chai ::
Še enkrat in zadnjič ti linkam tole https://www.joelonsoftware.com/2003/10/...
char lenght != string length
Pa nauči se že osnovne programerske komunikacije, kjer moraš biti krajši in bolj jasen.
"Rad bi namreč, da vrne samo stringe, ki so (na oko) dolžine 4." ---> Rad bi funkcijo, ki mi vrne število charov v stringu.
Pa dj preber si že ta post od Joela, ker drgač sam škodo delaš sam sebi in drugim. Dejansko onesnažuješ okolje in brazilske gozdove požigajo zaradi tebe.
char lenght != string length
Pa nauči se že osnovne programerske komunikacije, kjer moraš biti krajši in bolj jasen.
"Rad bi namreč, da vrne samo stringe, ki so (na oko) dolžine 4." ---> Rad bi funkcijo, ki mi vrne število charov v stringu.
Pa dj preber si že ta post od Joela, ker drgač sam škodo delaš sam sebi in drugim. Dejansko onesnažuješ okolje in brazilske gozdove požigajo zaradi tebe.
Zgodovina sprememb…
- spremenilo: mr_chai ()
rokp ::
Haha, ko sem videl naslov teme, sem:
1. vedel, da jo je odprl HotBurek
2. si mislil, da bi bilo dobro, ko bi si OP prebral tocno ta clanek
1. vedel, da jo je odprl HotBurek
2. si mislil, da bi bilo dobro, ko bi si OP prebral tocno ta clanek
HotBurek ::
To, da funkcija LENGTH ("é") vrne 2, je zelo ne intuitivno.
Iz dokumentacije, prvi stavek:
Returns the length of the string str.
Potem se pa zakomplicira.
Do verzije vključno 10.2 funkcija LENGTH ("é") vrne 1.
Od verzije 10.3 naprej pa:
- če SQL_MODE ne vsebuje ORACLE mode, vrne 2
- če SQL_MODE vsebuje ORACLE mode, vrne 1
V mojem primeru tega ORACLE mode-a nisem imel v SQL_MODE.
Tako da, če nadgradiš iz 9.x na 10.3 (ali več), ter v SQL_MODE ni ORACLE mode-a, funkcija LENGTH za ne-ASCII znake začne vračat drugačno dolžino, kot jo je pred nadgradnjo.
Iz dokumentacije, prvi stavek:
Returns the length of the string str.
Potem se pa zakomplicira.
Do verzije vključno 10.2 funkcija LENGTH ("é") vrne 1.
Od verzije 10.3 naprej pa:
- če SQL_MODE ne vsebuje ORACLE mode, vrne 2
- če SQL_MODE vsebuje ORACLE mode, vrne 1
V mojem primeru tega ORACLE mode-a nisem imel v SQL_MODE.
Tako da, če nadgradiš iz 9.x na 10.3 (ali več), ter v SQL_MODE ni ORACLE mode-a, funkcija LENGTH za ne-ASCII znake začne vračat drugačno dolžino, kot jo je pred nadgradnjo.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
Zgodovina sprememb…
- spremenilo: HotBurek ()
Vredno ogleda ...
Tema | Ogledi | Zadnje sporočilo | |
---|---|---|---|
Tema | Ogledi | Zadnje sporočilo | |
» | sharepoint in infopathOddelek: Programska oprema | 836 (660) | pero978 |
» | Yamaha in Xonar ne špilata skupajOddelek: Zvok in slika | 1154 (535) | X-Jumper |
» | [SQL] teževa pri iskanju zapisovOddelek: Programiranje | 2115 (1705) | lopow |
» | [Access] iskanje z formom / querijemOddelek: Programiranje | 1342 (1266) | zagy |
» | VB6 - ne zaključi proces programa - pomoč !!!Oddelek: Programiranje | 1398 (1239) | Mavrik |