![]() |
Datenbank: SQLite-3 • Version: 3 • Zugriff über: SQLConnect
SQLConnect ist erforderlich!
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen, ich bin in Fragen Datenbanken noch ein Greenhorn und brauche Hife.
Ich experimentiere mit einer SQLite-Datenbank und habe das Experimentalprogramm bereits in einer Version mit den Zeos-Komponenten unter Delphi 10.1 zum laufen gebracht. Nun unter Delphi 10.2 Tokio gibt es die Zeos-Komponenten noch nicht bzw. ich traue mich nicht sie zu installien. Eigentlich wollte ich mit den Mitteln von Delphi, also mit TSQLConnection und SQLQuery die Sache angehen, doch ich stecke mit nachfolgender Meldung fest: Fehlermeldung: Für diese Operation ist die Eigenschaft SQLConnection erforderlich. Nun habe ich doch SQLConnection verwendet. Was mache ich falsch. Das Programm läßt sich kompilieren, doch sofort kommt die Fehlermeldung. Ein Connect mit der Datenbank per Button "connect" wird hingegen positiv beantwortet. Ich bin noch relativ neu in Fragen Datenbanken und will mich einfach weiterbilden. Hoffentlich ist das ganze nicht völliger Blödsinn. Auf jedem Fall ist es ein Experimentalstadium nur zum Test, wie man es machen könnte. Für Anregungen, was da falsch läuft wäre ich daher sehr dankbar. Datenbank liegt bei. Norbert |
AW: SQLConnect ist erforderlich!
Moin...:P
Zitat:
In sofern kann ich dir helfen den QT, ohne Funktionsprüfung, mal durchzukorrigieren. :wink: ...dauert einen Moment...bis Morgen früh. 8-) |
AW: SQLConnect ist erforderlich!
Zitat:
Zum Thema trauen, du kannst nicht wirklich was kaputt machen! Wenn es nicht klappen sollte.. wird nicht anderes passieren, außer das es nicht klappen könnte ;). Lesen, Verstehen, anwenden(versuchen).. mehr ist nicht zu tun :-D |
AW: SQLConnect ist erforderlich!
Hallo,
ist Active auf True gesetzt? Dann wird bereits im FormCreate versucht, eine Verbindung zur DB herzustellen. Dort stehen wohl noch nicht alle Infos zur Verfügung? |
AW: SQLConnect ist erforderlich!
Im Objectinspektor ist active auf false. Im Quelltext wird
Delphi-Quellcode:
nach Bestimmung der Datenbank und des Treibers gesetzt. Nun habe ich an dieser Stelle connected auskommentiert und nur mit dem Button connect gestartet, aber die gleiche Fehlermeldung. Ich kenne keine weitere Stellschraube, um das Problem zu beheben.
con.Connected:=true;
Norbert |
AW: SQLConnect ist erforderlich!
Habe soeben den Fehler gefunden. Es gab doch noch eine Stellschraube. Im Objectinspektor habe ich versehentlich SQL Connection falsch eingestellt. Jetzt funktioniert es erst einmal. Doch wäre ich auch dankbar für Hinweise und Kritiken zum Text selbst. Denn mein eigentliches Ziel ist es, nach einer gesonderten Berechnung zB. des Preises bzw. von Rabatten oder was auch immer, dann dieses Ergebnis einem Datenbankfeld oder einer Tabelle zu übergeben, damit es nach einer neuen Verbindung zur Datenbanktabelle wieder zur Verfügung steht. Damit tue ich mich noch schwer. Es reicht ein Feld. Dann könnte ich diese Lösung auf weitere übertragen.
Nun merke ich gerade, dass meine Daten im Listview teilweise mit chinesischen/japanischen Zeichen (vermutlich ein unicode-Problem) ausgegeben werden. Gibt es dafür eine Einstellung oder muß ich das Listview ganz und gar verdammen? Norbert |
AW: SQLConnect ist erforderlich!
Liste der Anhänge anzeigen (Anzahl: 1)
Moin...:P
Du hast es so gewollt...:wink: Ohne Gewähr auf Vollständigkeit. Vergleiche das Original mit, dem Comparer deiner Wahl, dem hier...:thumb: Ansonsten benutze einen Codeformatter und die Codevervollständigung... da passieren weniger Tippfehler. (false statt False)
Delphi-Quellcode:
unit uMainWarenVK;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.Grids, Vcl.DBGrids, Vcl.ExtCtrls, Vcl.DBCtrls, // XPManager nicht mehr notwendig! Data.DB, system.UITypes, Data.DbxSqlite, Data.FMTBcd, Data.SqlExpr; type // !!! vernüftige Namen für die Controls oder Parameter, bei Controls mit Präfix für den Typ, vorzugsweise englisch und mit CamelCase...Denglisch sieht doof aus. :-) (BearbeitenClick) TMainFrm = class(TForm) // besser lvProductList: TListView; // Die Caption kannst du, unabhängig vom Namen, separat ändern! btnClose: TButton; // besser edtCustomerNumber: TEdit; Name: TEdit; Vorname: TEdit; Firma: TEdit; Produkt: TEdit; Anzahl: TEdit; Preis: TEdit; // besser, sagt was über den Inhalt aus mmoComment: TMemo; Neu: TButton; Bearbeiten: TButton; Uebernehmen: TButton; Abbruch: TButton; loeschen: TButton; // Auch auf die Form gelegte Komponenten sollen vernüftige Namen haben und nicht die Blubb1... qryMain: TSQLQuery; connectButton: TButton; executebutton: TButton; outputMemo: TMemo; // besser conMain: TSQLConnection; procedure btnCloseClick(Sender: TObject); procedure AbbruchClick(Sender: TObject); procedure BearbeitenClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure lvProductListClick(Sender: TObject); procedure loeschenClick(Sender: TObject); procedure NeuClick(Sender: TObject); procedure UebernehmenClick(Sender: TObject); procedure connectButtonClick(Sender: TObject); procedure executebuttonClick(Sender: TObject); private // Flags gehören nicht in die public Sichtbarkeit weil nicht von außen benutzt // Name besser IsEdit: boolean; procedure ClearAllFields; procedure RefreshItems(ID, KDNr, Name, Vorname, Firma, Produkt, Anzahl, Preis: string); public end; var MainFrm: TMainFrm; implementation {$R *.dfm} procedure TMainFrm.AbbruchClick(Sender: TObject); begin IsEdit := False; uebernehmen.Enabled := False; Abbruch.Enabled := False; lvProductList.SetFocus; end; //------------------------------------------------------------------------------ // laß das weg. Macht den Code imho schlechter lesbar. Es gibt bessere !Abgrenzungen. procedure TMainFrm.BearbeitenClick(Sender: TObject); begin IsEdit := True; uebernehmen.Enabled := true; abbruch.Enabled := true; end; procedure TMainFrm.connectButtonClick(Sender: TObject); begin try // Establish the connection. // !!! Kommentare nur wenn sie wirklich was über die "Funktion" aussagen...hier nicht conMain.Connected := True; executeButton.Enabled := True; showMessage('Connection erfolgreich!'); // später die Texte in Konstanten verlagern, wenn du die Texte mehrfach verwenden und nur einmal ändern willst. except on E: EDatabaseError do ShowMessage('Fehlermeldungstext connection:' + E.Message); end; end; procedure TMainFrm.ClearAllFields; //Initialiserung // !!! zur Methode des Formulars machen. begin // auch wenn es geht... *würg* // with MainFrm do ... obsolet mit der Verlagerung der Prozedure in pivate edtCustomerNumber.Clear; Name.Clear; // Name "Name" ist schlecht vorname.Clear; Firma.Clear; Produkt.Clear; Anzahl.Clear; Preis.Clear; mmoComment.Lines.Clear; name.SetFocus; end; procedure TMainFrm.RefreshItems(ID, KDNr, Name, Vorname, Firma, Produkt, Anzahl, Preis: string); // !!! zur Methode des Formulars machen. // Name besser. Paßt nun mit dem Inhalt der proedure zusammen. var Item: TListItem; begin Item := lvProductList.Items.Add; // durch die Verlagerung ins Formular kannst du direkt darauf zugreifen. Item.Caption := ID; Item.SubItems.Add(kdnr); Item.SubItems.Add(Name); Item.SubItems.Add(Vorname); Item.SubItems.Add(Firma); Item.SubItems.Add(Produkt); Item.SubItems.Add(Anzahl); Item.SubItems.Add(Preis); end; procedure TMainFrm.btnCloseClick(Sender: TObject); begin Close; end; procedure TMainFrm.executebuttonClick(Sender: TObject); begin outputMemo.ClearSelection; try qryMain.SQL.Text := 'SELECT * FROM WARENVERKAUF'; qryMain.Open; // besser // Active wird automatisch gesetzt except on E: Exception do outputMemo.text := 'Fehlermeldungstext execute: ' + E.Message; end; end; procedure TMainFrm.FormCreate(Sender: TObject); begin conMain.LibraryName := ExtractFilePath(Application.ExeName) + 'sqlite3.dll'; conMain.Params.Add('DataBase=' + ExtractFilePath(Application.ExeName) + 'WarenVK.sqlite'); // !!! keine hardcodierte Pfade verwenden conMain.Connected := True; qryMain.SQL.Clear; qryMain.Params.Clear; qryMain.SQL.Text := 'SELECT ID,KDNR,NAME,VORNAME,FIRMA,PRODUKT,ANZAHL,PREIS FROM WARENVERKAUF'; // Ich bevorzuge bei SQL immer die Großschreibung. Da grenzt sich das SQL von normalen Texten ab...kannst halten wie es willst...aber dann konsequent! qryMain.Open; while not qryMain.Eof do begin RefreshItems(qryMain.FieldByName('ID').AsString, qryMain.FieldByName('KDNR').AsString, qryMain.FieldByName('NAME').AsString, // Feldname "NAME" kann in die Hose gehen...reserviertes Wort. qryMain.FieldByName('VORNAME').AsString, qryMain.FieldByName('FIRMA').AsString, qryMain.FieldByName('PRODUKT').AsString, qryMain.FieldByName('ANZAHL').Asstring, qryMain.FieldByName('PREIS').Asstring); qryMain.Next; end; qryMain.Close; IsEdit := False; end; procedure TMainFrm.lvProductListClick(Sender: TObject); var CurrentCustomerID: string; // Name besser...eindeutiger begin if lvProductList.SelCount >= 1 then begin CurrentCustomerID := lvProductList.Selected.Caption; qryMain.SQL.Clear; qryMain.Params.Clear; qryMain.SQL.Text := 'SELECT * FROM WARENVERKAUF WHERE ID = :CID'; qryMain.ParamByName('CID').AsString := CurrentCustomerID; // besser Parameter qryMain.Open; edtCustomerNumber.Text := qryMain.FieldByName('KDNR').AsString; name.Text := qryMain.FieldByName('NAME').AsString; vorname.Text := qryMain.FieldByName('VORNAME').AsString; firma.Text := qryMain.FieldByName('FIRMA').AsString; Produkt.Text := qryMain.FieldByName('PRODUKT').AsString; Anzahl.Text := qryMain.FieldByName('ANZAHL').Asstring; Preis.Text := qryMain.FieldByName('PREIS').Asstring; mmoComment.Lines.Clear; mmoComment.Lines.Add(qryMain.FieldByName('MEMO').AsString); qryMain.Close; end; end; procedure TMainFrm.loeschenClick(Sender: TObject); var CurrentCustomerID: string; // Zeichen sind nicht mehr Mangelware begin if lvProductList.SelCount >= 1 then begin if MessageDlg('Sind Sie sicher, dass Sie den Datensatz löschen wollen?', mtconfirmation, [mbyes, mbno], 0) = mrYes then begin CurrentCustomerID := lvProductList.Selected.Caption; qryMain.SQL.Clear; qryMain.Params.Clear; qryMain.SQL.Text := 'DELETE FROM WARENVERKAUF WHERE ID = :CID'; qryMain.ParamByName('CID').AsString := CurrentCustomerID; qryMain.ExecSQL; // hier ist es richtig...gibt keine Datenmenge zurück lvProductList.Selected.Delete; end; end; end; procedure TMainFrm.NeuClick(Sender: TObject); begin ClearAllFields; uebernehmen.Enabled := True; abbruch.Enabled := True; IsEdit := False; end; procedure TMainFrm.UebernehmenClick(Sender: TObject); var CurrentCustomerID: string; // Zeichen sind nicht mehr Mangelware begin qryMain.SQL.Clear; qryMain.Params.Clear; //Parameter anlegen... passiert automatisch if IsEdit then // niemals auf True prüfen begin CurrentCustomerID := lvProductList.Selected.Caption; qryMain.SQL.Text := 'UPDATE WARENVERKAUF SET KDNR=:KDNR,NAME=:NAME,VORNAME=:VORNAME,FIRMA=:FIRMA,PRODUKT=:PRODUKT,ANZAHL=:ANZAHL,PREIS=:PREIS,MEMO=:MEMO WHERE ID = :CID'; qryMain.ParamByName('CID').AsString := CurrentCustomerID; // Namensgebung der Parameter verbesserungswürdig...schlechte Unterscheidung Feldname und Parameter qryMain.ParamByName('KDNR').Text := edtCustomerNumber.Text; qryMain.ParamByName('NAME').Text := Name.Text; qryMain.ParamByName('VORNAME').Text := vorname.Text; qryMain.ParamByName('FIRMA').Text := firma.Text; qryMain.ParamByName('PRODUKT').Text := produkt.Text; qryMain.ParamByName('ANZAHL').Text := Anzahl.Text; qryMain.ParamByName('PREIS').Text := preis.Text; qryMain.ParamByName('MEMO').Text := mmoComment.Lines.Text; qryMain.ExecSQL; // Wiederverwendbarkeit RefreshItems(CurrentCustomerID, edtCustomerNumber.Text, Name.Text, vorname.Text, firma.Text, produkt.Text, Anzahl.Text, Preis.Text); end else begin qryMain.SQL.Text := 'INSERT INTO WARENVERKAUF(KDNR,NAME,VORNAME,FIRMA,PRODUKT,ANZAHL,PREIS,MEMO) VALUES (:KDNR,:NAME,:VORNAME,:FIRMA,:PRODUKT,:ANZAHL,:PREIS,:MEMO)'; qryMain.ExecSQL; //LastID qryMain.SQL.Clear; qryMain.Params.Clear; qryMain.SQL.Text := 'SELECT LAST_INSERT_ROWID() AS ID FORM WARENVERKAUF'; qryMain.Open; CurrentCustomerID := qryMain.FieldByName('ID').AsString; qryMain.Close; // Wiederverwendbarkeit RefreshItems(CurrentCustomerID, edtCustomerNumber.Text, Name.Text, vorname.Text, firma.Text, produkt.Text, Anzahl.Text, Preis.Text); end; IsEdit := False; uebernehmen.Enabled := False; abbruch.Enabled := False; lvProductList.SetFocus; end; end. |
AW: SQLConnect ist erforderlich!
Ich danke dir für die Hinweise und Korrekturen und werde mir das alles genau einziehen. In deiner Version sind wundersam auch die bei mir aufgetretenen unicode-Probleme nicht mehr festzustellen. Woran lag das wohl? Jedenfalls erhalte ich jetzt alle Namen in deutscher Sprache. Wenn ich zu einzelnen Punkten deiner Hinweise nochmals Fragen habe, melde ich mich. Noch immer bin ich daran interessiert, eine Beispiellösung dazu zu erhalten, wie man das Ergebnis einer gesonderten Berechnung zB. a+b jeweils in TEdits dann in das Datenbankfeld übernimmt. Habe es mit einer Zuweisung DBEdit:=edit1.text... versucht, doch da stört ihn das die Datenbank nicht geöffnet sei... Wie macht man sowas richtig????
Erst einmal vielen Dank und ich werde wieder studieren:) |
AW: SQLConnect ist erforderlich!
Moin...:P
Zitat:
Zitat:
Zitat:
![]() 2. In der Datenbank die Felder mit vernüftigen Namen anlegen. (Stichwort: reservierte Wörter, Präfix für Tabellennamen und Feldnamen...da hast du das Problem nicht (z.B. F_CUSTOMER_NAME)) 3. In der Datenbank die Felder mit den zu speicherenden Datenbanktypen anlegen. (nicht nur string) 4. Normalisierung der Datentabellen ![]() Zitat:
Delphi-Quellcode:
...besser mit dem Datensatz komplett speichern. :zwinker:
Query.SQl.Text := 'UPDATE xxxxx (F_SUM) VALUES (:SUM) WHERE F_BLUBB = :MID'; // F_SUM muß bestehen
Query.ParamByName(MID).AsInteger := FMyID; Query.ParamByName(SUM).AsFloat := StrToFloat(edtLinks.Text) + StrToFloat(edtRichts.Text); // !!! Mit den Edits zu rechnen ist schlechter Stil. Besser: Die Eingaben auf Gültigkeit prüfen, zusammenrechnen und in einer Variablen "zwischenspeichern". Dann erst das Ergebnis dem SQL übergeben. Query.ExecSQL; Dazu kommt noch die Prüfung auf Gültigkeit der eingegebenen Werte dazu. Siehe: ![]() ...wer hat den gesagt das Programmieren langweilig ist. :zwinker: |
AW: SQLConnect ist erforderlich!
Hallo Haenschmann, vielen vieln Dank für Deine Hilfe für mich alten Zausel. Ich werde mir all das ganz in Ruhe durchsehen und nachvollziehen. Natürlich ist es wichtig, die richtige Syntax zu wählen und ich werde mich natürlich noch mehr bemühen, dies zu beherzigen. Das Programmchen war jedoch ein Experimentalentwurf. Was das unicode-Problem angeht glaube ich den Übeltäter eingegrenzt zu haben. Du hast den Inhalt der Methode "übernehmen" völlig anders angelegt und vermutlich sind die ftString das Problem. Egal jetzt funktioniert es.
Nun einige Fragen: 1. Ist der connect-Button mit der Methode überhaupt nötig, wenn doch ohnehin beim Aufruf des Programms die Verbindung zur Datenbank hergestellt wird. 2. ist ebenso der execute-Button mit der Methode nötig, da ohnehin alles bereits läuft? 3. Du schreibst, dass an gleicher Stelle das ein active Setzen nicht notwenig sei, das dies automatisch geschieht:
Delphi-Quellcode:
Wieso und wo wird es automatisch auf active gesetzt? In FormCreate mit:
qryMain.SQL.Text := 'SELECT * FROM WARENVERKAUF';
qryMain.Open; // besser // Active wird automatisch gesetzt
Delphi-Quellcode:
?
conMain.Connected := True;
qryMain.SQL.Clear; Sicher ergeben sich noch einige weitere Fragen, denn ich bin erst vor gut 30 Min. nach Hause gekommen und wollte unbedingt gleich antworten und nochmals meinen Dank für Deine Bemühungen aussprechen. Ich habe mir all das im Selbstudium, aus Büchern (leider schon gut 10-15 Jahre alt) Youtube-Videos und anderen Tutorials angeeignet. So schleichen sich natürlich auch einige Unsauberkeiten ein. Ich war jedoch froh, dass ein Andreas Hiller eine Folge von Beispieltutorials in Fragen SQLite-Datenbank Anwendungen vorgetragen hat. Ich habe so glaube ich mit Deinen Hinweisen wieder einen großen Schritt nach vorn gemacht. |
AW: SQLConnect ist erforderlich!
Liste der Anhänge anzeigen (Anzahl: 1)
Moin...:P
Zitat:
1. Codevervollständigung (besser als die eingebaute) 2. SourceHighlight Erweiterung (die bunten Striche) Da sieht man sofort in welcher "Ebene" man ist. 3. Cleaner 4. CodeFormatter ...usw. Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
try
qryMain.SQL.Text := 'SELECT * FROM WARENVERKAUF'; // Im Open/ExecSQL wird die Query INTERN geschlossen und am Ende wieder INTERN auf Active := True gesetzt. qryMain.Open; except on E: Exception do outputMemo.text := 'Fehlermeldungstext execute: ' + E.Message; end;
Delphi-Quellcode:
Nochmal der Hinweis auf das E-Book:
procedure TMainFrm.FormCreate(Sender: TObject);
begin conMain.LibraryName := ExtractFilePath(Application.ExeName) + 'sqlite3.dll'; conMain.Params.Add('DataBase=' + ExtractFilePath(Application.ExeName) + 'WarenVK.sqlite'); // !!! keine hardcodierte Pfade verwenden conMain.Connected := True; //qryMain.SQL.Clear; // nicht notwendig...passiert intern //qryMain.Params.Clear; // nicht notwendig...passiert intern qryMain.SQL.Text := 'SELECT ID,KDNR,NAME,VORNAME,FIRMA,PRODUKT,ANZAHL,PREIS FROM WARENVERKAUF'; // Ich bevorzuge bei SQL immer die Großschreibung. Da grenzt sich das SQL von normalen Texten ab...kannst halten wie es willst...aber dann konsequent! qryMain.Open; while not qryMain.Eof do begin RefreshItems(qryMain.FieldByName('ID').AsString, qryMain.FieldByName('KDNR').AsString, qryMain.FieldByName('NAME').AsString, // Feldname "NAME" kann in die Hose gehen...reserviertes Wort. qryMain.FieldByName('VORNAME').AsString, qryMain.FieldByName('FIRMA').AsString, qryMain.FieldByName('PRODUKT').AsString, qryMain.FieldByName('ANZAHL').Asstring, qryMain.FieldByName('PREIS').Asstring); qryMain.Next; end; // qryMain.Close; // braucht nicht wirklich geschlossen zu werden. (Ausnahmen bestätigen die Regel (keine Anzeige der Daten)) Mit der nächsten "Ausführung" passiert eh ein Close. IsEdit := False; end; ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:37 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz