Wenn ihr euch für eine gute Antwort bedanken möchtet, im entsprechenden Posting einfach den Knopf "sag Danke" drücken!
ZitatDie DB soll durch mehrere Personen bearbeitet werden,Da unterschätzt Du den Aufwand der dazu notwendig ist. Die Datenbank muss in diesem Fall auf Backend (nur die Tabellen) und Frontend (der Rest) aufgeteilt werden. Jeder User benötigt dann auch Access auf seinem PC. Mindestens als Runtimeversion (die es kostenlos gibt).
rs.Update
rs.Bookmark = rs.LastModified ' Aktualisiert den Zeiger auf den neuen Datensatz
ID = rs!Artikel_ID
rs.AddNew
rs!Materialnummer = MatNr
rs!Bezeichnung = MName
rs.Update
ID = rs!Artikel_IDAber wenn das sicher funktionieren würde, gäbe es die vielen Diskussionen, wie man an die ID des gerade eingefügten DS kommt, vermutlich nicht.ZitatDein aktueller Workflow leidet unter dem sogenannten RBAR-Syndrom (Row-By-Agonizing-Row – Zeile für schmerzhafte Zeile). Du öffnest für jeden fehlenden Datensatz Recordsets, feuerst langsame DLookup-Domänenfunktionen ab und führst nachträglich UPDATE-Befehle aus.In einem relationalen Datenbanksystem wie Access löst man so etwas performant über mengenbasierte SQL-Abfragen. Wir können die komplette Logik aus Schleifen, Dictionaries und VBA-Funktionen in nur drei SQL-Befehle gießen.Vielleicht solltest du mal deine KI nochmal befragen und in die richtige Richtung "stubsen", von alleine bekommt man nämlich keine optimalen Ergebnisse.
Public Sub Zeich2Mat_Mengenbasiert()
On Error GoTo Fehler
Dim cDB As DAO.Database
Set cDB = CurrentDb
' Ganzen Prozess in eine einzige Transaktion packen (alles oder nichts)
DBEngine.BeginTrans
' 1. Fehlende Materialien massenhaft anlegen
cDB.Execute "INSERT INTO tbl_Material (Materialnummer, Bezeichnung) " & _
"SELECT DISTINCT Z.MatNR, 'AutoEingabe_' & Z.Dateiname " & _
"FROM tbl_Zeichnung_LCL AS Z LEFT JOIN tbl_Material AS M ON Z.MatNR = M.Materialnummer " & _
"WHERE Z.MatNR Is Not Null AND Z.MatNR <> '0' AND M.Materialnummer Is Null;", dbFailOnError
' 2. RefID für die neuen Datensätze nachziehen
cDB.Execute "UPDATE tbl_Material SET RefID = Artikel_ID WHERE RefID Is Null OR RefID = 0;", dbFailOnError
' 3. Initialen Index (0) für neue Materialien anlegen
cDB.Execute "INSERT INTO tbl_Index (FS_Mat, IX) " & _
"SELECT M.Artikel_ID, 0 " & _
"FROM tbl_Material AS M LEFT JOIN tbl_Index AS I ON M.Artikel_ID = I.FS_Mat " & _
"WHERE I.FS_Mat Is Null;", dbFailOnError
' 4. Die Fremdschlüssel in der Zeichnungstabelle aktualisieren
cDB.Execute "UPDATE tbl_Zeichnung_LCL AS Z INNER JOIN tbl_Material AS M ON Z.MatNR = M.Materialnummer " & _
"SET Z.FS_MatID = M.Artikel_ID " & _
"WHERE Z.MatNR Is Not Null AND Z.MatNR <> '0';", dbFailOnError
' Wenn alles glatt lief: Speichern
DBEngine.CommitTrans
Debug.Print Now, "Workflow erfolgreich und mengenbasiert abgeschlossen!"
Exit Sub
Fehler:
DBEngine.Rollback
MsgBox "Fehler " & Err.Number & " im SQL-Workflow: " & Err.Description, vbCritical, "Datenbankfehler"
End Sub
ZitatWarum diese SQL-Lösung massiv besser ist:Kein Speicherüberlauf mehr:
- Da Access die Abfragen intern im Abfrage-Optimierer verarbeitet, entfällt das manuelle "Chuncking" (Aufteilen in 1000er-Schritte).
- Keine fehleranfälligen Lookups: Das gefährliche DLookup, das bei großen Tabellen die Performance komplett killt, ist restlos eliminiert.
- Echte atomare Transaktion: Tritt an irgendeiner Stelle ein Fehler auf, wird die gesamte Kette (Schritt 1 bis 4) sauber zurückgerollt. Es entstehen niemals "halbe" Datenleichen.
Zitat von: PhilS am August 03, 2026, 15:33:05Denke.mal darüber nach was DBEngine.BeginTrans eigentlich bewirkt.
If MatDikt.Exists(MNr) Then
rs!FS_MatID = MatDikt(MNr)
Else
DBEngine.CommitTrans
MatID = NeuMaterial(MNr, rs!Dateiname)
MatDikt.Add MNr, MatID
DBEngine.BeginTrans
DBEngine.Idle dbRefreshCache
End IfDamit läuft der Code wie gewünscht durch.