Postgresql 多字段唯一约束能否包含多个表中的字段?

Postgresql 多字段唯一约束能否包含多个表中的字段?,postgresql,database-design,join,constraints,unique-constraint,Postgresql,Database Design,Join,Constraints,Unique Constraint,我有以下两个表格: Bookings - User ID Shifts - Booking ID - Date 我想确保一个用户在同一天没有预订多个班次。换句话说,字段[Bookings.UserID,Shifts.date]的唯一约束 我可以在PostgreSQL中执行此操作吗?PostgreSQL中的索引位于一个表上,不能跨多个表 但是你可以通过适当的表格布局来解决你的问题。您可能需要的是一个n:m关系,由3个表实现。然后有各种各样的方法来执行你的条件 您可以在预订中冗余存

我有以下两个表格:

Bookings
  - User ID

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


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

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

但是你可以通过适当的表格布局来解决你的问题。您可能需要的是一个n:m关系,由3个表实现。然后有各种各样的方法来执行你的条件

  • 您可以在预订中冗余存储日期,在
    (usr\u id,shift\u date)
    上创建主键,而不是
    (usr\u id,shift\u id)
    ,并在
    (shift\u id,shift\u date)
    上使用多列外键保证参考完整性:

这还需要在
shift
上首先设置
唯一索引

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)
);
  • 另一种限制性较小但也不太可靠的方法是,在表
    预订
    上插入或更新
    时使用触发器,检查用户是否已经有了新日期的班次。可以在没有冗余日期列的情况下工作
我会选择第一种解决方案


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

您可以创建一个函数,为给定的
shift\u id
返回
shift\u date
,并声明它是
不可变的(尽管事实上它不是)。这样,您就可以在表达式上创建多列索引:

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));

这将强制执行你的条件。但老实说,这简直是自杀。索引取决于您无限期地为
shift\u id
获取相同日期的条件。如果
shift\u date
相对于其
shift\u id
发生任何更改,则必须重新创建索引,否则将产生不正确的结果。所以,不要这样做。

仅仅上述方法并不能解决您的问题

ALTER TABLE shifts
ADD CONSTRAINT uk_shifts_book UNIQUE (booking_id, date);

如果班次上已经有引用列,则只需在引用列和日期列上创建唯一约束(甚至是唯一索引)。

这些表是如何关联的?我认为没有明确说明外键关系。如果你有,它可能会非常简单。Shifts.booking_id==Bookings.id。我需要在Postgres中明确指定关系吗?(我使用的是Rails,它通常不会创建外键或类似的东西,我也不确定在Postgres中可以/不能做什么)。但我愿意在必要时创建它:-)。谢谢是的,我试图在轮班时不使用冗余的用户id(注意,您提出的DB结构与我在原始问题中使用的不太匹配,但可以)。我希望有这样的方法(可以在SQL Server中实现):我在回答中添加了一些内容。顺便说一句,在我的示例中,
shift\u date
是多余的,您可以在更新级联上使用
创建外键,这样您就不必担心必须在多个位置更新
shift\u date
。好的,我只会继续在模型逻辑上执行它,我只是想添加额外的安全性,如果这是直截了当的,但这听起来会带来比解决问题更多的问题。谢谢你的信息,不过,它肯定会在某个时候派上用场。谢谢@DanielMagliola当您遇到无法单独用外键或唯一索引表示的约束时,工具箱中另一个有用的选项是。我需要用户/日期的组合是唯一的,而不是预订id/日期
ALTER TABLE shifts
ADD CONSTRAINT uk_shifts_book UNIQUE (booking_id, date);