Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Hilfe zu SQLite, Aufbau, Abfrage, Ändern etc.


  • Please log in to reply
84 replies to this topic
fump2000
  • Members
  • 591 posts
  • Last active: Nov 11 2015 07:52 AM
  • Joined: 01 Nov 2012

Hallo zusammen,

 

es geht um SQLite.

Ich habe versucht anhand des Beispiels von hier http://www.autohotke...lite-mysql-ado/ die Abfolgen und den Aufbau selbst zu verstehen. Leider scheitere ich. Ich kann die Dinge die ich für SQLite benötige nicht aus dem Beispiel lösen und den Rest zu löschen.

 

Z. B. Welche Libs werden tatsächlich benötigt? Wie baue ich eine DB auf? Wie rufe ich Inhalt ab? Wie füge ich welchen ein? Wie ändere ich Inhalt? Wie füttert man ein Listview mit Daten aus einer DB?

 

Ich habe mich mit SQL leider noch nicht wirklich beschäftigen können. Ich weiß also nicht wirklich wie man mit einer DB umgehen muss/soll.

 

Den Vorteil den ich mir von einer SQLite DB erhoffe ist derer, dass es mit einer gewissen Masse an Einträgen leichter zu handhaben ist. Die DB kann mit der Zeit durchaus einige tausend Einträge haben.

 

Vielleicht mag mir jemand ein Beispiel geben wie es mit SQLite geht?

 

Danke im voraus!

 

MfG
fump



just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011

... oder Du schaust  DIr mal das inzwischen weiter entwickelte Basisskript samt Beispielen an -> SQLiteDB


Prefer ahkscript.org for the time being.


fump2000
  • Members
  • 591 posts
  • Last active: Nov 11 2015 07:52 AM
  • Joined: 01 Nov 2012

Vielen Dank für eure Antworten!

 

Ich habe mir den Code von just me genauer angeschaut. Anscheinend verstehe ich den Aufbau einer DB nicht.

 

Mir liegen folgnde Daten vor:

Eine ID (wird zufällig berechnet, Username und A_Now davon wird ein Hash berechnet, dies ist die ID)

Eine Kundenunmmer

Evtl. eine ID eine Kundenanschreibens

Ein "ToDo" (Klartext, begrenzt auf 300 Zeichen)

Ein "was wurde gemacht" (Klartext, begrenzt auf 300 Zeichen)

Ein wiedervorlage Datum

Eine Uhrzeit

Ein Status (offen oder geschlossen)

 

Nun wenn ich es recht verstehe wird eine DB erstellt, z. B. test.db

 

Ist es dann wie eine Excel Tabelle zu verstehen wo man Spalten entsprechend beschriftet?

Spalte A ist dann die ID

Spalte B die Kundennummer

etc

?

 

Oder funktioniert es anders?

 

Wie werden die Spalten in der DB angelegt? Und wie dann mit Inhalt gefüllt?

 

Im BeispielScript passiert dies hiermit:

If !DB.OpenDB(DBFileName) {
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
   ExitApp
}
SQL := "CREATE TABLE Test (Name, Fname, Phone, Room, PRIMARY KEY(Name ASC, FName ASC));"
If !DB.Exec(SQL)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
Start := A_TickCount
DB.Exec("BEGIN TRANSACTION;")
SQLStr := ""
_SQL := "INSERT INTO Test VALUES('Name#', 'Fname#', 'Phone#', 'Room#');"
Loop, 1000 {
   StringReplace, SQL, _SQL, #, %A_Index%, All
   SQLStr .= SQL
}
If !DB.Exec(SQLStr)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
DB.Exec("COMMIT TRANSACTION;")
SQLStr := ""

If !DB.OpenDB(DBFileName) : prüft ob die DB geöffnet werden konnte richtig?

 

SQL := "CREATE TABLE Test (Name, Fname, Phone, Room, PRIMARY KEY(Name ASC, FName ASC));" : Erklär mir bitte was hier genau passiert. CREATE TABLE erstellt eine Tabelle oder hier wohl mehrer Tabellen. Kann man das als Spaleten verstehen? Also wird die Spalte Name, Fname, Phone und Room erstellt. Was bedeutet bzw. wofür ist dies hier: KEY(Name ASC, FName ASC)? Am Ende eines jeden SQL Befehls muss ein ; stehen richtig?

 

Wozu ist dies: DB.Exec("BEGIN TRANSACTION;") ?

 

_SQL := "INSERT INTO Test VALUES('Name#', 'Fname#', 'Phone#', 'Room#');" : INSERT INTO Test VALUES bedeutet, dass in die DB Test Werte eingefügt werden sollen.

 

Es geht hier im Beispiel um SQLStr Der String _SQL wird im Loop 1000 mal verändert. Immer wird # durch A_Index ersetzt. Per SQLStr .= SQL wird ein langer String gebildet.

 

If !DB.Exec(SQLStr) : führt dies den SQL Befehl aus? Das ! prüft doch ob der Befehl korrekt ausgeführt wurde oder? Wenn nicht dann gibst die msgbox.

 

DB.Exec("COMMIT TRANSACTION;") : schließt die Transaktion ab, macht es sonst noch was?

 

 

Hoffe ich hab nicht zu viel Blödsinn geschrieben :) Ich will das Thema beherrschen.

 

MfG
fump



just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011

Vielen Dank für eure Antworten!
 
Ich habe mir den Code von just me genauer angeschaut. Anscheinend verstehe ich den Aufbau einer DB nicht.
 
