【问题标题】:Why does this vba table relink code result in error 3219?为什么这个 vba 表重新链接代码会导致错误 3219?
【发布时间】:2016-06-15 14:06:34
【问题描述】:

我正在尝试重新链接 MS Access 数据库中的表,该数据库与下面运行的代码不同;这样我就可以将修复数据库用作各种“补丁”......

我已经修改了我找到的代码here,以便它重新链接由“修复/补丁数据库”打开的数据库中的表

在我运行代码之前,我确保两个数据库都是打开的,以便一个可以修复另一个,以便更轻松地自动应用修复程序。

但是,当我运行代码时,当我到达读取 tdfLinked.RefeshLink 的行时,它会刷新链接表,我收到 Runtime error '3219' Invalid Operation 错误。

Sub FixDB()

    Call LinkTable("somelinkedTble", "SOMESERVER\NAMED_SQL_INST32", "Database1", "Some_Schema.somelinkedTble", True)

End Sub

Function LinkTable(LinkedTableAlias As String, Server As String, database As String, SourceTableName As String, OverwriteIfExists As Boolean)
    'This method will also update the link if the underlying table definition has been modified.

    'The overwrite parameter will cause it to re-map/refresh the link for LinktedTable Alias, but only if it was already a linked table.
    ' it will not overwrite an existing query or local table with the name specified in LinkedTableAlias.

    ' Begin: Bit that I modified to access the database that needs fixed.
    Dim objAccess As Access.application
    Dim loginInfo As New AuthInfoz

    loginInfo.workgroup = "E:\Tickets\Fix\SEC\Secured.mdw"
    loginInfo.username = "someuser"
    loginInfo.password = "********"
    loginInfo.dbs = "E:\Tickets\Fix\Report.mdb"

    Set objAccess = GetObject(loginInfo.dbs).application

    'Links to a SQL Server table without the need to set up a DSN in the ODBC Console.
    Dim dbsCurrent As database
    Dim tdfLinked As TableDef

    ' Open a database to which a linked table can be appended.
    Set dbsCurrent = objAccess.CurrentDb

    ' END: Bit that I modified to access the external database.

    'Check for and deal with the scenario ofthe table alias already existing
    If TableNameInUse(LinkedTableAlias) Then

        If (Not OverwriteIfExists) Then
            Debug.Print "Can't use name '" + LinkedTableAlias + "' because it would overwrite existing table."
            Exit Function
        End If

        'delete existing table, but only if it is a linked table
        If IsLinkedTable(LinkedTableAlias) Then
            dbsCurrent.TableDefs.Delete LinkedTableAlias
            dbsCurrent.TableDefs.Refresh
        Else
            Debug.Print "Can't use name '" + LinkedTableAlias + "' because it would overwrite an existing query or local table."
            Exit Function
        End If
    End If

    'Create a linked table
    Set tdfLinked = dbsCurrent.CreateTableDef(LinkedTableAlias)
    tdfLinked.SourceTableName = SourceTableName
    tdfLinked.Connect = "ODBC;DRIVER={SQL Server};SERVER=" & Server & ";DATABASE=" & database & ";TRUSTED_CONNECTION=yes;"

    On Error Resume Next
    dbsCurrent.TableDefs.Append tdfLinked
    If (Err.Number = 3626) Then 'too many indexes on source table for Access
            Err.Clear
            On Error GoTo 0

            If LinkTable(LinkedTableAlias, Server, database, "vw" & SourceTableName, OverwriteIfExists) Then
                Debug.Print "Can't link directly to table '" + SourceTableName + "' because it contains too many indexes for Access to handle. Linked to view '" & "vw" & SourceTableName & "' instead."
                LinkTable = True
            Else
                Debug.Print "Can't link table '" + SourceTableName + "' because it contains too many indexes for Access to handle. Create a view named '" & "vw" & SourceTableName & "' that selects all rows/columns from '" & SourceTableName & "' and try again to circumvent this."
                LinkTable = False
            End If
            Exit Function
    End If
    On Error GoTo 0

    tdfLinked.RefreshLink
    LinkTable = True

