MS Access与SQL Server视图相链接

4
我们正在升级一个使用Access数据库的系统,以便使用SQL Server作为其数据存储。但是我们遇到了一个问题。
这个数据库连接了2个SQL数据库,所以我们想简化一下,将主数据库中的每个表都链接到次要数据库中,这样Access只需要与一个SQL数据库直接通信即可。
当我们将Access链接到数据库视图时,我们选择了哪些字段是主键,因此这些视图不是只读的。我们有标准代码,可以在打开数据库时刷新所有链接以获取任何更改,但由于丢失了主键信息,链接的视图变为只读。
有没有一种方法可以在保留主键信息的情况下刷新视图链接呢?
约翰

1
你是如何刷新链接的?另外,SQL Server中的数据库结构是否经常更改以获取该信息? - shahkalpesh
3个回答

4
我已经包含了整个ODBC重连功能的代码。这个函数的前提是我有一个名为rtblODBC的表,其中存储了我需要重新连接的所有信息。如果您实现此功能,则无需担心连接到多个SQL数据库,因为每个要重新连接的表都具有自己的连接字符串。
在接近结尾处,您将看到我使用DAO来重新创建主键,使用db.Execute "CREATE INDEX " & sPrimaryKeyName & " ON " & sLocalTableName & "(" & sPrimaryKeyField & ")WITH PRIMARY;"。
如果您有任何问题,请随时问我。
Public Function fnReconnectODBC( _
    Optional bForceReconnect As Boolean _
    ) As Boolean
    ' Comments  :
    ' Parameters: bForceReconnect -
    ' Returns   : Boolean -
    ' Modified  :
    ' --------------------------------------------------'

    On Error GoTo Err_fnReconnectODBC

    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim tdf As DAO.TableDef
    Dim sPrimaryKeyName As String
    Dim sPrimaryKeyField As String
    Dim sLocalTableName As String
    Dim strConnect As String
    Dim varRet As Variant

    Dim con As ADODB.Connection
    Dim rst As ADODB.Recordset
    Dim sSQL As String

    If IsMissing(bForceReconnect) Then

        bForceReconnect = False

    End If

    sSQL = "SELECT rtblODBC.LocalTableName, MSysObjects.Name, MSysObjects.ForeignName, rtblODBC.SourceTableName, MSysObjects.Connect, rtblODBC.ConnectString " _
         & "FROM MSysObjects RIGHT JOIN rtblODBC ON MSysObjects.Name = rtblODBC.LocalTableName " _
         & "WHERE (((rtblODBC.ConnectString)<>'ODBC;' & [Connect]));"

    Set con = Access.CurrentProject.Connection
    Set rst = New ADODB.Recordset

    rst.Open sSQL, con, adOpenDynamic, adLockOptimistic

        'Test the recordset to see if any tables in rtblODBC (needed tables) are missing from the MSysObjects (actual tables)
        If rst.BOF And rst.EOF And bForceReconnect = False Then

            'No missing tables identified
            fnReconnectODBC = True

        Else

            'Table returned information, we don't have a perfect match, time to relink
            Set db = CurrentDb
            Set rs = db.OpenRecordset("rtblODBC", dbOpenSnapshot)

                'For each table definition in the database collection of tables
                For Each tdf In db.TableDefs

                    'Set strConnect variable to table connection string
                    strConnect = tdf.Connect

                    If Len(strConnect) > 0 And Left(tdf.Name, 1) <> "~" Then

                        If Left(strConnect, 4) = "ODBC" Then

                            'If there is a connection string, and it's not a temp table, and it IS an odbc table
                            'Delete the table
                            DoCmd.DeleteObject acTable, tdf.Name

                        End If

                    End If

                Next

                'Relink tables from rtblODBC
                With rs

                    .MoveFirst

                    Do While Not .EOF

                        Set tdf = db.CreateTableDef(!localtablename, dbAttachSavePWD, !SourceTableName, !ConnectString)

                        varRet = SysCmd(acSysCmdSetStatus, "Relinking '" & !SourceTableName & "'")

                        db.TableDefs.Append tdf
                        db.TableDefs.Refresh

                        If Len(!PrimaryKeyName & "") > 0 And Len(!PrimaryKeyField & "") > 0 Then

                            sPrimaryKeyName = !PrimaryKeyName
                            sPrimaryKeyField = !PrimaryKeyField
                            sLocalTableName = !localtablename

                            db.Execute "CREATE INDEX " & sPrimaryKeyName & " ON " & sLocalTableName & "(" & sPrimaryKeyField & ")WITH PRIMARY;"

                        End If

                        db.TableDefs.Refresh

                        .MoveNext

                    Loop

                End With

            subTurnOffSubDataSheets

            fnReconnectODBC = True

        End If

    rst.Close
    Set rst = Nothing

    con.Close
    Set con = Nothing


