5

次の2つのテーブルがあります。

Bookings
  - User ID

Shifts
  - Booking ID
  - Date

ユーザーが同じ日に複数のシフトで予約されていないことを確認したいと思います。つまり、フィールド [Bookings.UserID, Shifts.date] の UNIQUE 制約

PostgreSQLでこれを行うことはできますか?

4

2 に答える 2

7

PostgreSQL のインデックスは1 つのテーブル上にあり、複数のテーブルにまたがることはできません。

ただし、適切なテーブル レイアウトで問題を解決できます。おそらく必要なのは、3 つのテーブルで実装された n:m の関係です。次に、条件を強制するさまざまな方法があります。

  • 日付を重複して予約に保存し、代わりに主キーを作成し、(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?
);

これには、最初UNIQUE INDEXに onも必要です。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)
);
  • 制限が少ないが信頼性が低いもう1つの方法は、ユーザーが新しい日付ですでにシフトしているかどうかを確認するテーブルのトリガーです。 冗長な日付列がなくても機能します。ON INSERT OR UPDATEbooking

私は最初の解決策に行きます。


PostgreSQLのビューにもインデックスはありません(私の知る限り、v9.1 の時点で)。

特定の値を返す関数を作成して宣言することもできます(ただし、実際にはそうではありません)。これにより、式に複数列のインデックスを作成できます。shift_dateshift_idIMMUTABLE

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_idshift_dateが相対的に変更された場合shift_idは、インデックスを再作成する必要があります。そうしないと、誤った結果が得られます。だから、それをしないでください

于 2012-08-13T16:39:10.840 に答える
0

上記だけでは問題は解決しませんか?

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

シフトに参照される列が既にある場合は、参照される列と日付列に一意の制約 (または一意のインデックス) を作成するだけです。

于 2012-08-13T17:50:01.293 に答える