2009-02-27 11 views
7

एक आम पर्याप्त समस्या यह लगता है, लेकिन सबसे समाधान एकाधिक SQL कमान्ड, जो कुछ मेरा मानना ​​है कि एडीओ/VBA के साथ नहीं किया जा सकता श्रृंखलाबद्ध का उल्लेख (मैं हालांकि इस संबंध में गलत दिखाए जाने के लिए खुशी होगी)।एक्सेल वीबीए का उपयोग कर नए डाले गए रिकॉर्ड की आईडी कैसे प्राप्त करें?

मैं वर्तमान में तो मेरी नई रिकॉर्ड सम्मिलित (मुझे आशा है) गारंटी नहीं है कि केवल नव डाला रिकॉर्ड वापस किया जा सकता पर्याप्त क्षेत्रों का उपयोग कर एक का चयन क्वेरी चलाते हैं। मेरे डेटाबेस को एक ही समय में एक से अधिक व्यक्तियों द्वारा उपयोग किया जाता है (प्रश्नों के बीच होने वाले किसी अन्य सम्मिलन का नगण्य जोखिम) और तालिकाओं की संरचना के कारण, नए रिकॉर्ड की पहचान करना आमतौर पर बहुत आसान होता है।

अब मैं एक मेज है कि विशिष्टता के लिए ज्यादा गुंजाइश, कृत्रिम प्राथमिक कुंजी में अन्य की तुलना में नहीं है अद्यतन करने के लिए कोशिश कर रहा हूँ। इसका मतलब है कि एक नया खतरा अनूठा नहीं हो सकता है, और मैं विशिष्टता को मजबूर करने के लिए एक फ़ील्ड जोड़ने के लिए नाराज हूं।

क्या कोई पहुँच तालिका में एक रिकॉर्ड डालने के लिए सबसे अच्छा तरीका है तो इस स्थिति में एक्सेल से नए प्राथमिक कुंजी क्वेरी है?

उत्तर के लिए धन्यवाद। मैंने @@IDENTITY काम करने की कोशिश की है, लेकिन यह हमेशा नीचे दिए गए कोड का उपयोग करके 0 लौटाता है।

Private Sub getIdentityTest() 
    Dim myRecordset As New ADODB.Recordset 
    Dim SQL As String, SQL2 As String 

    SQL = "INSERT INTO tblTasks (discipline,task,owner,unit,minutes) VALUES (""testDisc3-3"",""testTask"",""testOwner"",""testUnit"",1);" 
    SQL2 = "SELECT @@identity AS NewID FROM tblTasks;" 

    If databaseConnection Is Nothing Then 
     createDBConnection 
    End If 

    With databaseConnection 
     .Open dbConnectionString 
     .Execute (SQL) 
     .Close 
    End With 

    myRecordset.Open SQL2, dbConnectionString, adOpenStatic, adLockReadOnly 

    Debug.Print myRecordset.Fields("NewID") 

    myRecordset.Close 

    Set myRecordset = Nothing 
End Sub 

कुछ भी जिम्मेदार होने का खड़ा है?

हालांकि, चेतावनियां सहायक के रेनॉड द्वारा आपूर्ति को देखते हुए (नीचे) क्या कोई अन्य विधि के साथ के रूप में @@IDENTITY उपयोग करने के साथ लगभग उतना ही जोखिम लगता है, इसलिए मैं अब के लिए SELECT MAX का उपयोग कर का सहारा लिया गया है। भविष्य के संदर्भ के लिए हालांकि मुझे यह देखने में दिलचस्पी होगी कि ऊपर दिए गए मेरे प्रयास में क्या गलत है।

+0

का उपयोग करते हुए 'Max' मुश्किल हो सकता है ...: वास्तव में, आप भी तालिका निर्दिष्ट करने की आवश्यकता नहीं है। यदि आप केवल एक ही रिकॉर्डिंग रिकॉर्ड हैं, तो आगे बढ़ें। –

उत्तर

12

अपने प्रश्न के बारे में:

अब मैं एक तालिका अद्यतन करने के लिए है कि नहीं है कोशिश कर रहा हूँ हवलदार विशिष्टता के लिए कृत्रिम प्राथमिक कुंजी के अलावा अन्य विशिष्टता। इसका मतलब है एक जोखिम है कि नया रिकॉर्ड अद्वितीय नहीं हो सकता है, और मैं से नाराज हूं, विशिष्टता को मजबूर करने के लिए केवल एक फ़ील्ड जोड़ें।

