2016-08-31 21 views
2

実行中に制約に違反するストアドプロシージャ内にSQL Serverの更新ステートメントがありますが、更新ステートメント全体が完了すると制約が有効です。特定の順序でSQL Serverの更新を実行する方法?

文は次のとおりです。

UPDATE SomeTable SET FieldA = 1 WHERE FieldB = @SomeFieldBValue; 

行テーブルSomeTableで親行を参照する子行との階層関係を形成します。この制約により、すべての子行にFieldAが非NULL値に設定されていない限り、親行はFieldAを非NULL値に設定できません。更新ステートメントが行1は、FIELDA以外に設定されていることは許されないので、それが制約違反で失敗し実行したときに今

Id | ParentId | FieldA | FieldB 
-- | -------- | ------ | ------ 
1 | NULL  | NULL | 123 
2 | 1  | NULL | 123 

したがって、たとえば、のはSomeTableには、以下のデータが含まれていることを想定してみましょうすべての子がFieldAをnull以外の値に設定していない限り、null値です。

この制約を一時的に無効にすることは、ユーザーにこれを許可する権限がないため、オプションではありません。

+1

更新ステートメントは何らかの順序で処理されません。これは、セットベースの操作です。ここで2つの別々の更新ステートメントを実行する必要があります。 –

+0

ありがとうございます。注文の前提条件を削除する質問を編集しました。 – flange

答えて

1

このようなトリガーでも同じことが達成できますか?

create trigger ... 
if exists (
    select i.Id 
    from 
     inserted i left outer join inserted i2 
      on i2.ParentId = i.Id 
    group by i.Id 
    having not (count(i.FieldA) = 0 or count(i2.FieldA) = count(i2.Id)) 
) rollback; 
+0

私はこの感謝のバージョンを使用しました。私は計算列を参照することができたので、実際にはより読みやすい制約が導かれました。私はトリガーを使用する際に危険があると理解していますが、この場合トリガーとして制約を実装するのが最も理にかなっており、簡単な解決策が得られました。 – flange

-1

制約を無効にできない場合は、1つのステートメントでこれを行うことはできません。ループを作成し、手動で「正しい順序」で更新を実行する必要があります。

擬似コード:T-SQLまたは任意のクライアント言語にこれを翻訳

Begin Transaction 
Do 
    recordsAffected = UPDATE SomeTable 
         SET FieldA = 1 
         WHERE (FieldA IS NULL OR FieldA <> 1) 
         AND FieldB = @SomeFieldBValue 
         AND NOT EXISTS (child with FieldA set to null); 
While recordsAffected > 0 
Commit Transaction 

は運動として残っています。 :-)

+0

@Downvoter:フィードバックは高く評価されています。 – Heinzi

0

WHILEループをSQLで使用しないでください。SQLは、Setベースの言語であり、手続き型ではありません。 #TEMPテーブルに親とすべての子を選択し、テンポラリテーブルの行を更新し、オリジナルを削除して新しいものを挿入してください。

BEGIN TRAN 

    SELECT Id, ParentID, FieldA, FieldB, 
    INTO #TEMP1 
    FROM SomeTable 
    WHERE FieldB = SomeValue 

    UPDATE #TEMP1 SET FieldA = 1 

    DELETE SomeTable where FieldB = SomeValue 

    INSERT SomeTable Set ..... FROM #TEMP1 
COMMIT 
+0

最後のDELETEをINSERT SomeTable FROM#TEMP1に置き換えます。 –

+1

自動生成された主キーでメッセージが送られますか? – flange

関連する問題