AHK Connect SQLite Variable in Datenbank auslagern Topic is solved

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

User avatar
Heloo1982
Posts: 27
Joined: 12 Jan 2017, 07:39

AHK Connect SQLite Variable in Datenbank auslagern

29 Aug 2018, 02:43

Hallo zusammen,
ich benötige Hilfe bei der Verbindung eines AHK Scripts mit einer SQLite db.

Anwendungsfall:
Ich habe eine InputBox, wo eine PLZ eingegen wird. Danach soll ein PopUp aufgehen, wo Informationen dazu angezeigt werden.

Code: Select all

^F1::
InputBox, FragePLZ, Bitte PLZ eingeben:

if(FragePLZ="70000")
	{
	Stadt=Stuttgart
	BL=BW
	}
	
if(FragePLZ="80000")
	{
	Stadt=München
	BL=Bayern
	}

MsgBox, Stadt %Stadt%, Bundesland %BL%

Return
Das Skript ist auch bereits fertig und wird produktiv eingesetzt, jedoch hat es ca. 160.000 Zeilen und muss regelmäßig gepflegt werden, was etwas umständlich ist. Nun kam mir die Idee, es wäre doch totschick, wenn man die ganzen Variablen in eine Datenbank auslagern könnte. Idealerweise sogar MySQL, ich hab mich erst einmal mit SQLite versucht. Hier habe ich folgende Tabelle erzeugt:

Code: Select all

CREATE TABLE `Deutschland` ( `PLZ` INTEGER NOT NULL UNIQUE, `Stadt` TEXT, `BL` TEXT, PRIMARY KEY(`PLZ`) )
Die Tabelle wurde mit den identischen Daten gefüllt:

Code: Select all

INSERT INTO Deutschland (PLZ, Stadt, BL) VALUES (70000, Stuttgart, BW);
INSERT INTO Deutschland (PLZ, Stadt, BL) VALUES (80000, Muenchen, Bayern);
Nach langer Googlesuche habe ich ein Script gefunden, was auch mit SQLite funktioniert, leider habe ich es nicht verstanden. Wahrscheinlich bin ich dazu einfach zu wenig Programmierer^^
https://github.com/IsNull/ahkDBA

Die Erklärung dazu konnte ich ebenfalls finden, also Script und db in einen Ordner gepackt und versucht anhand der Erklärung das Ganze auf meinen Anwendungsfall anzuwenden:
https://autohotkey.com/board/topic/7117 ... mysql-ado/

Code: Select all

^F2::
connectionString := "Hauptstadt.sqlite3"
db := DBA.DataBaseFactory.OpenDataBase("SQLite", connectionString)

 rs := db.OpenRecordSet("Select * from Deutschland where PLZ='70000'")
   while(!rs.EOF){   
      PLZ := rs["PLZ"] 
      Stadt := rs["Stadt"]  ; column-name oder Index

      MsgBox %PLZ% %Stadt%
      rs.MoveNext()
   }
   rs.Close()
	
Return
Wenn jetzt die Msgbox aufgegangen wäre mit "70000 Stuttgart" wäre ich überglücklich und würde diesen Thread wahrscheinlich gar nicht schreiben. ;)

Ich hoffe mir kann jemand helfen, ich bin für jede konstruktive Anregung dankbar. Irgendwas habe ich vergessen, vllt muss ich auch die sqlite3.dll irgendwie einbinden, ich komme aber allein nicht weiter. :headwall:
Vielen Dank im Voraus fürs lesen und hirnen.
Guest

Re: AHK Connect SQLite Variable in Datenbank auslagern

29 Aug 2018, 09:09

Vielleicht liegt es auch an fehlenden/falschen quotes und semicolons
zum Beispiel

Code: Select all

INSERT INTO Deutschland (PLZ, Stadt, BL) VALUES (70000, 'Stuttgart', 'BW');
btw sind PLZ im allgemeinen nicht unique in (PLZ, Stadt, BL), Muenchen hat dutzende.
User avatar
Heloo1982
Posts: 27
Joined: 12 Jan 2017, 07:39

Re: AHK Connect SQLite Variable in Datenbank auslagern

29 Aug 2018, 11:29

