创建 vba 代码以连接到远程 SQL 服务器,执行更新 accdb 文件上的 table 的存储过程
Creating vba code to connect to a remote SQL server, executre a stored procedure that updates a table on the accdb file
对不起文字,力求简洁
我们正在尝试建立一个流程,让我们的最终用户(在不同网络之间移动的笔记本电脑上的远程用户)使用访问数据库,向我们的 SQL 服务器发送请求以获得该服务器执行一个存储过程。一旦在 SQL 服务器收到此请求,服务器应为该用户查找一系列预期值,然后执行不同的存储过程以启动新的 link 返回给调用设备(基于关于这次它是如何连接到互联网的),运行 对该机器上的数据进行一系列验证,如果验证成功,它应该更新远程客户端上 table 中的数据,然后断开连接。
我们已经设置了调用程序,当它们直接使用 SSMS 从 SQL 服务器执行时,它们工作得很好(例如:我们登录到服务器 运行 宁 SQL 服务器,然后使用 SSMS 执行存储过程),如果我们将 link 留在那里,我们可以使用 SSMS read/edit/modify 远程客户端中的任何 data/tables。
但是,当从远程客户端调用存储过程时,它们会起作用,除非这些存储过程尝试 read/write 到远程 linked 服务器(例如:添加和删除 link 的存储过程s 到数据库工作正常,但是查看或编辑远程数据库中的数据的查询 return 一个看起来与文件访问权限相关的错误。
我们的 Environment:Devices 在我们的域上,SQLserver 2017 Express,Windows 10,accdb 数据库 (2007)
总结:我们正在编写 VBA 代码来在我们的域上执行远程 SQL Server 2017 Express 存储过程,以在同一调用 accdb 数据库(2007 ) 运行ning 在 windows 10 计算机上。
结果:为了增加安全性和效率,我们希望远程计算机仅 sql 服务器上的 运行 存储过程没有特定的 tables/views。即访问 vba 表示我在线,sql 服务器创建 link 并检查更新的联系人、下载和断开连接。
过程创建一个 LinkServer (sp_addlinkedserver),登录 (sp_addlinkedsrvlogin),更新一个 table (@sql = 'UPDATE '),删除 link (sp_dropserver)
一旦我们完成这项工作,我们计划创建其他存储过程来查询 accdb 文件并将新数据上传到 SQL 服务器。
当我们尝试通过 VBA 中的存储过程“SELECT”或“更新”远程访问文件时,我们被阻止了(存储过程在 SSMS 界面上运行良好)。
因此,在 SQL 服务器上我们目前有
CREATE PROCEDURE [dbo].[SQLserverlastconnect] @p_linkservername nvarchar(max) = null, @p_linkdatasrc nvarchar(max) = NULL
AS
DECLARE @sql NVARCHAR(MAX)
EXEC master.dbo.sp_addlinkedserver @server = @p_linkservername, @srvproduct=N'', @provider=N'Microsoft.ACE.OLEDB.12.0', @datasrc= @p_linkdatasrc
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname = N'<servername>\<instance>', @locallogin = NULL , @useself = N'True';
SET @sql = 'UPDATE ' + @p_linkservername + '...tbl_Ref_Local SET tqs_Data = ''' + CONVERT(varchar(50),FORMAT(CURRENT_TIMESTAMP, 'yyyy-MM-dd hh:mm:ss')) + ''' WHERE tqs_KeyIdentifier = ''LastConnect'''
EXEC(@sql)
EXEC master.sys.sp_dropserver @p_linkservername,'droplogins'
在 Access 365 中,我们有一个 Sub(对此尝试了许多更改,包括寻找连接字符串的问题)
Sub Test()
Dim connection As Object: Set connection = CreateObject("ADODB.Connection")
Dim rs As Object: Set rs = CreateObject("ADODB.Recordset")
With connection
.ConnectionString = "DRIVER=SQL Server;Server=<servername>\<Instance>;Trusted_Connection=Yes;APP=2007 Microsoft Office system;DATABASE=SixBit;User ID=sa;Password=********" ‘[we tried to remove User ID/Password and only use a trusted connection]
.CommandTimeout =0
.Open
End With
Set rs = connection.Execute("EXEC dbo.SQLserverlastconnect @p_linkservername = N'Test7', @p_linkdatasrc = N'\fileserver\Programming\TQS - Client 0.03.22.accdb'")
‘tried this also Set rs = connection.Execute("INSERT INTO [Test7]...[tbl_Ref_Local] ([tqs_KeyIdentifier],[tqs_Data],[tqs_GUID]) VALUES ('t', 't' ,'t')")
connection.Close: Set rs = Nothing: Set connection = Nothing
End Sub
我们尝试过的事情:我们已将所有人添加到文件所在的网络共享中,将所有人添加到临时路径,将 SQL 服务器服务“登录为”从默认更改为域管理员还有“网络服务”。
我们没有花太多时间的一个领域是 SQL 服务器上链接服务器属性上的“登录映射”(我们确实尝试过模拟“sa”)
这是 运行 宁 VBA 时我们收到的当前消息。尝试设置 NET USE U:,尝试指向另一个未打开的访问数据库(旧版本),因为消息似乎暗示我们无法在 运行ning 时打开数据库,还尝试了文本文件。
最后,我们创建了一个触发器,可以将其发送到 运行 一个 SELECT(大量拳头抽动),但不是 UPDATE 或 INSERT(悲伤的脸),但这可能对某些人有所暗示在那里。
有人有什么建议吗?
这似乎是一个糟糕的想法和方法。
首先,如果客户端以独占方式启动 Access,那么 Access 或 SQL 服务器将无法成功 link。
并且您必须确保 SQL 服务器不会尝试打开 (link) 独占客户端访问数据库。也许当您从 SSMS 进行测试时,您没有在打开同一个 accDB 文件的情况下启动访问副本。我没有仔细看,但我相信服务器 link 访问的默认设置是独占的(这意味着当 Access 客户端打开相同的文件时,无法打开客户端 accDB 文件。
更糟糕的是,如果您在客户端通过服务器端更新任何数据,那么任何行都将被拉到 sql 服务器,进行更新,然后通过网络发送回。为什么不将该更新代码移动到本地,并且您不会生成任何网络流量来实现对本地数据的更新。
与本地 LAN 相比,通过“wan”进行的此类更新非常慢。当您使用 SQL 系统更新时,您实际上是从本地文件“原始”读取数据,这在 WAN 连接上是一个非常糟糕的主意。如果连接中断,您将损坏并炸毁本地 accDB 文件。
从 Access 到 sql 服务器的 table 链接很好,因为“文件”没有被读取或通过网络传输。但是,linking SQL 服务器到本地客户端 accDB 意味着 windows 文件系统正在通过 VPN/WAN 连接从 SQL 服务器遍历。你“真的”想避免这种情况。这意味着 SQL 服务器正在执行文件打开,并且 widows 文件缓冲区和读取发生在服务器端。 ole jet/ace 引擎是 运行 服务器端,但文件读取来自客户端。
我在这篇文章中解释了为什么这是一个大的“腐败”问题:
http://www.kallal.ca/Wan/Wans.html
此外,linked服务器的“模型”和“想法”并不是真正的“跳进跳出”模型。因此,linked 服务器更像是一种“维护”类型的过程,在该过程中,您设置了一个 linked 服务器,它会保持原样。
因此,一些 link 即时访问其他服务(或访问文件)的多用户系统并不是 linked 服务器背后的想法和概念。
还不清楚当您有多个用户使用这样的系统时会发生什么?我想可以创建不同名称的 linked 服务器,但是话又说回来,你的 t-sql 代码必须在“许多”不同的 linked 服务器上运行。 (因此必须更改代码)。
这意味着你的 t-sql 以太币必须为“许多”不同的 linked 服务器工作以使用相同的 t-sql 代码,或者你总是使用相同的名称对于 linked 服务器。如果您使用相同的名称,那么一个客户端就可以操作。
我越想这种方法,它就越糟糕。
在我看来,一种更流畅的方法是让 Access linked tables 到 SQL 服务器。
如果您使用域身份验证连接到 sql 服务器,那么任何使用 Excel 的用户都可以“轻松”地对 sql 服务器执行一些查询,而您VPN 处于活动状态。如果他们启动 SSMS,情况也是如此。
我会考虑:
使用 SQL 服务器登录,因此授权用户无法使用 Excel、Access 或其他可以访问的客户端程序从 table 中提取或查看数据SQL 服务器轻松(包括本地客户端 运行 SSMS)。
不要在 linked table 中包含 UID/password。这意味着您不必(以纯文本形式)包括您用于此过程的 uid/logon。
不清楚 Access 应用程序是否“隐藏”了访问界面,但即使出于某种原因用户绕过了您的应用程序界面,他们也会通过尝试打开现有的 link编辑 table。 (在您的 VBA 代码执行简单登录之前,link 不会工作)。让客户端“登录”不需要创建任何新的 links 客户端(也不需要创建服务器端)。
我会强烈考虑让客户端 do/make 连接,我会尝试使用客户端代码更新本地客户端 table 以消除网络流量,但是最糟糕的是通过网络“打开”windows 文件。如果那个文件是“打开的”,而你的连接丢失了,那么你“实时”切割一个打开的 windows 文件和刷新本地磁盘缓存等简单的事情都会失败并丢失。
如果您从客户端使用 links,那么您永远不会通过该网络打开 windows 文件(只有一个套接字 ODBC 连接)。
就像一个接入应用程序拆分成前端,后端可以在可靠的本地 LAN 上运行良好,这样的设置在 WAN + VPN 上运行得非常差。
总结:
您可能可以让您的设置正常工作,但我不推荐它。
寻找什么:
检查 accDB 文件的独占 open/use(确保未启动访问或在客户端以独占方式打开 accDB 文件)。如果发生这种情况,那么 sql 方将无法对文件进行 link。
检查并确保在从该服务器端创建 sql link 到 accDB 文件时,sql 服务器未尝试“独占”。 (这将意味着 Access local 无法打开或使用该文件)。
事实上,我们已经“检查”两端是否会导致此设置失败,这已经是一个失败点,我们(您)必须确保正确完成。
如前所述,我不建议通过这样的网络打开 windows 文件。
于是查排他问题(两端)。但是,我会考虑让 Access 建立连接客户端,并执行存储过程。如果在该 sproc 中发生的最终更新和检查需要一些数据,则在服务器端进行检查,将生成的所需数据拉到客户端,然后执行本地代码进行更新。
因此,虽然我认为此设置不可靠,但最重要的是我会检查“独占”问题——两端都需要避免以独占方式打开 accDB 文件。
我使用此 sub 从 Access 执行 SQL 服务器代码(可以是任何内容,包括对存储过程的调用):
Public Sub ExecuteSQLServerCode(SQL As String)
Dim MyAccessDatabase As DAO.Database
Set MyAccessDatabase = CurrentDb()
With MyAccessDatabase.CreateQueryDef("")
.Connect = CurrentDb.TableDefs("LinkedTable").Connect
.SQL = SQL
.ReturnsRecords = False
.Execute
.Close
End With
MyAccessDatabase.Close
Set MyAccessDatabase = Nothing
End Sub
问题是,在我的情况下,我有一个静态 linked table 到 SQL 服务器,我可以从中 "borrow" 连接。
另外请记住,对于远程连接,您可能必须创建 SQL 服务器用户帐户,因为 AD 身份验证可能不起作用。
一般来说,我会尝试以下步骤:
- 从 AD 计算机创建一个 "permanent" link 到网络内部的 table。
- 测试 link 并使其远程工作。
- 使用上面的代码从本地 Access 测试 SQL 服务器代码的执行。
- 远程重复第 3 步。
- 尝试用本地动态 linking 替换永久 linked table。
- 远程重复步骤 5。
对不起文字,力求简洁
我们正在尝试建立一个流程,让我们的最终用户(在不同网络之间移动的笔记本电脑上的远程用户)使用访问数据库,向我们的 SQL 服务器发送请求以获得该服务器执行一个存储过程。一旦在 SQL 服务器收到此请求,服务器应为该用户查找一系列预期值,然后执行不同的存储过程以启动新的 link 返回给调用设备(基于关于这次它是如何连接到互联网的),运行 对该机器上的数据进行一系列验证,如果验证成功,它应该更新远程客户端上 table 中的数据,然后断开连接。
我们已经设置了调用程序,当它们直接使用 SSMS 从 SQL 服务器执行时,它们工作得很好(例如:我们登录到服务器 运行 宁 SQL 服务器,然后使用 SSMS 执行存储过程),如果我们将 link 留在那里,我们可以使用 SSMS read/edit/modify 远程客户端中的任何 data/tables。 但是,当从远程客户端调用存储过程时,它们会起作用,除非这些存储过程尝试 read/write 到远程 linked 服务器(例如:添加和删除 link 的存储过程s 到数据库工作正常,但是查看或编辑远程数据库中的数据的查询 return 一个看起来与文件访问权限相关的错误。
我们的 Environment:Devices 在我们的域上,SQLserver 2017 Express,Windows 10,accdb 数据库 (2007)
总结:我们正在编写 VBA 代码来在我们的域上执行远程 SQL Server 2017 Express 存储过程,以在同一调用 accdb 数据库(2007 ) 运行ning 在 windows 10 计算机上。 结果:为了增加安全性和效率,我们希望远程计算机仅 sql 服务器上的 运行 存储过程没有特定的 tables/views。即访问 vba 表示我在线,sql 服务器创建 link 并检查更新的联系人、下载和断开连接。 过程创建一个 LinkServer (sp_addlinkedserver),登录 (sp_addlinkedsrvlogin),更新一个 table (@sql = 'UPDATE '),删除 link (sp_dropserver) 一旦我们完成这项工作,我们计划创建其他存储过程来查询 accdb 文件并将新数据上传到 SQL 服务器。 当我们尝试通过 VBA 中的存储过程“SELECT”或“更新”远程访问文件时,我们被阻止了(存储过程在 SSMS 界面上运行良好)。
因此,在 SQL 服务器上我们目前有
CREATE PROCEDURE [dbo].[SQLserverlastconnect] @p_linkservername nvarchar(max) = null, @p_linkdatasrc nvarchar(max) = NULL
AS
DECLARE @sql NVARCHAR(MAX)
EXEC master.dbo.sp_addlinkedserver @server = @p_linkservername, @srvproduct=N'', @provider=N'Microsoft.ACE.OLEDB.12.0', @datasrc= @p_linkdatasrc
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname = N'<servername>\<instance>', @locallogin = NULL , @useself = N'True';
SET @sql = 'UPDATE ' + @p_linkservername + '...tbl_Ref_Local SET tqs_Data = ''' + CONVERT(varchar(50),FORMAT(CURRENT_TIMESTAMP, 'yyyy-MM-dd hh:mm:ss')) + ''' WHERE tqs_KeyIdentifier = ''LastConnect'''
EXEC(@sql)
EXEC master.sys.sp_dropserver @p_linkservername,'droplogins'
在 Access 365 中,我们有一个 Sub(对此尝试了许多更改,包括寻找连接字符串的问题)
Sub Test()
Dim connection As Object: Set connection = CreateObject("ADODB.Connection")
Dim rs As Object: Set rs = CreateObject("ADODB.Recordset")
With connection
.ConnectionString = "DRIVER=SQL Server;Server=<servername>\<Instance>;Trusted_Connection=Yes;APP=2007 Microsoft Office system;DATABASE=SixBit;User ID=sa;Password=********" ‘[we tried to remove User ID/Password and only use a trusted connection]
.CommandTimeout =0
.Open
End With
Set rs = connection.Execute("EXEC dbo.SQLserverlastconnect @p_linkservername = N'Test7', @p_linkdatasrc = N'\fileserver\Programming\TQS - Client 0.03.22.accdb'")
‘tried this also Set rs = connection.Execute("INSERT INTO [Test7]...[tbl_Ref_Local] ([tqs_KeyIdentifier],[tqs_Data],[tqs_GUID]) VALUES ('t', 't' ,'t')")
connection.Close: Set rs = Nothing: Set connection = Nothing
End Sub
我们尝试过的事情:我们已将所有人添加到文件所在的网络共享中,将所有人添加到临时路径,将 SQL 服务器服务“登录为”从默认更改为域管理员还有“网络服务”。 我们没有花太多时间的一个领域是 SQL 服务器上链接服务器属性上的“登录映射”(我们确实尝试过模拟“sa”) 这是 运行 宁 VBA 时我们收到的当前消息。尝试设置 NET USE U:,尝试指向另一个未打开的访问数据库(旧版本),因为消息似乎暗示我们无法在 运行ning 时打开数据库,还尝试了文本文件。
最后,我们创建了一个触发器,可以将其发送到 运行 一个 SELECT(大量拳头抽动),但不是 UPDATE 或 INSERT(悲伤的脸),但这可能对某些人有所暗示在那里。
有人有什么建议吗?
这似乎是一个糟糕的想法和方法。
首先,如果客户端以独占方式启动 Access,那么 Access 或 SQL 服务器将无法成功 link。
并且您必须确保 SQL 服务器不会尝试打开 (link) 独占客户端访问数据库。也许当您从 SSMS 进行测试时,您没有在打开同一个 accDB 文件的情况下启动访问副本。我没有仔细看,但我相信服务器 link 访问的默认设置是独占的(这意味着当 Access 客户端打开相同的文件时,无法打开客户端 accDB 文件。
更糟糕的是,如果您在客户端通过服务器端更新任何数据,那么任何行都将被拉到 sql 服务器,进行更新,然后通过网络发送回。为什么不将该更新代码移动到本地,并且您不会生成任何网络流量来实现对本地数据的更新。
与本地 LAN 相比,通过“wan”进行的此类更新非常慢。当您使用 SQL 系统更新时,您实际上是从本地文件“原始”读取数据,这在 WAN 连接上是一个非常糟糕的主意。如果连接中断,您将损坏并炸毁本地 accDB 文件。
从 Access 到 sql 服务器的 table 链接很好,因为“文件”没有被读取或通过网络传输。但是,linking SQL 服务器到本地客户端 accDB 意味着 windows 文件系统正在通过 VPN/WAN 连接从 SQL 服务器遍历。你“真的”想避免这种情况。这意味着 SQL 服务器正在执行文件打开,并且 widows 文件缓冲区和读取发生在服务器端。 ole jet/ace 引擎是 运行 服务器端,但文件读取来自客户端。
我在这篇文章中解释了为什么这是一个大的“腐败”问题:
http://www.kallal.ca/Wan/Wans.html
此外,linked服务器的“模型”和“想法”并不是真正的“跳进跳出”模型。因此,linked 服务器更像是一种“维护”类型的过程,在该过程中,您设置了一个 linked 服务器,它会保持原样。
因此,一些 link 即时访问其他服务(或访问文件)的多用户系统并不是 linked 服务器背后的想法和概念。
还不清楚当您有多个用户使用这样的系统时会发生什么?我想可以创建不同名称的 linked 服务器,但是话又说回来,你的 t-sql 代码必须在“许多”不同的 linked 服务器上运行。 (因此必须更改代码)。
这意味着你的 t-sql 以太币必须为“许多”不同的 linked 服务器工作以使用相同的 t-sql 代码,或者你总是使用相同的名称对于 linked 服务器。如果您使用相同的名称,那么一个客户端就可以操作。
我越想这种方法,它就越糟糕。
在我看来,一种更流畅的方法是让 Access linked tables 到 SQL 服务器。
如果您使用域身份验证连接到 sql 服务器,那么任何使用 Excel 的用户都可以“轻松”地对 sql 服务器执行一些查询,而您VPN 处于活动状态。如果他们启动 SSMS,情况也是如此。
我会考虑:
使用 SQL 服务器登录,因此授权用户无法使用 Excel、Access 或其他可以访问的客户端程序从 table 中提取或查看数据SQL 服务器轻松(包括本地客户端 运行 SSMS)。
不要在 linked table 中包含 UID/password。这意味着您不必(以纯文本形式)包括您用于此过程的 uid/logon。
不清楚 Access 应用程序是否“隐藏”了访问界面,但即使出于某种原因用户绕过了您的应用程序界面,他们也会通过尝试打开现有的 link编辑 table。 (在您的 VBA 代码执行简单登录之前,link 不会工作)。让客户端“登录”不需要创建任何新的 links 客户端(也不需要创建服务器端)。
我会强烈考虑让客户端 do/make 连接,我会尝试使用客户端代码更新本地客户端 table 以消除网络流量,但是最糟糕的是通过网络“打开”windows 文件。如果那个文件是“打开的”,而你的连接丢失了,那么你“实时”切割一个打开的 windows 文件和刷新本地磁盘缓存等简单的事情都会失败并丢失。
如果您从客户端使用 links,那么您永远不会通过该网络打开 windows 文件(只有一个套接字 ODBC 连接)。
就像一个接入应用程序拆分成前端,后端可以在可靠的本地 LAN 上运行良好,这样的设置在 WAN + VPN 上运行得非常差。
总结: 您可能可以让您的设置正常工作,但我不推荐它。
寻找什么:
检查 accDB 文件的独占 open/use(确保未启动访问或在客户端以独占方式打开 accDB 文件)。如果发生这种情况,那么 sql 方将无法对文件进行 link。
检查并确保在从该服务器端创建 sql link 到 accDB 文件时,sql 服务器未尝试“独占”。 (这将意味着 Access local 无法打开或使用该文件)。
事实上,我们已经“检查”两端是否会导致此设置失败,这已经是一个失败点,我们(您)必须确保正确完成。
如前所述,我不建议通过这样的网络打开 windows 文件。
于是查排他问题(两端)。但是,我会考虑让 Access 建立连接客户端,并执行存储过程。如果在该 sproc 中发生的最终更新和检查需要一些数据,则在服务器端进行检查,将生成的所需数据拉到客户端,然后执行本地代码进行更新。
因此,虽然我认为此设置不可靠,但最重要的是我会检查“独占”问题——两端都需要避免以独占方式打开 accDB 文件。
我使用此 sub 从 Access 执行 SQL 服务器代码(可以是任何内容,包括对存储过程的调用):
Public Sub ExecuteSQLServerCode(SQL As String)
Dim MyAccessDatabase As DAO.Database
Set MyAccessDatabase = CurrentDb()
With MyAccessDatabase.CreateQueryDef("")
.Connect = CurrentDb.TableDefs("LinkedTable").Connect
.SQL = SQL
.ReturnsRecords = False
.Execute
.Close
End With
MyAccessDatabase.Close
Set MyAccessDatabase = Nothing
End Sub
问题是,在我的情况下,我有一个静态 linked table 到 SQL 服务器,我可以从中 "borrow" 连接。
另外请记住,对于远程连接,您可能必须创建 SQL 服务器用户帐户,因为 AD 身份验证可能不起作用。
一般来说,我会尝试以下步骤:
- 从 AD 计算机创建一个 "permanent" link 到网络内部的 table。
- 测试 link 并使其远程工作。
- 使用上面的代码从本地 Access 测试 SQL 服务器代码的执行。
- 远程重复第 3 步。
- 尝试用本地动态 linking 替换永久 linked table。
- 远程重复步骤 5。