次の2つのテーブルがあります。
Bookings
- User ID
Shifts
- Booking ID
- Date
ユーザーが同じ日に複数のシフトで予約されていないことを確認したいと思います。つまり、フィールド [Bookings.UserID, Shifts.date] の UNIQUE 制約
PostgreSQLでこれを行うことはできますか?
次の2つのテーブルがあります。
Bookings
- User ID
Shifts
- Booking ID
- Date
ユーザーが同じ日に複数のシフトで予約されていないことを確認したいと思います。つまり、フィールド [Bookings.UserID, Shifts.date] の UNIQUE 制約
PostgreSQLでこれを行うことはできますか?
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)
);
ON INSERT OR UPDATE
booking
私は最初の解決策に行きます。
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));
これにより、条件が適用されます。しかし、正直なところ、これはかなり自殺行為です。インデックスは、無期限に同じ日付を取得するという条件に依存していますshift_id
。shift_date
が相対的に変更された場合shift_id
は、インデックスを再作成する必要があります。そうしないと、誤った結果が得られます。だから、それをしないでください。
上記だけでは問題は解決しませんか?
ALTER TABLE shifts
ADD CONSTRAINT uk_shifts_book UNIQUE (booking_id, date);
シフトに参照される列が既にある場合は、参照される列と日付列に一意の制約 (または一意のインデックス) を作成するだけです。