Erstmal danke für deine Hilfe.
Die Daten stehen in der Datenbank drin, das hab ich überprüft, das war auch nicht der Originalcode ;-)
Aber vllt liegt es wirklich an der Formatierung, wobei die Abfrage

Code: Select all

"Select * from Deutschland where PLZ='70000'")
über einen DB-Manager und die Konsole funktioniert. Ich schaffe es nur nicht, die Ergebnisse über AHK auszugeben bzw. weiß ich nicht, ob überhaupt eine Verbindung besteht.
Ich hatte es aber auch schon mit Varchar versucht, gleiches enttäuschende Ergebnis.....

Wobei ich mich frage, ob ich bei UNIQUE gerade einen Denkfehler habe? Klar gibt es München viele PLZ, ich dachte damit wird formuliert, dass es diese eine PLZ in der Datenbank nur einmalig geben darf und Duplikate ausgeschlossen werden?!?
Last edited by Heloo1982 on 30 Aug 2018, 01:30, edited 1 time in total.
Guest

Re: AHK Connect SQLite Variable in Datenbank auslagern

29 Aug 2018, 15:44

Wobei ich mich frage, ob ich bei UNIQUE gerade einen Denkfehler habe
ne ich.
User avatar
Heloo1982
Posts: 27
Joined: 12 Jan 2017, 07:39

Re: AHK Connect SQLite Variable in Datenbank auslagern

30 Aug 2018, 01:14

Gast wrote:
Wobei ich mich frage, ob ich bei UNIQUE gerade einen Denkfehler habe
ne ich.
Kein thema......ich hab übigens eine neue db erstellt und diese mal wirklich nur mit Text gefüllt, hat leider nichts gebracht :(
Hier der Vollständigkeit halber noch das Ergebnis vom Statement:
20180830_SQLite Statement AHK.JPG
(15.29 KiB) Downloaded 325 times
Leider kann ich die Datenbank nicht hochladen, da .db und .sqlite3 vom Server gesperrt sind.
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: AHK Connect SQLite Variable in Datenbank auslagern

30 Aug 2018, 04:05

Moin,

ich habe hier ein eigenes Skript für SQLite eingestellt. Wenn Du das mal probierst, könnte ich Dich bei Bedarf besser unterstützen. Mit der Version von IsNull kenne ich mich nicht aus.
User avatar
Heloo1982
Posts: 27
Joined: 12 Jan 2017, 07:39

Re: AHK Connect SQLite Variable in Datenbank auslagern

30 Aug 2018, 09:41

Moin,
ich glaub ich bin über dein Skript auch mal drüber gestolpert, hab es aber genauso wenig gecheckt wie das von "IsNull" :D
Auf die Gefahr hin, dass ich mich jetzt total blamiere, versuche ich mal mein Glück. Muss dazu sagen, ich hab auch keine Ahnung was ich hier mache.
Soweit hab ich mal verstanden:
  1. Ein Class SQLiteDB erstellen mit dem Namen New SQLiteDB

    Code: Select all

    class SQLiteDB 
    {
    MyDB := New SQLiteDB
    }
  2. Die Datei sqlite3.dll runterladen und ins gleiche Verzeichnis wie Datenbank und Skript kopieren.
    Screenshot.JPG
    (16.92 KiB) Downloaded 296 times
  3. In deinem Skript hab ich dann diesen Abschnitt gefunden und mal eingefügt, damit ist dann vermutlich die sqlite3.dll eingebunden.

    Code: Select all

    Class SQLiteDB Extends SQLiteDB.BaseClass {
    	Class BaseClass {
          	Static Version := ""
         	Static _SQLiteDLL := A_ScriptDir . "\SQLite3.dll"
          	Static _RefCount := 0
          	Static _MinVersion := "3.6"
       }
    }
    
  4. Als nächstes habe ich verstanden, dass du 4 verschiedene Arten von Abfragen eingebaut hast, wobei für mich vermutlich die MyDB.Query(SQL, RecordSet, ...) oder MyDB.StoreBLOB(SQL, BlobArray) in Frage kommt.
Jetzt bräuchte ich nochmal einen Schupser in die richtige Richtung. Wo definiere ich jetzt das Statement und die Variablen und wie verlinke ich die Datenbank? :crazy:
Danke im Voraus.
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: AHK Connect SQLite Variable in Datenbank auslagern

31 Aug 2018, 09:29

Moin,

ich melde mich noch mal. Im Augenblick fehlt mir die Zeit.
Ahk_fan
Posts: 50
Joined: 31 Aug 2018, 14:34

Re: AHK Connect SQLite Variable in Datenbank auslagern

31 Aug 2018, 14:46

Hallo,
Hast du die Bibliothek DBA.ahk eingebunden? Man muss dann noch die ganzen restlichen AHK Dateien aus dem lib Verzeichnis des Beispiels kopieren und in das lib Verzeichnis des Scripts einfügen. Die Verbindung mit der Datenbank muss dann wie DBAexample.ahk erfolgen...

Gruß AHK_fan
regards,
AHK_fan :)
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: AHK Connect SQLite Variable in Datenbank auslagern  Topic is solved

