Michał Matyas

Prywatny blog webdevelopera traktujący o tworzeniu i projektowaniu stron i serwisów internetowych.

Znajdowanie najbliższej liczby w MySQL

Podczas pracy nad aktualnym zleceniem (nie wiem czy mogę się nim chwalić, dlatego chwilowo cicho-sza) potrzebowałem znaleźć sposób, na pobieranie rekordu z bazy najbliższego pełnej godziny. Problem polegał na tym, że rekordów w bazie mogło być tysiące lub więcej, więc zwykłe pole typu DATE / TIMESTAMP było niewystarczające - jak sprawdzić, czy rekord o 11:59:59 był bliżej pełnej godziny niż 12:00:00, skoro mamy jeszcze 1000 mikrosekund pomiędzy? A co, jeśli ten pierwszy został dodany o 11:59:59.999, a ten drugi o 12:00:00.500 ?

Rozwiązaniem problemu było zapisywanie w polu typu DOUBLE wartości microtime() z PHP. Pojawiał się jednak nadal problem znalezienia najbliższej wartości pełnej godziny. Klient podkreślił, że pobieranie musi być “dookoła” danego czasu, a nie tylko najbliżej + pierwszy o pełnej, jak to miało miejsce w innym projekcie tego typu, który realizowałem.

W końcu bo wielu minutach Googlania i eksperymentach, znalazłem ostateczne rozwiązanie, które przedstawiam poniżej. Nie jest do końca moje, ale może komuś się przyda:

(
   SELECT * FROM :table WHERE timestamp > :timestamp 
   ORDER BY timestamp ASC LIMIT 1 
) 
UNION 
( 
   SELECT * FROM :table WHERE timestamp <= :timestamp 
   ORDER BY timestamp DESC LIMIT 1 
) 
ORDER BY ABS(timestamp - :timestamp) 
LIMIT 1

Nawiasem mówiąc, w module Database do Kohany 3.0 nie ma jeszcze obsługi UNION, ale widziałem ją w repozytorium GIT-a dla 3.1, więc jeśli korzystamy z ORM-a, chwilowo można się salwować takim rozwiązaniem:

$query = DB::query(Database::SELECT, 
  "( SELECT * FROM :table WHERE timestamp > :timestamp ". 
     " ORDER BY timestamp ASC LIMIT 1 ) ".
  "UNION".
  "( SELECT * FROM :table WHERE timestamp <= :timestamp ".
     "ORDER BY timestamp DESC LIMIT 1 ) ".
  "ORDER BY ABS(timestamp - :timestamp) LIMIT 1")
->parameters(
  array(
      ":table"     => "elements",
      ":timestamp" => 1295090875
      )
->as_object('Model_Element')->execute();

Moje kursy dot. Kohany 2.3 są już na tyle nieaktualne, że stwierdziłem, że daję sobie spokój z tą serią, była kochanym potworkiem, ale nadal potworkiem. Ostatnio zakochałem się w Ko3, więc może jak znajdę więcej czasu i będę miał coś ciekawego do napisania, zrobię kilka wpisów.

A dla zainteresowanych nie tylko technikaliami - przekonałem się w końcu do ORM-a. Wheee!

More Information