Nicht jede Datenänderung braucht ein gebundenes Formular. Oft willst du aus VBA
heraus einfach ein paar Datensätze anlegen, aktualisieren oder löschen — eine
Aktionsabfrage. Access bietet dafür zwei Wege: DoCmd.RunSQL und
CurrentDb.Execute. Sie sehen ähnlich aus, verhalten sich aber unterschiedlich.
Dieser Beitrag zeigt, welchen du wann nimmst und wie du die SQL-Strings sauber
baust.
DoCmd.RunSQL — der einfache Weg
DoCmd.RunSQL führt eine Aktionsabfrage aus. Es funktioniert nur mit
INSERT, UPDATE, DELETE und SELECT ... INTO — keine SELECT-Abfragen, die
Daten zurückgeben.
DoCmd.RunSQL "UPDATE Kunden SET Aktiv = False WHERE LetzterKauf < #01/01/2024#"
Der Haken: RunSQL zeigt vor der Ausführung eine Bestätigungsmeldung
(„Sie sind im Begriff, n Zeilen zu aktualisieren"). In einer Automatisierung
stört das. Viele schalten das dann mit SetWarnings ab:
' Antipattern — nicht nachmachen:
DoCmd.SetWarnings False
DoCmd.RunSQL "DELETE FROM Protokoll WHERE Datum < #01/01/2024#"
DoCmd.SetWarnings True
Warum das gefährlich ist: Wenn zwischen den beiden Zeilen ein Fehler auftritt, bleibt
SetWarningsaufFalse— und ab dann verschluckt Access alle Warnungen der Sitzung, auch wichtige. Der Anwender bekommt stumme Datenverluste. Nutze stattdessenExecute.
CurrentDb.Execute — der bessere Weg
Execute gehört zum DAO-Database-Objekt. Es zeigt keine Bestätigungs-
meldungen und braucht deshalb kein SetWarnings. Wichtiger noch: mit der Option
dbFailOnError löst es einen echten VBA-Laufzeitfehler aus, wenn etwas schiefgeht
(z. B. Verstoß gegen die referentielle Integrität).
CurrentDb.Execute _
"DELETE FROM Protokoll WHERE Datum < #01/01/2024#", _
dbFailOnError
Ohne dbFailOnError scheitert eine fehlerhafte Abfrage stillschweigend —
Access ändert einfach nichts und meldet nichts. Deshalb: dbFailOnError gehört
immer dazu.
RunSQL vs. Execute im Vergleich
| Eigenschaft | DoCmd.RunSQL | CurrentDb.Execute |
|---|---|---|
| Bestätigungsmeldung | ja (nervt) | nein |
Braucht SetWarnings | ja | nein |
| Fehler abfangbar | schwer | ja, mit dbFailOnError |
| Betroffene Zeilen abfragbar | nein | ja, RecordsAffected |
| Gehört zu | Makro-/DoCmd-Welt | DAO |
Fazit: Für Aktionsabfragen aus VBA ist Execute fast immer die richtige Wahl.
RecordsAffected — wie viele Zeilen?
Nach einem Execute verrät dir das Database-Objekt, wie viele Datensätze
betroffen waren. Dazu brauchst du eine Objektvariable, keinen Einzelaufruf von
CurrentDb (jeder CurrentDb-Aufruf liefert eine neue Instanz):
Public Sub AltKundenDeaktivieren()
Dim db As DAO.Database
Dim sql As String
Set db = CurrentDb
sql = "UPDATE Kunden SET Aktiv = False " & _
"WHERE LetzterKauf < #01/01/2024#"
db.Execute sql, dbFailOnError
Debug.Print db.RecordsAffected & " Kunde(n) deaktiviert"
Set db = Nothing
End Sub
SQL-Strings sauber bauen
Sobald du Werte aus Variablen in den SQL-Text einsetzt, wird das Quoten wichtig. Access-SQL hat feste Regeln für die einzelnen Datentypen:
| Datentyp | Begrenzer | Beispiel |
|---|---|---|
| Zahl | keiner | ... WHERE Preis > 100 |
| Text | einfache Anführungszeichen ' | ... WHERE Name = 'Meier' |
| Datum | Rauten, US-Format #mm/dd/yyyy# | ... WHERE Datum = #12/31/2024# |
Der häufigste Fehler bei Datumsangaben: Access-SQL erwartet immer das
US-Format mm/dd/yyyy, egal welche Ländereinstellung dein Windows hat. Für ein
Date-Feld aus VBA baust du das mit Format zuverlässig auf:
Public Sub BuchungAnlegen(ByVal kunde As String, _
ByVal betrag As Currency, _
ByVal wann As Date)
Dim db As DAO.Database
Dim sql As String
Set db = CurrentDb
sql = "INSERT INTO Buchungen (Kunde, Betrag, Datum) VALUES (" & _
"'" & Replace(kunde, "'", "''") & "', " & _
Replace(Str(betrag), ",", ".") & ", " & _
"#" & Format(wann, "mm\/dd\/yyyy") & "#)"
db.Execute sql, dbFailOnError
Set db = Nothing
End Sub
Drei Details, die hier zählen:
- Text: in
'einfassen. Enthält der Wert selbst ein'(z. B.O'Brien), wird es durchReplace(kunde, "'", "''")verdoppelt — sonst bricht der String. - Zahl: in VBA nutzt
Strbei deutscher Einstellung evtl. ein Komma; SQL will einen Punkt. DeshalbReplace(..., ",", "."). - Datum: mit
Format(wann, "mm\/dd\/yyyy")erzwingst du das US-Format und die Schrägstriche, unabhängig von den Systemeinstellungen.
SQL-Injection: warum String-Basteln riskant ist
Das obige Replace für Anführungszeichen ist nicht bloß Kosmetik. Wenn du
Benutzereingaben ungeprüft in SQL einsetzt, kann jemand über ein Textfeld eigene
SQL-Befehle einschleusen — SQL-Injection. Ein Name wie
x' OR '1'='1 würde ein WHERE aushebeln.
Merke: String-Verkettung ist fehleranfällig (Quoting, Datumsformate) und unsicher. Für alles, was Benutzereingaben verarbeitet, sind Parameterabfragen die bessere Lösung — sie kümmern sich um Quoting und Datentypen automatisch. Mehr dazu in der nächsten Lektion.
Zusammengefasst
DoCmd.RunSQLzeigt Bestätigungsmeldungen;CurrentDb.Executenicht — nimmExecute.- Immer
dbFailOnErrormitgeben, sonst scheitern Abfragen stillschweigend. - Finger weg vom
SetWarnings False-Antipattern: bleibt es hängen, verschluckt Access alle Warnungen. db.RecordsAffectedliefert nachExecutedie Anzahl betroffener Zeilen — dafürCurrentDbeinmal in eine Variable holen.- Werte richtig quoten: Text mit
'(und''verdoppeln), Datum mit#mm/dd/yyyy#, Zahlen mit Punkt. Bei Benutzereingaben besser Parameterabfragen.