01 Sep 2018, 05:56

Moin,

versuchen wir es mal.

Ich weiß nicht, wie weit Deine Kentnisse mit der AHK-Programmierung reichen. Wenn Du eher Anfänger bist, kommen Dir die AHK-Klassen wahrscheinlich eher merkwürdig vor. Das trifft ja aber sowohl auf Class_SQLiteDB.ahk wie auch auf DBA.ahk zu.

Zunächst einmal:
Eine Klassendefinition wie in SQLiteDB sollte immer komplett in das Skript übernommen werden. Man kann allenfalls einzelne Teile entfernen, tut das aber dann auf eigenes Risiko. Du solltest deshalb die komplette Klasse per

Code: Select all

#Include Class_SQLiteDB.ahk
in Dein Skript inkludieren oder den kompletten Klassencode in Dein Skript kopieren.

Damit das Ganze funktioniert, brauchst Du dann 3 Dinge:
  1. Ein AHK-Script.
  2. Eine SQLite-Datenbank.
  3. Die zu Deiner AHK-Version (32/64 Bit) passende SQLite3.dll von der SQLite Download Page:
    https://www.sqlite.org/2018/sqlite-dll- ... 240000.zip (32 Bit)
    https://www.sqlite.org/2018/sqlite-dll- ... 240000.zip (64 Bit)
Am Einfachsten ist es, wenn sich alle Drei in einem Verzeichnis befinden.

Auf GitHub findest Du das Skript SQLiteDB_sample.ahk. Darin finden sich Beispiele dafür, wie man mit AHK auf eine SQLite-Datenbank zugreift. Die wesentlichen Schritte für eine Datenbankabfrage will ich hier noch einmal erläutern.

Als Erstes muss eine eigenes Datenbankobjekt aus der Klasse erzeugt werden. Das geht mit

Code: Select all

DB := New SQLiteDB
Wenn dabei etwas schiefgeht, solltest Du eine Fehlermeldung bekommen.

Danach muss dem Datenbankobjekt eine Datenbank zugewiesen werden. Das macht man mit einem Aufruf der Methode OpenDB:

Code: Select all

DBFileName := A_ScriptDir . "\Hauptstadt.sqlite3"
If !DB.OpenDB(DBFileName) {
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
   ExitApp
}
Dabei muss im ersten Parameter der Pfad der Datenbankdatei übergeben werden.

Jetzt kannst Du Deine SQL-Statements auf die Datenbank loslassen. Für Statements, die keine Abfragen sind, gibt es die Methode

Code: Select all

DB.Exec(SQLStatement)
Die versucht, das Statement auszuführen, und gibt schlicht bei Erfolg 1 (True) und im Fehlerfall 0 (False) zurück. Ich gehe hier nicht weiter darauf ein.

Für Datenbankabfragen bietet SQLite eine Besonderheit. SQLite kann sämtliche Antworten einer Abfrage auf einen Schlag in einem Table-Objekt zurückgeben. Dafür gibt es die Methode DB.GetTable(). Die versucht, das im ersten Parameter übergebene SQL-Statement auszuführen, erstellt ggf. aus dem Ergebnis ein AHK-Objekt in der im zweiten Parameter übergebenen Variablen, gibt dann die Datenbankressourcen frei und 1 (True) zurück. Bei Fehlern wird auch hier 0 (False) zurückgegeben:

