SQlite Abfrage

Alles rund um die Programmierung mit Qt
ChrisRoo
Beiträge: 19
Registriert: 14. Januar 2017 16:37

SQlite Abfrage

Beitrag 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
Partsoft
Beiträge: 6
Registriert: 8. März 2016 17:09

Re: SQlite Abfrage

Beitrag von Partsoft »

1) Du musst deine Abfrage auch ausführen:

Code: Alles auswählen

lastID.exec();
2) Dann zur letzten Zeile wechseln:

Code: Alles auswählen

lastID.last();
3) Den Wert von "Bestand" kannst du anschließend so ermitteln:

Code: Alles auswählen

double bestand = lastID.value("Bestand").toDouble();
https://www.partsoft.de
Softwareentwicklung und Vertrieb
ChrisRoo
Beiträge: 19
Registriert: 14. Januar 2017 16:37

Re: SQlite Abfrage

Beitrag 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?
ChrisRoo
Beiträge: 19
Registriert: 14. Januar 2017 16:37

Re: SQlite Abfrage

Beitrag 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... :oops:
ChrisRoo
Beiträge: 19
Registriert: 14. Januar 2017 16:37

Re: SQlite Abfrage

Beitrag 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
Partsoft
Beiträge: 6
Registriert: 8. März 2016 17:09

Re: SQlite Abfrage

Beitrag von Partsoft »

Kein Problem und an der Stelle noch ein kleiner Tipp:

Code: Alles auswählen

double valueInhalt = 100 / 30000 * bestand;
Wenn du double vereinbarst, verwende in der Berechnung keine int-Konstanten. Korrekt wäre es also so:

Code: Alles auswählen

double valueInhalt = 100.0 / 30000.0 * bestand;
Vermutlich war das dein Problem...

Gruß, Sascha
https://www.partsoft.de
Softwareentwicklung und Vertrieb
ChrisRoo
Beiträge: 19
Registriert: 14. Januar 2017 16:37

Re: SQlite Abfrage

Beitrag 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:

Code: Alles auswählen

double bestand = anzeigeBestand(ArtikelKonto1);
VG
Chris
ChrisRoo
Beiträge: 19
Registriert: 14. Januar 2017 16:37

Re: SQlite Abfrage

Beitrag 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:

Code: Alles auswählen

bestand = anzeigeBestand("ArtikelKonto1");
Jetzt kommt wieder, dass Bestand nicht bekannt ist.

Oh Mann...
Partsoft
Beiträge: 6
Registriert: 8. März 2016 17:09

Re: SQlite Abfrage

Beitrag 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.
https://www.partsoft.de
Softwareentwicklung und Vertrieb
ChrisRoo
Beiträge: 19
Registriert: 14. Januar 2017 16:37

Re: SQlite Abfrage

Beitrag 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
Partsoft
Beiträge: 6
Registriert: 8. März 2016 17:09

Re: SQlite Abfrage

Beitrag 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!
https://www.partsoft.de
Softwareentwicklung und Vertrieb
ChrisRoo
Beiträge: 19
Registriert: 14. Januar 2017 16:37

Re: SQlite Abfrage

Beitrag 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. :)
MichaelS
Beiträge: 240
Registriert: 27. Dezember 2005 12:49

Re: SQlite Abfrage

Beitrag 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
ChrisRoo
Beiträge: 19
Registriert: 14. Januar 2017 16:37

Re: SQlite Abfrage

Beitrag 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. :shock: 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
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: SQlite Abfrage

Beitrag 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
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Antworten