Seite 1 von 3
SQlite Abfrage
Verfasst: 14. Januar 2017 16:58
von ChrisRoo
Hallo Leute,
habe vor kurzem angefangen mich mit Qt zu beschäftigen.
Bin also noch ein blutiger Anfänger...
Ich möchte gerne eine Lagerverwaltung erstellen und habe dazu eine Sqlite-Datenbank mit verschiedenen Tabellen. Unter anderen eine Tabelle ArtikelKonto.
Die ist folgendermaßen aufgebaut:
ID(int autoincrement) Datum(currentTimestamp) Buchungsart(TEXT(AB, ZU usw.)) Buchungswert(FLOAT) Bestand(FLOAT)
Ich möchte nun den Wert aus Spalte "Bestand" aus der letzten Zeile abfragen und in eine variable speichern, sodass ich damit rechnen kann.
Das versuche ich schon seit zwei Tage und bekomme es einfach nicht gebacken.
Hier mein bescheidener letzter Versuch, die letzte Zeile herauszufinden:
Code: Alles auswählen
connOpen();
if(!connOpen())
ui->statusBar->showMessage("Datenbank nicht erreichbar!");
else
ui->statusBar->showMessage("Datenbank OK!");
QSqlQuery lastID;
lastID.prepare("SELECT ID FROM ArtikelKonto ORDER BY ID DESC LIMIT 1");
<<Die Funktion zum öffen der Datenbank (connOpen()) befindet sich in der .h-Datei>>
Jetzt sollte doch eigentlich die ID der letzten Zeile in "lastID" gespeichert sein, oder?
Wie muss nun die Abfrage und das Speichern in eine Variable, mit der man rechnen kann, aussehen?
Kann mir bitte jemand dabei helfen?
Schon mal vielen Dank für eure Hilfe.
Gruß Chris
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 17:28
von Partsoft
1) Du musst deine Abfrage auch ausführen:
2) Dann zur letzten Zeile wechseln:
3) Den Wert von "Bestand" kannst du anschließend so ermitteln:
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 17:58
von ChrisRoo
Hallo "Partsoft",
erstmal vielen vielen Dank für die Hilfe.
Endlich mal keine Fehlermeldung und die UI startet.
Leider kommt in der Ausgabe (qt-creator) folgende Fehlermeldung:
QSqlQuery::value: unknown field name 'Bestand'
Bestand ist definitiv in der Tabelle ArtikelKonto vorhanden und wird auch so geschrieben.
Was könnte das denn sein?
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 18:32
von ChrisRoo
Habe gerade mal versucht meine Ermittlung der letzten Zeile etwas abzuändern:
Das hier
Code: Alles auswählen
lastID.prepare("SELECT ID FROM ArtikelKonto ORDER BY ID DESC LIMIT 1");
habe ich so verändert:
Code: Alles auswählen
lastID.prepare("SELECT * FROM ArtikelKonto ORDER BY ID DESC LIMIT 1");
Nun kommt die Meldung, dass "Bestand" unbekannt ist, nicht mehr.
bestand hat auch den Wert der letzten Zeile.
Nun rechne ich mit der Variablen und es kommt "0".
Hier nochmal der Code:
Code: Alles auswählen
connOpen();
QSqlQuery lastID;
lastID.prepare("SELECT * FROM ArtikelKonto ORDER BY ID DESC LIMIT 1");
lastID.exec();
lastID.last();
double bestand = lastID.value("Bestand").toDouble();
connClose();
double valueInhalt = 100 / 30000 * bestand;
valueInhalt hat nach der Rechnung den Wert 0
Was habe ich denn jetzt wieder für einen Bock geschossen? Wird ja langsam peinlich...

