Office Forum
www.Office-Loesung.de
Access :: Excel :: Outlook :: PowerPoint :: Word :: Office :: Wieder Online ---> provisorisches Office Forum <-
"LINQ for VBA" - Dynamisches SQL ohne Stringkaprio
zurück: Eigene Controls entwickeln weiter: TreeView ohne ActiveX mit Access Bordmitteln Unbeantwortete Beiträge anzeigen
Neues Thema eröffnen   Neue Antwort erstellen     Status: Tutorial Facebook-Likes Diese Seite Freunden empfehlen
Zu Browser-Favoriten hinzufügen
Autor Nachricht
Bitsqueezer
Office-VBA-Programmierer


Verfasst am:
19. Dez 2012, 20:43
Rufname:

"LINQ for VBA" - Dynamisches SQL ohne Stringkaprio - "LINQ for VBA" - Dynamisches SQL ohne Stringkaprio

Nach oben
       Version: (keine Angabe möglich)

Hallo zusammen,

wer schon mal in einer .NET-Programmiersprache gearbeitet hat, hat vielleicht schon mal mit LINQ gearbeitet. LINQ steht für "Language Integrated Query" und ist ein tolles Konzept von Microsoft, SQL-Abfragen als Sprachelement direkt in die Programmiersprache einzubauen. Dabei kann LINQ sogar noch mehr, beispielsweise die Abfrage von Collections auf die gleiche Weise.

Bei einem typisierten Dataset generiert man in der .NET-Sprache aus den gewünschten Tabellen in Visual Studio automatisch Code, der für jedes Feld und jede Tabelle entsprechende Eigenschaften und Methoden zur Abfrage anbietet. So kann man in der Programmiersprache selbst auf diese zurückgreifen und muß nicht erst mühsam SQL Strings zusammenbasteln und jedesmal nachsehen, wie der Name von Feld X geschrieben wurde.

Das gleiche Problem haben wir Access-Programmierer in VBA auch, leider gibt es hier kein LINQ. SQL-Strings, die nicht direkt als Abfrage gespeichert wurden oder werden können, müssen in VBA mühsam zusammengebastelt werden und man muß sehr genau auf die Syntax achten. Dazu kommen noch Access-SQL-Spezialitäten wie das seltsame Datums/Zeit-Format mit "#", das es so nur in Access gibt - usw.

Daher habe ich mir mal eine Art "LINQ für SQL" ausgedacht, mit dem man ebenfalls direkt im Code mit SQL-Befehlen arbeiten kann. Es ist nicht ganz so umfangreich wie echtes SQL, aber für die meisten Zwecke, die man gewöhnlich in Formularen oder Berichten benötigt, genügt es.

JOINs werden hierbei nicht unterstützt, was daran liegt, daß Access eine seltsame Art der Klammerung von JOINs verwendet, die es auch in anderen SQL-Dialekten nicht gibt. Die Klammerung stellt Access selbst ein, je nachdem, wie die Optimierung ausgeht, entsprechend ist nicht vorhersagbar, wie Access komplexe JOINs am Ende klammert. Das war mir ein wenig zu mühsam, dahinterzusteigen, es ist auch nicht notwendig, denn man kann einfach in diesem Fall eine komplexe Abfrage als gespeicherte Abfrage erstellen und dort mit JOINs verfahren, wie man es braucht, und dann diese Abfrage als Grundlage verwenden.

Die ganze Geschichte teilt sich in zwei Bereiche: Einen Generator, der wie Visual Studio einfach alle Tabellen und Abfragen der aktuellen Datenbank durchläuft und für jede passende Enums und Funktionen erstellt, und zwei Klassen, die den SQL-Generator darstellen.

1. Der Modulgenerator

Der Modulgenerator ist von den Klassen unabhängig, man kann ihn auch verwenden, wenn man die Klassen nicht benötigt. Einzig die generierte Funktion "CCSQL" und die zugehörige Variable kann man aus dem generierten Modul löschen, wenn man die Klassen nicht verwenden möchte.

Um das Modul zu generieren, geht man (nach dem Import des Moduls "modCCSQL_CreateEnums.bas" in die eigene Datenbank) in das Direktfenster des VBA-Editors und gibt ein:
Code:
CreateEnumModule
Im Ordner der aktuellen Datenbank wird dann das Modul "modCCSQL_TableEnums.bas" erzeugt, das man danach in die eigene Datenbank importiert - fertig.