Exit_fnReconnectODBC:

    Set tdf = Nothing
    Set rs = Nothing
    Set db = Nothing

    varRet = SysCmd(acSysCmdClearStatus)

    Exit Function

Err_fnReconnectODBC:

    fnReconnectODBC = False

    sPrompt = "Press OK to continue."
    vbMsg = MsgBox(sPrompt, vbOKOnly, "Error Reconnecting")
    If vbMsg = vbOK Then

        Resume Exit_fnReconnectODBC

    End If

End Function

David,很遗憾,当代码尝试附加tabledef时,我们遇到了错误3264。 - John
1
David,稍作修改,我们使用了DAO的refreshlink而不是删除和重新创建tabledef,然后创建了索引,现在一切都很好。感谢您的帮助。 - John

1
相当数量的无 DSN 代码重新链接访问表到 SQL Server 时,通常会先删除链接,再重新创建链接。代码然后设置连接字符串。因此,删除操作会导致您丢失主键是/仍然是什么。
我实际上建议您修改您的重链接代码,以避免删除表链接。
尝试类似以下的代码:
For Each tdfCurrent In dbCurrent.TableDefs
   If Len(tdfCurrent.Connect) > 0 Then
      If Left$(tdfCurrent.Connect, 5) = "ODBC;" Then
         strCon = "ODBC;DRIVER={sql server};" & _
           "SERVER=" & ServerName & ";" & _
           "DATABASE=" & DatabaseName & ";" & _
           "UID=" & UserID & ";" & _
           "PWD=" & USERpw & ";" & _
           "APP=Microsoft Office 2003;" & _
           "WSID=" & WSID & ";"
        End If
     End If
     tdfCurrent.Connect = strCon
     tdfCurrent.RefreshLink
  End If
Next tdfCurrent

0

这对我来说效果稍微好一点(请注意移动if语句的末尾):

Dim dbCurrent As Database
Set dbCurrent = CurrentDb()

StatusList.SetFocus
StatusList.AddItem ("starting... ")
I = DoEvents()
Dim tdfCurrent As DAO.TableDef
For Each tdfCurrent In dbCurrent.TableDefs
   If Len(tdfCurrent.Connect) > 0 Then
      If Left$(tdfCurrent.Connect, 5) = "ODBC;" Then
         strCon = "ODBC;DRIVER={sql server};" & _
           "SERVER=" & ServerName & ";" & _
           "DATABASE=" & DatabaseName & ";" & _
           "UID=" & UserID & ";" & _
           "PWD=" & USERpw & ";" & _
           "APP=Microsoft Office 2003;" & _
           "WSID=" & WSID & ";"

           StatusList.AddItem ("fixing " & tdfCurrent.Name)
        tdfCurrent.Connect = strCon
        tdfCurrent.RefreshLink
     End If
  End If
  I = DoEvents()
Next tdfCurrent

  StatusList.AddItem ("----Done.")

ODBC检查是正确的,即使“ODBC;”部分在MSysObjects视图中不显示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接