Mir liegen folgnde Daten vor:
Eine ID (wird zufällig berechnet, Username und A_Now davon wird ein Hash berechnet, dies ist die ID)
Eine Kundenunmmer
Evtl. eine ID eine Kundenanschreibens
Ein "ToDo" (Klartext, begrenzt auf 300 Zeichen)
Ein "was wurde gemacht" (Klartext, begrenzt auf 300 Zeichen)
Ein wiedervorlage Datum
Eine Uhrzeit
Ein Status (offen oder geschlossen)
 
Nun wenn ich es recht verstehe wird eine DB erstellt, z. B. test.db
 
Ist es dann wie eine Excel Tabelle zu verstehen wo man Spalten entsprechend beschriftet?
Spalte A ist dann die ID
Spalte B die Kundennummer
etc
?
 
Oder funktioniert es anders?
 
Nein, der Aufbau einer Tabelle in einer SQL-Datenbank entspricht im Wesentlichen dem Aufbau eines Excel-Tabellenblatts. Die Feldnamen/Felder definieren die Spalten, die Inhalte/Werte bilden die Reihen/Sätze.
 
Wie werden die Spalten in der DB angelegt? Und wie dann mit Inhalt gefüllt?
 
Im BeispielScript passiert dies hiermit:

If !DB.OpenDB(DBFileName) {
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
   ExitApp
}
SQL := "CREATE TABLE Test (Name, Fname, Phone, Room, PRIMARY KEY(Name ASC, FName ASC));"
If !DB.Exec(SQL)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
Start := A_TickCount
DB.Exec("BEGIN TRANSACTION;")
SQLStr := ""
_SQL := "INSERT INTO Test VALUES('Name#', 'Fname#', 'Phone#', 'Room#');"
Loop, 1000 {
   StringReplace, SQL, _SQL, #, %A_Index%, All
   SQLStr .= SQL
}
If !DB.Exec(SQLStr)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
DB.Exec("COMMIT TRANSACTION;")
SQLStr := ""
If !DB.OpenDB(DBFileName) : prüft ob die DB geöffnet werden konnte richtig?
 
Ja. Hier kommt noch eine Besonderheit von SQLite ins Spiel. SQLite verwaltet Datenbanken in einer einzigen Datei. Beim Aufruf von OpenDB() prüft SQLite, ob eine gleichnamige Datenbankdatei existiert. Wenn nicht, wird eine neue Datei mit allen notwendigen Verwaltungsstrukturen angelegt, wenn man nicht für den optionalen Parameter Create den Wert False/0 übergibt.
 
SQL := "CREATE TABLE Test (Name, Fname, Phone, Room, PRIMARY KEY(Name ASC, FName ASC));" : Erklär mir bitte was hier genau passiert. CREATE TABLE erstellt eine Tabelle oder hier wohl mehrer Tabellen. Kann man das als Spaleten verstehen? Also wird die Spalte Name, Fname, Phone und Room erstellt. Was bedeutet bzw. wofür ist dies hier: KEY(Name ASC, FName ASC)? Am Ende eines jeden SQL Befehls muss ein ; stehen richtig?
 
Die SQL-Anweisung CREATE TABLE erstellt eine neue Tabelle mit dem Namen Test und den Feldern Name, Fname, Phone und Room. Wenn wie hier keine Feldtypen angegeben werden, werden die Feldwerte später als Text abgelegt. PRIMARY KEY bestimmt den Primärschlüssel für die Tabelle, in diesem Fall eine Kombination der Felder Name und Fname. Der Primärschlüssel ist ein eindeutiger Wert, der in einer Tabelle nur genau einmal vorkommen darf. Außerdem wird für den Primärschlüssel ein sogenannter Index angelegt, der Zugriffe über diesen Schlüssel schneller macht. In Deinem Fall wäre es wohl die berechnete ID.
 
SQL-Anweisungen werden in der Regel mit einem Semikolon abgeschlossen. Wenn Du nur eine einzelne Anweisung ausführen lässt, kannst Du es aber auch weglassen.
 
Wozu ist dies: DB.Exec("BEGIN TRANSACTION;") ?
 
SQL-Datenbanken können Veränderungen der Daten in sogenannte Transaktionsklammern einschließen. Alle Veränderungen, die innerhalb einer Transaktion durchgeführt werden, werden entweder vollständig oder gar nicht ausgeführt. So kann man verhindern, dass bei einem Fehler ein inkonsistenter Zustand entsteht. BEGIN TRANSACTION bestimmt den Anfang einer Transaktion.
 
Im Fall von SQLite hat die Transaktionsklammer noch einen beschleunigenden Nebeneffekt. SQLite ist beim Einfügen "größerer Mengen" von Reihen relativ langsam, wenn jeder INSERT einzeln verarbeitet wird.  Deshalb empfehlen die Entwickler, "viele" aufeinanderfolgende INSERT Anweisungen in einer Transaktion zu kapseln.
 
_SQL := "INSERT INTO Test VALUES('Name#', 'Fname#', 'Phone#', 'Room#');" : INSERT INTO Test VALUES bedeutet, dass in die DB Test Werte eingefügt werden sollen.
 
Es geht hier im Beispiel um SQLStr Der String _SQL wird im Loop 1000 mal verändert. Immer wird # durch A_Index ersetzt. Per SQLStr .= SQL wird ein langer String gebildet.
 
Das SQLite-API unterstützt auch sogenannte multi-statement Anweisungen, d.h. mehrere durch Semikolon getrennte aneinandergehängte SQL-Anweisungen. Ich nutze das im Beispiel, um das Einfügen der 1000 neuen  Reihen schnellstmöglich durchzuführen.
 