Nun hat man für jede Tabelle und Abfrage passende Enums zur Verfügung, die man überall im eigenen Code verwenden kann. Der Vorteil ist, daß man so keine Literale mehr in den Code schreiben muß. Sollte sich irgendwann mal ein Feldname oder ein Tabellen- oder Abfragename ändern, generiert man das Modul mit dem Befehl oben einfach neu und importiert es erneut (vorher das alte löschen, sonst wird ein zweites eingefügt). Wenn man danach den Compiler laufenläßt, findet man alle Stellen, bei denen die Namen nicht mehr übereinstimmen und ändert sie einfach entsprechend.

2. Anwendung des erzeugten Moduls

Die Anwendung des erzeugten Moduls ist sehr einfach. Für jede Tabelle gibt es eine Enum, die mit "Tab_" beginnt und dem Namen der Tabelle. Also eine "Tabelle1" würde eine Enum erzeugen, die "Tab_Tabelle1" heißt. Diese Enum enthält nun wieder je einen Eintrag mit dem Feldnamen dieser Tabelle. Die einzelnen Einträge haben als Prefix ein "enm_", um nicht mit anderen Namen zu kollidieren. Mit dem Befehl:
Code:
?Tab_Tabelle1.enm_ID
 0
würde man beispielsweise eine "0" ausgegeben bekommen, wenn ein Feld "ID" in "Tabelle1" existiert und das erste Feld in der Liste ist. Das hilft einem in der Programmierung eher wenig, weil man seltener die Spaltennummer eines Feldes benötigt (aber wenn, kann man es natürlich so machen). Interessant ist ja der eigentliche Feldname, daher hat jede Tabelle auch noch eine Funktion, mit der man den zugehörigen Feldnamen ausgeben kann. Das geht dann so:
Code:
?Fld_Tabelle1(enm_ID)
[ID]
Klar wäre es kürzer, im Code einfach den String "[ID]" zu verwenden, aber wenn der Feldname geändert wird, geht die Suche los. Und der besondere Gag bei der Funktion ist, daß sie als Übergabeparameter die o.g. Enum verwendet und damit listet IntelliSense beim Schreiben der ersten Klammer alle Feldnamen der Tabelle auf - und nur diese. Die kann man nun bequem auswählen und die Klammer schließen, fertig.
Lediglich, wenn man den gleichen Feldnamen in einer anderen Tabelle nochmal verwendet hat, kommt es zu Namenskonflikten, dann muß man die Schreibweise etwas konkreter so schreiben:
Code:
?Fld_Tabelle1(Tab_Tabelle1.enm_ID)
Wenn man eine ganze Liste von Feldnamen haben möchte, gibt es dazu noch die Funktion "Fld_Tabelle1_All", die ebenfalls für jede Tabelle/Abfrage generiert wurde. Damit kann man einfach alle Felder der betreffenden Tabelle/Abfrage mit Komma separiert ausgeben. Das ist z.B. sehr praktisch, wenn man Code für das Duplizieren eines Datensatzes schreibt. Beim Schreiben des Datensatzes dürfen aber bestimmte Felder nicht mitgeschrieben werden, etwa eine AutoID oder bei SQL Server das Timestamp-Feld. Damit man Felder aus der Feldliste ausschließen kann, kann man eine beliebig lange Liste von Feldern als Parameter angeben, die nicht zurückgegeben werden sollen. Also z.B. so:
Code:
?Fld_Tabelle1_All(Tab_Tabelle1.enm_ID)
[Nachname],[Ort]
bzw., wenn ID nicht schon in einer anderen Tabelle existiert, dann so:
Code:
?Fld_Tabelle1_All(enm_ID)
[Nachname],[Ort]
Hier erhält man leider keine IntelliSense-Unterstützung, das liegt daran, daß ein ParamArray verwendet wird und das erlaubt nur Variant als Typ. Die Funktion überprüft aber, ob es sich um eine Zahl handelt (die die Enum ja zurückgibt) und liefert eine Fehlermeldung, wenn nicht. Mit IntelliSense kann man aber trotzdem arbeiten, wenn man die erste Variante verwendet, da dann die Feldnamen nur der Enum "Tab_Tabelle1" gelistet werden.

Für Abfragen funktioniert es genauso, nur daß die Enums mit "Qry_" beginnen und die Feldfunktionen mit "QFld_".

Weiterhin gibt es auch noch zwei Funktionen, die die Namen aller Tabellen bzw. alle Abfragen kommasepariert listen, "Tab_Names_All" und "Qry_Names_All". Diese kann man z.B. zum Füllen einer Listbox verwenden, wenn man das Komma in der deutschen Version gegen ein Semikolon austauscht.

