これは、DSNがないためではなく、VBAを介して作成したためです。アクセスGUIを介してビューをリンクすると、主キーの入力を求められます。
ただし、VBAを介すると、主キーがわからないため、リンクされたビューは更新できません。テーブルを使用すると、AccessはODBCを介して主キーを自動的に取得するため、テーブルは機能します。
解決策: VBAを介してビューをリンクした後、主キーを設定します:
S = "CREATE INDEX PrimaryKey ON MyViewName (MyPrimaryKeyField) WITH PRIMARY"
DB.Execute S
多くのビューがあり、それらを定期的に再リンクする場合(たとえば、開発データベースから本番データベースに移動する場合)、それらの名前とPKをハードコーディングすることは実用的ではなくなります。リンクされたビューからすべての主キーインデックスを取得し、リンク後にそれらを再作成する関数を作成しました。
必要に応じて、掘り下げることができます。
編集:
これが私がしていることです:
' 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
テーブルをリンクしたり、初めて表示したりするには 、私はこれを使用します(strTableはテーブル/ビュー名です):
DoCmd.TransferDatabase acLink, "ODBC", ODBC_String(), acTable, strTable, strTable, False, True
テーブルの場合、主キー(PK)は自動的に決定されます。ビューの場合、ビューを手動でリンクするのと同じように、[アクセス]ダイアログウィンドウでPKを指定します。
PK情報はリンクされたビューのTableDefオブジェクトに格納されるため、どこにもハードコーディングする必要はありません。 。
リンクされたすべてのビューのPK情報を保存するために、次のテーブルがあります(簡単にするためにAccessフロントエンドのローカルテーブルです):
t_LinkedViewPK
ViewName Text(100)
IndexFields Text(255)
そしてこの機能。すべてのビュー(およびのみ ビュー)は「v_ *」と呼ばれるので、名前で一覧表示できます。
TableDefオブジェクトから、テーブルを指しているのかビューを指しているのかを判断できるかどうかは実際にはわかりません。
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
テーブルまたはビューの構造を変更したり、ソースデータベースを変更したりする場合(これは、ODBC_String()
の出力を変更することによって行われます。 )、私はこの関数を呼び出します:
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
注:
テーブルの代わりにt_LinkedViewPK
、辞書オブジェクトを使用できます。しかし、これを開発する際に、実際のテーブルとして持つことは非常に役に立ちました。