If !DB.Exec(SQLStr) : führt dies den SQL Befehl aus? Das ! prüft doch ob der Befehl korrekt ausgeführt wurde oder? Wenn nicht dann gibst die msgbox.
 
Ja! Mit der Methode Exec() werden alle SQL-Anweisungen ausgeführt, die keine Werte aus der Datenbank liefern/abfragen. Wenn dabei ein Fehler auftritt, gibt die Methode False/0 zurück.
 
DB.Exec("COMMIT TRANSACTION;") : schließt die Transaktion ab, macht es sonst noch was?
 
Ja, es sorgt dafür, dass sämtliche Änderungen der Datenbank seit dem letzten BEGIN TRANSACTION wirksam werden. Im Falle eines Fehlers hättest Du hier die Möglichkeit, mit ROLLBACK TRANSACTION alle Änderungen zu verwerfen.
 
Hoffe ich hab nicht zu viel Blödsinn geschrieben happy.png Ich will das Thema beherrschen.
 
MfG
fump

 


Noch ein Hinweis zum Schluss: SQLite unterstützt nur eingeschränkt mehrere gleichzeitige Benutzer- bzw, Netzwerkzugriffe. Falls Du das brauchst, solltest Du Dich lieber mit einem "größeren" Datenbanksystem wie z.B. MySQL beschäftigen.


Prefer ahkscript.org for the time being.


fump2000
  • Members
  • 591 posts
  • Last active: Nov 11 2015 07:52 AM
  • Joined: 01 Nov 2012

Danke dir! Hab ich ja eigentlich die Funktion verstanden.

 

Es werden parallel nicht viele auf die DB zugriff nehmen, wenn dann auch nur mit Lesen nicht mit Schreiben. Zum Schreiben werd ich dann ein Flag setzen damit immer nur einer die Aktion durchführen kann.

Die User selber werden Lokal eine eigene DB nutzen. Nur die "geschlossenen" kommen in eine gesammt DB.

 

Wenn du erlaubst, machen wir mit dem Beispiel Code weiter:

;======================================================================================================================
; Use Class SQLiteDB : Using Exec() with callback function
; ======================================================================================================================
SQL := "SELECT COUNT(*) FROM Test;"
DB.Exec(SQL, "SQLiteExecCallBack")
; ======================================================================================================================
; Use Class SQLiteDB : Get some informations
; ======================================================================================================================
If !DB.LastInsertRowID(RowID)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
GuiControl, -ReDraw, ResultsLV
LV_Delete()
ColCount := LV_GetCount("Column")
Loop, %ColCount%
   LV_DeleteCol(1)
LV_InsertCol(1,"", "LastInsertedRowID")
LV_Add("", RowID)
GuiControl, +ReDraw, ResultsLV

SQL := "SELECT COUNT(*) FROM Test;"
Result := ""
If !DB.GetTable(SQL, Result)
   MsgBox, 16, SQLite Error: GetTable, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
ShowTable(Result)

; ======================================================================================================================
; Start of query using Query() : Get the column names for table Test
; ======================================================================================================================
SQL := "SELECT * FROM Test;"
If !DB.Query(SQL, RecordSet)
   MsgBox, 16, SQLite Error: Query, % "Msg:`t" . RecordSet.ErrorMsg . "`nCode:`t" . RecordSet.ErrorCode
GuiControl, -ReDraw, ResultsLV
LV_Delete()
ColCount := LV_GetCount("Column")
Loop, %ColCount%
   LV_DeleteCol(1)
LV_InsertCol(1,"", "Column names")
Loop, % RecordSet.ColumnCount
   LV_Add("", RecordSet.ColumnNames[A_Index])
LV_ModifyCol(1, "AutoHdr")
RecordSet.Free()
GuiControl, +ReDraw, ResultsLV

SQL := "SELECT COUNT(*) FROM Test;" : "Zählt" die Einträge in der Tabelle Test?

 

DB.Exec(SQL, "SQLiteExecCallBack") : Kann ich mir leider nicht erklären.

 

If !DB.LastInsertRowID(RowID) : ? Versteh ich auch nicht wirklich. Ich denke hier wird die ID der letzten Reihe abgefragt? Wenn keine zurück kommt dann kommt ein False/0 zurück.

 

ColCount := LV_GetCount("Column") : Gibt die Anzahl der Spalten zurück.

 

Der Loop entfernt alle Spalten.

 

LV_InsertCol(1,"", "LastInsertedRowID") & LV_Add("", RowID) : Es werden Spalten hinzugefügt ab 1 und Titel die in LastInsertedRowID vorliegen. Anschließend werden Daten hinzugefügt die unter RowID vorliegen.

 

GuiControl, +ReDraw, ResultsLV : Was macht das ResultsLV in diesem Befehl?

 

SQL := "SELECT COUNT(*) FROM Test;" : Zählt die Einträge erneut? Hätte doch eigentlich gar nicht gesetzt werden müssen oder? Die Var SQL wurde ja nicht verändert.

 

If !DB.GetTable(SQL, Result) : Füllt Result mit den Einträgen aus Tabelle Test?

 

ShowTable(Result) : Soll das Ergebnis zeigen aber wie? Was genau passiert hier?

 

SQL := "SELECT * FROM Test;" : Markiert alles in der Tabelle Test.

 

If !DB.Query(SQL, RecordSet) : Führt den SQL Befehl aus und speichert das Ergebnis in RecordSet.

 

