Lektionen/Datenzugriff

Parameterabfragen mit QueryDef

Profi10 Min. Lesezeit

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 PARAMETERS einen 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 echte PARAMETERS zu 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/ExecuteParameter + QueryDef
Quoting von Textmanuell ('')automatisch
Datumsformat#mm/dd/yyyy# von HandVBA-Date reicht
SQL-Injectionmöglichausgeschlossen
Lesbarkeitverschachtelte Stringsklare Trennung Werte/SQL
Wiederverwendungjedes Mal neu bauengespeicherte 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 über qdf.Parameters("name") = wert.
  • CreateQueryDef("") erzeugt eine temporäre, nicht gespeicherte Abfrage für den einmaligen Gebrauch.
  • Lesen mit qdf.OpenRecordset, ändern mit qdf.Execute dbFailOnErrorRecordsAffected gibt es bei beiden.
  • Gespeicherte Parameterabfragen holst du aus db.QueryDefs(...) und musst nur noch die Parameter füllen.
Nächste Lektion
Formulare per VBA steuern