我在各种表上有一些触发器,它们使用 raiserror 告诉用户他试图做坏事。我想以原子方式运行多个插入和更新,如果其中一个触发器这么说,则回滚。我在前世是邪恶的,所以我正在使用 Access VBA。
如果第一条语句有问题,我的 VBA 中会出现运行时错误。但是,如果第二个或后续语句调用 raiserror 那么我看不到任何错误消息。
解决方案:检查 connection.Errors 集合。
这是一个 Access 2007 ADP 前端和一个 SQL 2005 数据库。
下面的 VBA 是显示效果的最低限度。如果我将所有原子语句包装在存储过程中,我会得到相同的效果。
我认为我很聪明,将我的验证尽可能靠近数据库。明显不是!
如果您愿意尝试下面的代码,请在 CommandText 中交换 s1 和 s2 的顺序并欣赏不同的结果。
Public Sub TestSqlErrors2()
'CREATE TABLE [dbo].[tblStuff]([id] [int] IDENTITY primary key NOT NULL,[stuff] [varchar](255) NULL)
Dim cmd As ADODB.Command
Dim cnn As ADODB.Connection
Dim r As Long
Dim s1 As String
Dim s2 As String
s1 = " insert into tblStuff(stuff) values ('aaa') "
s2 = " if 1=1 begin raiserror ('me, i''m just a lawnmower',16,1) rollback transaction end "
Set cnn = Application.CurrentProject.Connection
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cnn
'cnn.BeginTrans 'makes no difference
cmd.CommandText = "begin transaction " & s2 & s1 & " commit transaction "
cmd.Execute r
'cnn.CommitTrans
'cnn.Errors.count is either 2 or 0
End Sub
我尝试了各种组合。在下面的存储过程中,我明确(重新)提出了一个错误。但是,该错误不会传递回 VBA。
--CREATE TABLE [dbo].[tblStuff]([id] [int] IDENTITY primary key NOT NULL,[stuff] [varchar](255) NULL)
alter proc AddMoreStuff2
as
begin try
begin transaction
--swap the two statements below around to see the difference
--if the first statement is raiserror then a run-time error appears in VBA
--if not, no error appears in VBA, although no records are added
insert into tblStuff(stuff) values ('aaa')
if 1=1 begin raiserror ('me, i''m just a lawnmower',16,1) rollback transaction end
commit transaction
end try
begin catch
declare @errormessage varchar(1024)
set @errormessage = error_message()
raiserror ( @errormessage, 16, 1 )
end catch
调用这个新过程的 VBA 代码是......
Public Sub TestSqlErrors2()
Dim cmd As ADODB.Command
Dim cnn As ADODB.Connection
Dim r As Long
Set cnn = Application.CurrentProject.Connection
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cnn
cmd.CommandText = "exec AddMoreStuff2"
cmd.Execute r
End Sub