Ebenso kann man natürlich auch an den Namen der Tabelle/Abfrage kommen, dazu gibt es die beiden Funktionen "Tab_Name" und "Qry_Name", die als Parameter einen Eintrag aus einer der beiden Enums "EnmMyTables" bzw. "EnmMyQueries" benötigen. So kommt man also an den Tabellennamen von "Tabelle1":
Code:
?Tab_Name(enmMyTables_Tabelle1)
[Tabelle1]
Natürlich hilft hier wieder IntelliSense, hier kann es auch nicht zu Namensduplikaten kommen, da in der Access-Tabellen/-Feldliste keine Duplikate vorkommen können.
Alle Namen werden immer automatisch mit eckigen Klammern versehen, damit auch unzulässige Benennungen korrekt verarbeitet werden.

3. "LINQ für VBA"

Auf dem generierten Modul aufbauend kann man nun die Klassen "clsCCSQL" und "clsCCSQL_Condition" verwenden, um eine Art "LINQ" in VBA zu erhalten. Nachdem man diese beiden Klassen in die eigene Datenbank importiert hat und das Modul, wie oben beschrieben, generiert und importiert hat, sollte auch ein Compiliervorgang sauber durchlaufen. Die Klassen benötigen als Grundlage diese Enums und Funktionen des generierten Moduls.

Wenn der Compiler alles ordentlich compiliert hat, kann man loslegen. Im generierten Modul gibt es eine Funktion "CCSQL", die automatisch ein Objekt der Klasse "clsCCSQL" instantiiert und in der Objektvariable "prv_objCCSQL" abgelegt, die auch automatisch im Modul generiert wurde. Man kann natürlich auch eigene, weitere Instanzen anlegen.

Somit kann man gleich nach den oben beschriebenen Schritten loslegen, einen SQL-Befehl zu schreiben. Das geht ganz einfach so (im einfachsten Fall):
Code:
    With CCSQL
        .SELECT_ Fld_Tabelle1(Tab_Tabelle1.enm_ID)
        .FROM_ enmMyTables_Tabelle1
        Debug.Print .SQLString
    End With
Die "Befehle" enden einfach auf "_", damit gibt es keine Namenskonflikte zu den echten SQL-Befehlen oder VBA-Namen. Durch das vorangestellte "With" führt man jeden Befehl einfach mit einem Punkt an und erhält so in IntelliSense die Liste aller verfügbaren Eigenschaften und Methoden der Klasse.

Am Ende kann man mit ".SQLString" den fertigen SQL-String abfragen.

Der SELECT-Befehl verwendet ganz absichtlich ein ParamArray, daß einfach Strings als Feldnamen verwendet. Grund ist, daß ein SELECT ja durchaus auch komplexere Dinge beinhalten kann, etwa der Aufruf einer Funktion oder eine Berechnung oder eine Unterabfrage. Daher muß man hier die "Fld_"-Funktion benutzen, wenn man mit dem generierten Modul arbeiten möchte, um den echten Feldnamen zu erhalten. ".FROM_" verwendet dagegen nur eine Tabelle der Enum "EnmMyTables". Um eine Abfrage zu verwenden, muß man die Funktion "FROMQRY_" benutzen und hat hier dann die Enum "EnmMyQueries" zur Verfügung. Eine Unterabfrage als String ist hier also nicht möglich, das hat aber seinen Sinn. Eine Unterabfrage kann man auch als gespeicherte Abfrage erstellen und dann hier verwenden. Der Sinn ist, daß später die Datentypen aus der betreffenden Abfrage/Tabelle ausgelesen werden, damit für Feldvergleiche die richtige Schreibweise generiert wird.

Dazu gibt es natürlich auch eine ".WHERE_"-Funktion, was dann so aussieht:
Code:
    With CCSQL
        .SELECT_ Fld_Tabelle1(Tab_Tabelle1.enm_ID)
        .FROM_ enmMyTables_Tabelle1
        .WHERE_ Fld_Tabelle1(Tab_Tabelle1.enm_ID), EQUAL_TO, "1"
        Debug.Print .SQLString
    End With
Als Ergebnis erhält man:
Code:
SELECT [ID] FROM [Tabelle1]  WHERE [ID] = 1
"WHERE_" nimmt einen String für den Feldnamen an, dann kann man aus einer Enum eine Vergleichsbedingung wählen und als dritter Parameter dann wieder ein String mit dem Wert. Das Praktische hieran ist, daß die Funktion automatisch den Datentyp des Feldes prüft und richtig anpaßt. Beispiel:
Code:
    With CCSQL
        .SELECT_ Fld_tblBestellungen_All
        .FROM_ enmMyTables_tblBestellungen
        .WHERE_ Fld_tblBestellungen(enm_BestellDatum), GREATER_OR_EQUAL, "07.05.2009"
        Debug.Print .SQLString
    End With
