【问题标题】:Connection string for opening linked table Access -> SQL server (vba)用于打开链接表访问的连接字符串 - > SQL server (vba)
【发布时间】:2012-04-06 20:29:24
【问题描述】:

我一直在寻找答案,因为有很多类似的问题,但没有找到这个特殊案例。

我有一个 SQL 服务器和一个访问文件(前端)。这个 Access 文件有链接表,与 SQL 服务器链接,每次我尝试打开一个表时,都会出现一个提示,要求输入用户名和密码。

好的,这很完美,因为它(几乎)是我想要的行为。

此外,还有一个本地表,其中包含密码加密的用户/密码。每次用户打开文件时,他/她的通行证都会被解密,我想打开一个连接,所以链接表不会要求通行证。

有人知道如何编码这个连接吗?

提前致谢!

【问题讨论】:

  • 看情况,不能用Windows安全代替SQL Server安全吗?那可以让你的生活更轻松。

标签: sql ms-access connection-string vba


【解决方案1】:

我想你想要的是"DSN-LESS connection"。我过去做过类似的事情。基本上,在用户登录时,您使用基于用户凭据构建的连接字符串重新链接表。

查看之前的SO Question 了解更多详情。

此外,这里有一些我过去使用过的例程,您可以随意使用 \ 修改。从您的登录过程中调用这些。

Public Function RelinkDSNTables( _
      ByVal ServerName As String, _
      ByVal DatabaseName As String, _
      ByVal UserName As String, _
      ByVal Password As String) As Boolean
On Error GoTo Err_Handler

Dim dsn As String
dsn = GetDSNLink(ServerName, DatabaseName, UserName, Password)
Dim td As TableDef
Dim db As DAO.Database
Set db = CurrentDb
Dim rst As ADODB.Recordset

'Get a list of tables that need to be relinked'
If GetLocalRecordSet(rst, "SELECT * FROM TableMapping") < 1 Then
   Err.Raise 1000, "Missing Tables!", "Missing Table Mappings!"
End If

Dim fNeedToRefresh As Boolean

'See if we actually need to relink the tables'
For Each td In db.TableDefs
   If td.Connect <> vbNullString Then
      If td.Connect <> dsn Then
         fNeedToRefresh = True
         Exit For
      End If
   End If
Next td

If fNeedToRefresh = False Then
   RelinkDSNTables = True
   GoTo Err_Handler
End If

'Drop linked table in Access'
For Each td In CurrentDb.TableDefs
   If td.Connect <> vbNullString Then
      CurrentDb.TableDefs.Delete td.Name
   End If
Next td

'Create new linked table using new DSN'
rst.MoveFirst
Do Until rst.EOF
   Set td = db.CreateTableDef(rst!LocalTableName, dbAttachSavePWD, rst!RemoteTableName, dsn)
   db.TableDefs.Append td
   rst.MoveNext
Loop

'Because I am paranoid, refresh the link'
db.TableDefs.Refresh
For Each td In db.TableDefs
   If td.Connect <> "" Then td.RefreshLink
Next td

RelinkDSNTables = True

Err_Handler:
   If Err.Number = 3011 Then
      'Happens if user does not have permission in SQL Server; Nothing to see here, move along'
      Err.Clear
      Resume Next
   ElseIf Err.Number = 3010 Then
      'already exists; should not occur, but if it does eat the exception and move on'
      Err.Clear
      Resume Next
   ElseIf Err.Number <> 0 Then
      Err.Raise Err.Number, Err.Source, Err.Description
   End If
End Function

Private Function GetDSNLink( _
      ByVal ServerName As String, _
      ByVal DatabaseName As String, _
      ByVal UserName As String, _
      ByVal Password As String) As String
On Error GoTo Err_Handler

If ServerName = "" Or DatabaseName = "" Then
   Err.Raise -1220, "Missing Server \ DB", _
      "Unable to refresh table links because you are missing the server or database name!"
End If

Dim dsnLink As String

