多くのテーブルからレコードを削除するスクリプトを書いていますが、削除する前に、ユーザーがコミットする前に確認するためのカウントを返す必要があります。
これはスクリプトの要約です。
BEGIN TRANSACTION SCHEDULEDELETE
BEGIN TRY
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
PRINT 'X rows deleted. Please commit or rollback.' --calculation cut out.
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
ROLLBACK TRANSACTION SCHEDULEDELETE
PRINT 'Error detected, all changes reversed.'
END CATCH
--COMMIT TRANSACTION SCHEDULEDELETE --Run this if count correct.
--ROLLBACK TRANSACTION SCHEDULEDELETE --Run this if there is any doubt whatsoever.
トランザクションを作成するのはこれが初めてです。トランザクション内にTRY/CATCHブロックを含めることは正しい/ベストプラクティスですか、それともトランザクションをTRYブロック内に置くべきですか?
このスクリプトの重要な要素は、ユーザーがトランザクションを手動でコミットする必要があることです。
TRY
ブロック内で実際のステートメントの直前になってからトランザクションを開き、すぐにコミットします。コントロールがバッチの最後に移動してトランザクションをコミットするのを待たないでください。
TRY
ブロックにいる間に何か問題が発生し、トランザクションを開いた場合、コントロールはCATCH
ブロックにジャンプします。トランザクションをそこでロールバックし、必要に応じて他のエラー処理を行うだけです。
トランザクションを実際にロールバックする前に、@@TRANCOUNT
関数を使用して開いているトランザクションのチェックを少し追加しました。このシナリオではあまり意味がありません。 TRY
ブロックでいくつかの検証チェックを行ってから、パラメータ値やその他のものをチェックし、検証チェックのいずれかがあればTRY
ブロックでエラーを発生させるなどのトランザクションを開く場合に便利です。失敗します。その場合、コントロールはトランザクションを開くことなくCATCH
ブロックにジャンプします。そこで、開いているトランザクションをチェックし、開いているトランザクションがある場合はロールバックできます。あなたの場合、トランザクション内で何か問題が発生しない限り、CATCH
ブロックに入ることはないので、開いているトランザクションをチェックする必要はありません。
DELETE
操作を実行した後、コミットまたはロールバックする必要があるかどうかを尋ねないでください。トランザクションを開く前にこれらすべての検証を行ってください。トランザクションが開かれたらすぐにコミットし、エラーが発生した場合はエラー処理を行います(ほとんどすべてのエラー関数を使用して詳細情報を取得することで、良い仕事をしています)。
BEGIN TRY
BEGIN TRANSACTION SCHEDULEDELETE
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
COMMIT TRANSACTION SCHEDULEDELETE
PRINT 'X rows deleted. Operation Successful Tara.' --calculation cut out.
END TRY
BEGIN CATCH
IF (@@TRANCOUNT > 0)
BEGIN
ROLLBACK TRANSACTION SCHEDULEDELETE
PRINT 'Error detected, all changes reversed'
END
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
END CATCH
M.ALiと上記の学部長による優れたアドバイスに加えて、SQL SERVERで新しい(新しい)TRY CATCH THROWパラダイムを使用することを検討している人にとっては、少し助けになります。
(完全な構文を簡単に見つけることができなかったので、ここに追加します)
要点: [〜#〜] here [〜#〜]
ここにサンプルストアドプロシージャコード(私の要点から):
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[pr_ins_test]
@CompanyID INT
AS
SET NOCOUNT ON
BEGIN
DECLARE @PreviousConfigID INT
BEGIN TRY
BEGIN TRANSACTION MYTRAN; -- Give the transaction a name
SELECT 1/0 -- Generates divide by zero error causing control to jump into catch
PRINT '>> COMMITING'
COMMIT TRANSACTION MYTRAN;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
PRINT '>> ROLLING BACK'
ROLLBACK TRANSACTION MYTRAN; -- The semi-colon is required (at least in SQL 2012)
END
THROW
END CATCH
END
シングルユーザーモードのデータベースでない限り、エンドユーザーがトランザクションをコミットするのを待たないでください。
要するに、それはブロッキングについてです。トランザクションは、更新されるリソースに対していくつかの排他的ロックを取得し、トランザクションが終了(コミットまたはロールバック)するまでそれらのロックを保持します。誰もそれらの行に触れることができません。バージョンストアのクリーンアップでスナップショット分離が使用される場合、いくつかの異なる問題があります。
最初に選択クエリを発行して、条件を満たす行の数を決定し、これをエンドユーザーに提示し、確認後、実際の削除を行う方がよいでしょう。