Als Ergebnis:
Code:
SELECT [ID],[Kennzeichen],[BestellNr],[Position],[BestellDatum],[PersonID] FROM [tblBestellungen]  WHERE [BestellDatum] >= #05/07/2009 0:0:0#
Wie man sieht, wird das Datum automatisch in ein passendes Universalformat umgewandelt.

Die Klasse kann aber noch einiges mehr. Beispielsweise will man ja oft in einer WHERE-Bedingung auch noch weitere Bedingungen verknüpfen. Das geht natürlich auch hier. Dazu gibt es passende Funktionen "AND_", "OR_", "NOT_". Als Beispiel erweitert man den Code nach dem "WHERE_" um folgende Zeile:
Code:
        .AND_ Fld_tblBestellungen(enm_Kennzeichen), EQUAL_TO, "Test"
Nun ist das Ergebnis:
Code:
SELECT [ID],[Kennzeichen],[BestellNr],[Position],[BestellDatum],[PersonID] FROM [tblBestellungen]  WHERE [BestellDatum] >= #05/07/2009 0:0:0# AND [Kennzeichen] = 'Test'
Auch hier kann man wieder sehen, daß automatisch Hochkommata eingefügt wurden, weil "Kennzeichen" ein Textfeld ist.

Was aber, wenn man komplexere Bedingungen mit Klammern schreiben will? Auch das ist möglich, dazu gibt es für jede logische Verknüpfung die Funktionen ".AND_Begin" und ".AND_End" (entsprechend für "OR" und "NOT"). Also kann man auch so etwas formulieren und gleich optisch schön strukturieren:
Code:
    With CCSQL
        .SELECT_ Fld_tblBestellungen_All
        .FROM_ enmMyTables_tblBestellungen
        .WHERE_ Fld_tblBestellungen(enm_BestellDatum), GREATER_OR_EQUAL, "07.05.2009"
        .AND_begin Fld_tblBestellungen(enm_Kennzeichen), EQUAL_TO, "Test"
              .OR_ Fld_tblBestellungen(enm_Kennzeichen), EQUAL_TO, "Test2"
        .AND_end
        Debug.Print .SQLString
    End With
Im Ergebnis:
Code:
SELECT [ID],[Kennzeichen],[BestellNr],[Position],[BestellDatum],[PersonID] FROM [tblBestellungen]  WHERE [BestellDatum] >= #05/07/2009 0:0:0# AND ([Kennzeichen] = 'Test' OR  [Kennzeichen] = 'Test2')
Ebenso kann man natürlich auch eine Gruppierung verwenden. Dazu gibt es sowohl ein "GROUPBY_" wie auch ein "HAVING_". "HAVING_" funktioniert genau wie "WHERE_" und unterstützt ebenfalls die Verwendung komplexer ANDs und ORs usw. Außerdem kann man sortieren mit "ORDERBY_" und für jedes weitere Feld dann "THENBY_". Ein Beispiel für so eine Abfrage kann so aussehen:
Code:
    With CCSQL
        .SELECT_ "ID", "Kennzeichen"
        .TestFieldExists = True
        .UseSquareBrackets = True
        .FROM_ enmMyTables_tblBestellungen
        .WHERE_ "ID", GREATER_THAN, "2"
            .AND_ "Kennzeichen", LIKE_, "Blau*"
            .AND_begin "ID", NOT_EQUAL_TO, "4"
                 .OR_ "Kennzeichen", NOT_EQUAL_TO, "Grün"
            .AND_end
        .GROUPBY_ "ID", "Kennzeichen"
        .HAVING_ "ID", LOWER_THAN, "3"
        .AND_ "Kennzeichen", IS_NOT_NULL, ""
        .ORDERBY_ Fld_tblBestellungen(enm_Kennzeichen), enmOrderDESC
        .THENBY_ Fld_tblBestellungen(enm_BestellDatum), enmOrderDESC
        .THENBY_ Fld_tblBestellungen(enm_BestellNr)
        Debug.Print .SQLString
        Debug.Print .GetErrorList
    End With