Code: Select all

SQL := "SELECT * FROM Test;"
If !DB.GetTable(SQL, Result)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
Das im Beispiel in der Variablen Result zurückgegebene Objekt ist innnerhalb der Klasse SQLiteDB als Subklasse _Table definiert und hat folgende Eigenschaften:

Code: Select all

Result.ColumnCount   -  Anzahl der zurückgelieferten Spalten
Result.RowCount      -  Anzahl der zurückgelieferten Zeilen
Result.ColumnNames   -  Einfaches Array mit Spaltennamen in der Reihenfolge der Abfrage
Result.Rows          -  Zweidimensionales Array mit den Ergebnissen der Abfrage:
                        0 - Rowcount Zeilen mit Index 1 - Rowcount
                        0 - ColumnCount Spalten mit Index 1 - ColumnCount
Result.HasNames      -  Result.ColumnNames enthält Werte (True / False)
Result.HasRows       -  Result.Rows enthält Werte (True / False)
Für den Zugriff auf das Ergebnis gibt es zwei Methoden. Mit Result.Next(Row)wird das Ergebnis sequentiell abgearbeitet. Mit Result.GetRow(RowIndex, Row) wird auf die in RowIndex übergebene Zeile zugegriffen. Beide Methoden stellen bei Erfolg ein Array mit den Spaltenwerten der Zeile in die Variable Row und geben 1 (True) zurück. Bei Fehlern bzw. wenn keine weitere Zeile zur Verfügung steht, wird 0 (False) zurückgegeben. Auf die Spaltenwerte kann dann im Gegensatz zu IsNulls DBA.ahk nur über den Index aber nicht über den Namen zugegriffen werden.

Code: Select all

Spalte1 := Row[1]
liefert den Wert der ersten Spalte.

Auf das Ergebnis in Result.Rows kann per Zeilen- und Spaltenindex aber auch direkt zugegriffen werden. So liefert

Code: Select all

Z1S2 := Result.Rows[1, 2]
den Wert der zweiten Spalte der ersten Zeile der gelieferten Tabelle.

Wenn Du die Datenbank nicht mehr brauchst, kannst Du sie mit Result.CloseDB() schließen. Notfalls erledigt AHK das bei Beendigung des Skripts auch automatisch.

Lange Rede, kurzer Sinn, Deine Frage könnte folgende Antwort haben (ungetestet):

Code: Select all

#NoEnv
DB := New SQLiteDB

DBFileName := A_ScriptDir . "\Hauptstadt.sqlite3"
If !DB.OpenDB(DBFileName) {
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
   ExitApp
}

SQL := "SELECT * FROM Deutschland WHERE PLZ = '70000';" ; keine Garantie für das SQL
If !DB.GetTable(SQL, Result)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
Else
   MsgBox, 0, SQLite, % "Zeilen = " . Result.RowCount . "`n"
                      . "Stadt1 = " Result.Rows[1, 2] . " - " . "BL1 = " . Result.Rows[1, 3]

DB.CloseDB()
ExitApp

#Include SQLiteDB.ahk
User avatar
Heloo1982
Posts: 27
Joined: 12 Jan 2017, 07:39

Re: AHK Connect SQLite Variable in Datenbank auslagern

04 Sep 2018, 02:27

Herzlichen Dank für beide Antworten und das ihr euch so ausgiebig mit meiner Problemstellung beschäftigt habt.

@Just me
Deine Antwort ist aus meiner Sicht eine der besten Anleitung für das Einbinden einer SQLite, welche aktuell im Netz zu finden ist. Ich denke, ich konnte es jetzt auch halbwegs nachvollziehen und werde die Erkenntnisse für weitere Projekte verwenden können.

So sieht es jetzt in meinem Ordner aus:
20180903_SQLite AHK.JPG
(18.51 KiB) Downloaded 176 times
Dein Skript habe ich fast komplett übernommen, ich habe nur ein paar kleine Anpassungen vorgenommen, da ich die Ergebisse in Einzelvariablen benötige:

Code: Select all

DB := New SQLiteDB