ColCount := LV_GetCount("Column") : Zählt wieder die Spalten anschließend werden alle Spaleten gelöscht.

 

LV_InsertCol(1,"", "Column names") : Woher kommen die Colum names?

 

Loop, % RecordSet.ColumnCount : Was genau erzeugt denn RecordSet.ColumnCount?

 

LV_Add("", RecordSet.ColumnNames[A_Index]) : Hier werden die Daten aus RecordSet in die Spalten eingefügt.

 

RecordSet.Free() : Was passiert denn hier?

 

Freu mich auf deine Antwort und bedanke mich im voraus!

 

MfG
fump2000



just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011

... ich hatte gestern nicht viel Zeit ...

 

Danke dir! Hab ich ja eigentlich die Funktion verstanden.

 

Es werden parallel nicht viele auf die DB zugriff nehmen, wenn dann auch nur mit Lesen nicht mit Schreiben. Zum Schreiben werd ich dann ein Flag setzen damit immer nur einer die Aktion durchführen kann.

Die User selber werden Lokal eine eigene DB nutzen. Nur die "geschlossenen" kommen in eine gesammt DB.

 

Wenn du erlaubst, machen wir mit dem Beispiel Code weiter:

;======================================================================================================================
; Use Class SQLiteDB : Using Exec() with callback function
; ======================================================================================================================
SQL := "SELECT COUNT(*) FROM Test;"
DB.Exec(SQL, "SQLiteExecCallBack")
; ======================================================================================================================
; Use Class SQLiteDB : Get some informations
; ======================================================================================================================
If !DB.LastInsertRowID(RowID)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
GuiControl, -ReDraw, ResultsLV
LV_Delete()
ColCount := LV_GetCount("Column")
Loop, %ColCount%
   LV_DeleteCol(1)
LV_InsertCol(1,"", "LastInsertedRowID")
LV_Add("", RowID)
GuiControl, +ReDraw, ResultsLV

SQL := "SELECT COUNT(*) FROM Test;"
Result := ""
If !DB.GetTable(SQL, Result)
   MsgBox, 16, SQLite Error: GetTable, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
ShowTable(Result)

; ======================================================================================================================
; Start of query using Query() : Get the column names for table Test
; ======================================================================================================================
SQL := "SELECT * FROM Test;"
If !DB.Query(SQL, RecordSet)
   MsgBox, 16, SQLite Error: Query, % "Msg:`t" . RecordSet.ErrorMsg . "`nCode:`t" . RecordSet.ErrorCode
GuiControl, -ReDraw, ResultsLV
LV_Delete()
ColCount := LV_GetCount("Column")
Loop, %ColCount%
   LV_DeleteCol(1)
LV_InsertCol(1,"", "Column names")
Loop, % RecordSet.ColumnCount
   LV_Add("", RecordSet.ColumnNames[A_Index])
LV_ModifyCol(1, "AutoHdr")
RecordSet.Free()
GuiControl, +ReDraw, ResultsLV

SQL := "SELECT COUNT(*) FROM Test;" : "Zählt" die Einträge in der Tabelle Test?

 

Liefert die Anzahl der Sätze/Reihen/Zeilen der Tabelle Test, weil in der SQL-Anweisung keine einschränkenden Auswahlkriterien enthalten sind.

 

DB.Exec(SQL, "SQLiteExecCallBack") : Kann ich mir leider nicht erklären.

 

SQLite bietet die Möglichkeit, der Exec() Methode eine Callback-Funktion zu übergeben. Diese Funktion wird dann intern mit dem/den Ergebnis/sen der einzelnen SQL-Anweisungen aufgerufen. Die der Funktion übergebenen Parameter sind im Kopf der Exec() Methode beschrieben. A_EventInfo enthält die Adresse des Strings der ausgeführten SQL-Anweisung.

 

If !DB.LastInsertRowID(RowID) : ? Versteh ich auch nicht wirklich. Ich denke hier wird die ID der letzten Reihe abgefragt? Wenn keine zurück kommt dann kommt ein False/0 zurück.

 

SQLite versorgt jede(n) Reihe/Satz einer Tabelle mit einer zusätzlichen und eindeutigen ID und legt diese in einem Feld namens ROWID ab. Man kann sich das als laufende Satznummer vorstellen.

 

ColCount := LV_GetCount("Column") : Gibt die Anzahl der Spalten zurück.

 

... gibt die aktuelle Anzahl der Spalten des ListViews zurück! Diese und die folgenden Fragen beziehen sich eigentlich nicht auf SQLite.

 

Der Loop entfernt alle Spalten.

 

Ja!

 

LV_InsertCol(1,"", "LastInsertedRowID") & LV_Add("", RowID) : Es werden Spalten hinzugefügt ab 1 und Titel die in LastInsertedRowID vorliegen. Anschließend werden Daten hinzugefügt die unter RowID vorliegen.

 

Nach dem Löschen aller Spalten wird eine Spalte 1 mit dem Header "LastInsertedRowID" eingefügt, dann die Daten in RowID.

 

GuiControl, +ReDraw, ResultsLV : Was macht das ResultsLV in diesem Befehl?

 

Das ist das Gegenstück zu GuiControl, -ReDraw, ResultsLV etwas weiter oben. Mit -Redraw wird die Anzeige der Veränderungen im ListView unterbunden, +Redraw zeichnet dann das Ergebnis nach Abschluss der Änderungen neu. Man kann damit bei umfangreichen Änderungen der Inhalte eines ListViews die Ausführung beschleunigen.

 

