sql - 在预订表中只允许工作时间

标签 sql postgresql database-design schedule postgresql-9.2

PostgreSql 9.2 Reservation 表定义为

CREATE EXTENSION btree_gist;
CREATE TABLE schedule (
  id serial primary key,
  during tsrange not null,
  EXCLUDE USING gist (during WITH &&)
);

节假日在表中列出

CREATE TABLE holiday ( day primary key );

工作时间为工作日的 8 点到 18:00,并且只能以 30 分钟为间隔进行预订。 如何在值期间添加约束,以便它只允许在工作时间进行预订:

  1. tsrange 中的开始日期和结束日期始终相同。
  2. 开始和结束日期不能是周六和周日
  3. 开始和结束日期不能出现在公共(public)假期表中
  4. 开始时间只能是 8:00、8:30、9:00、9:30、... 16:00、16:30、17:00 或 17:30(含)
  5. 结束时间只能是 8:30、9:00、9:30、... 16:00、16:30、17:00、17:30 或 18:00(不含)

将这些或其中一些约束添加到此表是否合理? 如果是,如何添加? 如果有帮助,可以更改调度表结构。

最佳答案

除了第 3 项,你可以用简单的 CHECK constraints 解决所有问题。 :

使用专用range functions lower(anysrange) and upper(anyrange)访问范围的下/上边界。

1.) tsrange 中的开始日期和结束日期始终相同。

CONSTRAINT schedule_same_day
CHECK (lower(during)::date = upper(during)::date)

2.) 开始和结束日期不能是周六和周日

使用isodow, not dow一个更简单的表达式。

CONSTRAINT schedule_no weekend
CHECK (EXTRACT(ISODOW FROM lower(during)) < 6)  -- upper on same day

3.) 开始和结束日期不能出现在公共(public)假期表中

唯一的异常(exception):为此您需要一个触发器,例如:

CREATE OR REPLACE FUNCTION trg_during_no_holy()
  RETURNS trigger AS
$func$
BEGIN

IF EXISTS (SELECT 1 FROM holiday WHERE day = lower(NEW.during)) THEN
    RAISE EXCEPTION 'Day too holy: %', lower(NEW.during);
END IF;

RETURN NEW;

END
$func$ LANGUAGE plpgsql VOLATILE;

CREATE TRIGGER insupbef_holycheck
  BEFORE INSERT OR UPDATE
  ON schedule
  FOR EACH ROW
  EXECUTE PROCEDURE trg_during_no_holy();

4.) 开始时间只能是 8:00、8:30、9:00、9:30、... 16:00、16:30、17:00 或 17:30(含)
5.) 结束时间只能是8:30, 9:00, 9:30, ... 16:00, 16:30, 17:00, 17:30 or 18:00 exclusive

CONSTRAINT schedule_8_inc_to_18_exc_half_hours
 CHECK (lower(during)::time BETWEEN time '8:00'AND time '17:30' -- time range
    AND upper(during)::time BETWEEN time '8:30'AND time '18:00'
    AND EXTRACT(MINUTE FROM lower(during)) IN (0, 30) -- only :00 or :30
    AND EXTRACT(MINUTE FROM upper(during)) IN (0, 30)
    AND lower_inc(during)          -- lower bound always incl.
    AND upper_inc(during) = FALSE  -- upper bound always excl.
)

评论中的附加问题

How to restrict seconds and fractional seconds to 0 only?

最简单的方法:强制转换为 timestamp(0)timestamptz(0) 或将此数据类型用于列开头。我引用 the manual here :

time, timestamp, and interval accept an optional precision value p which specifies the number of fractional digits retained in the seconds field.

关于sql - 在预订表中只允许工作时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13555736/

相关文章:

mysql - 从 tbl1.x = tbl2.x = tbl3.x 的多个表中选择/加入

sql - 如何指定 linq to sql 查询可以返回哪些列

java - 计算 SQLite 数据库中表的数量

java - Hibernate <generator> 混淆

database-design - 条件操作的数据库设计

php - 使用sql查询列出离我最近的联系人

PostgreSQL:如何返回复合类型

sql - 如何使用 Unicode 字母声明 SQL INSERT 语句

c# - 如何处理数据库和应用程序中的 "Type"字段?

sql - JSON 上的 PostgreSQL 索引