DBFileName := A_ScriptDir . "\Hauptstadt.sqlite3"
If !DB.OpenDB(DBFileName) {
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
   ExitApp
}


SQL := "SELECT * FROM Deutschland WHERE PLZ = '70000';" 
If !DB.GetTable(SQL, Result)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
Else
  
   
	var1 := % Result.RowCount 
                      					  
	var2 := % Result.Rows[1, 2]
	
	var3 := % Result.Rows[1, 3]
   
MsgBox, Zeile %Var1%, Stadt %Var2%, Bundesland %Var3%

DB.CloseDB()
ExitApp

#Include Class_SQLiteDB.ahk
Das Ergebnis war aber in beiden Fällen sehr erfreulich :dance:
20180903_SQL AHK Ergebnis.JPG
(15.37 KiB) Downloaded 176 times
Vielen Dank für deine Hilfe, alleine wäre ich hier wahrscheinlich nicht weiter gekommen.

Eine Frage stellt sich mir noch, da ich eigentlich das Statement über Variablen aus einer GUI manipulieren wollte, z.B:

Code: Select all

#NoEnv
#SingleInstance Force

F2::
Gui, New,,
Gui, show, w150 h150
Gui, add, edit, w100 vFragePLZ,
Gui, add, DropDownList, vLand, Deutschland||Frankreich|Belgien
Gui, add, Button, w50 gSQL_Abfrage Default, OK
GuiControl,Focus, FragePLZ
Return


SQL_Abfrage:
GUI, Submit

DB := New SQLiteDB

DBFileName := A_ScriptDir . "\Hauptstadt.sqlite3"
If !DB.OpenDB(DBFileName) {
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
   ExitApp
}


SQL := "SELECT * FROM %Land% WHERE PLZ = '%FragePLZ%';" 
If !DB.GetTable(SQL, Result)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
Else
  
   
	var1 := % Result.RowCount 
                      					  
	var2 := % Result.Rows[1, 2]
	
	var3 := % Result.Rows[1, 3]
   
MsgBox, Zeile %Var1%, Stadt %Var2%, Bundesland %Var3%

DB.CloseDB()
;ExitApp

#Include Class_SQLiteDB.ahk
Return
Aktuell bekomme ich hier eine Fehlermeldung, da er innerhalb des Statements die Variablen nicht ersetzt, sondern mit den %-Zeichen arbeiten möchte. wahrscheinlich als Wildcard interpretiert:
20180904_SQL_AHK_Fehlermeldung_GUI.JPG
(17.36 KiB) Downloaded 176 times
Gibt es hier noch einen Trick bzw. hab ich einen Fehler gemacht?
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: AHK Connect SQLite Variable in Datenbank auslagern

04 Sep 2018, 03:00

Moin,

die Zuweisung per := erwartet einen Ausdruck. In Ausdrücken unterscheidet man zwischen Text ("...") und Variablen. Innerhalb von Texten ist der Zugriff auf Variable nicht möglich. Für das Problem gibt es deshalb zwei Lösungen:

Ausdruck:

Code: Select all

SQL := "SELECT * FROM " . Land . " WHERE PLZ = '" . FragePLZ . "';"
Command-Syntax:

Code: Select all

SQL = SELECT * FROM %Land% WHERE PLZ = '%FragePLZ%';
Auch wenn die Command-Syntax verführerisch einfacher aussieht, ich würde auch wegen der Zukunftssicherheit den Ausdruck vorziehen. Den Verknüpfungoperator Punkt . darf man auch weglassen, wenn man es mag. Ein Leerzeichen zwischen den einzelnen zu verknüpfenden Teilen reicht:

Code: Select all

SQL := "SELECT * FROM " Land " WHERE PLZ = '" FragePLZ "';"
User avatar
Heloo1982
Posts: 27
Joined: 12 Jan 2017, 07:39

Re: AHK Connect SQLite Variable in Datenbank auslagern

04 Sep 2018, 04:02

Ich bin wunschlos glücklich :thumbup:
Thema aus meiner Sicht gelöst, vielen Dank für deine Zeit und Geduld mit mir.
LG

Return to “Ich brauche Hilfe”

Who is online

Users browsing this forum: No registered users and 5 guests