C++ C++ SQLite: Wert aus erster und letzter Zeile einer Spalte

T_55

Lieutenant
Registriert
Feb. 2013
Beiträge
643
Hi Coders,

ich möchte in der ersten Spalte den Wert der ersten und letzten existierenden Zeile auslesen.
Bisher habe ich beim Auslesen einfach alles durchgeschleift while(sqlite_step(statement)==SQLITE_ROW) was in dem Fall unsinnig wäre.
Hier (http://stackoverflow.com/questions/698047/most-efficient-way-to-select-1st-and-last-element-sqlite) habe ich so etwas wie eine Anleitung gefunden mit der ich allerdings nichts anfangen konnte da ich beim auslesen nur die Sache mit sqlite3_stmt, sqlite3_prepare_v2 und sqlite3_finalize kenne. Die Daten wurden ohne PRIMARY KEY angelegt und ich würde jetzt gerne einfach den Wert der ersten und letzten Zeile auslesen. Was die letzte Zeile angeht habe ich versucht mit sqlite3_last_insert_rowid weiterzukommen aber da war ich zu blöd für. Und zum Auslesen des ersten Wertes ist mir auch nichts eingefallen ausser eine Schleife zu machen und die nach dem ersten Wert abzubrechen aber schick ist das alles nicht :)


Code:
        int ersterWert;
        int letzterWert;

        sqlite3 *db;
        std::string temp_db_name = derDateiName;
        const char *db_name = temp_db_name.c_str();
        char *err_msg = 0;
        int rc = sqlite3_open(db_name, &db);
        if (rc != SQLITE_OK)
        {
            sqlite3_close(db);
        }

        std::string temp_text = "SELECT * FROM TabellenName;";
        const char *temp_char = temp_text.c_str();
        char buffer[1000];
        sprintf(buffer,temp_char);
        sqlite3_stmt *statement;
        if (sqlite3_prepare_v2(db,buffer, -1, &statement, 0)==SQLITE_OK)
        {
            // Hilfe! :-)
            ersterWert = ???
            letzterWert = ???

            sqlite3_finalize(statement);
        }
        else
        {
            //wenn Fehler
        }

Grüße
 
In deinem Select fehlt ein ORDER BY. Ohne kann man sich nicht darauf verlassen immer die gleichen Ergebnisse zu erhalten.
 
Ok danke das werde ich mal einfügen. Bin leider echt noch ein Datenbanklegastheniker.
Man könnte natürlich alles durchschleifen und den ersten und letzten Wert des Durchlaufs irgendwie abgreifen. Aber bei langen Tabellen dauert das natürlich auch alles. Gibt es denn nicht die Möglichkeit auf die erste und letzte Zeile gezielt zuzugreifen um die Werte abzugreifen?

Code:
        if (sqlite3_prepare_v2(db,buffer, -1, &statement, 0)==SQLITE_OK)
        {
            while(sqlite_step(statement)==SQLITE_ROW)
            {
               ersterWert = sqlite_column_int(statement, 0);
            }
            sqlite3_finalize(statement);
        }
 
T_55 schrieb:
Gibt es denn nicht die Möglichkeit auf die erste und letzte Zeile gezielt zuzugreifen um die Werte abzugreifen?
Solange man die Werte nicht in irgend einer Form sortiert, sind erste und letzte Zeile zufällig und können sich ändern.

Wenn man die Werte sortiert, kann man gezielt die erste und auch die letzte Zeile abfragen - das schon genannte ORDER BY hilft dabei. In Verbindung mit ASC bzw. DESC und LIMIT kann man dann gezielt den ersten bzw. letzten Datensatz abfragen.
 
Ok danke. Im SQLite DB Browser wird es in der richtigen Reihenfolge angezeigt mit aufsteigender Nr. Daher denke ich würde es prinzipiell auch per Zugriff auf erste und letzte Zeile die richtigen Werte liefern.
Es handelt sich bei dem Wert um einen Zeitstempel von daher entspricht automatisch der erste dem kleinsten Wert und der letzte dem größte Wert.

Also wenn ich es richtig verstanden hab sucht man dann in Datenbanken lieber nicht nach IDs sondern dann über Sortierungen (stelle ich mir allerdings bei sehr langen Tabellen performancemäßig schwierig vor). Hat evt jemand ein Codeschnipsel wie ich auf min/max Wert direkt zugreifen kann?
 
Das sieht ziemlich gut aus ich bin allerdings zu doof die Syntax in den C++ Code zu bringen sodass das die Variablen int ersterWert und int letzterWert den richtigen Wert bekommen. Habe immer nur mit dieser oben gezeigten Scheife mit sqlite3_stmt, sqlite3_prepare_v2, sqlite_step und sqlite3_finalize gearbeitet.
 
T_55 schrieb:
Ok danke. Im SQLite DB Browser wird es in der richtigen Reihenfolge angezeigt mit aufsteigender Nr.
Daher denke ich würde es prinzipiell auch per Zugriff auf erste und letzte Zeile die richtigen Werte liefern.
Es handelt sich bei dem Wert um einen Zeitstempel von daher entspricht automatisch der erste dem kleinsten Wert und der letzte dem größte Wert.
Dann sortiere doch nach diesem Zeitstempel.

So fragst Du den neuesten Datensatz ab.
Code:
std::string temp_text = "SELECT * FROM TabellenName ORDER BY Zeitstempel DESC LIMIT 1;";

So fragst Du den ältesten Datensatz ab.
Code:
std::string temp_text = "SELECT * FROM TabellenName ORDER BY Zeitstempel ASC LIMIT 1;";

T_55 schrieb:
Also wenn ich es richtig verstanden hab sucht man dann in Datenbanken lieber nicht nach IDs sondern dann über Sortierungen (stelle ich mir allerdings bei sehr langen Tabellen performancemäßig schwierig vor).
ID-Spalten sind im Normalfall nur eindeutige Bezeichner für einen Datensatz. Im Allgemeinen würde ich davon abraten, diesen Wert mit anderen Funktionalitäten zu versehen.

Wenn Du nach einer Spalte oder mehreren Spalten sortieren willst, dann legt man bei größeren Datenmengen einen Index auf diese Spalte(n). Dadurch sind Abfragen nach dem größten und kleinsten Wert wie auch Suchen nach einem bestimmten Wert in dieser Spalte sehr performant.
 
Danke, das Problem ist jetzt nur noch, dass if(sqlite3_prepare_v2(db,buffer, -1, &statement, 0)==SQLITE_OK) den Wert false zurück liefert und somit die Zuweisung an meine Variable letzterWert = sqlite_column_int(statement, 0); gar nicht ausführt. Die Datenbankverbindung ist erfolgreich aber ab dem if(sqlite3_prepare_v2... kommt dann false. Tabellenname und Zeilenname hab ich geprüft und sollte eigentlich korrekt sein...
ps: Ich weiß gar nicht ob sqlite_column_int(statement, 0); als Zuweisung ok ist denn eigentlich wird die Spalte ja auch schon beim SELECT definiert, dass ist im Übrigen auch was mich permanent verwirrt, man kann die Spalte bei SELECT definieren aber auch bei der Zuweisung so wie ich es im Schleifenbeispiel hab...?
 
Zuletzt bearbeitet:
T_55 schrieb:
Danke, das Problem ist jetzt nur noch, dass if(sqlite3_prepare_v2(db,buffer, -1, &statement, 0)==SQLITE_OK) den Wert false zurück liefert und somit die Zuweisung an meine Variable letzterWert = sqlite_column_int(statement, 0); gar nicht ausführt.
Welchen Fehlercode liefert denn sqlite3_prepare_v2(db,buffer, -1, &statement, 0) zurück?
 
Hi, ich habe nochmal alles sauber neu gemacht und dieses Problem ist dann nicht mehr aufgetaucht vermutlich ein Schreibfehler gewesen. Was jetzt noch nicht klappt, ist das ich nicht den Max oder Min -Wert erhalte. Ich habe mit DESC getestet aber es kommt 0 statt 9801 (99 zum Quadrat) in die Zielvariable letzterWert. Ich hänge mal den Code an. Ab dem Teil "// AUSLESEN " fangen spätestens die Fehler an ;)

Code:
#include "stdafx.h"
#include <iostream>
#include <string>
#include "sqlite3.h"

int main()
{

	sqlite3 *db;
	std::string temp_db_name = "Datenbank.db";
	const char *db_name = temp_db_name.c_str();
	char *err_msg = 0;

	// SCHREIBEN
	int rc = sqlite3_open(db_name, &db);
	if (rc != SQLITE_OK)
	{
		std::cout << "Fehler 1" << std::endl;
		sqlite3_close(db);
	}
	else
	{
		std::string TabellenNameOP = "NameTabelle";
		std::string temp_sql_001 = "CREATE TABLE IF NOT EXISTS " + TabellenNameOP + "(Zeitstempel INTEGER, wert1 REAL, wert2 REAL);";
		const char *sql_001 = temp_sql_001.c_str();
		char *err_msg = 0;
		int rc = sqlite3_exec(db, sql_001, 0, 0, &err_msg);
		if (rc != SQLITE_OK)
		{
			std::cout << "Fehler 2" << std::endl;
			sqlite3_free(err_msg);
			sqlite3_close(db);
		}
		else
		{
			for (int i = 50; i < 100; i++)
			{
				std::string temp_string = "INSERT INTO " + TabellenNameOP + "(Zeitstempel, wert1, wert2) VALUES ("
					+ std::to_string(i*i) + ","
					+ std::to_string(i) + ","
					+ std::to_string(i) +
					");";
				const char *sql29 = temp_string.c_str();
				int fehlerchecker = sqlite3_exec(db, sql29, 0, 0, &err_msg);
				if (fehlerchecker != SQLITE_OK)
				{
					std::cout << "Fehler 3" << std::endl;
					sqlite3_free(err_msg);
				}
				else
				{
					std::cout << "OK" << std::endl;
				}
			}
			sqlite3_close(db);
		}
	}



	// AUSLESEN
	int rc2 = sqlite3_open(db_name, &db);
	if (rc2 != SQLITE_OK)
	{
		std::cout << "Fehler 4" << std::endl;
		sqlite3_close(db);
	}

	std::string temp_text2 = "SELECT * FROM NameTabelle ORDER BY Zeitstempel DESC LIMIT 1;";
	const char *temp_char = temp_text2.c_str();
	char buffer[1000];
	sprintf(buffer, temp_char);
	sqlite3_stmt *statement;
	int letzterWert;
	if (sqlite3_prepare_v2(db, buffer, -1, &statement, 0) == SQLITE_OK)
	{
		letzterWert = sqlite3_column_int(statement, 0);
		sqlite3_finalize(statement);
	}
	else
	{
		sqlite3_free(err_msg);
		std::cout << "Fehler 5 " << err_msg << std::endl;
	}

	sqlite3_close(db);

	std::cout << "letzterWert = " << letzterWert << std::endl;

	std::cout << "Programm Zuende, Press any key to continue \n";    std::cin.get();
	return 0;
}
 
Ich habe gerade mit dem DB Browser For SQLite Deine Datenbank test weise angelegt und ein paar Datensätze eingefügt. Es lief alles fehlerfrei und auch die Abfragen funktionieren korrekt.

Der Fehler müsste also in Deinem C++ Code liegen. Da ich schon seit Jahren nichts mehr in C++ entwickelt habe, gibt es da sicherlich kompetentere Hilfen als mich hier im Forum.
 
Hallo Andreas besten danke für die Unterstützung ich habe nun endlich den Fehler gefunden. Und zwar hat einfach noch sqlite3_step(sqlite3_stmt*); gefehlt um Werte überhaupt zurückzugeben (die Info dann gefunden hier https://www.proggen.org/doku.php?id=dbs:sqlite:libsqlite3:ref:sqlite3_step). Das heißt bevor ich den Wert von sqlite3_column_int(statement, 0); an meine Variable übergebe muss ich übergeordnet sqlite3_step aufrufen. So klappt es nun und die min und Max Werte stimmen :)
 
Zurück
Oben