web-dev-qa-db-ja.com

SQLServerの延期可能な制約

SQL Serverのいずれかのバージョンが延期可能な制約(DC)をサポートしていますか?

バージョン8.0以降、 Oracleは延期可能な制約をサポートしています -個々のテーブルを挿入または更新するときではなく、ステートメントグループをコミットするときにのみ評価される制約。延期可能な制約は、制約がまだアクティブであるという点で、制約を無効化/有効化するだけとは異なります。制約は後で(バッチがコミットされたときに)評価されるだけです。

DCの利点は、個別に違法となる更新を評価して、累積的に有効な終了状態にすることができることです。例として、各行が2行の間のテーブルに循環参照を作成します。値が存在する必要があります。個々の挿入ステートメントは制約を通過しませんが、グループは通過できます。

私の目標を明確にするために、C#のORM実装をSQLServerに移植しようとしています-残念ながら、実装はOracle DCに依存して、行間の挿入/更新/削除の順序を計算しないようにしています。

34
LBushkin

これまでのところ、SQLServerはそれらをサポートしていません。あなたが解決している問題は何ですか?

11
A-K

OT:SQL Serverがサポートしていないものがかなりありますが、エンタープライズ環境では意味があります。

  • ここで述べた延期可能な制約
  • マース:なぜ完全に自然なもののオプションを設定する必要があるのですか?
  • CASCADE DELETE制約:SQL Serverは、特定のCASCADEDELETE制約に対して単一のカスケードパスのみを許可します。繰り返しになりますが、複数の可能なパスを介して削除時にカスケードすることを許可しない理由はわかりません。最終的に、実際に実行されるとき、実際に使用されるパスは常に1つだけなので、なぜですか。この制限はありますか?
  • 単一のADO.NET接続での並列トランザクションの防止。
  • このトランザクション内で実行されるトランザクションがある接続で実行されるすべてのコマンドの強制。
  • UNIQUEインデックスを作成する場合、NULLは実際の値であるかのように扱われ、インデックスに1回だけ表示されます。ただし、SQLの「不明な値」としてのNULLの概念は、インデックスを作成するときにNULL値が完全に無視されることを示します。

これらすべての小さなことにより、フルサイズのRDBMSに期待される参照整合性とトランザクション機能の多くがSQLServerではほとんど役に立たなくなります。たとえば、延期可能な制約はサポートされていないため、外部的に一貫性のある作業単位としての「トランザクション」の概念は部分的に否定されます。実行可能な唯一の解決策は、いくつかの汚い回避策を除いて、参照整合性制約をまったく定義しないことです。トランザクションの自然な動作は、トランザクション内で好きな方法と順序で作業できることであり、システムはコミット時に一貫性があることを確認します。 ON DELETE CASCADEを使用した参照整合性制約は、1つの制約のみがオブジェクトのカスケード削除につながる可能性があるという制限から、同様の問題が発生します。これは実際にはほとんどの現実のシナリオに適合しません。

25
Mirko Klemm

どうやらそうではありません。

SQLServer(さまざまなバージョン)が延期可能な制約をサポートしていないと言っている約5つの異なるブログ投稿を見つけました。

一方、 "永続化された計算列" (最後のエントリまでスクロール)を使用してこの機能を模倣しようとする投稿も見つかりましたが、警告emptor

3
Matthew Jones

あなたが抱えている問題は、SQLがDateとDarwenが「複数の割り当て」と呼ぶものをサポートしていないことのようです。これに対する標準SQLの応答は、SQLServerがサポートしていない「延期可能な制約」でした。 SQL ServerのFKまたはCHECK制約には、NOCHECKのフラグを付けることができますが、まったく同じではありません。詳細については、MSDNを参照してください: ALTER TABLE(Transact-SQL)

3
onedaywhen

特定の条件下で欠落している遅延制約の適用を回避する方法があります(2017年1月の時点では、SQL Serverでは遅延制約はサポートされていません)。次のデータベーススキーマについて考えてみます。

免責事項:スキーマの品質、またはユースケースは、ここでは議論の余地がありません。回避策の基本的な例として示されています

CREATE TABLE T (Id TYPE NOT NULL PRIMARY KEY, NextId TYPE NOT NULL);

ALTER TABLE T WITH CHECK ADD CONSTRAINT FK_T2T 
FOREIGN KEY (NextId) REFERENCES T (Id);

CREATE UNIQUE NONCLUSTERED INDEX UC_T ON T (NextId);

ここで、TYPEは、代理キーに適したデータ型です。代理キーの値は、INSERT操作中にRDBMSによって割り当てられると想定されています(つまり、IDENTITY)。

ユースケースは、エンティティTの「最新」バージョンをNextId = NULLで保持し、単一リンクリストT.NextId-> T.Idを維持することによって以前のバージョンを保存することです。

明らかに、新しい「最新」バージョンの挿入は古い「最新」の更新に先行する必要があり、その間、同じNextIdを持つ2つのレコードがデータベースに存在するため、指定されたスキーマは遅延制約問題の影響を受けます。値。

今、もし:

主キーのデータ型は数値である必要はなく、事前に計算できます(つまり、UNIQUEIDENTIFIER)。その後、次のようにMERGEステートメントを使用して遅延制約問題を回避します。

DECLARE @MergeTable TABLE (Id UNIQUEIDENTIFIER);

DECLARE @NewLatestVersion UNIQUEIDENTIFIER = NEWID();

INSERT INTO @MergeTable (Id) VALUES (@NewLatestVersion);
INSERT INTO @MergeTable (Id) VALUES (@OldLatestVersion);

MERGE INTO T
USING @MergeTable m ON T.Id = m.Id
WHEN MATCHED THEN UPDATE SET T.NextId = @NewLatestVersion
WHEN NOT MATCHED THEN INSERT (Id) VALUES (@NewLatestVersion);

どうやら、MERGEステートメントは制約をチェックする前にすべてのデータ操作を完了します。

2
bitterman0

独自のORMレイヤーがある場合、問題の1つの解決策は、ORMレイヤーのロジックによってオブジェクトの更新を参照の更新から分離することです。次に、ORMは、いくつかのステップで設定されたクライアント側の変更に基づいてトランザクションを処理します。

  1. 変更セットによって削除済みとして定義されているすべての外部キー参照を削除します。つまり、対応する外部キー列をNULLに設定するか、マッピングテーブルを使用する関係の場合は、必要に応じてマッピングテーブルからエントリを削除します。
  2. 変更セットによって「削除済み」として定義されたすべてのオブジェクトを削除します
  3. 変更セットにすべての新しいオブジェクトを作成しますが、外部キー列はまだ設定していません
  4. 変更セット内の更新されたオブジェクトのすべての「プリミティブ」値の変更を更新します。つまり、外部キー列を更新しません。
  5. 変更セットで定義されている外部キー列の値を設定します。
  6. テーブルベースの関係をマッピングするためのマッピングテーブルマッピングを追加する
  7. コミット

参照されるすべてのオブジェクトは外部キー値が設定されるといつでも存在するため、これで問題が解決するはずです。

1
Mirko Klemm

この方法を使用できます

ALTER TABLE your_table NOCHECK CONSTRAINT your_constraint

あなたの行動

ALTER TABLE your_table WITH CHECK CHECK CONSTRAINT ALL
1
Đăng Khoa