version=1.5.4
vdate=04.09.2019
fname=sqlscript.cls
ns=%NAMESPACE%
fpath=/vba/access/classes
====== [VBA][Access] Klasse SQLScript ======
//Eine Klasse um SQL-Scripts in seine einzelnen Befehle zu zerteilen und diese auszuführen. Diverse DML, DDL, und DCL werden unterstützt.//
==Version %%version%% (%%vdate%%)==
>//Das Modul hat versteckte Attribute. Damit diese aktiv übernommen werden reicht es nicht aus, den Code in ein neues Modul zu kopieren. Man muss das Modul aus der Datei nach VBA importieren.//
>{{popup>:vba:vba_importfile.png|Bild zum Import}}
{{%%ns%%:%%fname%%|Download %%fname%% (V-%%version%%)}}
Diese Klasse parst ein SQL-Scripte mit verschiedenen SQL-Befehlen. Einerseits ist sie ein Kontainer mit verschiedenen Befehlen drin, anderseits kann sie ein einzelner Befehl sein. Die einzelnen Befehle können auf die Datenbank angewendet werden.
===== Informationen zur SQL Console =====
==== Links zu weiteren Dokumentationen ====
=== Im Code verwendeteFunktionen/Klassen ===
* [[vba:access:functions:printrs]] Eine Funktion um Datensätze als Plaintext auszugeben
* [[vba:functions:printf:index]] sprintf() für VBA.
=== Weiterführnede Seiten ===
* [[vba:access:sqlscript:scriptexamples]] Diverse Beispiele zu den SQL-Befehlen
* [[vba:access:sqlscript:sqlconsole]] Eine SQL-Konsole für MS Access basierend auf der SQLScript Klasse
===== Definitionen =====
Die Klasse SQLScript ist einerseits ein Container mit verschiedenen Befehlen, anderseits auch ein Befehl selber. Je nach der Eigenschaft des Property [[#action]].
\\ Am besten sieht man das im Beispiel [[#Öffnen einer Script-Datei und die SQL-Statements einzeln ausführen]]
{{ :vba:access:containerprinzip.png?nolink |}}
==== Public Enumeratoren ====
=== sqlType ===
Der SQL-Type.
>DQL (Data Query Language) wird als DCL gehandhabt
* **stNA** N/A
* **stDML** Data Manipulation Language (DML, deutsch „Datenverarbeitungssprache“): Sprache oder Sprachteile für das Abfragen, Einfügen, Ändern oder Löschen von Nutzdaten
* **stDDL** Data Definition Language (DDL, deutsch „Datenbeschreibungssprache“): Sprache oder Sprachteile für das Anlegen, Ändern und Löschen von Datenstrukturen
* **stDCL** Data Control Language (DCL, deutsch „Datenaufsichtssprache“): Sprache oder Sprachteile für die Zugriffskontrolle
=== sqlActions ===
Dieser Enumerator beschreibt, um was ür ein SQL-Script es sich handelt
* **saAutomatic** Die Action ist nicht definiert und soll ermittelt werden
* **saContainer** Das Objekt ist ein Container. Also die Liste mit den versch. SQLs
* //**DDL** Data Definition Language (DDL, deutsch „Datenbeschreibungssprache“)//
* **saCreateView** Abfrageerstellungsscript
* **saCreate** Objekterstellungsscript
* **saAlter** Ändern eines Objektes (Tabelle, Index etc)
* **saDrop** Löschen eines Objektes (Tabelle, Index View, etc)
* //**DML** Data Manipulation Language (DML, deutsch „Datenverarbeitungssprache“)//
* **saUpdate**
* **saInsertOnDuplicateUpdate** Spezialfall INSERT INTO ... ON DUPLICATE KEY UPDATE ....
* **saSelectInto** SELECT INTO. Das erstellen einer Tabelle aus einem SELECT
* **saInsert**
* **saDelete**
* //**DCL** Data Control Language (DCL, deutsch „Datenaufsichtssprache“)//
* **saSelect** Ein einfaches Select als RS zurückgeben
* **saSelectWithParams** Ein einfaches Select mit Parametern als RS zurückgeben
* **saShow** Ausgeben von Auflistungen von Objekten
* **saShowIn** Spezialform von saShow
* **saShowObjects** Spezialform von saShow für Objekte
* **saShowVariables** Spezialform von saShow für Variablen
* **saSet** Setzt Variablen
* **saClearCache** löscht alle oder einzelne Variabeln
* **saPrompt** Zurückgeben eines Textes
* **saDirect** Alle nicht definierten werden direkt ausgeführt
=== objectType ===
Objekttypen die von Aktionen betroffen sein können werden mit dem Public Property affectedType ausgegeben
* **soTable** Tabelle
* **soQueryDef** Abfrage
* **soIndex** Index einer Tabelle
* **soParams** SQL-Variable
=== sqlParams ===
Action. Wie soll sich das Script verhalten. Dieser Enum ist kombinierbar spDirect+spOverwrite
* **spNone**
* **spDirect** Ohne nachfragen ausführen
* **spOverwrite** Bestehendes Objekt ohne Nachfragen überschreiben
* **spIgnore** Fehler ignorieren und weiterfahren
* **spLogText** Gibt anstelle des [[#returnValue]] gleich den genierten [[#logText]] zurück
=== text2ddlParams ===
Parameter um die Text-zu-TableCreate zu steuern
* **tdAutomatic**
* **tdNoHeader ** Die Erste Zeile ist keine Kopfzeile
* **tdSuppressDashLines** Linien die nur aus -_=| und Leerzeichen bestehen werden unterdrückt. Das werden Trennlinien sein
* **tdDropTable ** Erstelle zum CREATE TABEL auch ein DROP TABLE
==== Creatoren ====
=== instanceByFileDialog() ===
>Container
Set container = SQLScript.instanceByFileDialog([filePath])
Erstellt ein Container aus einer Datei, die mittels dem FileDialog ausgewählt wird
'/**
' * Erstellt ein DDLScriptcontainer aus einem File, das über den Filedialog ausgewählt wurde
' * @example Öffnen des FileDialoges mit direktem ausführen des Codes
' * Call SQLScript.instanceByFileDialog().execute
' * @param String Der Pfad/Dateiname, wo der Dialog öffnet
' * @retrun SQLScript oder bei Abrruch Nothing
' */
Public Static Function instanceByFileDialog(Optional ByVal iFilePath As String = Empty) As SQLScript
=== instanceByFilePath() ===
>Container
Set container = SQLScript.instanceByFilePath(filePath)
Erstellt ein Container aus einer Datei. Der Datepafad muss bekannt sein.
'/**
' * Erstellt ein DDLScriptcontainer aus einem File, das über einen direkten Pfad geöffnet wird
' * @example Öffnen und ausführen des ersten SQLs aus einer Date ohne Nachfrage
' * SQLScript.instanceByFilePath("C:\temp\vba_sql_test.sql")(0).execute(spDirect)
' * @param String Der Pfad/Datreiname
' * @retrun SQLScript
' */
Public Static Function instanceByFilePath(ByVal iFilePath As String) As SQLScript
=== instanceByTableText() ===
>Container
script = SQLScript.instanceByTableText(text, tabellenName [,Delemiter]
Diese Methode unterscheidet sich von den Anderen. Die Eingabe ist hier kein SQL, sondern eine Tabelle als Text in einer lesbarer form. Zum Beispiel als CSV
'/**
' * Erstellt ein DDLScriptcontainer aus einem Text, der eine Tabelle darstellt
' * @param String Tabelle in Textform. zB. CSV
' * @param String Tabellenname
' * @param String Mögliche Spaltendelemiter als RegExp-Pattern
' * @param text2ddlParams Steuerparameter
' * @param String Eine seperate Kopfzeile. Wenn die Kopfzeile bereits im iText ist,
' * muss sie nicht seperat mitgegeben werden. NoHeader wird ignoriert
' * @retrun SQLScript
' */
Public Function instanceByTableText( _
ByVal iText As String, _
ByVal iTableName As String, _
Optional ByVal iDelemiterRxPattern As String = "[,|;\t]", _
Optional ByVal iParams As text2ddlParams = tdSuppressDashLines, _
Optional ByVal iHeader As String = Empty _
) As SQLScript
=== instanceSubScript()===
>Statement
script = SQLScript.instanceSubScript(command [,action])
Erstellt eine Instance für ein einzelnes Script aus einem SQL-Statement heraus.
\\ Siehe Beispiel [[#Ein einsames Script erstellen und ausführen]]
'/**
' * Erstellt eine Instanze eines neuen Subscriptes
' * @param String SQL-String
' * @param sqlActions Art des Scriptes. Bei -1 wird die Action ermittelt
' * @retrun SQLScript
' */
Public Static Function instanceSubScript(ByVal iCmd As String, Optional ByVal iAction As sqlActions = saAutomatic) As SQLScript
==== Wichtigste Methoden ====
=== execute ===
>Container und Statement
result = container.execute([paramters] [,action])
Ist das Objekt ein Container, werden alle Scripte in dem Container ausgeführt.
\\ Der Rückgabewert ist je nach [[#action]] unterschiedlich.
'/**
' * Führt anhand der Action das Script aus
' * @param sqlParams
' * @param ddlAction (OUT) Angabe, um was für eine Action es sich wirklich handelt
' * @return Variant Je nach Script unterschiedlich. Recordset, Value, QueryDef, Boolean.
' * Wenn als Paramter spOutText ist es ein lesbaerer Rückgabestring
' */
Public Function execute(Optional ByVal iParams As sqlParams = spNone, Optional ByRef oAction As sqlActions) As Variant
Liste der Rückgabetypen nach Action
^ Action ^ Rückgabewert ^ Beschreibung ^
| saSelect | %%QueryDef%% | |
| saSelectWithParams | %%QueryDef%% | |
| saShow | ADODB.Recordset | |
| saShowIn | ADODB.Recordset | |
| saShowObjects | ADODB.Recordset | |
| saShowVariables | ADODB.Recordset | |
| saPrompt | String | Auszugebender Text |
| saSet | Variant | Wert des Set-Befehls |
| saClearCache | String | Name der Variable oder Empty falls keine Variable mitgegebn wurde|
| saCreateView | Boolean | |
| saCreate | Boolean | |
| saDrop | Boolean | |
| saAlter | Boolean | |
| saInsertOnDuplicateUpdate | Long | Anzahl betroffener Zeilen |
| saSelectInto | Long | Anzahl betroffener Zeilen |
| saInsert | Long | Anzahl betroffener Zeilen |
| saUpdate | Long | Anzahl betroffener Zeilen |
| saDelete | Long | Anzahl betroffener Zeilen |
| Else | Long | Boolean |
=== readFile() ===
>Container
container.readFile filePath
Liest eine Scriptdatei in ein bestehenden Container
'/**
' * Eine Datei einlesen und auswerten
' * @param String Dateipfad
' */
Public Sub readFile(ByVal iFilePath As String)
=== readText() ===
>Container
container.readText sql-Script-String
Parst ein SQL-Script-String. Zerlegt ihn in einzelne Scripte und erstellt im Conatianer jeweils ein Script-Objekt
'/**
' * Ein Script verarbeiten
' * @param String ScriptText (mehrere Scripts)
' */
Public Sub readText(ByVal iScriptText As String)
==== Wichtigste Properties ====
=== action ===
Gibt die Art des Scriptes zurück. Also, was für eine Aktion ausgeführt wird. Der Rückgabewert ist vom Type [[#sqlActions]]
Public Property Get action() As sqlActions
=== affectedItem ===
Vom Script betroffenes Objekt. Tabellen-, Abfrage-, Indexnamen etc.
Public Property Get affectedItem() As String
=== affectedType ===
Der Objekttyp, der vom Script betroffen ist. Der Rückgabewert ist vom Type [[#objectType]]
Public Property Get affectedType() As objectType
=== sqlType ===
Die Information um was für eine Art Script es sich handelt. Der Rückgabewert ist vom Type [[#sqlType]]
Public Property Get sqlType() As sqlType
=== count ===
Wenn die Instanz ein Container ist, gibt count die Anzahl Scripte zurück. Ansonsten -1
Public Property Get count() As Long
=== returnValue ===
Der Rückgabewert von Execute kann über dieses Property nachträglich nochmals ausgelesen werden
Public Property Get returnValue() As Variant
=== logText ===
Gibt einen Text zurück, der die ausgeführten Aktionen dokumentiert
Public Property Get logText() As String
=== filePath ===
Der pFad des Scriptfiles. Macht ntürlich auch nur bei einem Containerobjekt Sinn
Public Property Get filePath() As String
=== script ===
Gibt das SQL-SQL-Script zurück. Mit ; am Ende. Im Falle eines Containers wird das ganze Script ausgegeben
Public Property Get script() As String
==== verwendete Libraries ====
Die folgenden Funktionen müssen seperat geladen werden, damit die Klasse SQLScript funktioniert.
Sie sind zu gross um Sinnvoll in die Klasse zu kopieren.
* [[vba:functions:printf:index]]: Funktion sprintf() ist nützlich um Texte zu parsen
===== Beispiele =====
>Für die Ausgabe der %%QueryDefs%% und der Recordsets verwende ich die Funktion [[vba:access:functions:printrs]]
==== Programm Beispiele ====
=== Einfaches Ausführen einer Script-Datei ===
Eine Script-Datei öffnen und alle Script ausführen
Dim scriptContainer As SQLScript
Set scriptContainer = SQLScript.instanceByFilePath("C:\temp\sql\vba_sql_test2.sql")
scriptContainer.execute
=== Öffnen einer Script-Datei und die SQL-Statements einzeln ausführen===
Jeder Befehl einzeln ausführen und die [[#action]] und [[#sqlType]] ausgeben
Dim scriptContainer As SQLScript
Dim script As SQLScript
Set scriptContainer = SQLScript.instanceByFilePath("C:\temp\sql\vba_sql_test2.sql")
For Each script In scriptContainer
script.execute
Debug.Print script.sqlType, script.action
Next script
=== Ein einsames Script erstellen und ausführen ===
Dank der Instance-Funktionen kann man einfache Scripte ohne grossen Codeaufwand ausführen. Beide folgenden Script haben dasselbe Resultat. (Im Beispiel wird [[vba:access:functions:printrs]] verwendet)
printRs SQLScript.instanceSubScript("SHOW TABLES").execute()
debug.print SQLScript.instanceSubScript("SHOW TABLES").execute(spLogText)
| table_name | row_count | last_update | indexes |
|-----------------------------|-----------|---------------------|--------------------------------------------|
| ADDON_SQL_CONSOLE_SESSION | 19 | 13.04.2015 12:57:28 | ID, PrimaryKey (PK) |
| t_sql_test | 1 | 17.04.2015 10:08:24 | idx_sql_val, Index_F44530CA_8088_4FED (PK) |
| tbl_t1 | 2 | 13.04.2015 12:09:01 | idx_val, Index_B4C4285A_B98F_4415 (PK) |
| TODO: ADDON_SQL_CONSOLE_LOG | 0 | 13.04.2015 12:26:40 | PrimaryKey (PK), SESSION_ID, STEP_ID
=== Manuelles Ausführen einer Scriptdatei ohne GUI ===
Und hier noch ein Beispiel mit %%FileDialog und MsgBox%% um eine Scriptdatei auszuführen.
Dazu verwende ich einfach die Instanzierung über [[#instanceByFileDialog]]] und die Ausgabe von [[#execute]] mit dem [[#sqlParams]] spLogText.
MsgBox SQLScript.instanceByFileDialog().execute(spLogText)
=== Manuell erstellter Container ===
Ein Container kann auch Manuell gefüllt werden. Hier ein Beispiel in dem zuerst ein SET ausgeführt wird und anschliessend ein SELECT.
Dim scriptContainer As New SQLScript
'Neu initialisierte Objekte werden automatisch als Container definiert
'Dies könnte über den action-Parameter übersteuert werden
With scriptContainer
.addNewScript "SET a = 123"
.addNewScript "SELECT a"
.addNewScript "SHOW VARIABLES"
Debug.Print .item(0).execute
printRs .item(1).execute
printRs .item(2).execute
End With
123
| a |
|-----|
| 123 |
| variable_name | type | value |
|---------------|------|-------|
| A | BYTE | 123 |
=== Text in Tabellenscript wanden ===
Mit der Methode instanceByTableText() kann ein Tabelle in Textform in ein Create Table - & Insertscript konvertiert werden.
Häufig habe ich für Test Tabellen in der Textform oder einen ähnlichen.
ID, ITEM_NAME, ITEM_VALUE, CREATE_DATE
======================================
1, ABC , 123 , 1.1.1967
2, DEF , 346.3 , 11.12.2010
3, GHI , 10098 , 17.11.2016
4, JKL , ,
Und heir die Umsetzung für ein kleinen Test:
Sub testSqlScript()
Dim script As SQLScript
Dim txt(5) As String
txt(0) = "ID, ITEM_NAME, ITEM_VALUE, CREATE_DATE"
txt(1) = "======================================"
txt(2) = " 1, ABC , 123 , 1.1.1967 "
txt(3) = " 2, DEF , 346.3 , 11.12.2010 "
txt(4) = " 3, GHI , 10098 , 17.11.2016 "
txt(5) = " 4, JKL , , "
Set script = SQLScript.instanceByTableText(Join(txt, vbCrLf), "TBL_TEST", , tdDropTable + tdSuppressDashLines)
Debug.Print script.script
script.execute spIgnore
Debug.Print script.logText
End Sub
DROP TABLE [TBL_TEST];
CREATE TABLE [TBL_TEST] ([ID] BYTE,[ITEM_NAME] TEXT(3),[ITEM_VALUE] DOUBLE,[CREATE_DATE] DATE);
INSERT INTO [TBL_TEST] ([ID],[ITEM_NAME],[ITEM_VALUE],[CREATE_DATE]) VALUES (1,'ABC',123,#01-01-1967 00:00:00#);
INSERT INTO [TBL_TEST] ([ID],[ITEM_NAME],[ITEM_VALUE],[CREATE_DATE]) VALUES (2,'DEF',346.3,#12-11-2010 00:00:00#);
INSERT INTO [TBL_TEST] ([ID],[ITEM_NAME],[ITEM_VALUE],[CREATE_DATE]) VALUES (3,'GHI',10098,#11-17-2016 00:00:00#);
INSERT INTO [TBL_TEST] ([ID],[ITEM_NAME],[ITEM_VALUE],[CREATE_DATE]) VALUES (4,'JKL',NULL,NULL);
Table droped
Table created
Insert rows
Insert rows
Insert rows
Insert rows
==== Script Beispiele ====
Siehe [[vba:access:sqlscript:scriptexamples]]
===== Code =====
>//Das Modul hat versteckte Attribute. Damit diese aktiv übernommen werden reicht es nicht aus, den Code in ein neues Modul zu kopieren. Man muss das Modul aus der Datei nach VBA importieren.//
>{{popup>:vba:vba_importfile.png|Bild zum Import}}
{{%%ns%%:%%fname%%|Download %%fname%% (V-%%version%%)}}