存储开放时间/节假日

发布于 2024-10-08 01:05:51 字数 1192 浏览 0 评论 0原文

您建议使用哪种 SQL 模式来存储营业时间和节假日,以及使用哪种查询来检查餐厅是否营业?现在我有这个:

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;

但这实际上不起作用,因为,例如,一家餐馆可能会营业到凌晨 2:00,此时我需要检查之前的 dow

让事情变得更复杂的是,我必须处理假期:

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

这也有同样的问题 - 如果一家餐厅在 15:30 到 2:00 营业,这意味着它们在午夜到两点的街区也会关门。

我一直没能全神贯注地找到一个干净、优雅的解决方案来解决这个问题(几个混乱的解决方案来了又走了)。我需要出去走走,然后再回来——同时,我想我应该让你们尝试一下。

What kind of SQL schema would you suggest for storing hours and holidays, and what kind of query to check if a restaurant is open? Right now I have this:

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;

But that doesn't really work, because, for instance, a restaurant might be open until 2:00 am, at which point I would need to check for the previous dow.

To make matters a little more complicated, I have to deal with holidays:

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

Which has the same problem - if a restaurant is open from 15:30 to 2:00, that means they are also closed for the block from midnight to two.

I haven't been able to wrap my head around finding a clean, elegant solution for this (several messy ones have come and gone). I need to go take a walk and come back to it - in the mean time, I figured I would let you guys take a crack at it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

被翻牌 2024-10-15 01:05:51

回答我自己的问题似乎有点错误,但我发现了一些似乎有效的东西,尽管它很混乱:

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;

Seems kind of wrong to answer my own question, but I've found something that seems to work, as messy as it is:

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;
意中人 2024-10-15 01:05:51

总结评论:

1 - 使用通用查询结构 来自这个问题。

2 - 在您的表中添加一个位标志,用于 ClosePastMidnightOpenPastMidnight(以最适合您的思维方式为准),表示关闭是下一个日历日,并相应地调整你的逻辑。

To sum up the comments:

1 - Use the general query structure from this question.

2 - Add a bit flag to your table for ClosePastMidnight or OpenPastMidnight (whichever works best for your way of thinking) that indicates close is on next calendar day, and adjust your logic accordingly.

还给你自由 2024-10-15 01:05:51

您的表格设计缺少信息,当您尝试消除关闭和打开含义的歧义时,这些信息就会变得明显。比如12比2,是指2小时还是14小时?如果不做出假设,就没有办法解决它。

使用间隔:

例如,如果您的餐厅从下午 1:30 到凌晨 1:30,则可以检查 now() 是否在中间:

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

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

这样,只有开始的道琼斯指数很重要,您不应该遇到任何环绕问题。

Your table design has missing information that becomes apparent when you try to disambiguate what close and opening means. Such as 12 to 2. Does that mean 2 hours or 14? Without making assumptions there is no way to solve it.

Use intervals:

For example if your restaurant is from 1:30PM to 1:30AM this could check if now() is inbetween:

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

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

That way only the starting dow is important and you should not have any wraparound problems.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文