SQL := "SELECT COUNT(*) FROM Test;" : Zählt die Einträge erneut? Hätte doch eigentlich gar nicht gesetzt werden müssen oder? Die Var SQL wurde ja nicht verändert.

 

Im Beispiel sollen ja auch nur die Möglichkeiten der Abfragen aufgezeigt werden. Hier wird das normale Verfahren ohne ohne Calllback-Funktion gezeigt.

 

If !DB.GetTable(SQL, Result) : Füllt Result mit den Einträgen aus Tabelle Test?

 

Füllt Result mit den Ergebnissen der jeweiligen SQL-Anweisung!

 

ShowTable(Result) : Soll das Ergebnis zeigen aber wie? Was genau passiert hier?

 

In der Funktion werden die Inhalte von Result dynamisch in einen ListView übertragen.

 

SQL := "SELECT * FROM Test;" : Markiert alles in der Tabelle Test.

 

Wählt den kompletten Inhalt der Tabelle aus!

 

If !DB.Query(SQL, RecordSet) : Führt den SQL Befehl aus und speichert das Ergebnis in RecordSet.

 

Führt den SQL Befehl aus und gibt ein AHK-Objekt zurück. Das Ergebnis bleibt in einem internen SQLite Bereich und muss über die Methoden von RecordSet abgerufen werden.

 

ColCount := LV_GetCount("Column") : Zählt wieder die Spalten anschließend werden alle Spaleten gelöscht.

 

s.o.

 

LV_InsertCol(1,"", "Column names") : Woher kommen die Colum names?

 

"Column names" ist hier nur der Header. Die Spaltennamen des Ergebnisses der Abfrage liegen im Array ColumnNames des RecordSet Objekts.

 

Loop, % RecordSet.ColumnCount : Was genau erzeugt denn RecordSet.ColumnCount?

 

Im Feld ColumnCount des RecordSet Objekts ist die Anzahl der Ergebnisspalten abgelegt.

 

LV_Add("", RecordSet.ColumnNames[A_Index]) : Hier werden die Daten aus RecordSet in die Spalten eingefügt.

 

Hier werden die Inhalte des Arrays ColumnNames aus RecordSet eingefügt (s.o.).

 

RecordSet.Free() : Was passiert denn hier?

 

Weil SQLite für die Ergebnisse der Query() Methode eigene Datenstrukturen anlegt, sollte der dafür benötigte Speicher freigegeben werden, wenn man mit der Auswertung der Antwort fertig ist. Das erledigt (u.a.) RecordSet.Free().

 

Freu mich auf deine Antwort und bedanke mich im voraus!

 

MfG
fump2000

 


Prefer ahkscript.org for the time being.


fump2000
  • Members
  • 591 posts
  • Last active: Nov 11 2015 07:52 AM
  • Joined: 01 Nov 2012

Hallo just me,

 

entschuldige bitte das ich deine Kommentare bisher nicht gewürdigt habe. Ich habe sie natürlich gelesen und bedanke mich dafür!!!

 

Hier nun mein bisheriger Code, Grundlage ist dein Beispielscript, entsprechend angepasst.

 

Würdest du ihn dir bitte anschauen und mir sagen ob er so okay ist oder ob da grundlegende Fehler vorliegen? Das wäre super nett von dir!

 

Code:

; ======================================================================================================================
; AHK Settings
; ======================================================================================================================
#NoEnv
; #Warn
#SingleInstance force
SetWorkingDir, %A_ScriptDir%
SetBatchLines, -1
#MaxMem, 1024
; ======================================================================================================================
; Includes
; ======================================================================================================================
#Include Class_SQLiteDB.ahk
; ======================================================================================================================
; Start & GUI
; ======================================================================================================================
DBFileName := A_ScriptDir . "\Reminder.sql"
DBFileName2 := A_ScriptDir . "\ReminderClose.sql"
CBBSQL := "SELECT * FROM Reminder"