Hier sieht man als Variante dann auch, daß man auch direkte Strings verwenden kann. Außerdem gibt es weitere Eigenschaften in der Klasse wie "TestFieldExists", mit der der Feldname in der Quelle geprüft wird und "UseSquareBrackets", mit dem man das automatische Hinzufügen von eckigen Klammern steuern kann (Default = True). Ebenso die Methode "GetErrorList", mit der man am Ende eine Fehlerliste ausgeben kann, die durch die einzelnen Funktionen generiert werden.

Neben "SELECT" gibt es dann auch noch "INSERT_", "UPDATE_" und "DELETE_". Der Aufruf einer dieser Funktionen löscht alle Einstellungen aus der Klasse, die in früheren Befehlen generiert wurden, also z.B. die erzeugten Bedingungen, die OrderBy-Spalten usw., sowie die Fehlerliste, so daß man einen neuen Befehl schreiben kann.

Beispiel für DELETE_:
Code:
    With CCSQL
        .DELETE_
        .UseSquareBrackets = True
        .FROM_ enmMyTables_Mitglied
        .WHERE_ Fld_Mitglied(Tab_Mitglied.enm_Austritt), GREATER_OR_EQUAL, "30.09.2012"
        Debug.Print .SQLString
        Debug.Print .GetErrorList
    End With
Ausgabe:
Code:
DELETE * FROM [Mitglied]  WHERE [Austritt] >= #09/30/2012 0:0:0#
(DELETE funktioniert nicht mit Queries, wenn man also FROMQRY verwendet, erzeugt das einen Fehler.)

Beispiel für UPDATE_:
Code:
    With CCSQL
        .UPDATE_ enmMyTables_Mitglied
        .UseSquareBrackets = False
            .SET_ Fld_Mitglied(Tab_Mitglied.enm_Austritt), "31.07.2012"
            .WHERE_ Fld_Mitglied(Tab_Mitglied.enm_ID), GREATER_THAN, "1"
        Debug.Print .SQLString
        Debug.Print .GetErrorList
    End With
Ausgabe:
Code:
UPDATE Mitglied  SET Austritt = #7/31/2012#  WHERE ID > 1
Und ein Beispiel für INSERT_INTO:
Code:
    With CCSQL
        .INSERT_INTO enmMyTables_Mitglied
        .UseSquareBrackets = False
            .SET_ Fld_Mitglied(Tab_Mitglied.enm_Austritt), "31.07.2012"
        Debug.Print .SQLString
        Debug.Print .GetErrorList
    End With
