【问题标题】:Call SQL Stored Procedure using Procedure clause使用 Procedure 子句调用 SQL 存储过程
【发布时间】:2020-11-26 18:19:36
【问题描述】:

我正在尝试为 IT 设备库存建立一个数据库。它使用 MS Access Office 365 前端和 SQL 2017 后端。

在数据库中,我们不想删除记录,只需将它们归档到另一个表中。为此,我在 SSMS 中创建了一个存储过程,并验证它可以正常工作。

我希望 VBA 调用这个存储过程。对于这个过程,我需要传递它的识别信息。在 VBA 中,我试图将服务器名称值从表单分配给可以传递给存储过程调用的变量。我找到了使用 EXEC 命令的示例,但 Access 告诉我必须使用 Procedure 子句。

Private Sub Command148_Click()
    Dim SrvNameVar As String
    Dim strSQL As String
    Dim strParm As String
    SrvNameVar = Me.SrvName
    strParm = "PARAMETERS [Server Name] As CHAR;"

    Dim dbs As DAO.Database
    Dim qdf As DAO.QueryDef
    Set dbs = CurrentDb
    strSQL = strParm & "PROCEDURE dbo.sp_ArchiveServer [Server Name];"
    Set qdf = dbs.CreateQueryDef("SrvArchive", strSQL)

    dbs.Execute ("SrvArchive")
End Sub

在 SSMS 中正常运行的存储过程:

CREATE PROCEDURE sp_ArchiveServer @Server nvarchar(30) AS
   BEGIN TRANSACTION;
   INSERT INTO FSC.dbo.Archive_Servers ([SrvID],[SID],[SrvName],[Make],
            [Model],[SN],[SrvIP],[RemoteMgmt],[OSID],[IsDP],[IsIEMRelay],
            [IsGUP],[DatePurch],[WarrantyExp],[RAIDConfig],[PrintSrv],
            [ConnectedToUPS],[VirtHost],[VirtMachine])
   SELECT FSC.dbo.Servers.*
   FROM FSC.dbo.Servers
   WHERE FSC.dbo.Servers.SrvName = @Server;

   DELETE FROM FSC.dbo.Servers
   WHERE FSC.dbo.Servers.SrvName = @Server;

   COMMIT;

【问题讨论】:

标签: sql-server vba ms-access stored-procedures


【解决方案1】:

目前,您将 MS Access SQL 方言与 SQL Server 方言混为一谈。只有 MS Access SQL 查询支持PARAMETERS。但是,您正在尝试运行 SQL Server 查询,特别是执行存储过程。

MS Access 确实允许对后端数据库进行直通查询,因此您可以调整 QueryDef(默认为 Access 后端)以连接到 MSSQL 数据库,然后运行EXEC 命令。所有直通查询都应符合后端的 SQL 方言。

Private Sub Command148_Click()
   Dim dbs As DAO.Database
   Dim qdf As DAO.QueryDef
   Dim SrvNameVar, strSQL As String

   SrvNameVar = Me.SrvName
   strSQL = "EXEC dbo.sp_ArchiveServer @Server='" & SrvNameVar &"'"

   Set dbs = CurrentDb
   Set qdf = dbs.CreateQueryDef("SrvArchive")

   ' ASSIGN ODBC DSN CONNECTION
   qdf.Connect = "ODBC; DATABASE=database; UID=user; PWD=password; DSN=datasourcename;" 
   qdf.SQL = strSQL
   qdf.Execute
End Sub

为了有效地使用参数化,请考虑使用不同的 API,即 ADO(可扩展到任何后端数据库)而不是 DAO(更适合 Access 数据库)。

