Jakiego rodzaju schematu SQL zaproponowałbyś do przechowywania godzin i dni wolnych oraz jakiego rodzaju zapytania sprawdzają, czy restauracja jest otwarta? W tej chwili mam to:
CREATE TABLE hours (
"restaurant" integer NOT NULL REFERENCES restaurants ON DELETE CASCADE,
"dow" integer NOT NULL,
"open" time NOT NULL,
"close" time NOT NULL
);
CREATE FUNCTION is_open(r integer) RETURNS boolean AS $$
DECLARE
h record;
t time;
BEGIN
SELECT open, close INTO h
FROM hours WHERE restaurant = r AND dow = EXTRACT(dow FROM now());
IF NOT FOUND THEN
RETURN false;
END IF;
t := current_time;
IF h.close <= h.open THEN
RETURN (t < h.close OR t > h.open);
ELSE
RETURN (t > h.open AND t < h.close);
END IF;
END;
$$ LANGUAGE plpgsql;
Ale to naprawdę nie działa, ponieważ na przykład restauracja może być otwarta do 2 nad ranem, w którym to momencie muszę sprawdzić poprzednią dow
.
Żeby sprawy były nieco bardziej skomplikowane, mam do czynienia z wakacjami:
CREATE TABLE holidays (
"restaurant" integer NOT NULL REFERENCES restauraunts ON DELETE CASCADE,
"day" date NOT NULL
);
Który ma ten sam problem - jeśli restauracja jest otwarta od 15:30 do 2:00, oznacza to, że są one również zamknięte dla bloku od północy do dwóch.
Nie byłem w stanie objąć głowyznalezienie dla niej czystego, eleganckiego rozwiązania (kilka niechlujnych pojawiło się i zniknęło). Muszę iść na spacer i wrócić do tego - w międzyczasie doszedłem do wniosku, że pozwolę ci się na tym popracować.
Odpowiedzi:
1 dla odpowiedzi № 1Wygląda na to, że źle jest odpowiedzieć na moje własne pytanie, ale znalazłem coś, co wydaje się działać tak samo niechlujnie jak to jest:
CREATE FUNCTION is_open(r integer) RETURNS boolean AS $$
DECLARE
t time;
yesterday date;
dow_today integer;
dow_yesterday integer;
BEGIN
t := current_time;
yesterday := current_date - 1;
dow_today := EXTRACT(dow FROM current_date);
dow_yesterday := EXTRACT(dow FROM yesterday);
PERFORM * FROM hours
WHERE restaurant = r AND ((
dow = dow_today
AND NOT EXISTS(
SELECT * FROM holidays
WHERE restaurant = r AND day = current_date
) AND (
(open < close AND t > open AND t < close)
OR (open >= close AND t > open)
)
) OR (
open >= close AND dow = dow_yesterday
AND NOT EXISTS(
SELECT * FROM holidays
WHERE restaurant = r AND day = yesterday
) AND t < close
));
RETURN FOUND;
END;
$$ LANGUAGE plpgsql;
0 dla odpowiedzi nr 2
Podsumowując komentarze:
1 - Użyj ogólnej struktury zapytania z tego pytania.
2 - Dodaj bitową flagę do twojego stołu ClosePastMidnight
lub OpenPastMidnight
(w zależności od tego, który z nich działa najlepiej na swój sposób myślenia), który wskazuje, że zamknięcie jest w następnym dniu kalendarzowym, i odpowiednio dostosuj swoją logikę.
0 dla odpowiedzi № 3
W twoim projekcie stołu brakuje informacjistaje się oczywiste, gdy próbujesz ujednoznacznić to, co oznacza zamknięcie i otwarcie. Takich jak 12 do 2. Czy to oznacza 2 godziny lub 14? Bez przyjmowania założeń nie ma sposobu, aby go rozwiązać.
Użyj przedziałów:
Na przykład, jeśli Twoja restauracja jest od 13:30 do 1:30, może to sprawdzić, czy teraz () jest pomiędzy:
test=# select
now() > (now()::date || " 13:30")::timestamp
and now() < (now()::date || " 13:30")::timestamp + interval "12 hours";
?column?
----------
t
(1 row)
W ten sposób ważne jest tylko początkowe dow i nie powinieneś mieć żadnych problemów z zawijaniem.