1

条件付きでいくつかのデータをテーブルに挿入しようとしています。ここでは、列値の各組み合わせがテーブルに表示されるのは最大で1回だけです。スキーマは次のようになります。

CREATE TABLE foobar (
    id SERIAL PRIMARY KEY,
    a_id INTEGER,
    b_id INTEGER,
    c_id INTEGER,
    ident VARCHAR(32),
    date_a timestamp,
    date_b timestamp,
    FOREIGN KEY a_id REFERENCES a (id) ON DELETE CASCADE,
    FOREIGN KEY b_id REFERENCES b (id) ON DELETE CASCADE,
    FOREIGN KEY c_id REFERENCES c (id) ON DELETE CASCADE));

(a_id、b_id、c_id、ident)の組み合わせは一意ですが、date_aとdate_bの両方がNULLである行にのみ適用されます。

a_id、b_id、c_id、タスクの組み合わせがまだデータベースにない場合にのみ、新しい行を挿入できるようにしたい。もしそうなら、それは何もする必要はありません。

最初はこれらの列に一意の制約を作成しようとしましたが、問題は、a_id、b_id、およびc_idの少なくとも1つがnullでない限り、それらをNULLにできることです。これにより、固有の制約が台無しになります。a、b、およびc_idフィールドは外部キーであるため、他のスタブ値(-1など)に設定することはできません。

私は(私のより良い判断に反して)ロックで遊んでみましたが、テストから数分以内にデッドロックが発生しました。

この問題の標準的な解決策はありますか?

4

2 に答える 2

1

一意性制約を使用するのではなく、チェックしたい正確な条件で一意性インデックスを使用する必要があります。次に、null値を-1などのダミー値に合体させることができます。何かのようなもの:

CREATE UNIQUE INDEX
foobar_test ON foobar
(COALESCE(a_id, -1), COALESCE(b_id, -1), COALESCE(c_id, -1), ident) -- Nulls become -1
WHERE date_a is null and date_b is null; -- Only check when date_a and date_b is null

これにより、、、、およびがすべての行で一意であり(null値の組み合わせを含む)、とがの両方でa_idあることが確認されます。b_idc_ididentdate_adate_bnull

于 2013-03-18T16:35:51.933 に答える
0

私の複数の生産的なデータベースでの同様の状況では、参照されるテーブルに「デフォルトの行」を追加するだけです。私id = 0はこれらに使用し、実際の代理キーを10または100から開始します。または、予約されている-1場合は(または自分に合ったものを)使用できます。0

このようにして、すべてのfk列を設定できNOT NULL DEFAULT 0、(部分的な)UNIQUE制約はそのままで機能します。

CREATE UNIQUE INDEX tbl_uni_idx ON tbl (a_id, b_id, c_id, ident)
WHERE date_a IS NULL AND date_b IS NULL;
于 2013-03-18T17:07:01.443 に答える