SQL-Text für Filterbedingungen mit Klasse

Mit dem Einsatz von Klassen können Sie Ihren Programmcode übersichtlich gestalten. Wenn Sie konkrete Aufgaben mittels wiederverwendbarer Klassen umsetzen, erhalten Sie zusätzlich eine Code-Sammlung, die die Code-Qualität erhöht, weil Sie Korrekturen im Code nur noch an einer Stelle umsetzen müssen. Die in diesem Beitrag beschriebenen Klassen sind wiederverwendbare Klassen für die Erstellung eines Filterausdrucks, die Sie ohne änderung in Ihre Anwendung importieren und nutzen können.

Ziel

Das Erstellen von SQL-Filterausdrücken soll standardisiert und ohne hohen Programmieraufwand für unterschiedliche SQL-Dialekte anwendbar werden.

Ausgangssituation

SQL-Text zum Filtern von Formulardaten oder als Bestandteil von SQL-Anweisungen für Recordsets wird regelmäßig benötigt. Beim Zusammenstellen der SQL-Anweisungen muss auf die passende Konvertierung in Text geachtet werden. Die Konvertierung sowie das Zusammenfügen mehrerer Filter-Kriterien können zu schlecht lesbarem Code führen. Eine Sammlung von Hilfsprozeduren und Klassen soll diese Aufgaben vereinfachen.

Anforderungen

Die Lösung stellt die folgenden Anforderungen:

  • Unterstützung für verschiedene SQL-Dialekte
  • Unterschiedliche Einsatzmöglichkeiten – von der Konvertierung eines Wertes zu SQL-Text über das Erstellen eines einzelnen Kriteriums bis zur automatischen Filterung in Formularen, wenn Werte in Filter-Steuerelementen geändert werden.
  • Definieren statt programmieren
  • übersichtlicher Code in den Prozeduren, die die Klassen verwenden
  • Wiederverwendbarer Code

Lösungsansatz

Der Lösungsansatz beinhaltet die folgenden Elemente:

  • Klassen mit konkreten Aufgaben (Single-Responsibility-Prinzip)
  • Austauschbare Klassen – falls spezielle Anforderungen benötigt werden
  • Anforderungen für unterschiedliche SQL-Dialekte über Parameter/Eigenschaften einstellbar

Klasse SqlTools

Die Klasse SqlTools stellt Methoden zum Erstellen eines SQL-Ausdrucks bereit. Die Methoden TextToSqlText, NumberToSqlText, DateToSqlText und BooleanToSqlText konvertieren Werte mit einem bestimmten Datentyp in einen SQL-konformen Text.

Damit diese Konvertierungsfunktion Text für verschiedene SQL-Dialekte erzeugen können, müssen Sie die gewünschten Formate als Parameter an die Konvertier-Funktionen weitergeben oder Sie stellen die Formate mit den Eigenschaften SqlDateFormat, SqlBooleanTrueString und SqlWildCardString für die Klassen-Instanz ein. Die Methode ConvertToSqlText bildet einen zentralen Einstiegspunkt dieser Konvertierungsfunktionen. In Listing 1 sehen Sie Auszüge aus der Beispiele-Datei SqlTools_Beispiele.mdb.

Private Sub DatentypToSqlText()
     [...]
     FilterWert = DateSerial(2015, 12, 24)
     SqlText = SqlTools.DateToSqlText(FilterWert, "\#yyyy-mm-dd\#")
     Debug.Print "Aus "; FilterWert; " wird "; SqlText
     '' --> Aus 24.12.2015  wird #2015-12-24#
     [...]
End Sub
Private Sub ConvertToSqlText_JetDaoDialekt()
     [...]
     ''SQL-Formate einstellen
     With SqlTools
         .SqlDateFormat = "\#yyyy-mm-dd\#"
         .SqlBooleanTrueString = "True"
     End With
     [...]
     FilterWert = DateSerial(2015, 12, 24)
     SqlText = SqlTools.ConvertToSqlText(FilterWert, SQL_Date)
     Debug.Print "Aus "; FilterWert; " wird "; SqlText
     [...]
End Sub

Listing 1: Einsatz der Konvertierungsfunktionen

Zum Erstellen eines Filterausdrucks übergeben Sie den Datenfeldnamen, den Datentyp, den gewünschten Vergleichsausdruck und den Wert an die Methode BuildCriteria. Innerhalb der Methode wird der Wert über die Konvertierungsfunktion für den jeweiligen Datentyp in SQL-Text umgeformt. Aus den Enum-Werten vom RelationalOperator-Parameter wird der Vergleichsausdruck erstellt.

