Access Design:Parameterabfrage

Aus DBWiki
Wechseln zu: Navigation, Suche

Der Begriff Parameterabfrage ist leider nicht eindeutig definiert. Neben Abfragen mit einer SQL "PARAMETERS"-Sektion (die hier jetzt nicht behandelt werden sollen) werden damit meist Abfragen mit fehlenden oder falsch geschriebenen Feldnamen verstanden, die Access dann über eine kleine Dialogbox als fehlende Parameter vom Benutzer nachfragt.

Diese Art von Abfragegestaltung hat zwar den vermeintlichen Vorteil, dass man eine Benutzereingabe schnell und ohne Entwurf weiterer Formulare in die Abfrage einbauen kann, geht aber mit einer ganzen Reihe von Nachteilen einher:

  • Der Parameter-Nachfrage-Dialog ist sehr benutzerunfreundlich (speziell, wenn da mehrere Parameter nacheinander angefragt werden).
  • Eine Plausibilitäts- oder Typprüfung lässt sich mit diesem Dialog nicht vornehmen, ebenso ist keine saubere Fehlerbehandlung möglich.
  • Derartige Parameterabfragen lassen sich nicht in Recordsets verwenden oder per Automation ansprechen (z.B. als Serienbrief-Datenquelle).
  • Nullwerte lassen sich hierbei nur sehr umständlich (mit geschachtelten "OR IS NULL"-Klauseln) berücksichtigen.

"Parameterabfragen" sollten daher vermieden und durch ein vorgeschaltetes Formular ersetzt werden.

Warum Parameterabfragen sinnvoll sind

Gibt man im Querydesigner als Kriterium einen beliebigen Text (der keinem Feldnamen entspricht) in eckige Klammern ein (z.B. "[Mitarbeitername eingeben]"), dann wird dieser Text von Access automatisch als Parameter behandelt, so daß die PARAMETERS-Klausel nicht notwendig ist.

Der Einsatz von Parametern in der Form, daß der Benutzer ein Eingabefenster präsentiert bekommt, in der er nun selbst raten muß, was er eingeben soll (und das, wie oben erwähnt, nicht per Programm geprüft werden kann), ist so nicht sinnvoll, jedoch sind Parameterabfragen beinahe immer vorzuziehen, wenn es um performante und sichere Abfragegestaltung geht.

Eine Abfrage mit Parametern kann in VBA auch in Recordsets eingesetzt werden, wie folgendes Beispiel demonstriert:

    Dim qd As DAO.QueryDef
    Dim rs As DAO.Recordset
    Set qd = CurrentDb.QueryDefs("qryParameter")
    qd.Parameters("[Mitarbeiter eingeben]") = "Schmitz"
 
    Set rs = qd.OpenRecordset()

"qryParameter" ist der Name der Abfrage, "[Mitarbeiter eingeben]" ist der Text in eckigen Klammern, den man in der Abfrage definiert hat - anders ausgedrückt, der Name der Parameter-Variablen. Durch die Erstellung eines Objektverweises auf das QueryDef-Objekt, das diese Abfragedefinition beinhaltet, kann man mit Hilfe der Parameters-Auflistung den Parameter mit dem gewünschten Inhalt befüllen und dann ein Recordset daraus erstellen.

Die Performance von gespeicherten Abfragen ist grundsätzlich besser als ein zusammengesetzter SQL-String in VBA, daher sind gespeicherte Abfragen immer vorzuziehen, mit und ohne Parameter. (Die dargestellte Form läßt sich sogar für die Zuweisung auf Formular-Recordsets verwenden, ist allerdings etwas trickreich.)