Ausgabe:
Code:
INSERT INTO Mitglied (Austritt) VALUES (#7/31/2012#)
In den letzten beiden Beispielen kann man außerdem die Auswirkung von "UseSquareBrackets=False" sehen.

Der aufmerksame Betrachter wird erkennen, daß die INSERT_INTO-Funktion genauso funktioniert wie die UPDATE_-Funktion, nämlich mit der "SET_"-Funktion. Grund ist, daß ich es für wesentlich einfacher und übersichtlicher halte, den Wert eines Feldes zu seinem Namen hinzuzustellen, als eine Feldliste anzugeben und dann eine Wertliste. Im originalen INSERT-Befehl muß man dann immer die Spalten abzählen und schauen, was für ein Feldname unter "VALUES" steht, um den richtigen Feldwert in die Feldwertliste zu schreiben. MySQL beispielsweise erlaubt es auch in SQL, SET-Befehle wie bei UPDATE zu verwenden - diese Möglichkeit hat man so nun auch in VBA.

Für Abfragen stehen übrigens die Pendants "INSERT_INTO_QRY" und "UPDATEQRY_" zur Verfügung, da ja hier wieder unterschieden werden muß für die Verwendung der passenden Enum.

Ein INSERT-SELECT ist nicht direkt als Funktion vorhanden, läßt sich aber mit den vorhandenen trotzdem bewerkstelligen. Hier mal ein einfacher Code, mit dem man einen Datensatz duplizieren kann:
Code:
    Dim strSelect As String
    Dim strFields() As String
    Dim varFields() As Variant

    strFields = Split(Fld_tblBestellungen_All(Tab_tblBestellungen.enm_ID), ",")
    varFields = ConvertToParamArray(strFields)
    With CCSQL
        .SELECT_ varFields
        .FROM_ enmMyTables_tblBestellungen
        .WHERE_ "ID", EQUAL_TO, "2"
        strSelect = "INSERT INTO " & Tab_Name(enmMyTables_tblBestellungen) & _
                                 " (" & Fld_tblBestellungen_All(Tab_tblBestellungen.enm_ID) & ") " & _
                    .SQLString
        Debug.Print strSelect
    End With
"Split" funktioniert nicht mit Variant-Arrays, daher muß man hier ein Stringarray verwenden. "ParamArray" funktioniert wiederum nur mit Variant-Arrays, wobei jedes Element ein Variant sein muß. Daher gibt es die Funktion "ConvertToParamArray", die ein String-Array in ein Variant-Array umwandelt. Die Funktion wird im oben generierten Modul mit erzeugt.
Innerhalb von SELECT_ wird unterschieden, ob das erste Element ein Array ist, in dem Fall wird das Element "hochkopiert", ein Trick, der nur mit Variant funktioniert: Man kann einfach ein Variant einem Array gleichsetzen, dadurch wird das gesamte Array des eigentlich ersten Elementes zu einem Variant-Array. Schwer in Worte zu fassen, sieht im "SELECT_" so aus:
Code:
        If IsArray(varField(0)) Then
            If UBound(varField) = 0 Then varField = varField(0)            ' Copy an array to "varField" so it can used like a normal ParamArray
        End If
Wenn also das erste Element von ParamArray selbst ein Array ist, und ParamArray nur aus einem Element besteht, wird mit "varField = varField(0)" das Array zum ParamArray und so kann die Funktion genausogut ein Array wie auch einzelne Feldnamen mit Komma getrennt verarbeiten.

Im Code oben wird dann "INSERT INTO" manuell zusammengesetzt, was sich aber nur auf den Text und die Klammern beschränkt. Die Feldliste wird automatisch über die "..._All"-Funktion generiert und die ID-Spalte aus der Liste ausgenommen. Das gleiche für den SELECT-Befehl und so erhält man im Ergebnis:
Code:
INSERT INTO [tblBestellungen]
      ([Kennzeichen],[BestellNr],[Position],[BestellDatum],[PersonID])
SELECT [Kennzeichen],[BestellNr],[Position],[BestellDatum],[PersonID]
  FROM [tblBestellungen]  WHERE [ID] = 2
(Die Ausgabe ist etwas schöner formatiert zur besseren Übersicht, SQLString liefert natürlich keine Zeilenumbrüche.)
Der Duplikat-Code ist so auch universell, da er die "All"-Funktion benutzt. Also zukünftige Änderungen an der Tabelle würde der Code automatisch berücksichtigen, sobald das Modul neu generiert wird. Lediglich die Spalte für ID wird explizit genannt, wenn diese sich ändert, muß man halt hier den Namen anpassen. Das wiederum spuckt der Compiler dann automatisch aus.

Die Module sind, wie immer, ausführlich dokumentiert, Näheres kann man also auch noch dem Code entnehmen. Außerdem steht es natürlich jedem frei, den Code mit eigenen Ideen zu erweitern. Mit dieser Klasse kann man natürlich auch einen einfachen Abfragegenerator für Enduser programmieren, weil der dynamische SQL-String am Ende automatisch generiert wird. Ich hatte schon begonnen, einen solchen zu schreiben, aber der ist dann doch etwas komplexer geworden, wenn ich mal viel Zeit habe, schreibe ich ihn vielleicht zuende. Vorerst soll mal diese Modulgruppe genügen, die hoffentlich so manches Projekt vereinfacht.

Viel Spaß beim Experimentieren

Christian



CCSQL.zip
 Beschreibung:
"LINQ für VBA" - Enthält die Klassenmodule "clsCCSQL", "clsCCSQL_Condition" und "modCCSQL_CreateEnums" zum Einfügen in jede Access-Version.

Download
 Dateiname:  CCSQL.zip
 Dateigröße:  10.48 KB
 Heruntergeladen:  31 mal

Nouba
nicht ganz unwissend :)


Verfasst am:
31. Dez 2012, 08:02
Rufname:
Wohnort: Berlin


AW: "LINQ for VBA" - Dynamisches SQL ohne Stringka - AW: "LINQ for VBA" - Dynamisches SQL ohne Stringka

Nach oben
       Version: (keine Angabe möglich)

Hallo Christian,

Du bist ja mal wieder sehr kreativ gewesen. Ich habe etwas mit Deinem Konzept herum gespielt und muss sagen, dass es mir sehr gut gefällt. :D

Ich habe mir ein VBA Com.Addin mit VB6 dafür erstellt, um schnell das Enum-Modul anpassen zu können. Zur Installation genügt es, die Daten aus dem bin-Ordner zu entpacken und register_LinQ4VBA.bat auszuführen. Das Ding findet man dann im VBA-Editor unter dem Add-In Menü wieder.

PS: Der Quellcode liegt bei - allerdings mit Änderungen der Klassen- und des Modulnamens ich mag halt kein clsXXX.

