ऐसा इसलिए नहीं है क्योंकि यह डीएसएन-कम है, बल्कि इसलिए कि आपने इसे वीबीए के माध्यम से बनाया है। यदि आप एक्सेस GUI के माध्यम से दृश्य को लिंक करते हैं, तो यह आपसे प्राथमिक कुंजी मांगता है।
लेकिन वीबीए के माध्यम से, यह प्राथमिक कुंजी नहीं जानता है, इसलिए लिंक किया गया दृश्य अद्यतन करने योग्य नहीं है। तालिका के साथ, ओडीबीसी के माध्यम से एक्सेस को प्राथमिक कुंजी स्वचालित रूप से मिलती है, इसलिए तालिका काम करती है।
समाधान: VBA के माध्यम से दृश्य को जोड़ने के बाद प्राथमिक कुंजी सेट करें:
S = "CREATE INDEX PrimaryKey ON MyViewName (MyPrimaryKeyField) WITH PRIMARY"
DB.Execute S
यदि आपके पास कई विचार हैं, और उन्हें नियमित रूप से फिर से लिंक करें (जैसे देव से उत्पादन डेटाबेस में जाना), तो उनके नाम और पीके को हार्डकोड करना अव्यावहारिक हो जाता है। मैंने लिंक किए गए दृश्यों से सभी प्राथमिक कुंजी अनुक्रमणिका पुनर्प्राप्त करने और लिंक करने के बाद उन्हें फिर से बनाने के लिए एक फ़ंक्शन लिखा था।
यदि आप चाहें, तो मैं इसे खोद सकता हूं।
संपादित करें:
मैं यही करता हूं:
' 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
तालिकाओं के लिए, प्राथमिक कुंजी (पीके) स्वचालित रूप से निर्धारित होती है। एक दृश्य के लिए, मुझे पीके निर्दिष्ट करने के लिए एक्सेस डायलॉग विंडो मिलती है, जैसे कि मैं मैन्युअल रूप से दृश्य को लिंक करता हूं। पीके जानकारी टेबलडिफ ऑब्जेक्ट में लिंक किए गए दृश्य के लिए संग्रहीत होती है, इसलिए मुझे इसे कहीं भी हार्डकोड नहीं करना पड़ता है ।
सभी लिंक किए गए दृश्यों के लिए पीके जानकारी संग्रहीत करने के लिए, मेरे पास यह तालिका है (यह सरलता के लिए एक्सेस फ्रंटएंड में एक स्थानीय तालिका है):
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
, एक शब्दकोश वस्तु का उपयोग किया जा सकता है। लेकिन इसे विकसित करते समय, इसे वास्तविक तालिका के रूप में रखना बहुत उपयोगी था।