» »

[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):
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
  • 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.

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

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.
root@debian:/# iptraf-ng
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 ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

sharepoint in infopath

Oddelek: Programska oprema
11806 (630) pero978
»

Yamaha in Xonar ne špilata skupaj

Oddelek: Zvok in slika
81129 (510) X-Jumper
»

[SQL] teževa pri iskanju zapisov

Oddelek: Programiranje
102065 (1655) lopow
»

[Access] iskanje z formom / querijem

Oddelek: Programiranje
61316 (1240) zagy
»

VB6 - ne zaključi proces programa - pomoč !!!

Oddelek: Programiranje
131366 (1207) Mavrik

Več podobnih tem