/ / Przechowywanie godzin otwartych / dni wolnych - sql, schema, plpgsql

Przechowywanie godzin otwartych / świąt - sql, schema, plpgsql

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 № 1

Wyglą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.