In der letzten Lektion hast du SQL-Strings von Hand zusammengesetzt — mit allem, was dazugehört: Anführungszeichen verdoppeln, Datumsformate erzwingen, Zahlen- Trennzeichen umbiegen. Das ist mühsam und fehleranfällig. Parameterabfragen nehmen dir diese Arbeit ab. Du übergibst Access die Werte als typisierte Parameter, und Access kümmert sich um Quoting und Formatierung. Das ist sicherer und sauberer.
Warum Parameter statt String-Verkettung?
Drei Gründe sprechen klar für Parameter:
- Sicherheit: Ein Parameter ist immer ein Wert, nie ausführbares SQL. Damit ist SQL-Injection ausgeschlossen — egal, was der Anwender eintippt.
- Datentypen: Du gibst
PARAMETERSeinen Typ. Access weiß dann, dass ein Datum ein Datum ist, und du musst dich nicht um#mm/dd/yyyy#kümmern. - Datumsformate: Kein
Format(..., "mm\/dd\/yyyy")-Gebastel mehr. Du übergibst eine ganz normale VBA-Date-Variable.
Der PARAMETERS-Aufbau
Eine Parameterabfrage beginnt mit einer PARAMETERS-Klausel, die die Platzhalter
und ihre Datentypen deklariert. Danach folgt die eigentliche Abfrage, die diese
Platzhalter verwendet:
PARAMETERS pKunde Text ( 50 ), pAbDatum DateTime;
SELECT * FROM Buchungen
WHERE Kunde = pKunde AND Datum >= pAbDatum;
Die gängigen Parametertypen: Text, Long, Double, Currency, DateTime,
Short, Yes/No.
QueryDef aus VBA erstellen und füttern
In VBA baust du dazu einen temporären QueryDef. Wichtig: Übergibst du beim
Erstellen einen leeren Namen (""), wird die Abfrage nicht in der Datenbank
gespeichert — perfekt für einmalige Ad-hoc-Abfragen:
Public Sub BuchungenLesen(ByVal kunde As String, ByVal abDatum As Date)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", _
"PARAMETERS pKunde Text(50), pAbDatum DateTime; " & _
"SELECT * FROM Buchungen " & _
"WHERE Kunde = pKunde AND Datum >= pAbDatum")
' Werte setzen — ganz ohne Quoting oder Format
qdf.Parameters("pKunde") = kunde
qdf.Parameters("pAbDatum") = abDatum
Set rs = qdf.OpenRecordset(dbOpenSnapshot)
Do Until rs.EOF
Debug.Print rs!Datum, rs!Betrag
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set qdf = Nothing
Set db = Nothing
End Sub
Beachte: kunde und abDatum gehen direkt und unverändert in die Parameter. Kein
Replace, kein Format — Access erledigt das anhand der deklarierten Typen.
Aktionsabfragen mit Parametern: qdf.Execute
Für INSERT, UPDATE und DELETE nutzt du qdf.Execute statt OpenRecordset.
Auch hier gilt: dbFailOnError mitgeben.
Public Sub PreisErhoehen(ByVal kategorie As String, ByVal faktor As Double)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", _
"PARAMETERS pKat Text(50), pFaktor Double; " & _
"UPDATE Artikel SET Preis = Preis * pFaktor " & _
"WHERE Kategorie = pKat")
qdf.Parameters("pKat") = kategorie
qdf.Parameters("pFaktor") = faktor
qdf.Execute dbFailOnError
Debug.Print qdf.RecordsAffected & " Artikel angepasst"
Set qdf = Nothing
Set db = Nothing
End Sub
RecordsAffected steht auch beim QueryDef zur Verfügung — direkt nach dem
Execute.
Gespeicherte Parameterabfragen aus VBA füttern
Oft hast du die Abfrage schon im Navigationsbereich gespeichert — etwa
qryBuchungenNachKunde mit einer PARAMETERS-Zeile. Die musst du in VBA nicht neu
schreiben, sondern holst sie einfach aus der QueryDefs-Auflistung und setzt nur
die Parameter:
Public Sub GespeicherteAbfrageNutzen(ByVal kunde As String)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Set db = CurrentDb
Set qdf = db.QueryDefs("qryBuchungenNachKunde")
qdf.Parameters("pKunde") = kunde
Set rs = qdf.OpenRecordset(dbOpenSnapshot)
' ... rs auswerten ...
rs.Close
Set rs = Nothing
Set qdf = Nothing
Set db = Nothing
End Sub
Hinweis: Bezieht sich eine gespeicherte Abfrage auf ein Formularfeld (z. B.
[Formulare]![frmFilter]![txtKunde]), löst Access den Wert automatisch auf, solange das Formular offen ist. Aus VBA ist es aber robuster, solche Verweise als echtePARAMETERSzu deklarieren und die Werte explizit zu setzen — so funktioniert die Abfrage auch ohne geöffnetes Formular.
Vorteile gegenüber RunSQL auf einen Blick
String + RunSQL/Execute | Parameter + QueryDef | |
|---|---|---|
| Quoting von Text | manuell ('') | automatisch |
| Datumsformat | #mm/dd/yyyy# von Hand | VBA-Date reicht |
| SQL-Injection | möglich | ausgeschlossen |
| Lesbarkeit | verschachtelte Strings | klare Trennung Werte/SQL |
| Wiederverwendung | jedes Mal neu bauen | gespeicherte Abfrage füttern |
Zusammengefasst
- Parameterabfragen trennen Werte von SQL — dadurch keine Injection und kein Quoting-Gebastel.
- Deklariere Platzhalter mit
PARAMETERS name Typ;und setze sie überqdf.Parameters("name") = wert. CreateQueryDef("")erzeugt eine temporäre, nicht gespeicherte Abfrage für den einmaligen Gebrauch.- Lesen mit
qdf.OpenRecordset, ändern mitqdf.Execute dbFailOnError—RecordsAffectedgibt es bei beiden. - Gespeicherte Parameterabfragen holst du aus
db.QueryDefs(...)und musst nur noch die Parameter füllen.