sql >> Database teknologi >  >> RDS >> Sqlserver

Hvordan opretter man programmæssigt en ODBC-linket tabel til en SQL Server-visning og får den redigerbar?

Det er ikke fordi det er DSN-frit, men fordi du har oprettet det via VBA. Hvis du forbinder visningen via Access GUI, beder den dig om den primære nøgle.

Men via VBA kender den ikke den primære nøgle, så den linkede visning kan ikke opdateres. Med en tabel får Access primærnøglen automatisk via ODBC, så tabellen fungerer.

Løsning: indstil den primære nøgle efter at have linket visningen via VBA:

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

Hvis du har mange visninger og genlinker dem regelmæssigt (f.eks. går fra dev til produktionsdatabase), bliver det upraktisk at hardkode deres navne og PK'er. Jeg skrev en funktion til at hente alle primære nøgleindekser fra linkede visninger og genskabe dem efter linkning.
Hvis du vil, kan jeg grave det op.

Rediger:
Dette er, hvad jeg 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

For at linke en tabel eller visning første gang , jeg bruger dette (strTable er tabellen/visningsnavnet):

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

For tabeller bestemmes den primære nøgle (PK) automatisk. For en visning får jeg adgangsdialogvinduet til at angive PK'en, det samme som hvis jeg linker visningen manuelt.
PK-informationen er gemt i TableDef-objektet for den sammenkædede visning, så jeg behøver aldrig at hardkode den nogen steder .

For at gemme PK-oplysningerne for alle sammenkædede visninger har jeg denne tabel (det er en lokal tabel i Access-frontenden for nemheds skyld):

t_LinkedViewPK
    ViewName        Text(100)
    IndexFields     Text(255)

og denne funktion. Alle visninger (og kun). Views) kaldes "v_*", så jeg kan angive dem efter navn.
Jeg er faktisk ikke sikker på, om du ud fra et TableDef-objekt kan bestemme, om det peger på en tabel eller en visning.

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 jeg foretager ændringer i tabel- eller visningsstrukturer eller ændrer kildedatabasen (det gøres ved at ændre outputtet af ODBC_String() ), kalder jeg denne funktion:

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

Bemærk:
I stedet for tabellen t_LinkedViewPK , kunne et ordbogsobjekt bruges. Men under udviklingen af ​​dette, var det meget nyttigt at have det som en egentlig tabel.



  1. PHP + MySQL transaktionseksempler

  2. Hvordan skriver man IF ELSE-sætning i en MySQL-forespørgsel

  3. Få første dag i ugen i SQL Server

  4. Postgres - den sidste version 0.14.0 af pg gem giver fejl