_________________
mit freundlichen Grüssen Nouba

Wenn beim Lesen eines Beitrags der Eindruck entsteht, dass sich der Fragesteller wenig Mühe gegeben hat, so erhöht das nicht unbedingt die Motivation, eine Antwort zu verfassen.



LinQ4VBA.png
 Beschreibung:
 Dateigröße:  20.14 KB
 Angeschaut:  1042 mal

LinQ4VBA.png



LinQ4VBA.zip
 Beschreibung:

Download
 Dateiname:  LinQ4VBA.zip
 Dateigröße:  118.93 KB
 Heruntergeladen:  39 mal

Bitsqueezer
Office-VBA-Programmierer


Verfasst am:
31. Dez 2012, 13:40
Rufname:

AW: "LINQ for VBA" - Dynamisches SQL ohne Stringka - AW: "LINQ for VBA" - Dynamisches SQL ohne Stringka

Nach oben
       Version: (keine Angabe möglich)

Hallo Nouba,

freut mich, daß Dir mein kleines Experiment gefällt. Das finde ich super, daß Du daraus ein COM-Addin gemacht hast, hast Dir ja eine Menge Arbeit damit gemacht. Leider konnte ich es nicht testen, der Versuch, die DLL zu registrieren, endet immer in einem Fehler 80004005. (Windows Vista 32Bit)

Wenn ich wüßte, wo ich da nach dem Fehler suchen sollte, würde ich es selbst neu unter Vista compilieren.

Gruß

Christian
Nouba
nicht ganz unwissend :)


Verfasst am:
31. Dez 2012, 14:40
Rufname:
Wohnort: Berlin

AW: "LINQ for VBA" - Dynamisches SQL ohne Stringka - AW: "LINQ for VBA" - Dynamisches SQL ohne Stringka

Nach oben
       Version: (keine Angabe möglich)

Hallo Christian,

Sascha Trowitzsch hat das Problem unter COM-Add-Ins installieren beschrieben und ein Tool zum Registrieren bereitgestellt.

_________________
mit freundlichen Grüssen Nouba

Wenn beim Lesen eines Beitrags der Eindruck entsteht, dass sich der Fragesteller wenig Mühe gegeben hat, so erhöht das nicht unbedingt die Motivation, eine Antwort zu verfassen.
Bitsqueezer
Office-VBA-Programmierer


Verfasst am:
01. Jan 2013, 13:11
Rufname:

AW: "LINQ for VBA" - Dynamisches SQL ohne Stringka - AW: "LINQ for VBA" - Dynamisches SQL ohne Stringka

Nach oben
       Version: (keine Angabe möglich)

Hallo Nouba,

so kompliziert wie auf der Seite beschrieben ist es gar nicht, aber das hat mich auf die richtige Idee gebracht: Einfach "als Administrator ausführen" auf Deiner Batch-Datei, dann funktioniert es. Daran hatte ich nicht gedacht.

Habe nun Dein Add-In ausprobieren können, so geht es natürlich noch viel einfacher als in meiner Version.

Lediglich diese Zeile in Deinem Source:
Code:
    s.WriteText "Private Function ConvertToParamArray(sArray() As String) As Variant()" & vbCr
müßte geändert werden, da die Function auch Public sein muß, damit sie für SELECT_ etc. verwendbar ist, wie oben beschrieben.

Über die Namensgebung kann man sich streiten, jeder, wie er mag...Smile
Ich persönlich finde "cls" und "mod" in Access weit sinnvoller, da auch alle anderen Objekte mit drei Buchstaben begonnen werden wie "tbl", "qry" usw.
In anderen Sprachen wie .NET oder VB6 hat man ja eher immer das große C für Klassen usw. Lediglich bei Interface-Klassen verwende ich auch immer das große I, weil das auch in Access so Standard ist (für die internen Interface-Klassen).
Aber wie gesagt, das ist eine andere Diskussion und soll hier ja nicht das Thema sein.

Ich habe die ursprüngliche Klasse/den Artikel hier gerade für ein englisches Forum (Experts Exchange) übersetzt, hättest Du etwas dagegen, wenn ich Deine Add-In-Version dort mit veröffentliche (unter Angabe Deines Namens natürlich)?

Gruß

Christian
Nouba
nicht ganz unwissend :)


Verfasst am:
01. Jan 2013, 17:06
Rufname:
Wohnort: Berlin


Re: AW: "LINQ for VBA" - Dynamisches SQL ohne Stri - Re: AW: "LINQ for VBA" - Dynamisches SQL ohne Stri