End Function

Function BuildSQLConnectionString(Server As String, DBName As String) As String
    BuildSQLConnectionString = "Driver={SQL Server};Server=" & Server & ";Database=" & DBName & ";TRUSTED_CONNECTION=yes;"
End Function

Function TableNameInUse(TableName As String) As Boolean
    'check for local tables, linked tables and queries (they all share the same namespace)
    TableNameInUse = DCount("*", "MSYSObjects", "(Type = 4 or type=1 or type=5) AND [Name]='" & TableName & "'") > 0
End Function

Function IsLinkedTable(TableName As String) As Boolean
    IsLinkedTable = DCount("*", "MSYSObjects", "(Type = 4) AND [Name]='" & TableName & "'") > 0
End Function

【问题讨论】:

  • 如果tdfLinked是新创建的,你为什么还要创建tdfLinked.RefreshLink
  • 哦,那是因为它已经存在了。我正在重新链接它。
  • 您过于复杂了。没有理由删除链接表,只需设置新的/修改后的 Connect 并执行 RefreshLink。
  • 也许我误读了您的代码,但在我看来,您正在删除链接,然后使用更新的连接信息重新创建它 (CreateTableDef)。如果您只是按照 Gustav 的建议更改现有链接的 .Connect 属性,那么您将调用 RefreshLink 以向 Access 发出信号,它需要更新它存储的有关链接表的元数据。
  • 试试这个。 CurrentDB.TableDefs(TableName).RefreshLink 代替。您还确定要添加带有追加的字段吗?

标签: sql-server ms-access vba linked-tables


【解决方案1】:

这是一个您应该能够采用的经过验证的示例:

Public Function AttachSqlServer( _
    ByVal Hostname As String, _
    ByVal Database As String, _
    ByVal Username As String, _
    ByVal Password As String) _
    As Boolean

' Attach all tables linked via ODBC to SQL Server or Azure SQL.
' 2016-04-24. Cactus Data ApS, CPH.

    Const cstrQuery1    As String = "_Template"
    Const cstrQuery2    As String = "_TemplateRead"
    Const cstrQuery3    As String = "VerifyConnection"

    Const cstrDbType    As String = "ODBC"
    Const cstrAcPrefix  As String = "dbo_"

    Dim dbs             As DAO.Database
    Dim tdf             As DAO.TableDef
    Dim strConnect      As String
    Dim strName         As String

    On Error GoTo Err_AttachSqlServer

    Set dbs = CurrentDb
    strConnect = ConnectionString(Hostname, Database, Username, Password)

    For Each tdf In dbs.TableDefs
        strName = tdf.Name
        If Asc(strName) <> Asc("~") Then
            If InStr(tdf.Connect, cstrDbType) = 1 Then
                If Left(strName, Len(cstrAcPrefix)) = cstrAcPrefix Then
                    tdf.Name = Mid(strName, Len(cstrAcPrefix) + 1)
                End If
                tdf.Connect = strConnect
                tdf.RefreshLink
                Debug.Print Timer, tdf.Name, tdf.SourceTableName, tdf.Connect
                DoEvents
            End If
        End If
    Next
    dbs.QueryDefs(cstrQuery1).Connect = strConnect
    dbs.QueryDefs(cstrQuery2).Connect = strConnect
    dbs.QueryDefs(cstrQuery3).Connect = strConnect
    Debug.Print "Done!"

    AttachSqlServer = True

Exit_AttachSqlServer:
    Set tdf = Nothing
    Set dbs = Nothing
    Exit Function

Err_AttachSqlServer:
    Call ErrorMox
    Resume Exit_AttachSqlServer

End Function

【讨论】:

  • 我正在连接到正在重新链接的数据库之外的数据库。上面的代码似乎意味着它连接到一个本地,其中正在运行的模块位于 .mdb 文件中。我连接的那个不包含模块,它是从一个单独的.mdb 调用的
猜你喜欢
  • 2011-03-16
  • 2011-07-07
  • 2017-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多