多字段UNIQUE约束是否可以包含多个表中的字段?

Dan*_*ola 5 postgresql database-design join constraints unique-constraint

我有以下2个表格:

Bookings
  - User ID

Shifts
  - Booking ID
  - Date
Run Code Online (Sandbox Code Playgroud)

我想确保用户在同一天没有预订多个班次.换句话说,字段的UNIQUE约束[Bookings.UserID,Shifts.date]

我可以在PostgreSQL中执行此操作吗?

Erw*_*ter 7

PostgreSQL中的索引位于一个表中,不能跨越多个表.

但您可以使用正确的表格布局解决您的问题.您可能需要的是一个n:m关系,用3个表实现.然后有各种方法来强制你的病情.

  • 您可以存储日期的冗余预订,创建于主键(usr_id, shift_date)代替(usr_id, shift_id),并保证与参照完整性多列外键(shift_id, shift_date):

CREATE TABLE usr(
  usr_id serial PRIMARY KEY
 --, more?
);

CREATE TABLE shift(
  shift_id serial PRIMARY KEY
 ,shift_date date
 --, more?
);
Run Code Online (Sandbox Code Playgroud)

这也需要UNIQUE INDEXshift第一:

CREATE UNIQUE INDEX shift_date_idx ON shift (shift_id, shift_date);

CREATE TABLE booking(
  usr_id int REFERENCES usr(usr_id)
 ,shift_id int
 ,shift_date date
 --, more?
 ,CONSTRAINT booking_pkey PRIMARY KEY (usr_id, shift_date)
 ,CONSTRAINT booking_fkey FOREIGN KEY (shift_id, shift_date)
 REFERENCES shift(shift_id, shift_date)
);
Run Code Online (Sandbox Code Playgroud)
  • 另一种限制较少但也不太可靠的方法是在桌面上触发 ,检查用户是否已经转换了新日期.没有冗余日期列可以工作.ON INSERT OR UPDATEbooking

我会选择第一个解决方案.


PostgreSQL中的视图也没有索引(据我所知,从v9.1开始).

可以创建一个返回shift_date给定的函数shift_id并声明它IMMUTABLE(尽管实际上并非如此).有了它,您可以在表达式上创建一个多列索引:

CREATE function f_shift_date (shift_id int)
 RETURNS date LANGUAGE SQL IMMUTABLE AS
$BODY$
   SELECT shift_date FROM shift WHERE shift_id = $1;
$BODY$;

CREATE UNIQUE INDEX shift_date_idx ON booking (shift_id, f_shift_date(shift_id));
Run Code Online (Sandbox Code Playgroud)

这会强制你的条件.但说实话,这是非常自杀的.索引依赖于您shift_id无限期获得相同日期的条件.如果shift_date相对于它进行了更改shift_id,则必须重新创建索引,否则将产生不正确的结果.所以,不要这样做.