आप हैं अपने प्राथमिक कुंजी के लिए एक AutoIncrement का उपयोग कर, तो आप विशिष्टता है और आप SELECT @@Identity; का उपयोग पिछले स्वत: जनरेट की आईडी मूल्य प्राप्त करने के (नीचे चेतावनियां देखें) कर सकता है।

आप नहीं autoincrement का उपयोग कर, और आप Access से रिकॉर्ड डालने रहे हैं, लेकिन आप Excel से पिछले एक को पुनः प्राप्त करना चाहते हैं:,

  • सुनिश्चित करें कि आपके प्राथमिक कुंजी sortable हो ताकि आप कर सकते हैं

    SELECT MAX(MyPrimaryField) FROM MyTable; 
    SELECT TOP 1 MyPrimaryField FROM MyTable ORDER BY MyPrimaryField DESC; 
    
  • या, यदि आपकी प्राथमिक क्षेत्र छँटाई आपने पिछले एक नहीं देना होगा, तो आप एक दिनांक समय क्षेत्र को जोड़ने के लिए की आवश्यकता होगी (जैसे कि InsertedDate) एक: पिछले एक इनमें से किसी की तरह एक क्वेरी का उपयोग कर पाने के nd वर्तमान दिनांक और समय आपको लगता है कि तालिका में एक नया रिकॉर्ड बनाने के लिए हर समय की बचत तो आप इस तरह पिछले एक मिल सकता है:

    SELECT TOP 1 MyPrimaryField FROM MyTable ORDER BY InsertedDate DESC; 
    

इन दोनों स्थितियों में, मुझे लगता है कि आप एक जोड़ने मिलेगा से निपटने के लिए बहुत आसान होने के रूप में AutoIncrement प्राथमिक कुंजी:

  • यह आप खर्च करने के लिए नहीं जा रहा है बहुत

  • यह आप अपने रिकॉर्ड की विशिष्टता की गारंटी करने जा रहा है बिना इसके बारे में सोचने के लिए

  • यह आपके लिए सबसे हाल ही में रिकॉर्ड लेने के लिए के लिए बनाने के लिए जा रहा है, या तो @@Identity का उपयोग कर या प्राथमिक कुंजी द्वारा छँटाई या Max() हो रही के माध्यम से।

    • एक प्रश्न का उपयोग कर एक डेटा लिंक बनाने, ताकि आप परिणाम का उपयोग कर सकते हैं:

    एक्सेल से

    एक्सेल में डेटा प्राप्त करने के लिए, आप विकल्पों की एक जोड़ी सीधे एक सेल या एक सीमा में। VBA से

  • क्वेरी:

    Sub GetLastPrimaryKey(PrimaryField as string, Table as string) as variant 
        Dim con As String 
        Dim rs As ADODB.Recordset 
        Dim sql As String 
        con = "Provider=Microsoft.ACE.OLEDB.12.0;" & _ 
          "Data Source= ; C:\myDatabase.accdb" 
        sql = "SELECT MAX([" & PrimaryField & "]) FROM [" & MyTable & "];" 
        Set rs = New ADODB.Recordset 
        rs.Open sql, con, adOpenStatic, adLockReadOnly 
        GetLastPrimaryKey = rs.Fields(0).Value 
        rs.Close 
        Set rs = Nothing 
    End Sub 
    

नोट के बारे में @@Identity

आप careful of the caveats होने के लिए जब मानक एक्सेस डेटाबेस में @@Identity का उपयोग कर (*) होना:

  • यह केवल ऑटोइंक्चर पहचान फ़ील्ड के साथ काम करता है।

  • यह केवल उपलब्ध है अगर आप ADO का उपयोग करें और SELECT @@IDENTITY;

  • यह हाल ही में उपयोग काउंटर देता है, but that's for all tables चलाते हैं। आप एमएस एक्सेस में एक विशिष्ट तालिका के लिए काउंटर वापस करने के लिए इसका उपयोग नहीं कर सकते (जहां तक ​​मुझे पता है, अगर आप FROM mytable का उपयोग कर तालिका निर्दिष्ट करते हैं, तो इसे अनदेखा कर दिया जाता है)।
    संक्षेप में, वापस लौटाया गया मूल्य आपके द्वारा अपेक्षित नहीं हो सकता है।

  • गलत जवाब प्राप्त करने के जोखिम को कम करने के लिए आपको इसे INSERT के बाद सीधे पूछना चाहिए।
    इसका मतलब है कि यदि आप एक समय में अपना डेटा डाल रहे हैं और किसी अन्य समय (या दूसरी जगह) पर अंतिम आईडी प्राप्त करने की आवश्यकता है, तो यह काम नहीं करेगा।

  • अंतिम लेकिन कम से कम नहीं, चर केवल तभी सेट किया जाता है जब प्रोग्रामिंग कोड के माध्यम से रिकॉर्ड डाले जाते हैं।
    इसका मतलब है कि रिकॉर्ड यूजर इंटरफेस के माध्यम से जोड़ा गया था, @@IDENTITY सेट नहीं किया जाएगा।

