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
just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011

Hallo fump,

 

Deine SQL-Anweisung wird schon korrekt sein, Du musst aber beachten, was Dir GetTable() und Query() als Ergebnis liefern, und das steht (wenn auch in englisch) in den Kommentaren (der Inlinedokumantation) innerhalb von Class_SQLiteDB.ahk.

 

Beide Methoden liefern das Ergebnis in Form eines Objekts. Bei GetTable() ist das eine reines und unabhängiges AHK-Objekt (Class _Table{}), bei Query() ein AHK-Objekt (CLass _RecordSet{}), das einen Zeiger auf ein SQLite-Objekt enthält.

 

GetTable(SQL, TB):

Diese Methode ist eine Spezialität von SQLite. Im Normalfall würde ich immer GetTable() für Abfragen nutzen, auch wenn ich nur genau ein Feld als Antwort erwarte. Dann wird eben eine "Tabelle" mit einer Reihe und einer Spalte geliefert. Die Methoden GetRow(), Next() und Reset() braucht man nicht wirklich, um auf das Ergebnis zuzugreifen. Diese Methoden sollen nur ermöglichen, dass man das Ergebnis ähnlich wie das Ergebnis aus Query() verarbeiten kann.

  • TB.HasRows enthält 0, wenn keine Antwortsätze gefunden wurden, sonst 1.
  • TB.HasNames enthält 0, wenn die Spaltennamen nicht im Array TB.Names abgelegt wurden, sonst 1. 
  • TB.RowCount enthält die Anzahl der gefundenen Zeilen.
  • TB.ColumnCount enthält die Anzahl der gefundenen Spalten.
  • TB.ColumnNames enthält ggf. ein Array mit den Spaltennamen. 
  • TB.Rows enthält ggf. ein Array mit den zurückgelieferten und fertig aufbereiteten Werten, dort ist für jede Zeile ein Array mit den Spaltenwerten abgelegt.

Wenn ein Aufruf von GetTable() genau einen Wert liefert, sind deshalb normalerweise TB.RowCount = 1, TB.ColumnCount = 1, TB.HasRows = 1, TB.HasNames = 1, der Spaltenname liegt in TB.Names[1] und der Spaltenwert in TB.Rows[1][1].

 

Query(SQL, RS):

Diese Methode entspricht der normalen Methode für SQL-Abfragen. Wenn in der Antwortmenge BLOB-Felder enthalten sind, muss man sie verwenden. Weil das Recordset-Objekt nur einen Zeiger auf ein SQLite-Objekt enthält, kann man nicht direkt auf die Ergebnisse zugreifen, sondern nur über den Aufruf der Methode Next(), die dann pro Zeile ein Array mit den Spaltenwerten liefert. Die meisten Properties gibt es nur, um eine gewisse Kompatibilität zum Ergebnis aus GetTable() herzustellen.

  • RS.HasRows enthält immer 1.
  • RS.HasNames enthält immer 1.
  • RS.ColumnCount enthält die Anzahl der gefundenen Spalten
  • RS.ColumnNames enthält ein Array mit den Spaltennamen.

Wenn ein Aufruf von Query() genau einen Wert liefert, sind deshalb RS.ColumnCount = 1, RS.HasRows = 1, RS.HasNames = 1, der Spaltenname liegt in RS.ColumnNames[1] und den Spaltenwert liefert ein einmaliger Aufruf von RS.Next(Row) in Row[1]. Und weil es sich hier um ein SQLite-Objekt handelt, sollte man das Ergebnisobjekt nach Verarbeitung per RS.Free() freigeben.

 

Edit: Namen des Feldes mit den Spaltennamen für GetTable() korrigiert.


Prefer ahkscript.org for the time being.


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

Ich hab es gelesen, deine comments in der Class_SQLiteDB.ahk

Hab es Übersetzt, konnte mir aber keinen richtigem Reim drauf machen...

 

Jetzt hab ich es verstanden und konnte den Code anpassen, nun funktionierts.

 

Erneut bedanke ich mich für deinen Support!

Vielen dank!



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

Hallo just me,

 

ich brauche einen Rat, da Du dich in diesem Fall am besten auskennst und den Reminder ansich auch schon kennst, folgende Frage.

 

Ich möchte eine Art Livemonitor ermöglichen. In diesem Monitor soll man sehen können ob offene Vorgänge "liegen" bleiben. Ein Admin kann so den User nochmals darauf hinweisen oder entsprechend den Vorgang einem anderen User zuweisen.

 

