web-dev-qa-db-ja.com

これらの外部キー制約が問題を引き起こすのはなぜですか? (Azure SQL Server 12)

これは私が作成しようとしているデータベースの単純化されたバージョンです:

create table Worker (
    ID int,

    constraint PKW
    primary key (ID)
)

create table Business (
    ID int,
    W int,

    constraint PKB
    primary key (ID),

    constraint FKBW
    foreign key (W) references Worker (ID)
    on delete set null on update cascade
)

create table Note (
    ID int,
    B int,
    W int,

    constraint PKN
    primary key (ID),

    constraint FKNB
    foreign key (B) references Business (ID)
    on delete cascade on update cascade,

    constraint FKNW
    foreign key (W) references Worker (ID)
    on delete set null on update cascade
)

基本的に、各ビジネスには労働者が割り当てられており、どの労働者もあらゆるビジネスに関するメモを作成できます。これらの関係を反映する3つの外部キー制約がありますが、これによりエラーが発生します。

テーブル 'Note'にFOREIGN KEY制約 'FKNW'を導入すると、サイクルまたは複数のカスケードパスが発生する可能性があります。 ON DELETE NO ACTIONまたはON UPDATE NO ACTIONを指定するか、他のFOREIGN KEY制約を変更してください。

このセットアップには関係サイクルはありません。 FKBW on delete cascadeを使用すると、Noteへの削除パスが2つ作成されることがわかりますが、現在の設定ではそうではありません。 FKBWとFBNWの両方からon update cascadeを削除しても、エラーが解決しません。 set nullがどのように問題を引き起こすのかわかりません。

どんな明快さもいただければ幸いです!

3
Will

問題はON UPDATE CASCADEsのようです。ON DELETEsで問題ありません。 ON UPDATEsを削除してもエラーになりません。

で受け入れられた回答によると、「外部キー制約により、サイクルまたは複数のカスケードパスが発生する可能性があります。」スタックオーバーフロー では、SQL Serverはカスケードパスの「詳細」検査を行わず、浅いパスのみを検査します。テーブルAのテーブルBにカスケード制約がある場合、それはABの間のカスケードグラフにすでにエッジを誘導しています。対象の列の。

したがって、ここではWorkerからNoteへの直接パスとWorkerからBusinessを経由してNoteへのパスがあります。 Noteはグラフに2回表示されます。

ここでは、特定の列で競合は発生しませんが、Microsoftサポート記事 としてすでに十分です。複数のカスケードパスを引き起こす可能性のあるFOREIGN KEY制約を作成すると、エラーメッセージ1785が発生します。 " 状態:

このエラーメッセージが表示されるのは、SQL Serverでは、DELETEまたはUPDATEステートメントのいずれかによって開始されたすべてのカスケード参照アクションのリストにテーブルを複数回表示できないためです。たとえば、カスケード参照アクションのツリーは、カスケード参照アクションツリーの特定のテーブルへのパスを1つだけ持つ必要があります。

トリガーはこれを回避することをお勧めします。ただし、主キー以外の方法でinserted疑似テーブルの行とdeleted疑似テーブルの行をマップする方法がわからないため、トリガーに関する大きな問題が発生します。しかし、それが更新で変更された場合、一致する可能性はなく、変更された値のペアを検出する方法はありません。

したがって、主キーを更新せずにON UPDATE NO ACTIONを使用する以外に方法はないと思います。そして、オプションとして持つのはいいことですが、通常、とにかく主キーを更新する必要はありません。

2
sticky bit