如何在MS Access中查找ADO查询的结果

问题描述

MS Access 2019 sql Server 2017

VBA代码中是否有任何简单直接的方法来确定此查询是导致提交还是回滚。

这不是不可解决的,但我正在寻找一种不太复杂的方法

在MS Access模块​​中:

  Dim sqlDB As Object
  Dim ADOcom As Object
  Dim sql As String

  sql = _
    "BEGIN TRY " & _
    "  BEGIN TRAN " & _
    "    UPDATE MyTable SET MyColumn=100 WHERE AnotherColumn=5 " & _
    "  COMMIT TRAN " & _
    "END TRY " & _
    "" & _
    "BEGIN CATCH " & _
    "  ROLLBACK TRAN " & _
    "END CATCH"
  
  Set sqlDB = CreateObject("ADODB.Connection")
  Set ADOcom = CreateObject("ADODB.Command")
  sqlDB.Open "Driver={sql Server Native Client 11.0};Server=sql;Database=MyDatabase;Trusted_Connection=yes;"
  sqlDB.CursorLocation = adUseClient
  Set ADOcom.activeconnection = sqlDB
  With ADOcom
    .CommandText = sql
    .Execute sql

' Code to find out if the .execute resulted in Commit

  End With
  Set ADOcom = nothing
  sqlDB.Close
End Sub

完成: 在此示例中,两个查询从任意MS Access模块​​发送到任意sql Server。 第一个查询返回期望值,但第二个查询不返回。 这两个查询在SSMS中都可以正常工作。 第二个查询出了什么问题?

Sub Example()
  Dim sqlDB As Object
  Dim query_1 As String,query_2 As String
  Dim rs As Object
  
  Set sqlDB = CreateObject("ADODB.Connection")
  sqlDB.Open "Driver={sql Server Native Client 11.0};Server=MysqLserver;Database=MyDatabase;Trusted_Connection=yes;"
  Set rs = CreateObject("ADODB.Recordset")
  Set rs.activeconnection = sqlDB
  
  query_1 = _
    "SELECT 1"
  
  rs.Open query_1
  Debug.Print rs(0) ' Expected 1,got 1.
  rs.Close
  
  query_2 = _
    "DECLARE @Success INT " & _
    "BEGIN TRY " & _
    "  BEGIN TRAN " & _
    "    SELECT 1/0 " & _
    "    SET @Success=1 " & _
    "  COMMIT TRAN " & _
    "END TRY" & _
    " " & _
    "BEGIN CATCH " & _
    "  ROLLBACK TRAN " & _
    "  SET @Success=0 " & _
    "END CATCH " & _
    "SELECT @Success AS [Success]"

  rs.Open query_2
  Debug.Print rs(0) ' Expected 0 but rs is nothing and got Error 3265
  rs.Close
  
  sqlDB.Close
End Sub

解决方法

您可以返回一个status值或@variable。例如,

  sql = _
    "BEGIN TRY " & _
    "  BEGIN TRAN " & _
    "    UPDATE MyTable SET MyColumn=100 WHERE AnotherColumn=5 " & _
    "    SELECT 0 AS [ErrorStatus] " & _
    "  COMMIT TRAN " & _
    "END TRY " & _
    "" & _
    "BEGIN CATCH " & _
    "  ROLLBACK TRAN " & _
    "  SELECT 1 AS [ErrorStatus] " & _
    "END CATCH"

您可以在以下代码中使用此结果。在CATCH中,您可以使用THROW来获取原始错误并仍使事务回滚:

BEGIN CATCH
      ROLLBACK TRAN;
      THROW;
END CATCH

这意味着您需要在vb.code本身中进行try / catch。如果您需要错误详细信息的另一种方法是使用以下功能(在SSMS中执行此功能):

BEGIN TRY  
    -- Generate a divide-by-zero error.  
    SELECT 1/0;  
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;  
END CATCH;  
GO

他们正在返回错误的详细信息。您可以将它们返回或将它们分配给变量,然后再进行处理。

,

我想我找到了解决此问题(错误?)的方法(解决方法)。

如果将SET NOCOUNT ON添加为query_2中的第一条语句,它将突然起作用。我不知道为什么,但这是事实。

Sub Example()
  Dim SQLDB As Object
  Dim query_1 As String,query_2 As String
  Dim rs As Object
  
  Set SQLDB = CreateObject("ADODB.Connection")
  SQLDB.Open "Driver={SQL Server Native Client 11.0};Server=MySQLserver;Database=MyDatabase;Trusted_Connection=yes;"
  Set rs = CreateObject("ADODB.Recordset")
  Set rs.activeconnection = SQLDB
  
  query_1 = _
    "SELECT 1"
  
  rs.Open query_1
  Debug.Print rs(0) ' Expected 1,got 1.
  rs.Close
  
  query_2 = _
    "SET NOCOUNT ON " & _
    "DECLARE @Success INT " & _
    "BEGIN TRY " & _
    "  BEGIN TRAN " & _
    "    SELECT 1/0 " & _
    "    SET @Success=1 " & _
    "  COMMIT TRAN " & _
    "END TRY" & _
    " " & _
    "BEGIN CATCH " & _
    "  ROLLBACK TRAN " & _
    "  SET @Success=0 " & _
    "END CATCH " & _
    "SELECT @Success AS [Success]"

  rs.Open query_2
  Debug.Print rs(0) ' Expected 0,got 0.
  rs.Close
  
  SQLDB.Close
End Sub