Gui, +LastFound +OwnDialogs +Disabled
Gui, Add, Text, x2 y0 w130 h20 , Offene Wiedervorlagen:
Gui, Add, Text, x132 y0 w860 h20 +Center, Klicke Doppelt auf einen Eintrag um ihn für den Editor freizuschalten.
Gui, Add, ListView, x2 y20 w990 h250 vResultsLV HWNDh_LV1, ListView
Gui, Add, GroupBox, x2 y270 w990 h140 , Editor
Gui, Add, Text, x12 y290 w70 h20 , Reminder-ID:
Gui, Add, Text, x82 y290 w320 h20 , Text
Gui, Add, Text, x12 y320 w60 h20 , Dein ToDo:
Gui, Add, DropDownList, x112 y320 w130 h20 r3, Outbound|Systemänderung|Kontrolle
Gui, Add, Edit, x12 y340 w230 h60 , Edit
Gui, Add, Text, x252 y320 w120 h20 , Was hast Du gemacht?
Gui, Add, Edit, x252 y340 w230 h60 , Edit
Gui, Add, Text, x502 y290 w140 h20 +Center, Datum/Uhrzeit:
Gui, Add, DateTime, x502 y310 w140 h30 , dd.MM.yyyy HH:mm
Gui, Add, Text, x490 y350 w80 h20 +Right, Kundennummer:
Gui, Add, Edit, x574 y350 w80 h20 , Edit
Gui, Add, Text, x490 y370 w80 h20 +Right, ggf. Text ID:
Gui, Add, Edit, x574 y370 w80 h20 , Edit
Gui, Add, Button, x672 y300 w70 h80 , Speichern
Gui, Add, Button, x752 y300 w70 h80 , Mit CallNote`nschlließen
Gui, Add, Button, x832 y300 w70 h80 , Eintrag`nlöschen
Gui, Add, Button, x912 y300 w70 h80 , Neuer`nEintrag
Gui, Add, Text, x2 y410 w990 h20 , Geschlossene Widervorlagen (werden nach 10 Tagen ins Archiv verschoben):
Gui, Add, ListView, x2 y430 w990 h180 vResultsLV2 HWNDh_LV2, ListView
Gui, Show, x257 y134 h619 w1005,
Gui, ListView, %h_LV1%
If FileExist(DBFileName)
	{
		DB := new SQLiteDB
		If !DB.OpenDB(DBFileName) {
			MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
			ExitApp
		}
	}
else
	{
		DB := new SQLiteDB
		If !DB.OpenDB(DBFileName) {
		   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
		   ExitApp
		}
		SQL := "CREATE TABLE Reminder (Reminder_ID, ToDo, KD_Nr, Text_ID, Wiedervorlage, Status, Benutzer, ToDo_Text, ToDo_Erl_Text, PRIMARY KEY(Reminder_ID ASC, KD_Nr ASC, Text_ID ASC, Benutzer ASC));"
		If !DB.Exec(SQL)
		   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
		DB.Exec("BEGIN TRANSACTION;")
		 _SQL := "INSERT INTO Reminder VALUES('Reminder_ID#', 'ToDo', 'KD_Nr#', 'Text_ID#', 'Wiedervorlage#', 'Status#', 'Benutzer#', 'ToDo_Text#', 'ToDo_Erl_Text#');"
		Loop, 20 
			{
				StringReplace, SQL, _SQL, #, %A_Index%, All
				SQLStr .= SQL
			}
		If !DB.Exec(SQLStr)
			MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
		DB.Exec("COMMIT TRANSACTION;")
		SQLStr := ""
	}
LVName:="ResultsLV"
Table:=" Reminder "
SQL := "SELECT COUNT(*) FROM" Table ";"
GoSub DBInfo
SQL := "SELECT * FROM" Table ";"
GoSub DBQuery
GoSub RunSQL
If !DB.CloseDB()
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
   
If FileExist(DBFileName2)
	{
		DB := new SQLiteDB
		If !DB.OpenDB(DBFileName2) {
			MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
			ExitApp
		}
	}
else
	{
		DB := new SQLiteDB
		If !DB.OpenDB(DBFileName2) {
		   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
		   ExitApp
		}
		SQL := "CREATE TABLE ReminderClose (Reminder_ID, ToDo, KD_Nr, Text_ID, Wiedervorlage, Status, Benutzer, ToDo_Text, ToDo_Erl_Text, PRIMARY KEY(Reminder_ID ASC, KD_Nr ASC, Text_ID ASC, Benutzer ASC));"
		If !DB.Exec(SQL)
		   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
		DB.Exec("BEGIN TRANSACTION;")
		 _SQL := "INSERT INTO ReminderClose VALUES('Reminder_ID#', 'ToDo', 'KD_Nr#', 'Text_ID#', 'Wiedervorlage#', 'Status#', 'Benutzer#', 'Text_Text#', 'ToDo_Erl_Text#');"
		Loop, 20 
			{
				StringReplace, SQL, _SQL, #, %A_Index%, All
				SQLStr .= SQL
			}
		If !DB.Exec(SQLStr)
			MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
		DB.Exec("COMMIT TRANSACTION;")
		SQLStr := ""
	}
Gui, ListView, %h_LV2%
LVName:="ResultsLV2"
Table:=" ReminderClose "
SQL := "SELECT COUNT(*) FROM" Table ";"
GoSub DBInfo
SQL := "SELECT * FROM" Table ";"
GoSub DBQuery
GoSub RunSQL
If !DB.CloseDB()
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode

Gui, -Disabled
Return

GuiClose:
Gui, Destroy
ExitApp


; ======================================================================================================================
; Other Subs
; ======================================================================================================================
; Use Class SQLiteDB : Get some informations
; ======================================================================================================================
DBInfo:
;DB.Exec(SQL, "SQLiteExecCallBack")
DB.Exec(SQL)
If !DB.LastInsertRowID(RowID)
   MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
GuiControl, -ReDraw, %LVName%
LV_Delete()
ColCount := LV_GetCount("Column")
Loop, %ColCount%
   LV_DeleteCol(1)
LV_InsertCol(1,"", "LastInsertedRowID")
LV_Add("", RowID)
GuiControl, +ReDraw, %LVName%
SQL := "SELECT COUNT(*) FROM" Table ";"
Result := ""
If !DB.GetTable(SQL, Result)
   MsgBox, 16, SQLite Error: GetTable, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
ShowTable(Result)
Return
; ======================================================================================================================
; Start of query using Query() : Get the column names for table Test
; ======================================================================================================================
DBQuery:
If !DB.Query(SQL, RecordSet)
   MsgBox, 16, SQLite Error: Query, % "Msg:`t" . RecordSet.ErrorMsg . "`nCode:`t" . RecordSet.ErrorCode
GuiControl, -ReDraw, %LVName%
LV_Delete()
ColCount := LV_GetCount("Column")
Loop, %ColCount%
   LV_DeleteCol(1)
LV_InsertCol(1,"", "Column names")
Loop, % RecordSet.ColumnCount
   LV_Add("", RecordSet.ColumnNames[A_Index])