Diese Texte werden mit dem Feldnamen zu einem Filterausdruck zusammengefügt und als Funktionsergebnis zurückgegeben. Die Beispiele in Listing 2 zeigen übliche Varianten für Vergleichsausdrücke.

Private Sub BuildCriteria_EqualGreaterThan()
     [...]
     FilterWert = "O''Neill"
     SqlText = SqlTools.BuildCriteria("Textfeld", SQL_Text, SQL_Equal + SQL_GreaterThan, FilterWert)
    Debug.Print "SQL_Text:", SqlText
    '' --> Textfeld >= ''O''''Neill''
     [...]
End Sub
Private Sub BuildCriteria_Like()
     [...]
    FilterWert = "abc"
    SqlText = SqlTools.BuildCriteria("Textfeld", SQL_Text, SQL_Like, FilterWert)
    Debug.Print "SQL_Text:", SqlText
    '' --> Textfeld Like ''abc''
    FilterWert = "a"
    SqlText = SqlTools.BuildCriteria("Textfeld", SQL_Text, SQL_Like + SQL_Add_WildCardSuffix, FilterWert)
    Debug.Print "SQL_Text:", SqlText
    '' --> Textfeld Like ''a*''
    FilterWert = "c"
    SqlText = SqlTools.BuildCriteria("Textfeld", SQL_Text, SQL_Like + SQL_Add_WildCardPrefix, FilterWert)
    Debug.Print "SQL_Text:", SqlText
    '' --> Textfeld Like ''*c''
End Sub

Listing 2: BuildCriteria-Beispiele

Für Between-Filterbedingungen gibt es spezielle Features in der SqlTools-Klasse. Wenn Sie beispielsweise einen Datumsfilter erzeugen wollen und in den zu filternden Werten auch die Uhrzeit enthalten ist, können Sie SQL_Add_WildCardSuffix verwenden, um den ganzen Tag des Ende-Datums anzugeben. Der Between-Ausdruck wird zu einem Feld >= Startdatum And Feld < (EndDatum+1)-Ausdruck umgeschrieben.

übergeben Sie Null an einen der Wert-Parameter, wird der Between-Ausdruck wieder umgeformt, da Null standardmäßig als Filterwert nicht berücksichtigt werden soll. Beispiele zu diesen Features sehen Sie in Listing 3.

Private Sub BuildCriteria_Between_Features()
     [...]
     ''Datum + SQL_Add_WildCardSuffix:
     ErsterWert = DateSerial(2015, 12, 1)
     ZweiterWert = DateSerial(2015, 12, 31)
     SqlText = SqlTools.BuildCriteria("Datumsfeld", SQL_Date, _
         SQL_Between + SQL_Add_WildCardSuffix, ErsterWert, ZweiterWert)
     Debug.Print "SQL_Date + SQL_Add_WildCardSuffix: zwischen "; _
         ErsterWert; "und "; ZweiterWert; "ergibt:"; vbNewLine; SqlText
     '' --> Datumsfeld >= #2015-12-01# And Datumsfeld < #2016-01-01#
     ''Nullwerte:
     ErsterWert = 1
     ZweiterWert = Null
     SqlText = SqlTools.BuildCriteria("Zahlenfeld", SQL_Numeric, _
         SQL_Between, ErsterWert, ZweiterWert)
     Debug.Print "ZweiterWert = Null: "; SqlText
     '' --> Zahlenfeld >= 1
     ErsterWert = Null
     ZweiterWert = 5
     SqlText = SqlTools.BuildCriteria("Zahlenfeld", SQL_Numeric, _
         SQL_Between, ErsterWert, ZweiterWert)
     Debug.Print "ErsterWert = Null: "; SqlText
     '' --> Zahlenfeld <= 5
End Sub

Listing 3: BuildCriteria: Between-Features

Wie Ihnen bereits bei der Between-Bedingung aufgefallen ist, kann man an die BuildCriteria-Methode mehr als einen Filterwert für eine Filterbedingung übergeben. Für einen Between-Ausdruck werden immer zwei Werte benötigt. Für einen In-Filterausdruck können Sie ein Array als übergabewert verwenden.

Listing 4 zeigt neben der In-Variante noch eine weitere Variante, mit der Sie mehrere Filterwerte für ein Datenfeld in einer BuildCriteria-Zeile verwenden können. Wenn Sie ein Array mit Werten übergeben und als RelationalOperator nicht SQL_In verwenden, wird für jeden Array-Wert ein Filterausdruck erzeugt und diese Filterausdrücke werden mit Or verbunden.

Private Sub BuildCriteria_ArrayUebergabe()
     [...]
     '' In(...):
     SqlText = SqlTools.BuildCriteria("Textfeld", SQL_Text, _
         SQL_In, Array("a", "c", "l"))
     Debug.Print "SQL_Text, In(...):", SqlText
     '' --> Textfeld In (''a'',''c'',''l'')
     SqlText = SqlTools.BuildCriteria("Zahlenfeld", SQL_Numeric, _
         SQL_In, Array(1, 3, 5))
     Debug.Print "SQL_Numeric, In(...):", SqlText
     '' --> Zahlenfeld In (1,3,5)
     '' Mehrere Filter mit Or kombiniert
     SqlText = SqlTools.BuildCriteria("Textfeld", SQL_Text, _
         SQL_Like + SQL_Add_WildCardSuffix, Array("a", "c", "l"))
     '' --> Textfeld Like ''a*'' Or Textfeld Like ''c*'' Or Textfeld Like ''l*''
End Sub

Listing 4: BuildCriteria: Array-übergabe

Die bisher erwähnten Methoden und Eigenschaften sind für den Aufgabenbereich der Klasse ausreichend. In der Klasse sind noch zwei weitere Methoden enthalten, die die Verwendung der Klasse vereinfachen. Mit Clone können Sie eine vorhandene Instanz einschließlich der Formateinstellungen kopieren. NewInstance ermöglicht die Erstellung einer neuen Instanz mit der Möglichkeit, die SQL-Formate als Parameter einzustellen. Die letzten zwei Methoden sind nützlich, da SqlTools selbst-instanziierend gestaltet ist. Sie können den Klassennamen direkt in VBA einsetzen und auf eine Factory-Methode verzichten.

Das ist vorteilhaft, wenn Sie hauptsächlich einen bestimmten SQL-Dialekt verwenden und nur selten SQL-Text für einen anderen Dialekt benötigen. Sie müssen dafür nur einmalig beim Anwendungsstart die SQL-Formate übergeben oder im Code der SqlTools-Klasse die Konstanten im Klassenkopf für die Standardwerte entsprechend einstellen.

Klasse FilterStringBuilder

In vielen Fällen werden mehr als ein Filterkriterium benötigt. Für diese Aufgabe – das Zusammenführen von mehreren Filterbedingungen – ist die Klasse FilterStringBuilder zuständig. Zum Erstellen eines kombinierten Filterausdrucks erzeugen Sie eine neue Instanz der FilterStringBuilder-Klasse. Falls die Instanz nicht die Standard-Instanz der SqlTools verwenden soll, übergeben Sie an die Eigenschaft SqlTool eine passende Referenz von einer SqlTools-Instanz oder Sie stellen über die Methode ConfigSqlFormat die benötigten SQL-Formate ein. Für die Verwendung in einer Prozedur können Sie einen With-Ausdruck zum Erzeugen einer Instanz verwenden. In Listing 5 sehen Sie eine Grundstruktur für einen Code, der mittels FilterStringBuilder einen Filterausdruck erzeugt.

Private Sub FilterStringBuilder_Grundstruktur()
     Dim FilterString As String
     With New FilterStringBuilder
     ''SQL-Formate einstellen
         .ConfigSqlFormat "\#yyyy-mm-dd\#", "True", "*"
         ''oder neue SqlTools-Instanz erzeugen:
         ''Set .SqlTool = SqlTools.Clone("\#yyyy-mm-dd\#", "True", "*")
         ''oder vorhandene SqlTools-Instanz verwenden:
         ''Set .SqlTool = DaoSqlTools 
         ''Filterbedingungen anfügen:
         .Add "Datumsfeld", SQL_Date, SQL_LessThan, DateSerial(2015, 12, 24)
         .Add "Zahlenfeld", SQL_Numeric, SQL_Equal + SQL_GreaterThan, 1.23
         '' ...
         ''Filterausdruck ausgeben:
         FilterString = .ToString(SQL_And)
     End With
     Debug.Print FilterString
     '' --> (Datumsfeld < #2015-12-24#) And (Zahlenfeld >= 1.23)
End Sub

Listing 5: FilterStringBuilder verwenden

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar