Sprawdzanie czy termin jest wolny
Wydawałoby się, że sprawdzenie czy w danym terminie są wolne pokoje to coś prostego. Przysporzyło mi to jednak dość dużo problemów i z pomocą przyszedł mi CoYoT (#php.pl), który podesłał mi gotowe zapytanie, które sam kiedyś opracował.
Zanim jednak podam to zapytanie, stwórzmy przykładową tabelę w PostgreSQL i wypełnijmy ją danymi:
Teraz nasze magiczne zapytanie.
Wyjaśnienie zapytania:
(1) sprawdza czy spotkanie nie jest wewnątrz innego
(2) sprawdza czy spotkanie nie zawiera całego spotkania
(3) sprawdza czy spotkanie nie przecina innego
Dalsza część kodu, która przetestuje nasze zapytanie.
Jeśli nie chcemy by w tym samym dniu kończył się termin i zaczynał wystarczy w (3) dodać ">=" i "<=" zamiast ">" i "<". W taki sam sposób możemy sprawdzić grafik godzinowy w interesującym nas dniu.
Słowa kluczowe: PHP, PostgreSQL, Techblog, termin, wolny, artykuł, blog

Komentarze i opinie
Eee tam, po co tak kombinować? Zapoznaj się lepiej z operatorem OVERLAPS w PostgreSQL (http://developer.postgresql.org/pgdocs/postgres/functions-datetime.html).
count(*)
You are doing it wrong. count(termId) prędzej ;)
count(*) w tym wypadku wystarcza, gdyż autora interesuje wynik zerowy. Poza tym termId nie może przyjmować NULL-i, więc i tak nie będzie różnicy.
Najlepsze byłoby oczywiście uniknięcie niepotrzebnego zliczania, np. poprzez dołożenie sprytnego LIMIT 1.
A nie prościej tak:
SELECT IdWniosku
FROM urlopy_wniosek
WHERE $strDateStart BETWEEN DataOd AND DataDo
OR $strDateEnd BETWEEN DataOd AND DataDo
@zeus: Twój przykład wykłada się, gdy odpytywany okres zawiera się w całości w zapisanym już w bazie.
Najszybsze rozwiązanie:
SELECT COUNT(*)
FROM terms
WHERE ( $startDate , $endDate ) OVERLAPS ( startDate , endDate )
LIMIT 1;
OVERLAPS zadziała szybko i nie trzeba martwić się wszystkimi trzema warunkami. LIMIT 1 daje to, że jeśli będzie wiele spotkań kolidujących z szukanym terminem, to nie trzeba zliczać ich wszystkich (pamiętajmy, że w PostgreSQL COUNT() jest liniowy).
@Zboczuch: bardzo fajny operator, dzięki za komentarz :)
@Zboczuch. Używam co prawda MySQL, ale u mnie działa.
@zeus: Także dla następującego przypadku?
$strDateStart --> 2009-01-01
$strDateEnd --> 2009-12-31
DataOd --> 2009-04-01
DataDo --> 2009-07-31
Czy overlaps tu robi to, co powinno?
Bo wg. manuala mysql:
Overlaps(g1,g2)
Returns 1 or 0 to indicate whether g1 spatially overlaps g2. The term spatially overlaps is used if two geometries intersect and their intersection results in a geometry of the same dimension but not equal to either of the given geometries.
Więc ja tak to rozumiem, że szuka w dwóch podanych w nawiasie liczbach...
@Juin: Nie wiem, dlaczego zaglądasz do manuala MySQL.
Napisałem to odnośnie tego komentarza:
"@Zboczuch. Używam co prawda MySQL, ale u mnie działa." - z tego co wyczytałem odnośnie tego operatora w Mysql, to chyba nie powinno?
@Juin: Rozumiem. zeus miał raczej na myśli, że zaproponowane przez niego zapytanie na dwa porównania działa. Pomimo tego, że nie rozpatruje jednego z przypadków zawierania się w sobie przedziałów. Oczywiście jest to nieprawda.
A w kwestii Overlaps() w MySQL - pewnie masz rację.
A czy któryś z Was sprawdził jak ma się ów overlaps do wydajności? Np. na polach korzystających z indeksów? Oraz pogooglał troche n/t tego dlaczego ta funkcja w ogóle trafiła do postgresa?
@Egz: Pierwsze słyszę, aby w PostgreSQL były "pola korzystające z indeksów". Jeśli już, to są zapytania wykorzystujące indeksy założone na polach.
A odnośnie Twojego pytania - zakładam, że dysponujesz wiedzą, o którą pytasz w ten sposób. Może w takich razie podzielisz się nią z nami.
Od siebie mogę napisać tyle, że założeniem PostgreSQL jest, że programista nie musi przejmować się kształtem zapytania, wystarczy, że da do zrozumienia bazie danych, poprzez zapytania, co chce uzyskać. Silnik PostgreSQL powinien zapytania przeanalizować i przekształcić do najbardziej optymalnej formy. Tak więc, jeśli OVERLAPS działa w jakimś konkretnym przypadku gorzej od wersji na trzy porównania, to silnik powinien dokonać odpowiedniej operacji przekształcenia.
Oczywiście jest to teoria i programiści PostgrSQL mają jeszcze dużo do zrobienia w tej materii, aczkolwiek z każdym kolejnym wydaniem tej bazy bazy danych jest coraz lepiej. Samo OVERLAPS możesz łatwo sprawdzić sam.
Z innej beczki - w PostgreSQL można zakładać indeksy funkcyjne. Myślę, że OVERLAPS łatwo da się wykorzystać w przypadku użycia odpowiednio napisanego indeksu tego typu.
W kwestii przyczyn włączenia tej funkcji do PostgreSQL - dziwne pytanie. Pozwolę je sobie odwrócić - dlaczego nie ma jej w innych bazach? Z chęcią przeczytam wyniki Twojej analizy po przeprowadzeniu śledztwa w Google.
"to silnik powinien dokonać odpowiedniej operacji przekształcenia."
To dlaczego PERFORM jest szybsze od SELECT ? Bzdury wygadujesz ziomuś. Twój ton pisania jeszcze bardziej mnie w tym uświadamia. W dodatku piszę w postgresql już od jakiegoś czasu i wiem że są to BEZEDURY.
Pozdro poćwicz.
3 zapytania w tym przypadku też się przydadzą, bo czasem trzeba napisać kod uniwersalny pod różne bazy danych.
Dodam jeszcze, że jeśli dołożymy czas, to potrzebny jest jeszcze 4 warunek.
Nowy komentarz