複数のSQL UPDATEステートメントまたはCASEを含むシングル?
-
08-07-2019 - |
質問
優先順位を適切に保ち、重複する優先順位値を許可しないようにするトリガーを作成しました。考慮すべきことがいくつかあります。
- ユーザーは優先度を自由に設定できます。
- 他のアイテムと同じ優先度を選択することを妨げるものは何もありません。
-
値が別の値と等しく入力された場合、新しく優先順位が付けられた項目が優先順位で優先され、もう一方が増分される必要があります。
CREATE TRIGGER dbo.trg_Priority ON dbo.Stories AFTER INSERT,UPDATE,DELETE AS BEGIN SET NOCOUNT ON; -- Insert statements for trigger here DECLARE @StoryId INT DECLARE @OldLocation INT DECLARE @NewLocation INT SELECT @NewLocation = Priority, @StoryId = StoryId FROM INSERTED SELECT @OldLocation = Priority FROM DELETED IF @NewLocation = @OldLocation RETURN; IF @NewLocation IS NULL BEGIN UPDATE Stories SET Priority = Priority - 1 WHERE Priority > @OldLocation END IF @NewLocation > @OldLocation BEGIN UPDATE Stories SET Priority = Priority + 1 WHERE Priority >= @NewLocation AND StoryId <> @StoryId END IF @NewLocation < @OldLocation BEGIN UPDATE Stories SET Priority = Priority + 1 WHERE Priority >= @NewLocation AND Priority < @OldLocation AND StoryId <> @StoryId END END GO
このトリガーを十分にテストしていないので、懸念のある分野がある場合は、お気軽に声をかけてください。最終的に知りたいのは、これをcaseステートメントを使用して単一の更新に変換してみるべきかどうかです。 (それが可能であれば。)
これを単一の UPDATE
ステートメントにするとパフォーマンスが向上する場合は、実際に手を使って考え出すことができます!
解決
トリガーを書き換える必要があります。一度に1つのレコードのみが挿入/更新または削除されることを想定しています。その前提でトリガーを記述することはできません。トリガーは行単位ではなくデータのバッチで動作します。更新で挿入および削除に参加する必要があります。はい、そうです、私はcaseステートメントで更新を書きます。
そして、なぜこれが削除されたトリガーなのですか?削除された場合、更新するレコードはありません。
他のヒント
@@ ROWCOUNT&gt;の場合、必ずロールバックしてエラー(重大度16)を発生させてください。 1.現在作成されているトリガーは、一度に複数の行を挿入、更新、または削除しようとしたユーザーの大量のデータ破損を引き起こします。
とはいえ、IronGoofyは正しいです。条件に関係なく、テーブルに触れるのは1回だけです。そのため、複数のステートメントに分割すると、コードが読みやすくなり、保守が容易になります。
複数の行を一度に更新できるようにする場合、これを変更する必要があります。ロジックは手ごわいかもしれません!
これについてはどうですか:
UPDATE Stories SET Priority = CASE
WHEN Priority > @OldLocation THEN Priority-1
WHEN Priority >= @NewLocation AND StoryID <> @StoryID THEN Priority+1
WHEN Priority >= @NewLocation AND @Priority < @OldLocation And StoryID <> StoryID THEN Priority +1
END
GO
(顕著な)パフォーマンスの違いはありません。いずれの場合も、データベースに単一の更新ステートメントを発行します。
私はこのアイデアを捨てることにし、優先度を更新するためにUIに任せることにしました。ユーザー入力の許可を停止しました。
これらの回答のどれが正しいかわからないので、これを正しいとマークし、コミュニティに試行錯誤をさせます。 :)