LV_ModifyCol(1, "AutoHdr")
RecordSet.Free()
GuiControl, +ReDraw, %LVName%
Return
; ======================================================================================================================
; Execute SQL statement using Exec() / GetTable()
; ======================================================================================================================
RunSQL:
If !InStr("`n" . CBBSQL . "`n", "`n" . SQL . "`n") {
   GuiControl, , SQL, %SQL%
   CBBSQL .= "`n" . SQL
}
If (SubStr(SQL, 0) <> ";")
   SQL .= ";"
Result := ""
If RegExMatch(SQL, "i)^\s*SELECT\s") {
   If !DB.GetTable(SQL, Result)
      MsgBox, 16, SQLite Error: GetTable, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
   Else
      ShowTable(Result)
} Else {
   If !DB.Exec(SQL)
      MsgBox, 16, SQLite Error: Exec, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
}
Return
; ======================================================================================================================
; Exec() callback function sample
; ======================================================================================================================
SQLiteExecCallBack(DB, ColumnCount, ColumnValues, ColumnNames) {
   This := Object(DB)
   MsgBox, 0, %A_ThisFunc%
      , % "SQLite version: " . This.Version . "`n"
      . "SQL statement: " . StrGet(A_EventInfo) . "`n"
      . "Number of columns: " . ColumnCount . "`n" 
      . "Name of first column: " . StrGet(NumGet(ColumnNames + 0, "UInt"), "UTF-8") . "`n" 
      . "Value of first column: " . StrGet(NumGet(ColumnValues + 0, "UInt"), "UTF-8")
   Return 0
}
; ======================================================================================================================
; Show results
; ======================================================================================================================
ShowTable(Table) {
   Global
   Local ColCount, RowCount, Row
   GuiControl, -ReDraw, %LVName%
   LV_Delete()
   ColCount := LV_GetCount("Column")
   Loop, %ColCount%
      LV_DeleteCol(1)
   If (Table.HasNames) {
      Loop, % Table.ColumnCount
         LV_InsertCol(A_Index,"", Table.ColumnNames[A_Index])
      If (Table.HasRows) {
         Loop, % Table.RowCount {
            RowCount := LV_Add("", "")
            Table.Next(Row)
            Loop, % Table.ColumnCount
               LV_Modify(RowCount, "Col" . A_Index, Row[A_Index])
         }
      }
      Loop, % Table.ColumnCount
         LV_ModifyCol(A_Index, "AutoHdr")
   }
   GuiControl, +ReDraw, %LVName%
}

Desweiteren wüsste ich gerne wie ich einen Eintrag verändern kann? Ich will es so machen das nach einem Doppelklick auf einen der oberen Einträge sich die Felder füllen. Entweder der Eintrag wird geschlossen dann soll er von der oberen DB in die untere DB wandern, einmal unten drin ist er nicht mehr veränderbar. Sollte der Eintrag aber nach dem einfügen verändert und gespeichert werden muss der vorhandene Eintrag ja geändert werden. Da wüsste ich nicht wie ich das hinbekommen soll.

 

Ich dnke mal, man nimmt die ID als Grundlage, sucht sich die passende Zeile heraus und füllt Vars mit dem entsprechenden Inhalt. Zurück dann das gleiche nur umgekehrt, werte in Vars speichern, SQL String zusammensetzen und per Exec durchführen oder?



just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011

Desweiteren wüsste ich gerne wie ich einen Eintrag verändern kann? Ich will es so machen das nach einem Doppelklick auf einen der oberen Einträge sich die Felder füllen. Entweder der Eintrag wird geschlossen dann soll er von der oberen DB in die untere DB wandern, einmal unten drin ist er nicht mehr veränderbar. Sollte der Eintrag aber nach dem einfügen verändert und gespeichert werden muss der vorhandene Eintrag ja geändert werden. Da wüsste ich nicht wie ich das hinbekommen soll.

 

Ich dnke mal, man nimmt die ID als Grundlage, sucht sich die passende Zeile heraus und füllt Vars mit dem entsprechenden Inhalt. Zurück dann das gleiche nur umgekehrt, werte in Vars speichern, SQL String zusammensetzen und per Exec durchführen oder?

 

 

Für das Verändern vom Daten gibt es die UPDATE Anweisung. Was Du meiner Meinung nach brauchst, ist

  1. Ein GUI als Eingabemaske für neue Sätze oder das Verändern von Sätzen,
  2. eine Routine, die prüft, ob Felder geändert wurden, und
  3. ggf. eine passende INSERT bzw. UPDATE Anweisung aufbaut und per Exec ausführt.

Für die "geschlossenen" Wiedervorlagen, die noch nicht in die Archivdatenbank verschoben wurden,  braucht Du weder eine eigene Datenbank noch eine eigene Tabelle. Die Unterscheidung zwischen "offen" und "geschlossen" sollte anhand des Status-Feldes möglich sein. Das Status-Feld entscheidet dann darüber, in welchem Bereich der Satz angezeigt wird.

 

Wenn Du "geschlossene" Sätze nach Ablauf einer bestimmten Frist in die Archivdatenbank schieben willst, braucht es meiner Meinung nach ein zusätzliches Datenbankfeld, das bei jeder Änderung automatisch mit dem Zeitpunkt der letzten Änderung versorgt wird. Dieses Feld darf natürlich manuell änderbar sein.

 

Für den Zugriff auf die Archivdatenbank würde ich eine eigene Anwendung basteln, auch wenn das für die Nutzer weniger komfortabel ist.


Prefer ahkscript.org for the time being.


