Egy kis MySQL hack

Fabók Péter
Tepi Journal
Published in
2 min readMay 20, 2015

Ilyet is ritkán írok, de ez most kicsit érdekes probléma (számomra) és leírom, hogy rögzüljön.

Egy ügyfél siteján lapozhatóan itemeket jelenítünk meg, a képernyő tetején egy “előző” és egy “következő” nyílra kattintva lehet haladni egy katalógusban. Az itemek sorszámáról egy egész szám gondoskodott eddig, de egy felhasználói baki miatt muszáj volt az 1000. és az 1001. közé egy tételt beszúrni. Az volt a cél, hogy 1000/1 legyen a sorszáma, legalábbis így jelenjen meg a képernyőn, az admin felületen úgy csináljuk, ahogy akarjuk. Így tehát FLOAT típusúvá konvertáltam az eddigi INT típusú mezőt, mert az volt a tervem, hogy majd 1000.1 lesz a sorszám és majd képernyőre tevéskor a pontot per jellé alakítom, de számként kell tárolnom, hogy a sorrendet tudjam tartani.

Az az előtti állapothoz készült SQL — ami lekéri a sorban előzőt — így nézett ki:

SELECT * FROM items WHERE ordering<1001 ORDER BY ordering DESC LIMIT 1

Ekkor lehozta az 1000 orderinggel rendelkező itemet, ez tök jó volt (eddig).
De most, mivel lett egy 1000.1 orderinggel rendelkező item, amikor erre a tételre lapoztunk, az “előző” linkre kattintva ugyanezt a tételt kaptuk, nem az 1000. számút.

Sajnos ez a helyzet a FLOAT adattípus tárolásának mikéntjéből fakad, röviden az a gond, hogy igazából az ezer nem ezer, hanem 999.9999999 (vagy 1000.0000001), tehát nem pontosan azt az egzakt számot tárolja az adatbázis, amit mi odaírtunk. Emiatt az összehasonlító operátorok sem úgy működnek, ahogy az elvárt. Próbáltam mondjuk DECIMAL (6,1) formátumban tárolni, de akkor az egész számú itemek is 1000 helyett 1000.0 formátumban lettek eltárolva (ronda, és az esetek 99.99%-ában nem is indokolt, hogy így vigyük fel), ellenben így sem ment a sorrendiség. Végül abban az irányban kezdtem gondolkodni, hogy mi lenne, ha mondjuk tízzel szoroznám az értékeket és így hasonlítanám össze, ebből ez az SQL lett:

SELECT * FROM items WHERE (ordering*10)<(1000.1*10) ORDER BY ordering DESC LIMIT 1

Ami még mindig nem működött, ugyanúgy rossz számot hozott eredményül. Pedig érezhetően ez egy jó irány lenne. Aztán kiderült, hogy ha CAST-olom is, akkor sikerrel járok, tehát végül a

SELECT * FROM items WHERE CAST((ordering*10) AS UNSIGNED)<CAST((1000.1*10) AS UNSIGNED) ORDER BY ordering DESC LIMIT 1

kóddal már helyes értékeket kaptam, belátom, hogy ronda, de működik.

Hát, kalandos az élet.

--

--