sql >> Database >  >> RDS >> Sqlserver

Hoe maak je programmatisch een ODBC-gekoppelde tabel aan een SQL Server-weergave en bewerkbaar?

Het is niet omdat het DSN-minder is, maar omdat je het via VBA hebt gemaakt. Als u de weergave koppelt via de Access GUI, wordt u om de primaire sleutel gevraagd.

Maar via VBA kent het de primaire sleutel niet, dus de gekoppelde weergave kan niet worden bijgewerkt. Bij een tabel krijgt Access de primaire sleutel automatisch via ODBC, dus de tabel werkt.

Oplossing: stel de primaire sleutel in na het koppelen van de weergave via VBA:

S = "CREATE INDEX PrimaryKey ON MyViewName (MyPrimaryKeyField) WITH PRIMARY"
DB.Execute S

Als je veel views hebt en ze regelmatig opnieuw koppelt (bijvoorbeeld van dev naar de productiedatabase), wordt het onpraktisch om hun namen en PK's hard te coderen. Ik heb een functie geschreven om alle primaire-sleutelindexen van gekoppelde weergaven op te halen en ze na het koppelen opnieuw te maken.
Als je wilt, kan ik het opgraven.

Bewerken:
Dit is wat ik doe:

' This function returns the full DSN-less connect string
Private Function ODBC_String() As String
    ' In the real world there are several constants and variable in there
    ODBC_String = "ODBC;DRIVER={SQL Server};SERVER=aaa;DATABASE=bbb;UID=ccc;PWD=ccc;LANGUAGE=us_english;TRUSTED_CONNECTION=No"
End Function

Een tafel koppelen of de eerste keer bekijken , ik gebruik dit (strTable is de naam van de tabel/weergave):

DoCmd.TransferDatabase acLink, "ODBC", ODBC_String(), acTable, strTable, strTable, False, True

Voor tabellen wordt de primaire sleutel (PK) automatisch bepaald. Voor een weergave krijg ik het Access-dialoogvenster om de PK te specificeren, hetzelfde als wanneer ik de weergave handmatig koppel.
De PK-informatie wordt opgeslagen in het TableDef-object voor de gekoppelde weergave, dus ik hoef deze nooit ergens hard te coderen .

Om de PK-informatie voor alle gekoppelde weergaven op te slaan, heb ik deze tabel (het is een lokale tabel in de Access-frontend voor de eenvoud):

t_LinkedViewPK
    ViewName        Text(100)
    IndexFields     Text(255)

en deze functie. Alle weergaven (en alleen Views) worden "v_*" genoemd, dus ik kan ze bij naam noemen.
Ik weet eigenlijk niet zeker of je aan de hand van een TableDef-object kunt bepalen of het naar een tabel of view verwijst.

Private Sub StoreViewPKs()

    Dim TD As TableDef
    Dim idx As index
    Dim FD As Field
    Dim RS As Recordset
    Dim S As String

    ' DB is a global Database object, set to CurrentDB
    DB.Execute "Delete * From t_LinkedViewPK"
    Set RS = DB.OpenRecordset("t_LinkedViewPK")

    For Each TD In DB.TableDefs
        If TD.Name Like "v_*" Then
            ' Views must have exactly one index. If not: panic!
            If TD.Indexes.Count <> 1 Then
                MsgBox "View " & TD.Name & " has " & TD.Indexes.Count & " Indizes.", vbCritical
                Stop
            End If

            Set idx = TD.Indexes(0)
            ' Build field list (the index may contain multiple fields)
            S = ""
            For Each FD In idx.Fields
                If S <> "" Then S = S & ", "
                S = S & FD.Name
            Next FD

            RS.AddNew
            RS!ViewName = TD.Name
            RS!IndexFields = S
            RS.Update
        End If
    Next TD

    RS.Close

End Sub

Wanneer ik wijzigingen aanbreng in tabel- of weergavestructuren, of de brondatabase wijzig (dit wordt gedaan door de uitvoer van ODBC_String() te wijzigen ), noem ik deze functie:

Public Function Sql_RefreshTables()

    Dim TD As TableDef
    Dim S As String
    Dim IdxFlds As String

    DB.TableDefs.Refresh

    ' save current Indizes for Views (recreated after .RefreshLink)
    Call StoreViewPKs

    For Each TD In DB.TableDefs
        If Len(TD.Connect) > 0 Then
            If Left(TD.Connect, 5) = "ODBC;" Then

                Debug.Print "Updating " & TD.Name
                TD.Connect = ODBC_String()
                TD.RefreshLink

                ' View?
                If TD.Name Like "v_*" Then
                    IdxFlds = Nz(DLookup("IndexFields", "t_LinkedViewPK", "ViewName = '" & TD.Name & "'"))
                    If IdxFlds = "" Then Stop

                    ' Create PK
                    S = "CREATE INDEX PrimaryKey ON " & TD.Name & " (" & IdxFlds & ") WITH PRIMARY"
                    DB.Execute S
                End If

            End If
        End If
    Next TD

    DB.TableDefs.Refresh

End Function

Opmerking:
In plaats van de tabel t_LinkedViewPK , kan een woordenboekobject worden gebruikt. Maar tijdens het ontwikkelen hiervan was het erg handig om het als een echte tafel te hebben.



  1. Een Access-database koppelen aan SQL Server in Access 2016

  2. Wat is het equivalent van SQL Server APPLY in Oracle?

  3. Problemen oplossen wanneer er geen werkthreads meer zijn

  4. Hoe pascal zaak te forceren met Oracle's Entity Framework-ondersteuning?