(*): बस स्पष्ट होना, @@IDENTITY अलग ढंग से व्यवहार करती है, और एक अधिक भविष्य कहनेवाला रास्ते में, यदि आप अपने डेटाबेस के लिए एएनएसआई-92 एसक्यूएल मोड का उपयोग करें।
मुद्दा यह है कि एएनएसआई 9 2 में से थोड़ा अलग सिंटैक्स है जो एक्सेस द्वारा समर्थित एएनएसआई 89 स्वाद है और इसका उपयोग SQL सर्वर के साथ संगतता बढ़ाने के लिए है जब एक्सेस को फ्रंट एंड के रूप में उपयोग किया जाता है।

+1

"चयन करें MAX" वास्तविक खराब गंध करता है। हालांकि यह वर्णित परिस्थितियों में काम करेगा, क्योंकि सभी मामलों में चीजें समय के साथ बदलती हैं, और इससे पहले कि आप इसे जानते हों, यह कोड असफल हो जाएगा! सुगंधित कोड न करें, अगले व्यक्ति के बारे में सोचें – TFD

+1

@ टीएफडी: सिद्धांत पर सहमत हुए, लेकिन कम से कम एमएस एक्सेस में पोस्टर क्या चाहता है, हासिल करने के कई तरीके नहीं हैं। यह हमेशा एक व्यापार बंद होने जा रहा है। मैक्स() स्ट्रिंग समेत अधिकांश डेटा प्रकारों के लिए ठीक काम करेगा, हालांकि मैं मानता हूं कि ऐसे मामले हैं जहां आप जो चाहते हैं उसे प्राप्त नहीं कर सकते हैं। –

+0

विस्तृत उत्तर के लिए धन्यवाद, और @@ पहचान के बारे में सहायक चेतावनी के लिए - अगर मैं कर सकता तो मैं वोट दूंगा। – Lunatik

7

कृत्रिम कुंजी एक autonumber है, तो आप @@ पहचान का उपयोग कर सकते हैं।

ध्यान दें कि इन दोनों उदाहरणों के साथ, लेनदेन अन्य घटनाओं से अलग है, इसलिए वापस लौटाई गई पहचान सिर्फ एक डाली गई है। आप Debug.Print db.Records पर कोड को रोककर इसका परीक्षण कर सकते हैं। प्रभावित या डीबग.प्रिंट lngRecs और तालिका 1 में मैन्युअल रूप से रिकॉर्ड डालने, कोड जारी रखें और ध्यान दें कि लौटाई गई पहचान मैन्युअल रूप से डाले गए रिकॉर्ड की नहीं है, लेकिन पिछले कोड द्वारा दर्ज रिकॉर्ड।

डीएओ उदाहरण

'Reference: Microsoft DAO 3.6 Object Library ' 
Dim db As DAO.Database 
Dim rs As DAO.Recordset 

Set db = CurrentDb 

db.Execute ("INSERT INTO table1 (field1, Crdate) " _ 
      & "VALUES (46, #" & Format(Date, "yyyy/mm/dd") & "#)") 
Debug.Print db.RecordsAffected 
Set rs = db.OpenRecordset("SELECT @@identity AS NewID FROM table1") 
Debug.Print rs.Fields("NewID") 

एडीओ उदाहरण

Dim cn As New ADODB.Connection 
Dim rs As New ADODB.Recordset 

Set cn = CurrentProject.Connection 

cn.Execute ("INSERT INTO table1 (field1, Crdate) " _ 
      & "VALUES (46, #" & Format(Date, "yyyy/mm/dd") & "#)"), lngRecs 
Debug.Print lngRecs 
rs.Open "SELECT @@identity AS NewID FROM table1", cn 
Debug.Print rs.Fields("NewID") 
+0

धन्यवाद, यह एक कोशिश करेगा। – Lunatik

+0