If UserName = "" Then
   'trusted connection'
   dsnLink = "ODBC;DRIVER=SQL Server;SERVER=" & ServerName & _
            ";DATABASE=" & DatabaseName & ";Trusted_Connection=Yes"
Else
   'MixedMode connection'
     '//WARNING: This will save the username and the password with the linked table information.
   dsnLink = "ODBC;DRIVER=SQL Server;SERVER=" & ServerName & _
            ";DATABASE=" & DatabaseName & ";UID=" & UserName & ";PWD=" & Password
End If

GetDSNLink = dsnLink

Err_Handler:
   If Err.Number <> 0 Then
      Err.Raise Err.Number, Err.Source, Err.Description
   End If
End Function

编辑:添加示例 GetLocalRecordSet 函数

Public Function GetLocalRecordSet(ByRef rs As ADODB.Recordset, ByVal sql As String) As Long
On Error GoTo Err_Handler

If sql = vbNullString Then
   Err.Raise vbObjectError + 1001, _
      "Empty SQL String", "Empty SQL String Passed to GetLocalRecordset Function!"
End If

Set rs = New ADODB.Recordset

rs.Open sql, CurrentProject.Connection, adOpenKeyset, adLockOptimistic

If rs Is Nothing Then
   GetLocalRecordSet = -1
   GoTo Err_Handler
End If

If rs.State = adStateOpen Then
   If Not rs.EOF Then
      rs.MoveLast
      GetLocalRecordSet = rs.RecordCount                 'store number of records
      rs.MoveFirst
   Else
      GetLocalRecordSet = 0
   End If
Else
   GetLocalRecordSet = -2
End If

Err_Handler:
   If Err.Number <> 0 Then
      Err.Raise Err.Number, Err.Source, Err.Description
   End If
End Function

【讨论】:

  • 您在我忙于打字时发布了您的答案。你的答案看起来不错,甚至可能比我的还要好。我看到的唯一区别之一是我确实有代码为每个链接表创建一个名为“__UniqueIndex”的索引。我不记得我为什么这样做了——也许 SQL Server ODBC 链接表不需要它。
  • @HK1 - 关于唯一索引的要点。我跳过了这个,因为我在 SQL Server 中的表总是有一个唯一的索引。但是,如果该表在 SQL Server 中没有唯一索引,您将无法在 MS Access 中针对该表执行更新,而无需先在 Access 中创建索引。如果您愿意,请随时更新我的​​答案:)
  • 我很乐意用一些免费代码更新您的答案,但它需要您存储主键字段名称才能创建唯一索引。因此,您需要在表格映射表中添加另一个字段。
  • 那么您所做的是每次都重新链接所有表格,对吗?由于链接表还包括用户和通行证,您必须删除并再次创建它们。我想在开场时建立一个连接,但我会尝试这个解决方案。 GetLocalRecordSet 是你定义的函数?
  • @Pete - 我使用了一个很像 Tim 的函数,我只是在数据库打开时重新链接所有表。这些连接似乎没有问题地保持在原位,直到数据库关闭。在数据库打开时,您不必重新链接或刷新表,除非您进行了大量需要立即生效的表更改。
【解决方案2】:

您可以编写代码以编程方式使用存储在本地表中的用户名/密码连接到 SQL 数据库。这应该在 Access 应用加载时发生(例如,使用 Autoexec 宏)。

您可以在此处阅读有关 Autoexec 宏的信息:http://www.vb123.com/toolshed/05_map/ch04_autoexec.htm

因此,您将拥有一个功能,例如在应用程序启动时从 Autoexec 宏调用的 OpenConnection()。任何后续的表打开都不应提示输入密码。

不过,我不确定这是否适用于 SQL 后端。希望它会。

【讨论】:

    猜你喜欢
    • 2016-03-27
    • 1970-01-01
    • 2021-10-02
    • 2012-09-26
    • 1970-01-01
    • 2012-09-18
    相关资源
    最近更新 更多