Access behandelt Parameter ohne Abfrage als Text (Typ "dbText", wenn man in qd oben z.B. mit "qd.Parameters(0).Type" ausgeben läßt (10=dbText)). Daher ist eine zusätzliche PARAMETERS-Klausel sinnvoll, die man entweder in der SQL-Ansicht des Abfragedesigners von Hand eingibt (dabei muß man aber auch die Datentypen kennen) oder (zumindest ab Access 2007 aufwärts) im Abfragedesigner unter dem Ribbon "Entwurf" unter "Einblenden/Ausblenden" unter "Parameters" in einem dann erscheinenden Fenster definieren kann. Hierbei erscheint der bereits eingegebene Text "[Mitarbeiter eingeben]" nicht in der Parameterliste, was unlogisch erscheint - aber hier werden eben nicht die bereits verwendeten Variablen angezeigt, sondern die Definition der Variablen, genauso, wie man unter VBA eine Variable erst mit Dim bekannt macht, läßt man es weg, ist die Variable vom Typ "Variant".

Im Parameterfenster kann man also sozusagen ein "Dim" für SQL vornehmen, da der Text "[Mitarbeiter eingeben]" schon geschrieben wurde, muß man den gleichen Text hier nochmal schreiben, damit Access den hier definierten Datentyp dieser Variable zuordnet.

Da, wie oben erwähnt, eine Direktausgabe an den Benutzer nicht sinnvoll ist, ist es auch nicht sinnvoll, Parameter mit Eingabeaufforderungstexten zu definieren, also nennt man am besten beides um in "[Mitarbeiter]" (in der Parameterdefinition und in der WHERE-Klausel).

Jetzt hat man sogar eine typsichere Parameterabfrage. Vorteilhaft ist das besonders für VBA in der oben gezeigten Form, denn nun bekommt man abfangbare Fehlermeldungen zur Laufzeit, wenn der falsche Datentyp angegeben wird.

Der Punkt Sicherheit kommt hierbei ebenfalls ins Spiel: So definierte und so verwendete Parameter sind sicher vor SQL Injection und Variablen können nun auch solche Sonderzeichen enthalten, die beim Zusammensetzen als SQL String zu Problemen führen, wie etwa das einfache Hochkomma (') oder Anführungszeichen usw. Bei Datumsabfragen muß ein Datumsstring ebenfalls nicht mehr in "#" eingeschlossen werden, sondern kann ganz normal formuliert werden, also z.B. so:

qd.Parameters("[Datumsparameter]") = "24.07.2011"

aber auch so:

qd.Parameters("[Datumsparameter]") = CDate("24.07.2011")

Access wandelt also den einfachen String implizit selbst in ein Datum um, erkennt aber auch, wenn der Datentyp ein echtes Datum ist.

Fazit

Parameterabfragen zu definieren ist eine sinnvolle, sichere und performante Methode, mit Datenquellen umzugehen, die unbedingt anderen Methoden vorzuziehen ist, wo immer es möglich ist. Sie werden beim Speichern von der JET-Engine compiliert und optimiert und sind damit immer schneller als dynamisches SQL, das vermieden werden sollte, wo immer es geht. Sie sind sicherer durch Typsicherheit, Vermeidung von SQL Injection und ermöglichen Sonderzeichen. Sie können in Recordsets verwendet werden, auch (und besonders!) für das Einfügen, Ändern und Löschen von Daten per SQL-Abfrage, da hier die Sicherheit besonders wichtig ist (das QueryDef-Objekt verfügt dazu auch über eine Execute-Methode).

Sie sollten allerdings nicht dazu mißbraucht werden, Access dazu zu bringen, einen Eingabedialog zur Eingabe von Parametern durch den Benutzer anzuzeigen, das ist die einzig falsche Verwendung.

Demgegenüber ist es sinnlos, zur Laufzeit eine neue QueryDef zu definieren, da man so nur ständig die Objekttabelle von Access aufbläht, die dann wieder reorganisiert werden muß. QueryDefs (also Abfragen) sollten immer nur zum Designzeitpunkt erstellt werden. VBA-Kommandos, die Designobjekte zu ändern in der Lage sind, sollten der AddIn-Programmierung vorbehalten sein.

Siehe auch