Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Jak programowo utworzyć tabelę połączoną ODBC z widokiem SQL Server i czy można ją edytować?

Nie dlatego, że jest pozbawiony DSN, ale dlatego, że stworzyłeś go za pomocą VBA. Jeśli połączysz widok za pomocą GUI programu Access, zostaniesz poproszony o klucz podstawowy.

Ale za pośrednictwem VBA nie zna klucza podstawowego, więc połączonego widoku nie można aktualizować. W przypadku tabeli program Access automatycznie pobiera klucz podstawowy przez ODBC, dzięki czemu tabela działa.

Rozwiązanie: ustaw klucz podstawowy po połączeniu widoku za pomocą VBA:

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

Jeśli masz wiele widoków i regularnie je łączysz (np. przechodząc z bazy deweloperskiej do produkcyjnej), niepraktyczne staje się zakodowanie ich nazw i PK na sztywno. Napisałem funkcję do pobierania wszystkich indeksów klucza głównego z połączonych widoków i ponownego ich tworzenia po połączeniu.
Jeśli chcesz, mogę to wykopać.

Edytuj:
Oto co robię:

' 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

Aby połączyć tabelę lub wyświetlić pierwszy raz , używam tego (strTable to nazwa tabeli/widoku):

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

W przypadku tabel klucz podstawowy (PK) jest określany automatycznie. W przypadku widoku otrzymuję okno dialogowe Access, aby określić PK, tak samo jak w przypadku ręcznego łączenia widoku.
Informacje PK są przechowywane w obiekcie TableDef dla połączonego widoku, więc nigdy nie muszę ich nigdzie kodować na stałe .

Aby przechowywać informacje PK dla wszystkich połączonych widoków, mam tę tabelę (dla uproszczenia jest to tabela lokalna w interfejsie Access):

t_LinkedViewPK
    ViewName        Text(100)
    IndexFields     Text(255)

i tę funkcję. Wszystkie widoki (i tylko Widoki) nazywają się „v_*”, więc mogę je wymienić według nazwy.
Właściwie nie jestem pewien, czy na podstawie obiektu TableDef można określić, czy wskazuje on na tabelę, czy na widok.

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

Kiedy wprowadzam zmiany w strukturach tabeli lub widoku lub zmieniam źródłową bazę danych (odbywa się to poprzez zmianę danych wyjściowych ODBC_String() ), nazywam tę funkcję:

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

Uwaga:
Zamiast tabeli t_LinkedViewPK , można użyć obiektu słownika. Ale podczas opracowywania tego bardzo przydatne było posiadanie go jako rzeczywistej tabeli.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zakres tabel tymczasowych w SQL Server

  2. Jak skonfigurować pocztę bazy danych w programie SQL Server (SSMS)

  3. Może SQL Server PIVOT?

  4. SQL, Pomocnicza tabela liczb

  5. 13 najlepszych praktyk w zakresie bezpieczeństwa SQL Server