Private Sub Command148_Click()
   ' SET REFERENCE TO Microsoft ActiveX Data Object #.# Library
   Dim conn As ADODB.Connection, cmd As ADODB.Command
   Dim SrvNameVar As String

   SrvNameVar = Me.SrvName

   ' OPEN DRIVER OR DSN CONNECTION
   Set conn = New ADODB.Connection         
   conn.Open "DRIVER={SQL Server};server=servername;database=databasename;UID=username;PWD=password;"
   ' conn.Open "DSN=datasourcename"

   ' OPEN AND DEFINE COMMAND OBJECT
   Set cmd = New ADODB.Command     
   With cmd
       .ActiveConnection = conn
       .CommandText = "sp_ArchiveServer"
       .CommandType = adCmdStoredProc

       ' BIND PARAMETERS BY POSITION AND NOT NAME
       .Parameters.Append .CreateParameter("param1", adVarchar, adParamInput, 255, SrvNameVar)
       .Execute
   End With

   conn.close()
   Set cmd = Nothing: Set conn = Nothing
End Sub

【讨论】:

  • 感谢您的建议!我把它放好,它仍然踢回运行时错误 3129。无效的 SQL 语句;非参数化代码上的预期 DELETE、INSERT、PROCEDURE、SELECT 或 UPDATE
  • 即使有所需的.Connect 行?错误表示您没有运行直通查询。请注意,您要调整连接字符串的参数,而不是关键字。
  • Visual Basic 编辑器正在标记qdf.SQL = strSQL
  • 你需要在.SQL之前分配.Connect。创建 QueryDef 后立即分配 .Connect
  • 确实如此。谢谢@ErikA。 ODBC 连接定义了对 querydef 应用哪种 SQL 方言。 Mattyd,在重试之前删除之前的查询。
【解决方案2】:

在 Access 设计器中创建传递查询。

您可以在查询(sql 视图)中键入该命令。所以,你有一个传递查询,它看起来像这样:

EXEC dbo.sp_ArchiveServer @Server='test'

保存上述查询。 (确保它是通过查询)。

好的,现在您的 VBA 代码将如下所示:

With CurrentDb.QueryDefs("qryPass")
   .SQL = "EXEC dbo.sp_ArchiveServer @Server='" & Me.SrvName & "'"
   .ReturnsRecords = False
   .Execute
End With

【讨论】:

    【解决方案3】:

    感谢大家的帮助!使用您提供的所有信息,它现在可以正常工作。为此,我首先按照 Albert 的示例创建 Pass Through 查询,然后在他的代码中附加来自 Parfait 和 ErikA 的有关连接字符串的信息。然后我添加了一个简单的 MsgBox 命令和一个 Close Form 命令,让它更“漂亮”一些。这是最终的有效代码:

    Private Sub Command148_Click()
    
    With CurrentDb.QueryDefs("SrvQryPass")
       .Connect = "ODBC;DSN=ODBC_17;Description=FSC;Trusted_Connection=Yes;APP=Microsoft Office;DATABASE=FSC;Network=DBMSSOCN;"
       .SQL = "EXEC dbo.sp_ArchiveServer @Server='" & Me.SrvName & "'"
       .ReturnsRecords = False
       .Execute
    End With
    
    MsgBox "Archived!"
    DoCmd.Close
    
    End Sub
    

    【讨论】:

    • 好吧,如果你有现有的链接表,那么 PT 查询也像表一样有一个连接字符串。因此,根据我的示例代码,无需担心代码中的连接内容。换句话说,当您链接和设置表时,还要为您拥有的 PT 查询链接和设置连接。这样就不需要 VBA 中的连接字符串或代码。因此,不必在代码中处理连接字符串是个好主意,因为如果稍后您更改链接表和您连接的数据库?那么你也不必去寻找带有连接字符串的 VBA 代码。
    猜你喜欢
    • 1970-01-01
    • 2014-01-24
    • 1970-01-01
    • 1970-01-01
    • 2018-08-27
    • 2017-04-26
    • 1970-01-01
    • 1970-01-01
    • 2018-12-14
    相关资源
    最近更新 更多