» »

[MariaDB] Zakaj SQL enači "ab " z "ab" v WHERE pogoju?

[MariaDB] Zakaj SQL enači "ab " z "ab" v WHERE pogoju?

HotBurek ::

Dobro jutro.


Evo, še malo, pa bo nov dan. A nov izziv je že tu.


Setup je sledeč. Database je MariaDB (InnoDB). Tabela ima definiran stolpec "key", katerega COLLATE je utf8mb4_bin. V tem stolpcu so vnešene vrednosti dolžine od 1 do 3 ("abc", "aa", "ab", "a", "a1", "a1a" itn.). Ter, na tem stolpcu je unique index.

Zakaj pri SELECT-u, kjer je v WHERE pogoju string "ab " (a-b-presledek), vrača id za vrednost "ab"?

Zadevo sem zaenkrat pofixal tako, da v WHERE pogoju dodatno preverjam še dolžino obeh stringov (parameter ter vrednost v tabeli).

Sample test run:
SET @id1 = -1;
SET @id2 = -1;
SET @p_key = 'ab ';

SELECT `id` INTO @id1
FROM `database_1`.`table_1`
WHERE `key` = @p_key;

SELECT `id` INTO @id2
FROM `database_1`.`table_1`
WHERE `key` = @p_key AND LENGTH (@p_key) = LENGTH (`key`);

SELECT @id1 AS 'id1', @id2 AS 'id2';

Output:
id1|id2|
---+---+
 97| -1|

Torej, zakaj v prvem primeru, kjer SQL išče string "ab " (a-b-presledek), najde match v stringu "ab"?

Test, kjer dodam string na začetku (se pravi " ab"), pa ne enači z "ab". Kar je prav.


UPDATE:

Še dve opcije za WHERE:
WHERE `key` = RTRIM(@p_key);
WHERE BINARY `key` = @p_key;

Vir: https://stackoverflow.com/questions/366...
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 ()

hbgqzR ::

Bravo, da ni vse samo politika.

Mogoče imaš polje tipa CHAR(3) - fixed length - auto pad.

kljuka13 ::

Ignoriranje presledkov pri primerjavi je namerno. Specifikacija ANSI namreč določa, da lahko primerjamo le dva niza z enako dolžino. Če je eden krajši, ga je treba dopolniti s presledki na koncu. Preden torej lahko strežnik primerja vrednosti v tvojem stolpcu `key` z vrednostjo 'ab ', jih mora narediti vse enako dolge, to pomeni, da vrednost 'ab' postane 'ab '.

Če je to v tvojem primeru zares težava, obstajajo različne rešitve.

  • Uporaba operatorja LIKE, ki pravilno primerja nize različnih dolžin:
    SELECT * FROM `table1` WHERE `key` LIKE 'ab '

  • Dodatni pogoj z LENGTH oziroma DATALENGTH:
    SELECT * FROM `table1` WHERE `key` = 'ab ' AND LENGTH(`key`) = LENGTH('ab ')

  • Trik z dodatnim nizem:
    SELECT * FROM `table1` WHERE CONCAT(`key`, '*') = CONCAT('ab ', '*')

OracleDev ::

hbgqzR je izjavil:

Bravo, da ni vse samo politika.

Mogoče imaš polje tipa CHAR(3) - fixed length - auto pad.

To preveri ja.

kuall ::

fun fact: če mixaš Char(3) in varchar (3), npr spremenljivka bo eno v polju drugo, in uporabljaš like ne bo delalo prav. Ker char doda space na koncu, varchar ne, like pa potem upošteva te space. = jih ne upošteva ravno zato, da se izognemo temu bugu.

Zgodovina sprememb…

  • spremenilo: kuall ()

kuall ::

In zarad podobnega razloga bi lahko ukinili null, v izogib bugom, čeprav je teoretično prav, da je null in da se space upošteva pri =.

Zgodovina sprememb…

  • spremenilo: kuall ()

Utk ::

Z null ni nič narobe. Ustrelit bi pa treba tistega, ki je izumil char() z neko fiksno dolžino, ki dodaja space na koncu avtomatsko. Če je nekaj fiksne dolžine 5, naj bo 5, naj bojo tudi 4 spaci od tega zarad mene, ampak to ni enako drugemu stringu, ki ima space več ali manj. Space je čisto legit znak in ni razloga, da bi ga ignorirali ali pa dodajali kar avtomatsko. Če že je nek tip s fiksno dolžino, bi moral vržt exception, ko skušaš zapisat kaj krajšega od tega.

kuall ::

Skiši se lepo Utk, kar si spesnu ravnokar. Ampak saj se tudi teorija komunizma sliš lepo.

praksa kolega, praksa.

Utk ::

Če ti iz prakse ne veš zakaj je null koristen, čeprav včasih boleč, pol nimaš neke prakse.

HotBurek ::

Polje ima tip VARCHAR(3), COLLATION je utf8mb4_bin.

Na koncu sem se odločil, da bom primerjal dolžine stringov (vhodneg parametra z vrednostjo iz table). Soldi solution.

Let's move on to the next challenge.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

DamijanD ::

Pa ni trajalo dolgo do novega :D


Vredno ogleda ...

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

Kako pohitrit build-anje index za autocomplete?

Oddelek: Programiranje
111066 (598) DamijanD
»

SQL Recursion 2.

Oddelek: Programiranje
12711 (535) korenje3
»

SQL vprasanje (strani: 1 2 )

Oddelek: Programiranje
688345 (5024) BivšiUser2
»

PostgreSQL pomoč

Oddelek: Programiranje
162504 (1997) Mato989
»

sql-t stored procedure

Oddelek: Programiranje
101057 (924) detroit

Več podobnih tem