クライアントソフトウェアにパッチを適用するプログラムを実装しようとしています。最初は.SQLが実行されますが、スクリプトが失敗した場合は、データベースをロールバックして、クライアントDLLのインポートプロセスが機能しなくなります。
SQLスクリプトには「GO」ステートメントが含まれているため、「GO」が許可されていないため、使用するための気の利いたストアドプロシージャをまとめることができませんsp_executesql
でした。代わりに、次のようなSQLスクリプトがある場合:
USE [SomeDatabase]
BEGIN TRANSACTION
GO
IF ( OBJECT_ID(N'[dbo].[ProcedureToUpdate]') IS NOT NULL )
DROP PROCEDURE [dbo].[ProcedureToUpdate]
GO
IF @@ERROR <> 0
AND @@TRANCOUNT > 0
ROLLBACK TRAN
GO
IF @@TRANCOUNT = 0
BEGIN
--Flag that the procedure hasn't been dropped, begin another transaction
BEGIN TRANSACTION
END
GO
PRINT 'Creating procedure'
GO
CREATE PROCEDURE [dbo].[ProcedureToUpdate]
AS
SELECT *
FROM [dbo].[SomeTable] st
INNER JOIN [dbo].[AnotherTable] at ON st.PK = at.fk
GO
IF @@ERROR <> 0
AND @@TRANCOUNT > 0
ROLLBACK TRAN
GO
IF @@TRANCOUNT = 0
BEGIN
--Flag that the procedure hasn't been created, begin another transaction
BEGIN TRANSACTION
END
GO
次に、問題のデータベースに対して.NETのトランザクション内で各「アクション」(goステートメントによって分割)を実行します。これにより、ループ内のいずれかが失敗した場合にデータベースがロールバックされます。
Using con As New SqlConnection(ConnectionString)
con.Open()
Dim cmd As SqlCommand = con.CreateCommand()
Dim transaction As SqlTransaction = con.BeginTransaction("Upgrade")
cmd.Connection = con
cmd.Transaction = transaction
Try
For Each transactionalScript In transactionalScripts
cmd.CommandText = transactionalScript
Dim result = cmd.ExecuteNonQuery()
Next
transaction.Commit()
Catch ex As Exception
Log(String.Format("{0} : Script Failed", DateTime.Now.ToString()))
Log(String.Format("{0} : Reason: {1}", DateTime.Now.ToString(), ex.Message))
transaction.Rollback("Upgrade")
Log(String.Format("{0} : Database rolled back", DateTime.Now.ToString()))
End Try
End Using
最後に-ここに私の質問があります。最大4つの.SQLスクリプトを処理する必要があります。これらのスクリプトは、それぞれ1つのサーバー上の異なるデータベース用です。4つのスクリプトのいずれかが失敗した場合、スクリプトが影響を与えたすべてのデータベースをロールバックする必要があります-何か提案はありますか?