Mit meinem Wissen würde ich nun per Loop und Parsen jede User DB nach Vorgängen durchsuchen die älter als A_Now sind und diese ins LV schreiben. So würde sich nach und nach das LV füllen, sofern Vorgänge da sind.

 

Wie würdest du sowas angehen?

Anders als ich es machen würde?



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

Moin,

 

wenn jeder User eine eigene Datenbank hat, bleibt Dir wohl nichts anderes übrig. Allerdings kann man so etwas als "Leistungskontrolle" bezeichnen, und das wird nicht überall gern gesehen.

 

Du müsstest diese Abfrage in regelmäßigen Abständen laufen lassen und die Ergebnisse abgleichen, und selbst dann kannst Du nicht ausschließen, dass der User just in der Zehntelsekunde nach Deiner letzten Abfrage den Fall bearbeitet hat. Ein richtiger "Livemonitor" ist das nicht.


Prefer ahkscript.org for the time being.


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

Ich denke nicht, dass sich jemand dahin setzt und die ganze zeit die Vorgänge kontrolliert. Es soll lediglich dazu dienen wirklich überfällige Vorgänge zu erkennen und rechtzeitig eingreiffen zu können.

 

Es geht ja meist um Kundenkommunikation. Hier muss schon darauf geachtet werden, dass nix daneben geht.



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

Hi just me,

 

ich habe die Archivierung entsprechend erweitert. Erst stell ich das Archiv zusammen dann prüfe ich im gesamten Archiv auf Einträge die älter als "SelectDate := A_YYYY . 0101000000" sind, gibt es da welche werden diese in das Vorjahres Archiv geschrieben und im aktuellen gelöscht.

 

Ich habe dies nun einmal durchgetestet mit simulierten Daten und stelle dabei folgendes fest:

1. die Daten werden gefunden, 45 Datensätze.

2. die Datensätze werden korrekt in die andere DB geschrieben.

3. die 45 Datensätze werden anscheinend in der aktuellen DB gelöscht.

 

Wenn ich nun hingehe und mir alle Einträge die in der DB vorliegen anzeigen lasse dann habe ich in der Vorjahres DB 45 Einträge. In der aktuellen keinen mehr. So sollte es auch sein.

 

Schau ich mir dann aber die Größe der Datei an, dann hat sie unverändert 14kb. Ich frage mich, warum wird der Speicher nicht freigegeben? Was muss man tun damit das passiert?

 

Wenn der Speicher nie freigegeben wird dann wachsen die User Datenbanken ja kontinuierlich an, obwohl ja immer wieder die älteren Datensätze ins Archiv wandern.

 

Hast du eine Idee dazu?

 

MfG
fump



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

Hallo fump,

 

ganz so schlimm ist das nicht. Die DB-Dateien werden zwar nicht kleiner, der freie Platz in der DB wird aber wiederverwendet, wenn neue Datensätze eingefügt werden. Wenn Du mal aufräumen musst, gibt es das VACUUM oder das PRAGMA auto_vacuum Statement.

 

MfG

 

just me


Prefer ahkscript.org for the time being.


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

Hi just me,

danke dir!

 

Wenn ich das richtig verstehe erstellt der VACUUM Befehl die Datenbank neu, er erstellt also eine journal Datei und schreibt dann die eigentliche Datenbank neu. Dadurch wäre auch ein ROLLBACK möglich.

 

Wohingegen das PRAGMA in der Datenbank ein Flag ändert welches dafür sorgt das beim löschen, verschieben etc. der Platz direkt freigegeben wird. Jedoch kann dies trotz aller Vorteile auch zu Fragmentierungen führen.

 

Liege ich da richtig?

 

Was nutzt du denn? Bzw. was würdest du für diese Art Projekt empfehlen?

 

Wie nutzt man diese PRAGMA Befehle? Schau ich mir die Dokumentation an verstehe ich nicht so ganz wie ich diese Befehle anwende.

 

Gibt es abgesehen davon auch Befehle zum Optimieren oder sogar Reparieren? Bei MySQL hab ich sowas schonmal gesehen.

 

MfG
fump



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

Hallo fump,

 

die PRAGMA Anweisungen werden wie normale "Non-Query" Anweisungen per Exec(SQL) ausgeführt. Der Doku zufolge muss man das Pragma auto_vacuum direkt nach dem Erzeugen der Datenbank und vor dem Erstellen irgendwelcher Tabellen ausführen. Spezielle Befehle zum Reparieren oder Optimieren sind mir noch nicht über den Weg gelaufen.

 

