/ / Armazenando horas / feriados abertos - sql, schema, plpgsql

Armazenando Horas / Feriados Abertos - sql, schema, plpgsql

Que tipo de esquema SQL você sugeriria para armazenar horas e feriados, e que tipo de consulta verificar se um restaurante está aberto? Agora eu tenho isso:

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;

Mas isso realmente não funciona, porque, por exemplo, um restaurante pode estar aberto até às 2:00 da manhã, altura em que eu precisaria verificar a anterior dow.

Para tornar as coisas um pouco mais complicadas, tenho que lidar com feriados:

CREATE TABLE holidays (
"restaurant" integer NOT NULL REFERENCES restauraunts ON DELETE CASCADE,
"day" date NOT NULL
);

Que tem o mesmo problema - se um restaurante está aberto das 15:30 às 2:00, isso significa que eles também estão fechados para o bloco de meia-noite a duas.

Eu não fui capaz de envolver minha cabeçaencontrar uma solução limpa e elegante para isso (vários desarrumados vieram e se foram). Eu preciso ir dar um passeio e voltar a isso - nesse meio tempo, eu imaginei que eu deixaria vocês darem uma olhada nisso.

Respostas:

1 para resposta № 1

Parece meio errado responder a minha própria pergunta, mas eu encontrei algo que parece funcionar, por mais confuso que seja:

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 para resposta № 2

Para resumir os comentários:

1 - Use a estrutura de consulta geral desta questão.

2 - Adicione um sinalizador de bit à sua mesa para ClosePastMidnight ou OpenPastMidnight (O que for melhor para a sua maneira de pensar) que indica que o fechamento está no próximo dia de calendário e ajuste sua lógica de acordo.


0 para resposta № 3

Seu design de tabela tem informações que faltamtorna-se aparente quando você tenta desambiguar o que significa fechar e abrir. Tal como 12 a 2. Isso significa 2 horas ou 14? Sem fazer suposições, não há como resolvê-lo.

Use intervalos:

Por exemplo, se o seu restaurante é de 1:30 PM a 1:30 AM, isso pode verificar se now () está entre:

test=# select
now() > (now()::date || " 13:30")::timestamp
and now() < (now()::date || " 13:30")::timestamp + interval "12 hours";

?column?
----------
t
(1 row)

Dessa forma, apenas o início dow é importante e você não deve ter nenhum problema envolvente.