fump2000
  • Members
  • 591 posts
  • Last active: Nov 11 2015 07:52 AM
  • Joined: 01 Nov 2012

Ich habe mir die SQL Befehle bzw. Anweisungen schon rausgesucht.

 

Wie ich das genau hinbekomme mit dem verschieben eines geschlossenen Eintrags in das untere LV weiß ich nicht. Auch das letztendliche entfernen des Eintrages nach 10 Tagen und verschieben in ein Archiv stellt mich noch vor ein Rätzel.

 

Für das Archiv ansich gibt es dann eine Adminanwendung. Da soll auch das Suchen möglich sein. Auch da weiß ich noch nicht wie ich das hinbekomme.

 

Noch hab ich hier viele Fragezeichen. Aber ich hoffe das diese sich in Wissen bzw. Lösungen wandeln.

 

Ich danke dir viel mals für deine Hilfe bisher!



just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011

Du solltest Dich vom Testskript lösen. Das soll ja nur zeigen, wie man die unterschiedlichen Möglichkeiten nutzen kann und unbekannte Ergebnisse dynamisch in einen ListView stellt. In Deinem Fall ist der Tabellenaufbau bekannt und Du kannst - wie ich es sehe - immer mit vollständigen Datensätzen arbeiten. Damit wird Vieles einfacher. Schau Dir das mal an:

 

Spoiler

 

Und jetzt Du!


Prefer ahkscript.org for the time being.


fump2000
  • Members
  • 591 posts
  • Last active: Nov 11 2015 07:52 AM
  • Joined: 01 Nov 2012

Verschiedene Wege führen nach Rom :)

 

Vielen dank für den Code! Darauf wäre ich so nie gekommen. Ich versuche mit AHK zurecht zu kommen und war schon sehr froh das ich dein Beispiel anpassen konnte. Das es auch so geht, darauf wäre ich nicht gekommen.

 

Könntest du mir noch zeigen wie man anhand des Datums wenn denn A_Now 10 Tage größer ist in eine andere DB verschiebt?

 

Noch eine Frage, wozu ist in diesem String der . ? SQL := "SELECT * FROM " . TableName . " WHERE Status = '" . StatusArray[3] . "';"



just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011

Verschiedene Wege führen nach Rom happy.png

 

Ja, nur das manche Non-Stop Flüge sind.

 

Vielen dank für den Code! Darauf wäre ich so nie gekommen. Ich versuche mit AHK zurecht zu kommen und war schon sehr froh das ich dein Beispiel anpassen konnte. Das es auch so geht, darauf wäre ich nicht gekommen.

 

Das ist wirklich ein Problem, denn Du führst da einen Zweifrontenkrieg!

 

Könntest du mir noch zeigen wie man anhand des Datums wenn denn A_Now 10 Tage größer ist in eine andere DB verschiebt?

 

Möglicherweise:

SelectDate := A_Now
SelectDate += -10, Days
FormatTime, SelectDate, %SelectDate%, yyyy-MM-dd
SQL := "SELECT * FROM " . TableName . " WHERE StatusDatum <= '" . SelectDate . "';"

Noch eine Frage, wozu ist in diesem String der . ? SQL := "SELECT * FROM " . TableName . " WHERE Status = '" . StatusArray[3] . "';"

 

Der . (Punkt)  ist der "offizielle" AHK "Verkettungssoperator". Man 'darf' ihn auch weglassen, aber das tue ich bisher eher selten. 


Prefer ahkscript.org for the time being.


fump2000
  • Members
  • 591 posts
  • Last active: Nov 11 2015 07:52 AM
  • Joined: 01 Nov 2012

Hallo!

 

Also einen weiteren eintrag hinzufügen das klappt. Aber einen Eintrag Updaten das klappt nicht.

 

Ich habe den Code zu zusammengesetzt:

        DB.Exec("BEGIN TRANSACTION;")
        SQL := "UPDATE Reminder SET KD_Nr='" . RM_KDNr . "', Doxis_ID='" . RM_DoxisID . "', ToDo='" . RM_ToDo_DropDown . "', RR_Nr='" . RM_RRNr . "', WVL_Zeitpunkt='" . RM_DateTime . "', Status='Offen', ToDo_Text='" . RM_ToDo_Text . "', ToDo_Erl_Text='" . RM_ToDo_Erl_Text . "', Benutzer='" . UserName . "', FullTime= '" . FullTime . "' WHERE Reminder_ID= '" . RM_ID . "';"
        If !DB.Exec(SQL)
            MsgBox, 16, SQLite Error, % "Msg:`t" . DB.ErrorMsg . "`nCode:`t" . DB.ErrorCode
        DB.Exec("COMMIT TRANSACTION;")

Was ist falsch? Ich hab mich am String für "INSERT INTO Reminder VALUES" orientiert.

 

 

 

// EDIT

 

Der Fehler lag bei mir. Die Var "RM_ID" war immer leer. Hatte nicht daran gedacht, dass bei "Gui, Submit" der Inhalt von Textcontrols nicht übernommen wird.

 

Gibt es dafür eine Lösung?



just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011

Ja! Gib dem Textfeld einen Namen, dann kannst Du den Inhalt mit GuiControlGet auslesen.


Prefer ahkscript.org for the time being.


fump2000
  • Members
  • 591 posts
  • Last active: Nov 11 2015 07:52 AM
  • Joined: 01 Nov 2012

Den hat es ja...

 

Gui, Add, Text, x87 y290 w100 h20 cGreen vRM_ID,

 

Muss man es dann immer einzeln per GuiControlGet auslesen?