Ich nutze SQLite nur in einer Anwendung, und da auch nur lesend.

 

MfG

 

just me


Prefer ahkscript.org for the time being.


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

Also lässt es sich nachträglich nicht mehr aktivieren?

 

// EDIT

 

Habs grad gelesen. Son mist...

 

Also muss ich was schreiben das alles aus der jetzt bestehenden DB ausließt und in eine neue DB verschiebt mit aktiven PRAGMA Statement.

Naja wer keine Arbeit hat, der macht sich welche...

 

Da ich nicht abschätzen kann wie groß die Datenbanken wirklich werden ist es wohl besser es entsprechend umzustellen oder!?

 

// EDIT 2

 

Also ich denke, es ist vorerst nicht nötig da was zu unternehmen da ich ohnehin nicht abhschätzen kann wie groß die Datenbanken werden. Wie du schon geschrieben hast, geht der Speicher ja nicht verloren, die Zeilen sind lediglich leer und werden wenn benötigt wieder gefüllt. Also kein Problem.

 

Die UserDatenbanken in diesem Projekt werden auf keine riesen Größe anwachsen. Kontinuierlich werden geschlossene Vorgänge in eine neue Archiv DB verschoben. Dadurch wird immer wieder Platz frei in der UserDatenbank.

Das UserArchiv wird vom Admin Tool eingelesen und die Einträge ins Gesamtarchiv eingefügt anschließend wird das UserArchiv gelöscht.

Im Gesamtarchiv wird nur gespeichert, nicht gelöscht. Also ansich, sollten sich hier keine Probleme zeigen.

 

 

Zum prüfen ob eine DB okay ist kann man das PRAGMA integrity_check nutzen.

 

This pragma does an integrity check of the entire database. It looks for out-of-order records, missing pages, malformed records, and corrupt indices. If any problems are found, then strings are returned (as multiple rows with a single column per row) which describe the problems. At most integer errors will be reported before the analysis quits. The default value for integer is 100. If no errors are found, a single row with the value "ok" is returned.

Der SQL Befehl dazu sollte so richtig sein oder?

SQL:="PRAGMA " . DBName . ".integrity_check;"

Wird dieser dann auch mit Exec(SQL) ausgelöst? Wie komm ich dann an das Ergebnis der Prüfung?



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

Exec(SQL) kannst Du nur mit Pragmas verwenden, die nichts zurückliefern bzw. für die der Rückgabewert nicht weiter interessiert. Wenn Du Werte abfragen willst oder wie in diesem Fall ein Ergebnis zurückgeliefert wird, nimm einfach GetTable().


Prefer ahkscript.org for the time being.


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

Mit Arrays hab ich noch so meine Probleme. Kann man den gesamten Inhalt eines Arrays in einer msgbox ausgeben? Oder als TXT speichern?

Wie geht das?

An einen einzelnen Wert kommt ich dran, aber wenns das komplette sein soll dann???



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

This pragma does an integrity check of the entire database. It looks for out-of-order records, missing pages, malformed records, and corrupt indices. If any problems are found, then strings are returned (as multiple rows with a single column per row) which describe the problems. At most integer errors will be reported before the analysis quits. The default value for integer is 100. If no errors are found, a single row with the value "ok" is returned.

 
GetTable() liefert Dir kein Array, sondern ein Objekt. Dieses Objekt (nennen wir es mal Tabelle) hat einige nützliche Eigenschaften (properties):

  • Tabelle.RowCount -> Anzahl der Ergebniszeilen
  • Tabelle.ColumnCount -> Anzahl der Ergebnisspalten
  • Tabelle.Rows -> zweidimensionales Array (ein Array mit den Spaltenwerten je Zeile)

Hier wird eine Tabelle mit einer Spalte und sovielen Zeilen zurückgegeben, wie es Fehler gab. Wenn alles fehlerfrei ist, sollte in der einzigen Spalte der ersten Zeile "ok" stehen.

If (Tabelle.Rows[1, 1] = "ok") ; alles ist gut
{
   ...
}
Else
{
   Meldung := ""
   For Jede, Zeile In Tabelle.Rows
      Meldung .= Zeile[1] . "`n"
   MsgBox, 16, Böse Überraschung, %Meldung%
}

Prefer ahkscript.org for the time being.


nnnik
  • Members
  • 1625 posts
  • Last active: Jan 24 2019 02:19 PM
  • Joined: 28 Jul 2012

Mit dem For loop kannst du es schön in eine Stringform umwandeln.


Visit the new forum ahkscript.org.

http://ahkscript.org


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

Vielen Dank!