Re: SQlite Abfrage
Verfasst: 14. Januar 2017 18:36
von ChrisRoo
Hab es herausgefunden...
Wenn ich 0.0033 * bestand nehme, dann kommt das richtige Ergebnis.
Noch mal vielen lieben Dank für die Hilfe!
Gruß
Chris
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 19:35
von Partsoft
Kein Problem und an der Stelle noch ein kleiner Tipp:
Wenn du double vereinbarst, verwende in der Berechnung keine int-Konstanten. Korrekt wäre es also so:
Vermutlich war das dein Problem...
Gruß, Sascha
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 19:58
von ChrisRoo
Hi Sascha,
das leuchtet ein.
Ich lagere gerade diese Abfrage in eine Funktion aus, da ich noch mehrere Bestände aus unterschiedlichen Tabellen abfragen muss.
Natürlich hängt es jetzt wieder an etwas.
Ich muss die Query ja variabel gestalten.
Ich übergebe also der Funktion den Tabellennahmen und versuche nun die Variable in den Query-String einzubauen. Natürlich ohne Erfolg...
Hier mein Code (Aber nicht lachen...

):
Code: Alles auswählen
double anzeigeBestand(char32_t ktoTAB)
{
QSqlQuery lastID;
lastID.prepare("SELECT * FROM '"+ktoTAB+"' ORDER BY ID DESC LIMIT 1");
lastID.exec();
lastID.last();
double bestand = lastID.value("Bestand").toDouble();
connClose();
return bestand;
}
Was mache ich denn hier wieder falsch?
Hier der Funktionsaufruf:
VG
Chris
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 21:02
von ChrisRoo
Mittlerweile sieht die Funktion so aus:
Code: Alles auswählen
double anzeigeBestand(const char* ktoTAB)
{
qDebug()<< ktoTAB;
connOpen();
QSqlQuery lastID;
lastID.prepare("SELECT * FROM :ktoTAB ORDER BY ID DESC LIMIT 1");
lastID.bindValue(":ktoTAB", ktoTAB);
lastID.exec();
lastID.last();
double bestand = lastID.value("Bestand").toDouble();
connClose();
return bestand;
}
Der Funktionsaufruf so:
Jetzt kommt wieder, dass Bestand nicht bekannt ist.
Oh Mann...
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 21:19
von Partsoft
Code: Alles auswählen
lastID.prepare("SELECT * FROM '"+ktoTAB+"' ORDER BY ID DESC LIMIT 1");
Dabei kommt folgendes raus:
SELECT * FROM 'blabla' ORDER BY ID DESC LIMIT 1
Das Apostroph benötigst du in SQL für Zeichenketten (Konstanten), Tabellennamen musst du stattdessen in Anführungszeichen einschließen. In deinem Fall benötigst du die aber gar nicht, genauso wenig wie den Datentyp "char32_t", bzw. "const char*". Dafür gibt es in Qt die Klasse QString:
Code: Alles auswählen
double anzeigeBestand(const QString &ktoTAB) {
QSqlQuery lastID;
lastID.prepare(QString("SELECT * FROM %1 ORDER BY ID DESC LIMIT 1").arg(ktoTAB));
lastID.exec();
lastID.last();
double bestand = lastID.value("Bestand").toDouble();
connClose();
return bestand;
}
Deine Variante mit bindValue() habe ich mir jetzt nicht angeschaut, da ich gerade noch am Antworten war. Für Tabellennamen habe ich das auch noch nicht benutzt, müsste ich mir selbst erst einmal anschauen.
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 21:37
von ChrisRoo
Hi Sascha, es funktioniert.
Zum Glück hast Du dich heute hier sehen lassen.
Dadurch bin ich jetzt einen großen Schritt weiter. Nochmal Danke dafür!
Gruß, Chris
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 21:58
von Partsoft
Wie gesagt, kein Problem!
Ich habe bindValue() in Kombination mit einer Tabelle auch noch einmal ausprobiert, das funktioniert nicht! Den Quellcode habe ich mir jetzt zwar nicht angeschaut, aber der Name "bindValue()"sagt ja eigentlich schon alles!
Re: SQlite Abfrage
Verfasst: 14. Januar 2017 22:11
von ChrisRoo
Das habe ich im Zusammenhang mit der Nutzung von Variablen im Query gefunden.
War ne englische Seite.
Ich weiß jetzt auf jeden Fall wie es geht.

Re: SQlite Abfrage
Verfasst: 15. Januar 2017 22:38
von MichaelS
lastID.prepare(QString("SELECT * FROM %1 ORDER BY ID DESC LIMIT 1").arg(ktoTAB));
lastID.exec();
lastID.last();
double bestand = lastID.value("Bestand").toDouble();
Eine Frage hätte ich noch: Wenn Du nur den Bestand haben möchtest, warum fragst Du dann alle Tabellenfelder ab und nicht nur das Feld Bestand:
SELECT bestand FROM %1 ORDER BY ID DESC LIMIT 1
Außerdem fehlt in Deiner Funktion ein Fehlerhandling. Wenn die Abfrage fehlschlägt, bekommst Du einen Bestand von 0, ohne das Du überhaupt merkst, dass ein Fehler aufgetreten ist. M.E. solltest Du da noch ein paar Prüfungen einbauen:
double bestand = 0.0;
if ( ! lastID.exec() )
{
/*Fehlermeldung ausgeben */
return bestand;
}
if ( lastID.last() )
bestand = lastID.value( 0 ).toDouble();
Gruß Michael
Re: SQlite Abfrage
Verfasst: 16. Januar 2017 17:55
von ChrisRoo
Hi Michael,
die Abfrage hatte ich mir aus einem Beispiel zusammengestrickt.
Wenn ich das richtig verstehe, schaut er mit deiner Abfrage nur in der Spalte Bestand, geht in die erste freie Zelle und springt eine zurück. Richtig?
Das mit dem Fehlerhandling stimmt natürlich auch. Hab es jetzt eingebaut. Danke.
Im Moment hänge ich wieder an einem kniffligen Problemchen.
Ich möchte den durchschnittlichen 3-Tages-Verbrauch errechnen.
Ich muss also eine Abfrage bzw. eine Funktion erstellen, die im Artikelkonto alle Buchungen von den letzten drei Buchungstagen summiert.
Also,wenn heute der 16. ist und am 11., 12.,14. und 15. eine Abbuchung erfolgte, dann sollen die Buchungen vom 12., 14., und 15. summiert werden. Also nicht von den letzten drei Tagen sondern von den letzten drei Tagen, an denen etwas abgebucht wurde.
Ich denke, die Lösung muss so sein, dass in einer Funktion das aktuelle Datum -1Tag errechnet werden muss. Dann mittels einer Schleife die Tabelle, angefangen vom errechneten Datum (heute -1) solange alle Buchungen sammeln, bis das 4. Datum kommt.

Oh Mann, komplizierter geht es bestimmt nicht. Da ich "Blödel" die Tabellen mit CURRENT_TIMESTAMP ausgestattet habe, gehe ich am besten schon mal hin und mache eine getrennte Datums- und Uhrzeitspalte, oder?
In Excel habe ich so etwas schon gebaut, nur hier mit Qt und c++ fällt es mir noch schwer.
Hat vielleicht jemand eine Idee?
Danke und viele Grüße
Chris
Re: SQlite Abfrage
Verfasst: 16. Januar 2017 18:21
von Christian81
Das ist kein Qt sondern ein SQl-Problem. Das Wörtchen LIMIT war ja schon in einer Abfrage drin. Gepaart mit ORDER BY sollte es ungefähr so aussehen:
Code: Alles auswählen
SELECT ... FROM tabelle ORDER BY <zeitspalte> DESC LIMIT 3
Siehe auch
https://www.sqlite.org/lang_select.html