Dzisiejszy wpis ponownie będzie krótki i prosty, ponownie też podejmę temat zapytań SQL przydatnych w codziennej pracy programisty. Czym w takim razie się zajmiemy? Otóż, w związku z tym, że “czasem” musimy wykonać pewne instrukcje w zależności od istnienia bądź nieistnienia rekordów dodanych w konkretnym przedziale czasu (np. wczoraj, w ostatnim tygodniu), w tym wpisie chciałbym pokazać, jak to zrobić w prosty i przyjemny sposób. Zapraszam do lektury.

Fotografia: thejaymo, CC-BY-SA.

SQL: Znajdowanie rekordów dodanych w przedziale czasu.

Na początku załóżmy, że będziemy operować na następującej tabeli z danymi:

CREATE TABLE IF NOT EXISTS `posts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `content` text DEFAULT NULL,
  `createdAt` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Krótko: mamy tabelę zawierającą wpisy [np. na blogu] - każdy z nich składa się z tytułu, treści i daty dodania.

Aby otrzymać wyniki pochodzące z tej tabeli musimy wykonać następujące zapytanie:

SELECT `id`, `name`, `content`, `createdAt`
FROM posts

Nie było to zbyt trudne, prawda? Nasze zapytanie ma jednak istotny problem - zwróci baaardzo dużo danych, a my, zgodnie z tytułem wpisu chcemy dostać tylko te, które zostały opublikowane w pewnym odstępie czasu.

Jak to osiągnąć? Spróbujmy z przykładem - weźmy wszystkie wpisy opublikowane przedwczoraj. Przedwczoraj, to znaczy nie wcześniej niż dwa dni temu i nie później niż wczoraj o północy. Odpowiednie zapytanie SQL przedstawia się następująco:

SELECT `id`, `name`, `content`, `createdAt`
FROM posts
WHERE createdAt > DATE(DATE_SUB(NOW(), INTERVAL 2 DAY)) AND createdAt < DATE(DATE_SUB(NOW(), INTERVAL 1 DAY))

Nie wygląda na specjalnie skomplikowane, prawda? Zobaczmy więc, co oznaczają poszczególne elementy klauzuli WHERE.

Główny warunek “createdAt > X AND createdAt < Y” jest jasny, także mogę go pominąć w opisie. Cała zabawa zaczyna się w momencie, kiedy wgłębimy się w istotę funkcji opisujących punkty czasu.

Pierwsza funkcja otaczająca oba wyrażenia to DATE() - zwraca ona samą datę z podanego argumentu. Oznacza to w uproszczeniu tyle, że jeśli przekażemy do niej wartość pola typu DATETIME, to dostaniemy samą datę. Jeśli chcielibyśmy, żeby to zapytanie zwróciło nie rekordy opublikowane przedwczoraj, ale np. 24h temu poczynając od teraz, wystarczy usunąć tą funkcję i zostawić same jej argumenty.

Rdzeniem całego zapytania jest funkcja DATE_SUB(), która najprościej mówiąc odejmuje jedną datę od drugiej i zwraca odpowiedni wynik. Klucz do sukcesu to możliwość wstawienia do jej argumentów operatora INTERVAL, który potrafi “wygenerować” dowolny odstęp w czasie. W związku z tym, jeśli odejmiemy od wartości funkcji NOW() odstęp INTERVAL 1 DAY, to otrzymamy dokładny punkt w czasie… 24 godziny temu. Podobne zadanie realizuje funkcja DATE_ADD(), która oczywiście zamiast odejmować, dodaje podane daty i zwraca odpowiedni wynik. Możemy jej użyć, żeby sprawdzić np. daty i czas w przyszłości. ;]

Oczywiście DAY nie jest jedyną wartością, jaką może przyjąć wspomniany operator. Do wyboru mamy:

  • SECOND
  • MINUTE
  • HOUR
  • DAY
  • MONTH
  • YEAR
oraz wiele więcej. Wystarczy skorzystać z konstrukcji takich, jak np.:
  • INTERVAL 2 YEAR
  • INTERVAL 4 WEEK
  • INTERVAL 2 SECOND
a życie od razu stanie się prostsze.

Mam nadzieję, że ten wpis przyda Wam się w rozwiązywaniu nietrywialnego problemu, jakim jest operowanie na datach i czasie w programowaniu. Miłego programowania. ;]