Nach oben
       Version: (keine Angabe möglich)

Hallo Christian,

freut mich, dass das Add-In auch unter Vista läuft. Ich werde das Binary mit der geänderten ConvertToParamArray anhängen, damit auch andere fehlerfrei das Modul erstellen können.

Bitsqueezer - 01 Jan 13, 12:11 hat folgendes geschrieben:
...hättest Du etwas dagegen, wenn ich Deine Add-In-Version dort mit veröffentliche (unter Angabe Deines Namens natürlich)?
das ist ok.
_________________
mit freundlichen Grüssen Nouba

Wenn beim Lesen eines Beitrags der Eindruck entsteht, dass sich der Fragesteller wenig Mühe gegeben hat, so erhöht das nicht unbedingt die Motivation, eine Antwort zu verfassen.



LinQ4VBA.zip
 Beschreibung:
nur das neu kompilierte Add-In

Download
 Dateiname:  LinQ4VBA.zip
 Dateigröße:  49.7 KB
 Heruntergeladen:  27 mal

Neues Thema eröffnen   Neue Antwort erstellen Alle Zeiten sind
GMT + 1 Stunde

Diese Seite Freunden empfehlen

Seite 1 von 1
Gehe zu:  
Du kannst Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.
Du kannst Dateien in diesem Forum nicht posten
Du kannst Dateien in diesem Forum herunterladen

Verwandte Themen
Forum / Themen   Antworten   Autor   Aufrufe   Letzter Beitrag 
Keine neuen Beiträge Access Tabellen & Abfragen: Brauche auto. Zähler in Tabelle mittels SQL o. DAO 19 Danny G. 5458 26. Jul 2009, 05:40
Willi Wipp Brauche auto. Zähler in Tabelle mittels SQL o. DAO
Keine neuen Beiträge Access Tabellen & Abfragen: Autowert aktualisieren nach löschen über SQL 14 Gast 4058 30. Apr 2007, 06:41
jens05 Autowert aktualisieren nach löschen über SQL
Keine neuen Beiträge Access Tabellen & Abfragen: Laufzeitfehler 3061 / UPDATE SQL 6 Spoldo 4349 18. Jan 2006, 21:01
jens05 Laufzeitfehler 3061 / UPDATE SQL
Keine neuen Beiträge Access Tabellen & Abfragen: Feldwert ergänzen per SQL 16 grub 2243 27. Jul 2005, 16:50
Willi Wipp Feldwert ergänzen per SQL
Keine neuen Beiträge Access Tabellen & Abfragen: Access ändert meine SQL Strings 1 Nil 608 24. Feb 2005, 13:25
lothi Access ändert meine SQL Strings
Keine neuen Beiträge Access Tabellen & Abfragen: Zeitspanne bei Datumswerten mit SQL filtern...? 3 DoMe 4372 15. Feb 2005, 17:57
Willi Wipp Zeitspanne bei Datumswerten mit SQL filtern...?
Keine neuen Beiträge Access Tabellen & Abfragen: SQL Gruppierung -AXP 2 nepokat 601 03. Feb 2005, 08:46
nepokat SQL Gruppierung -AXP
Keine neuen Beiträge Access Tabellen & Abfragen: SQL: Like Operator geht nicht 2 Klaus-Peter_ 11242 31. Jan 2005, 18:54
Klaus-Peter SQL: Like Operator geht nicht
Keine neuen Beiträge Access Tabellen & Abfragen: Tabelle per SQL umbennen (Access 2000) 2 DerPater 1084 09. Dez 2004, 14:02
Gast Tabelle per SQL umbennen (Access 2000)
Keine neuen Beiträge Access Tabellen & Abfragen: Per SQL maximalen Spaltenwert im VBA code ermitteln 2 Gast 4779 31. Okt 2004, 23:10
Tom2002 Per SQL maximalen Spaltenwert im VBA code ermitteln
Dieses Thema ist gesperrt, du kannst keine Beiträge editieren oder beantworten. Access Tabellen & Abfragen: Wenn-Dann-Sonst in SQL??? 2 SCHNEEMANN 998 18. Okt 2004, 17:26
Willi Wipp Wenn-Dann-Sonst in SQL???
Keine neuen Beiträge Access Tabellen & Abfragen: SQL - Abfrage ob ein Wert in der Tabelle enthalten ist 1 notausgang 1301 23. Sep 2004, 09:42
stpimi SQL - Abfrage ob ein Wert in der Tabelle enthalten ist
 

----> Diese Seite Freunden empfehlen <------ Impressum - Besuchen Sie auch: Access Tabellen