我有一个具有这种结构的约会表(为了便于阅读而分块):
appointments:
- id
- staff_id
- start_time
- end_time
- cancelled
我想添加一个数据库约束,以便无法预约约会。我想知道是否可以在以下行中添加约束:
when staff_id = ? and cancelled = false then set a "unique" constraint on start_time
如果这是不可能的,我可以做些类似的事情来实现我的最终目标吗?
这是完整的约会表
CREATE TABLE "appointments" (
"id" uuid,
"customer_id" uuid NOT NULL REFERENCES customers ON DELETE CASCADE ON UPDATE CASCADE,
"staff_id" uuid NOT NULL REFERENCES staff ON DELETE CASCADE ON UPDATE CASCADE,
"start_time" timestamp NOT NULL,
"end_time" timestamp NOT NULL,
"notes" text,
"cancelled" boolean NOT NULL DEFAULT false,
"created_at" timestamp with time zone NOT NULL,
"updated_at" timestamp with time zone NOT NULL,
);
排除:
CREATE TABLE "appointments" (
"id" uuid,
"customer_id" uuid NOT NULL REFERENCES customers ON DELETE CASCADE ON UPDATE CASCADE,
"staff_id" uuid NOT NULL REFERENCES staff ON DELETE CASCADE ON UPDATE CASCADE,
"start_time" timestamp NOT NULL,
"end_time" timestamp NOT NULL,
"notes" text,
"cancelled" boolean NOT NULL DEFAULT false,
"created_at" timestamp with time zone NOT NULL,
"updated_at" timestamp with time zone NOT NULL,
EXCLUDE USING gist (
staff_id WITH =,
tsrange(start_time, end_time) WITH &&
) WHERE (NOT cancelled),
PRIMARY KEY ("id")
);
执行排除错误:
data type uuid has no default operator class for access method "gist"
答案 0 :(得分:2)
您需要排除约束才能停止预约的双重预约。所选答案中的方法仅停止两个约会具有相同的开始时间。如果在第一次约会后开始约会,它不会阻止一个约会重叠。
CREATE TABLE appointments (
id serial PRIMARY KEY,
staff_id int,
start_time timestamp,
end_time timestamp,
cancelled bool DEFAULT false,
EXCLUDE USING gist (
staff_id WITH =,
tsrange(start_time, end_time) WITH &&
) WHERE (NOT cancelled)
);
现在你不能双重预约。
INSERT INTO appointments (staff_id, start_time, end_time) VALUES
( 1, '01-01-2010T07:30', '01-01-2010T09:30' ),
( 1, '01-01-2010T08:00', '01-01-2010T09:45' )
;
ERROR: conflicting key value violates exclusion constraint "appointments_staff_id_tsrange_excl"
DETAIL: Key (staff_id, tsrange(start_time, end_time))=(1, ["2010-01-01 08:00:00","2010-01-01 09:45:00")) conflicts with existing key (staff_id, tsrange(start_time, end_time))=(1, ["2010-01-01 07:30:00","2010-01-01 09:30:00")).
您也可以删除start_time
和end_time
并将其全部设为timestamp-ranges
答案 1 :(得分:1)
create unique index the_index on appointments (staff_id, start_time)
where not cancelled;