इसके साथ मुझे 3001 त्रुटि मिलती है "तर्क गलत प्रकार के हैं, स्वीकार्य सीमा से बाहर हैं, या एक दूसरे के साथ संघर्ष में हैं"। मुझे ऑब्जेक्ट ब्राउज़र में "OpenRecordset" भी नहीं मिल रहा है, जो कुछ हद तक चीजों को समझा सकता है। मेरे पास कोई संदर्भ के रूप में एडीओ 2.6 लाइब्रेरी सेट है, यदि यह कोई मदद है। – Lunatik

+0

कोड डीएओ के लिए है, जो आमतौर पर एमएस एक्सेस के लिए सबसे अच्छा है। यदि आपको इसकी ज़रूरत है, तो मुझे एडीओ में कुछ चलाने में सक्षम होना चाहिए। – Fionnuala

0

निम्नलिखित मैक्रो code.First कोड विंडो में नियंत्रण बॉक्स के चादर करने के लिए एक आदेश बटन जोड़ने के लिए और निम्नलिखित कोड पेस्ट

Private Sub CommandButton1_Click() 
    MsgBox GetLastPrimaryKey 
End Sub 

Private Function GetLastPrimaryKey() As String 
Dim con As String 
Dim cn As ADODB.Connection 
Dim rs As ADODB.Recordset 
Dim sql As String 
con = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\myaccess.mdb;Persist Security Info=False" 
sql = "SELECT MAX(id) FROM tblMyTable" 

Set cn = New ADODB.Connection 
Set rs = New ADODB.Recordset 
cn.Open con 
rs.Open sql, cn, 3, 3, 1 
If rs.RecordCount <> 0 Then 
    GetLastPrimaryKey = rs.Fields(0).Value 
End If 
rs.Close 
cn.Close 
Set rs = Nothing 
Set cn = Nothing 
End Function 
3

पुन प्रयास करें: "मैं पाने के लिए @@ पहचान काम कर की कोशिश की है, लेकिन यह हमेशा नीचे दिए गए कोड का उपयोग कर 0 देता है। "

आपका कोड विभिन्न कनेक्शन ऑब्जेक्ट्स के माध्यम से SQL और SQL2 भेजता है। मुझे नहीं लगता कि @@identity शून्य से अलग कुछ भी लौटाएगा जबतक कि आप उसी कनेक्शन से पूछें जहां आपने अपना INSERT कथन निष्पादित किया था।

इस बदलने का प्रयास करें:

myRecordset.Open SQL2, dbConnectionString, adOpenStatic, adLockReadOnly 

रहे हैं:

myRecordset.Open SQL2, databaseConnection, adOpenStatic, adLockReadOnly 
+0

डी ओह, मुझे विभिन्न परियोजनाओं से कोड के बिट्स का पुन: उपयोग करने के लिए यही मिलता है! मैं फिलहाल एक और प्रोजेक्ट पर हूं, लेकिन आपका सुझाव सही समझ में आता है और मुझे मौका मिलने पर मैं कोशिश करूंगा। – Lunatik

0

यहाँ मेरी समाधान है कि @@ सूचकांक या मैक्स का उपयोग नहीं करता है।

Const connectionString = "Provider=SQLOLEDB; Data Source=SomeSource; Initial Catalog=SomeDB; User Id=YouIDHere; Password=YourPassword" 
Const RecordsSQL = "SELECT * FROM ThatOneTable" 

Private Sub InsertRecordAndGetID() 
    Set connection = New ADODB.connection 
    connection.connectionString = connectionString 
    connection.Open 
    Set recordset = New ADODB.recordset 
    recordset.Open SQL, connection, adOpenKeyset, adLockOptimistic 

    With recordset 
     .AddNew 
     !Field1 = Value1 
     !Field2 = Value2 
    End With 

    recordset.MoveLast 
    ID = recordset.Fields("id") 

End Sub 

आनंद लें!

0

पार्टी के लिए 8 साल देर से ... आप जिस समस्या का सामना कर रहे हैं वह यह है कि आप नया कनेक्शन बनाने के लिए dbConnectionString का उपयोग कर रहे हैं। @@ पहचान आपके द्वारा उपयोग किए जा रहे कनेक्शन के लिए विशिष्ट है।

पहले, मूल कनेक्शन बंद नहीं करते

'.Close 

कनेक्शन आपने पहले डालने

myRecordset.Open SQL2, databaseConnection, adOpenStatic, adLockReadOnly 

के लिए इस्तेमाल के साथ बदलें

myRecordset.Open SQL2, dbConnectionString, adOpenStatic, adLockReadOnly 

और आप किया गया है था सब तैयार।अगर किसी रिकॉर्ड डालने जाता है, तो यह आपको एक और रिकार्ड की आईडी दे सकता है

SQL2 = "SELECT @@identity AS NewID"