Entwickler-Ecke
Datenbanken - [Delphi 2006] Daten abfragen, einfügen
dontello - Mi 09.03.11 16:46
Titel: [Delphi 2006] Daten abfragen, einfügen
Hallo,
erstmal ein herzliches Hallo an alle hier im Forum.
Meine erste Frage: Gibt es eine Übersicht über die SQLite Funktionen? (also nicht die unterstützten SQL Befehle)
Zweite Frage:
Ich habe eine SQLite Tabelle erstellt und schreibe einen Datensatz hinein und lese ihn auch wieder aus. Soweit funktioniert das auch.
Wie kann ich jetzt einen zweiten Datensatz einfügen? Irgendwie wird mir immer der erste Datensatz wieder überschrieben.
Anbei mal noch etwas Code:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60:
| var slDBpath: string; sldb: TSQLiteDatabase; sltb: TSQLIteTable; sqlstring: String;
begin
slDBPath := ExtractFilepath(application.exename) + 'test.db';
sldb := TSQLiteDatabase.Create(slDBPath); try
if sldb.TableExists('testtabelle') then begin sqlstring := 'DROP TABLE testtabelle'; sldb.execsql(sqlstring); end;
sqlstring := 'CREATE TABLE testtabelle ([ID] INTEGER PRIMARY KEY,'; sqlstring := sqlstring + '[Name] VARCHAR (255),[Ort] VARCHAR (255), [Nummer] INTEGER);';
sldb.execsql(sqlstring);
sldb.BeginTransaction;
name := txt_name.Text; ort := txt_ort.Text; nummer := strtoint(txt_nummer.Text);
sqlstring := 'INSERT INTO testtabelle(Name,Ort,Nummer) VALUES ("'+ name +'","' + ort+ '",' + inttostr(nummer)+ ');'; sldb.ExecSQL(sqlstring);
sldb.Commit;
sltb := slDb.GetTable('SELECT * FROM testtabelle');
try
if sltb.Count > 0 then begin
Memo1.Text := 'Name: '+ sltb.FieldAsString(sltb.FieldIndex['Name']) + ' Ort: ' + sltb.FieldAsString(sltb.FieldIndex['Ort']) + ' Nummer: '+ sltb.FieldAsString(sltb.FieldIndex['Nummer']);
end;
finally sltb.Free; end;
finally sldb.Free;
end;
end; |
Wie kann ich mehrere Inserts durchführen ohne das der erste Datensatz überschrieben wird?
Und wie kann ich im Select dann alle Datensätze auswählen und anzeigen lassen?
Moderiert von
Narses: Code- durch Delphi-Tags ersetzt
Xion - Mi 09.03.11 16:50
dontello hat folgendes geschrieben : |
Wie kann ich jetzt einen zweiten Datensatz einfügen? Irgendwie wird mir immer der erste Datensatz wieder überschrieben.
[...]
Delphi-Quelltext 1: 2: 3: 4: 5:
| if sldb.TableExists('testtabelle') then begin sqlstring := 'DROP TABLE testtabelle'; sldb.execsql(sqlstring); end; | |
Es ist nicht verwunderlich dass die Daten weg sind, wenn du sie löschst ;)
Wenn du mehrere Inserts machen möchtest, dann kannst du das einfach genau so tun: mehrere Inserts hintereinander schreiben.
Vielleicht hast du da ein Verständnisproblem: Die Tabelle ist nicht weg, wenn du das Programm neu startest. Du musst nicht bei jedem Insert erst die Tabelle erstellen.
//Edit:
wenn ich mich recht erinnere, ist hier ein gutes Beispielprojekt beim Download dabei:
http://www.itwriting.com/blog/?page_id=659
Vielleicht verwendest du das ja, dann guck mal in dem Ordner ;)
dontello - Mi 09.03.11 16:58
Moderiert von
Narses: Komplett-Zitat des letzten Beitrags entfernt.
Ok du hast Recht. ;)
Das mit dem Drop Table macht Sinn. Habe den Code nur aus einem Beispiel und die Zeile übersehen.
Versuche mich gerade mal ein bisschen mit SQLite zu beschäftigen.
Mit "Select *" müsste ich ja alle Datensätze bekommen. Wie kann ich mir die dann ausgeben lassen?
Und mal noch eine andere Frage. Gibt es eine Möglichkeit die SQLite3.dll direkt mit in die .exe einzubinden oder muss ich die dll immer separat hinzufügen?
Xion - Mi 09.03.11 17:05
dontello hat folgendes geschrieben : |
| Mit "Select *" müsste ich ja alle Datensätze bekommen. Wie kann ich mir die dann ausgeben lassen? |
Du hast ja oben schon den ersten Eintrag ausgeben. Das musst du nur als Schleife erweitern:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| Memo1.Text := 'Name: '+ sltb.FieldAsString(sltb.FieldIndex['Name']) + ' Ort: ' + sltb.FieldAsString(sltb.FieldIndex['Ort']) + ' Nummer: '+ sltb.FieldAsString(sltb.FieldIndex['Nummer']);
while not sltb.EOF do begin sltb.Next Memo1.Lines.Add ( 'Name: '+ sltb.FieldAsString(sltb.FieldIndex['Name']) + ' Ort: ' + sltb.FieldAsString(sltb.FieldIndex['Ort']) + ' Nummer: '+ sltb.FieldAsString(sltb.FieldIndex['Nummer'])); end; |
dontello - Mi 09.03.11 17:12
Moderiert von
Narses: Komplett-Zitat des letzten Beitrags entfernt.
Funktioniert, Danke. Bekomme dann leider nur noch immer eine Meldung: "Table is at End Of File". ISt das normal oder gibt es auch einen anderen Weg?
vagtler - Mi 09.03.11 17:20
Ja, indem Du die Schleife umstellst.
Xion - Mi 09.03.11 17:27
Also ich kriegst selbst nicht hin :lol: Irgendwie war das bei der BDE anders :P
Edit: Quatsch :wall:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| sltb.MoveFirst; Memo1.Lines.Clear;
while not sltb.EOF do begin Memo1.Lines.Add ( 'Name: '+ sltb.FieldAsString(sltb.FieldIndex['Name']) + ' Ort: ' + sltb.FieldAsString(sltb.FieldIndex['Ort']) + ' Nummer: '+ sltb.Nextsltb.FieldAsString(sltb.FieldIndex['Nummer'])); end; |
dontello - Mi 09.03.11 18:20
Moderiert von
Narses: Komplett-Zitat des letzten Beitrags entfernt.
ja funktioniert. Danke.
Kann jemand vielleicht noch was dazu sagen, ob man die dll direkt in die exe einbinden kann oder ob ich die sqlite3.dll immer mitliefern muss?
Tankard - Mi 09.03.11 18:22
Delphi-Quelltext
1: 2: 3: 4: 5:
| while not sltb.EOF do begin Memo1.Lines.Add ( 'Name: '+ sltb.FieldAsString(sltb.FieldIndex['Name']) + ' Ort: ' + sltb.FieldAsString(sltb.FieldIndex['Ort']) + ' Nummer: '+ sltb.FieldAsString(sltb.FieldIndex['Nummer'])); sltb.Next; end; |
Xion - Mi 09.03.11 18:58
Sehe grad, da hab ich wohl die Formatierung zerlegt...wunder mich warum ich das nicht gesehen hab ^^
Übrigens:
Dontello, du musst nicht immer die ganze Antwort zitieren ;)
dontello - Mi 09.03.11 20:53
ja alles klar...diesmal ohne Zitat ;)
Wie sieht es denn mit der sqlite3.dll aus? Muss ich die immer zu der .exe Datei hinzufügen oder kann ich die auch mit in die .exe direkt einfügen? Also das ich nur noch eine Datei habe. Die exe-Datei.
dontello - Do 10.03.11 00:03
gibt es denn sqlite delphi wrapper, die frei zuverwenden sind und ohne dll auskommen?
Oder brauch ich dringend einen externen wrapper? oder kann ich auch diedelphi komponentenverwenden für sqlite? zum beispiel die dbexpress.
Xion - Do 10.03.11 10:11
Also wenn ich mich nicht total täusche, dann IST die dll das SQLite. Der Wrapper dazu sind die .pas Dateien ;)
dontello - Do 10.03.11 10:14
Xion hat folgendes geschrieben : |
| Also wenn ich mich nicht total täusche, dann IST die dll das SQLite. Der Wrapper dazu sind die .pas Dateien ;) |
aber wo findet man dann die befehle, die ich verwenden kann?
steh ich da jetz grade etwas auf dem schlauch?
---
Moderiert von
Narses: Beiträge zusammengefasst---
Wie ist es möglich die Datenbankdatei zu überprüfen ob Sie verändert wurde? Es soll quasi verhindert werden, das der User unerlaubt die Datei verändert?
Gibt es eine Möglichkeit die Datenbank-Datei zu crypten. Also das die gespeicherten Daten nicht mit einem anderen Programm, das SQLite unterstützt ausgelesen werden können?
Xion - Do 10.03.11 16:16
dontello hat folgendes geschrieben : |
| aber wo findet man dann die befehle, die ich verwenden kann? |
Also SQLite kann so ziemlich die Befehle, die eben SQL ausmachen. Was der Wrapper kann, das kriegst du ja von Delphi angezeigt bzw siehst du auch an einem Beispielprojekt. Du kannst natürlich auch die .pas aufmachen und gucken, was der Wrapper kann.
Weiß nicht genau auf was du hinaus willst
dontello hat folgendes geschrieben : |
Wie ist es möglich die Datenbankdatei zu überprüfen ob Sie verändert wurde? Es soll quasi verhindert werden, das der User unerlaubt die Datei verändert?
Gibt es eine Möglichkeit die Datenbank-Datei zu crypten. Also das die gespeicherten Daten nicht mit einem anderen Programm, das SQLite unterstützt ausgelesen werden können? |
Naja. Also verschlüsseln tut man normal nicht die Datenbankdatei, sondern den Inhalt. Im Endeffekt ist es so, wenn die Datei bei mir im Ordner liegt, dann lösch ich sie und weg ist sie. Da will ich mal sehen was dein Programm macht ;) Ob es bei SQLite auch die Möglichkeit gibt, die Datei zu per Passwort zu sichern weiß ich nicht. Aber wie sicher das dann ist :nixweiss: Richtig wichtige Daten liegen normal irgendwo auf nem Server, wo keiner ran kann (außer über die freigegebenen Schnittstellen)
dontello - Fr 11.03.11 12:06
Also so weit so gut bin ich jetzt vorangekommen.
Allerdings habe ich momentan ein Speicher Problem. Ich führe erst einen INSERT aus und möchte danach einen SELECT * machen.
Der INSERT funktioniert, doch beim SELECT bekomme ich eine Zugriffsverletzung.
Auf der sqlite Webseite habe ich gelesen, das man den Speicher wieder mit sqlite3_malloc freigeben kann. Jedoch finde ich dies Funktion bei mir nicht.
Mit sqlite3_free() hatte ich auch keinen Erfolg.
Wie kann ich mein Problem lösen? Hat jemand einen Ansatz?
Xion - Fr 11.03.11 12:09
So aus der hohlen Hand kann ich da nix sagen. Zeig mal deinen Code dazu. Es ist relativ unwahrscheinlich dass die Datenbank die AV auslöst ;) Im schlechtesten Fall ist es der Wrapper. Aber ich vermute eher, es liegt an deinem Code.
dontello - Fr 11.03.11 12:13
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83:
| procedure TForm4.btn_insertClick(Sender: TObject); var db : TSQLiteDB; dbback : TSQLiteExecCallback; sqlstring: PAnsiChar; udata: Pointer; error: PAnsiChar; name: string; ort: string;
begin
if sqlite3.SQLite3_Open('C:\temp\teschtlitedb.bcdb',db) = 0 then begin
sqlstring := 'CREATE TABLE IF NOT EXISTS tescht ([id] INTEGER PRIMARY KEY, [name] VARCHAR (255), [ort] VARCHAR (255))';
if sqlite3.SQLite3_Exec(db,sqlstring,dbback,udata,error) = 0 then begin
name := txt_name.Text; ort := txt_ort.Text;
sqlstring := PChar('INSERT INTO tescht (name, ort)VALUES("'+ name + '", "' + ort + '")');
if sqlite3.SQLite3_Exec(db,sqlstring,dbback,udata,error) = 0 then begin
Memo1.Text := EmptyStr; Memo1.Text := 'Daten aktualisiert'; sqlite3.sqlite3_close(db); end else begin Memo1.Text := sqlite3.sqlite3_errmsg(db); end; end else begin Memo1.Text := sqlite3.sqlite3_errmsg(db); end; end else begin Memo1.Text := sqlite3.sqlite3_errmsg(db); end;
end;
procedure TForm4.btn_selectClick(Sender: TObject); var db : TSQLiteDB; dbback : TSQLiteExecCallback; sqlstring: PAnsiChar; udata: Pointer; error: PAnsiChar; result: TSQLiteResult; row: Cardinal; col: Cardinal;
begin
if sqlite3.SQLite3_Open('C:\temp\teschtlitedb.bcdb',db) = 0 then begin sqlstring := PChar('SELECT name, ort FROM tescht');
if sqlite3.SQLite3_Exec(db,sqlstring,dbback,udata,error) = 0 then begin
Memo1.Text := inttostr(sqlite3.sqlite3_gettable(db,sqlstring,result,row,col,error));
end else begin Memo1.Text := sqlite3.sqlite3_errmsg(db); end; end;
end; |
Das ganze ist nur zum probieren und verstehen für mich. :)
Moderiert von
Klabautermann: Code- zu Delphi-Tags geändert
Xion - Fr 11.03.11 12:19
Rufst du direkt die Funktionen aus dem Wrapper auf? :shock:
Das find ich irgendwie gewagt. Warum verwendest du nicht die Klassen dafür wie bisher?
Wenn du z.B. "db." eintippst, dann kriegst du doch angezeigt was die Komponente kann. Das ist dann auch getestet und sollte gut funktionieren. Wenn du die Funktionen aus der SQLite3 direkt aufrufst, wer weiß was er da intern macht :nixweiss:
dontello - Fr 11.03.11 12:21
Ja schon, aber eigentlich müsste es doch auch so funktionieren.
Xion - Fr 11.03.11 12:25
Kann es sein, dass du die Klassen, die du verwendest, vorher initialisieren musst?
Delphi-Quelltext
1:
| sqlite3.SQLite3_Open('C:\temp\teschtlitedb.bcdb',db) |
Weil hier wäre ja db ein nil-Pointer. Wobei...es ist ja ein var-Parameter. Gute Frage.
Auf jeden Fall ruft die SQLite3.pas direkt die dll auf, da kann ich nichts dazu sagen. In welcher Zeile kommt denn die AV?
dontello - Fr 11.03.11 12:28
Das Problem tritt hier auf:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| begin
if sqlite3.SQLite3_Open('C:\temp\teschtlitedb.bcdb',db) = 0 then begin
sqlstring := PChar('SELECT name, ort FROM tescht');
--->>>> if sqlite3.SQLite3_Exec(db,sqlstring,dbback,udata,error) = 0 then begin
end else begin Memo1.Text := sqlite3.sqlite3_errmsg(db); end; end; |
Xion - Fr 11.03.11 12:35
Ok, dein dbBack ist eine Funktion:
Delphi-Quelltext
1: 2:
| TSQLiteExecCallback = function(UserData: Pointer; NumCols: integer; ColValues: PPAnsiCharArray; ColNames: PPAnsiCharArray): integer; cdecl; |
Du solltest diesem Dingens auch eine Funktion zuweisen. Gut möglich dass die dll da einfach was rüberschicken will, und dann krachts.
dontello - Fr 11.03.11 12:37
Wie kann ich da eine Funktion zuweisen? Wie meinst du das?
Xion - Fr 11.03.11 12:40
Vor deinem Aufruf:
Delphi-Quelltext
1:
| dbBack:=MyCallbackFunction; |
Und in deinem Projekt (weiter oben) definierst du die:
Delphi-Quelltext
1: 2: 3: 4:
| function MyCallbackFunction(UserData: Pointer; NumCols: integer; ColValues: PPAnsiCharArray; ColNames: PPAnsiCharArray): integer; begin beep; end; |
//PS: da das ne Funktion ist, musst du vermutlich irgend einen bestimmten Wert zurückgeben. Frag mich aber nicht welchen ;)
dontello - Fr 11.03.11 12:45
Die Funktion ist doch aber schon in der sqlite3.pas definiert oder versteh ich jetzt was falsch?
Quelltext
1: 2: 3: 4:
| type TSQLiteExecCallback = function(UserData: Pointer; NumCols: integer; ColValues: PPAnsiCharArray; ColNames: PPAnsiCharArray): integer; cdecl; TSQLiteBusyHandlerCallback = function(UserData: Pointer; P2: integer): integer; cdecl; |
Quelltext
1:
| function SQLite3_Exec(db: TSQLiteDB; SQLStatement: PAnsiChar; CallbackPtr: TSQLiteExecCallback; UserData: Pointer; var ErrMsg: PAnsiChar): integer; cdecl; external SQLiteDLL name 'sqlite3_exec'; |
:? :?:
Xion - Fr 11.03.11 12:55
Nee, das ist nur die Definition, wie die Funktion auszusehen hat. cdecl hat übrigens nur was mit der Parameterübergabe an die dll zu tun.
Der Sinn ist es, dass du einen "Ansprechpartner" mitlieferst, den die dll dann aufrufen kann.
Ob das alles natürlich wirklich so ist, kann ich nicht sagen, bin kein Vollprofi was SQLite angeht (genau genommen hab ich erst ein kleines Projekt damit gemacht). Auf jeden Fall definiert der Typ nur, wie die Funktion auszusehen hat, die Funktion selbst musst du mit übergeben. Wäre vielleicht am besten, du guckst dir mal den Source-Code der entsprechenden Klassen an, wie die das aufrufen.
dontello - Fr 11.03.11 13:02
ok ich werd mal schauen. ist das denn überhuapt der richtige weg um einen select zu machen?
Xion - Fr 11.03.11 13:07
Gute Frage. Warum nimmst du nicht einfach die Table?
Der normale Select sieht so aus:
dontello hat folgendes geschrieben : |
Delphi-Quelltext 1:
| sltb := slDb.GetTable('SELECT * FROM testtabelle'); |
|
dontello - Fr 11.03.11 13:09
Ich möchte halt eigentlich nicht mit externen Wrappern arbeiten.
Bei dem Insert Befehl bekomme ich ja komischerweise auch keine Probleme. :?
Xion - Fr 11.03.11 13:15
Na ein Insert ist ja banal. Am Ende wird nur der SQL-String einfach rübergereicht.
Select ist knifflig. Denn die Datenbank reicht dir nicht die ganze Tabelle rüber (man stelle sich den Aufwand bei 100.000 Einträgen vor). Du kriegst bestenfalls einen Wert, und dann musst du den Durchschalten (deswegen auch sltb.Next) (Cursor-Prinzip). Keine Ahnung wie schwer das dann wird.
Auf jeden Fall ist der Wrapper ja genau dafür da, dass du ihn benutzt und nicht alles selbst machen musst. :D
dontello - Fr 11.03.11 13:17
Habe ich denn irgendwelche Einschränkungen wenn ich denn Wrapper benutze? Setzt der alle SQLite Funktionen um?
Xion - Fr 11.03.11 13:22
Gute Frage. Ich denke aber schon. SQL-Befehle werden einfach durchgereicht, da sollte es keine Probleme geben. Der Select ist ja eingebaut...hmm, ansonsten fällt mir garnichts ein, was es noch gibt...Trigger vielleicht. Keine Ahnung ob die gehen, ich vermute es aber.
dontello - Fr 11.03.11 14:08
Hast du vielleicht eine Idee, warum ich, wenn ich mir sqlite_version() ausgeben lasse, die 3.6.14 angezeigt bekomme?
Habe jedoch die neueste dll von sqlite.org runtergeladen und eingebunden.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!