2009-10-27 20 views
31

Mam tabelę JET z numerem automatycznym jako kluczem podstawowym i chciałbym wiedzieć, w jaki sposób mogę pobrać tę liczbę po wstawieniu wiersza. Myślałem o użyciu MAX(), aby pobrać wiersz o najwyższej wartości, ale nie jestem pewien, jak wiarygodne byłoby to. Niektóre przykładowy kod:Wartość automatycznego numerowania ostatniego wstawionego wiersza - MS Access/VBA

Dim query As String 
Dim newRow As Integer 
query = "INSERT INTO InvoiceNumbers (date) VALUES (" & NOW() & ");" 
newRow = CurrentDb.Execute(query) 

Teraz wiem, że to nie będzie działać, ponieważ Execute() nie zwróci wartość klucza podstawowego, ale jest to w zasadzie rodzaj kodu szukam. Będę musiał użyć klucza podstawowego nowego wiersza, aby zaktualizować liczbę wierszy w innej tabeli.

Jaki byłby najprostszy/najbardziej czytelny sposób robienia tego?

Odpowiedz

32

Jeśli DAO używać

RS.Move 0, RS.LastModified 
lngID = RS!AutoNumberFieldName 

Jeśli ADO używać

cn.Execute "INSERT INTO TheTable.....", , adCmdText + adExecuteNoRecords 
Set rs = cn.Execute("SELECT @@Identity", , adCmdText) 
Debug.Print rs.Fields(0).Value 

cn jest prawidłowe połączenie ADO, @@Identity powróci ostatni Identity (AutoNumber) włożona na tym połączeniu.

Zauważ, że @@Identity może być kłopotliwe, ponieważ ostatnia wygenerowana wartość nie może być jeden jesteś zainteresowany. Dla silnika bazy danych Access, należy rozważyć VIEW który łączy dwie tabele, z których oba mają właściwość IDENTITY, a ty INSERT INTOVIEW. W przypadku serwera SQL należy rozważyć, czy istnieją wyzwalacze, które z kolei wstawiają rekordy do innej tabeli, która również ma właściwość IDENTITY.

BTW DMax nie działałby tak, jakby ktoś wstawił rekord zaraz po włożeniu rekordu, ale zanim funkcja Dmax zakończy wykonywanie polecenia, otrzymasz jego rekord.

+14

DAO może zrobić SELECT @@ IDENTITY, zbyt - nie trzeba ADO. Robię to cały czas: lngID = db.OpenRecordset ("SELECT @@ IDENTITY") (0), gdzie "db" to ta sama zmienna bazy danych, która została użyta do wykonania wstawki. Nie otwieram już zestawów rekordów i Dodaj do tego. –

41

W twoim przykładzie, ponieważ używasz CurrentDB do wykonania INSERT, utrudniłeś to sobie. Zamiast tego, będzie to działa:

Dim query As String 
    Dim newRow As Long ' note change of data type 
    Dim db As DAO.Database 

    query = "INSERT INTO InvoiceNumbers (date) VALUES (" & NOW() & ");" 
    Set db = CurrentDB 
    db.Execute(query) 
    newRow = db.OpenRecordset("SELECT @@IDENTITY")(0) 
    Set db = Nothing 

kiedyś zrobić dodaje otwierając rekordów AddOnly i zbierając identyfikator stamtąd, ale jest to o wiele bardziej efektywne. I, uwaga, Tony, że nie wymaga ADO.

+2

i działa nawet wtedy, gdy zestaw rekordów jest połączoną tabelą programu SQL Server! Wspaniale ! –

+0

możesz także dodać dbFailOnError jako opcję do Execute. W przeciwnym razie program Access nie powie nic, jeśli się nie powiedzie. ----- db.Execute query, dbFailOnError – JustJohn

+0

@iDevlop SQL Server obsługuje [składnię "SELECT @@ IDENTITY"] (https://msdn.microsoft.com/en-us/library/ms187342.aspx). Interesujące byłoby zobaczenie, co dzieje się w innych połączonych typach tabel, takich jak Excel, lub innych RDBMS, takich jak Oracle lub MySQL. –

3

To jest adaptacja mojego kodu dla ciebie. Zainspirował mnie developpez.com (Zobacz na stronie: "Wlać insérer des données, vaut-il mieux passer par un Zestaw rekordów lub typ INSERT?"). Wyjaśniają (z odrobiną francuskiego). Ta droga jest znacznie szybsza niż ta górna. W tym przykładzie było to 37 razy szybciej. Spróbuj.

Const tableName As String = "InvoiceNumbers" 
Const columnIdName As String = "??" 
Const columnDateName As String = "date" 

Dim rsTable As DAO.recordSet 
Dim recordId as long 

Set rsTable = CurrentDb.OpenRecordset(tableName) 
Call rsTable .AddNew 
recordId = CLng(rsTable (columnIdName)) ' Save your Id in a variable 
rsTable (columnDateName) = Now()  ' Store your data 
rsTable .Update 

recordSet.Close 

LeCygne

+3

Czy możesz wskazać, który konkretny przykład jest "37 razy szybszy" niż? –

1
Private Function addInsert(Media As String, pagesOut As Integer) As Long 


    Set rst = db.OpenRecordset("tblenccomponent") 
    With rst 
     .AddNew 
     !LeafletCode = LeafletCode 
     !LeafletName = LeafletName 
     !UNCPath = "somePath\" + LeafletCode + ".xml" 
     !Media = Media 
     !CustomerID = cboCustomerID.Column(0) 
     !PagesIn = PagesIn 
     !pagesOut = pagesOut 
     addInsert = CLng(rst!enclosureID) 'ID is passed back to calling routine 
     .Update 
    End With 
    rst.Close 

End Function 
+1

Nie widzę odpowiedzi na oryginalne pytanie. Dodaj kontekst, aby zobaczyć, jak to pasuje? – GPI

+1

Ta odpowiedź jest niejasna. Proszę dodać wyjaśnienia. Nie wszyscy z nas wiedzą ** wszystko ** o vba. – MJH

Powiązane problemy