web-dev-qa-db-ja.com

ALTER TABLEステートメントがFOREIGN KEY制約と競合しました

変更を加えたい列にデータがある既存のテーブルに新しい外部キーを追加しようとしています。

開発者では、データが存在する場合と存在しない場合にこれを試しました。データがない場合、これは正常に機能します。

ALTER TABLE [rpt].ReportLessonCompetency WITH CHECK
ADD CONSTRAINT [FK_Grade_TraineeGrade_Id]
FOREIGN KEY (Grade) REFERENCES [rpt].TraineeGrade(Id)

データがあるところに次のエラーが出ます

ALTER TABLEステートメントがFOREIGN KEY制約「FK_Grade_TraineeGrade_Id」と競合しました。データベース「T_test」、テーブル「Core.Report.TraineeGrade」、列「Id」で競合が発生しました。

ライブデータベースが既存のデータを保持するかどうかを制御できないため、データが存在する場合と存在しない場合にこれが機能することを確認するために何が必要かを誰かに教えてもらえたら幸いです。

ありがとう

サイモン

3
Simon Price

[rpt]。[ReportLessonCompetency]テーブルに孤立したレコードがあるため、エラーが発生する可能性があります。孤立したレコードとは、親テーブルに対応する親レコードのない子テーブルのレコードです。あなたの場合、[rpt]。[ReportLessonCompetency]には、[rpt] .TraineeGrade(Id)テーブルに存在しない[Grade]の値が含まれます。

外部キーを作成するには、2つのオプションがあります(ただし、有効なオプションは1つしかありません)。

データをクリーンアップします
最初に、対応する親レコードがない子テーブルのレコードを検索できます。次に、子テーブルのレコードを削除/更新するか、欠落している親レコードを親テーブルに追加する必要があります。その後、外部キー制約を作成できます。参照整合性が保証され、外部キーが信頼されるため、これはこれまでのところ最良のオプションです。
次のクエリを実行すると、孤立したレコードを見つけることができます。

SELECT *
FROM [rpt].ReportLessonCompetency rlc
WHERE NOT EXISTS
(
    SELECT 1 
    FROM [rpt].TraineeGrade tg
    WHERE tg.Id = rlc.Grade
)

チェックなし
他のオプションは、WITH NOCKECKを使用して外部キーを作成することです。 SQL Serverは、テーブル内の既存のデータを検証せずに外部キーを作成します。子テーブルのデータを更新/挿入しても、それらのレコードはチェックされます。その結果、外部キーは信頼できないものとしてマークされ、クエリオプティマイザーは実行プランを生成するための制約を考慮しません。
ここ パフォーマンスへの影響の例を見つけることができます。

8
Thomas Costers

WITH NOCHECKを使用すると、既存のデータに対するFOREIGN KEY制約の検証を回避できます。

ALTER TABLE [rpt].ReportLessonCompetency WITH NOCHECK
ADD CONSTRAINT [FK_Grade_TraineeGrade_Id]
FOREIGN KEY (Grade) REFERENCES [rpt].TraineeGrade(Id)

無視された制約違反により、後で更新が失敗する可能性があるため、これを行うことはお勧めしません。代わりにデータをクリーンアップする必要があります。

0
Tahir Riaz