sql >> Databasteknik >  >> RDS >> Sqlserver

Hur man programmatiskt skapar en ODBC-länkad tabell till en SQL Server View och får den att vara redigerbar?

Det är inte för att det är DSN-fritt, utan för att du skapat det via VBA. Om du länkar vyn via Access GUI, ber den dig om primärnyckeln.

Men via VBA känner den inte till primärnyckeln, så den länkade vyn kan inte uppdateras. Med en tabell får Access primärnyckeln automatiskt via ODBC, så tabellen fungerar.

Lösning: ställ in primärnyckeln efter att ha länkat vyn via VBA:

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

Om du har många vyer och återlänkar dem regelbundet (t.ex. går från dev till produktionsdatabas), blir det opraktiskt att hårdkoda deras namn och PK:er. Jag skrev en funktion för att hämta alla primära nyckelindex från länkade vyer och återskapa dem efter länkning.
Om du vill kan jag gräva upp det.

Redigera:
Det här är vad jag gör:

' 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

För att länka en tabell eller vy första gången , jag använder detta (strTable är tabellen/vyns namn):

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

För tabeller bestäms primärnyckeln (PK) automatiskt. För en vy får jag Access-dialogfönstret för att specificera PK, samma som om jag länkar vyn manuellt.
PK-informationen lagras i TableDef-objektet för den länkade vyn, så jag behöver aldrig hårdkoda den någonstans .

För att lagra PK-informationen för alla länkade vyer har jag den här tabellen (det är en lokal tabell i Access-gränssnittet för enkelhetens skull):

t_LinkedViewPK
    ViewName        Text(100)
    IndexFields     Text(255)

och denna funktion. Alla vyer (och endast Views) kallas "v_*", så jag kan lista dem efter namn.
Jag är faktiskt inte säker på om du kan avgöra från ett TableDef-objekt om det pekar på en tabell eller vy.

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

När jag gör ändringar i tabell- eller vystrukturer, eller ändrar källdatabasen (detta görs genom att ändra utdata från ODBC_String() ), kallar jag den här funktionen:

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

Obs!
Istället för tabellen t_LinkedViewPK , kan ett ordboksobjekt användas. Men under utvecklingen av detta var det mycket användbart att ha det som en faktisk tabell.



  1. MySQL får saknade ID från tabellen

  2. Skicka flera uppsättningar eller matriser av värden till en funktion

  3. Infoga bild i SQL Server 2005 Image Field med endast SQL

  4. FIX:MySQL – VÄLJ kommando nekad till användare