Befehl insert

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
Joachim Raap
Beiträge: 143
Registriert: Mo 30. Mär 2020, 12:37

Befehl insert

Beitrag von Joachim Raap »

warum funktioniert der Insert-Befehl bei folgendem Code nicht? ich bekommen die Fehlermeldung "Cannot open a nonselect Statement".

procedure TFMGruppen.BTSpeichernClick(Sender: TObject);
var
heute: string[10];
begin
if (Zeile) and (StrGrpNr<>'') and (StrGrpBez<>'')
then begin
//in StrGrpNr kann wg eines numerischen Feldes nur 0 bis 9 sein
Heute:=FormatDateTime('dd.mm.yyyy', now);
FMGruppen.SQLQuery1.SQL.Text:='insert into gruppen (Nr,Bez,Anlg,Ktn,MonUms,JahresUms,Aktiv) VALUES ('''+StrGrpNr+''','''+StrGrpBez+''','''+Heute+''',0,0,0,1);';
FMGruppen.SQLQuery1.open;
Fehlermeldung(1);
LVAnzeigen; //hier wird die DB geschlossen
end
else Fehlermeldung(90);
InitEDT;
InitRec;
end;

oleg
Beiträge: 28
Registriert: So 6. Okt 2019, 17:04
OS, Lazarus, FPC: Win10Pro-(Laz 2.2.0 - FPC 3.2.0)-Rasp4(8GB)+MySQL+GITEA 1.20.2 <-> GIT 2.44.0
Wohnort: Leipzig

Re: Befehl insert

Beitrag von oleg »

Hey, du versuchst mit SQL.Open die Abfrage zu öffnen. Verwende SQL.Execute um die Insert Anweisung auszuführen.

Dein SQL Statement wir leserlicher wenn du mit :Parametern arbeitest, außerdem erhöhst du die Sicherheit in Bezug auf Injection.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6209
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Befehl insert

Beitrag von af0815 »

oleg hat geschrieben:
Fr 11. Nov 2022, 12:14
Hey, du versuchst mit SQL.Open die Abfrage zu öffnen. Verwende SQL.Execute um die Insert Anweisung auszuführen.

Dein SQL Statement wir leserlicher wenn du mit :Parametern arbeitest, außerdem erhöhst du die Sicherheit in Bezug auf Injection.
Den ist nichts hinzuzufügen. Und im Forum Code Tags verwenden - das ist oben im Editor das </> Symbol. Damit bleibt es lesbar.

Faustregel:
Bei einem SELECT immer Query.Open verwenden, da ein Resultset zurückgeliefert wird
Bei allen anderen Execute verwenden, da es kein Resultset gibt.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Joachim Raap
Beiträge: 143
Registriert: Mo 30. Mär 2020, 12:37

Re: Befehl insert

Beitrag von Joachim Raap »

Danke.
ich hatte es mit "execsql" auch probiert. Da gibt es zwar keine Fehlermeldung doch kommt in der Datenbank nichts an (habe das da direkt geprüft).... :shock:
Das mit den Parametern habe ich bei af0815 schon mal gelesen - weiß aber nicht, wie ich das umsetzen soll. Darf ich da um ein Beispiel bitten?
Gruß

oleg
Beiträge: 28
Registriert: So 6. Okt 2019, 17:04
OS, Lazarus, FPC: Win10Pro-(Laz 2.2.0 - FPC 3.2.0)-Rasp4(8GB)+MySQL+GITEA 1.20.2 <-> GIT 2.44.0
Wohnort: Leipzig

Re: Befehl insert

Beitrag von oleg »

Abfrage und Einfügen mit :Parametern
In der Connection muss Parameter erlaubt sein (Standard ist : ) und AutoCommit := True

Beispiel für "select"

Code: Alles auswählen

with DataModul.ZQuery do begin
   Close;
   SQL.Clear;
   SQL.Add('select li.name, li.partner, li.telefon, li.mail, li.adresse from lieferanten li');
   SQL.Add('where li.name = :name');
       ParamByName('name').AsString :=  Edit1.Text;;
    Open;
  end;
Beispiel für "Insert"

Code: Alles auswählen

with DataModul.ZQuery do begin
   Close;
   SQL.Clear;
   SQL.Add('insert into lieferanten');
   SQL.Add('(name, partner, telefon, mail, adresse)');
   SQL.Add('values');
   SQL.Add('(:name, :partner, :telefon, :mail, :adresse)');
      ParamByName('name').AsString := Edit1.Text;
      ParamByName('partner').AsString := Edit2.Text;
      ParamByName('telefon').AsString := Edit3.Text;
      ParamByName('mail').AsString := Edit4.Text;
     if Memo1.Text <> '' then
        if Length(Trim(Memo1.Text)) > 0 then
          ParamByName('adresse').AsString := Memo1.Text
           else
         ParamByName('adresse').Value := NULL;
   ExecSQL;
  end; 
Abschließend natürlich noch das obligatorische

Code: Alles auswählen

DataModul.ZQuery.Refresh.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6209
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Befehl insert

Beitrag von af0815 »

Bei Tips sollte man beachten das es zwischen SQLdb (bei Lazarus dabei) und ZEOS kleine aber feine Unterschiede gibt. Die können durchaus einiges bewirken (auch das gar keine Daten an die DB gehen). Damit sollte man als Fragender auch mal sagen, welche DB-Komponenten man verwendet und auch welche DB.

Joachim verwendet vermutlich SQLdb aus Lazarus. Damit fängt der mit Tips für ZEOS in bestimmten Fällen nichts an.

Je nach DB-Systemen (SQLdb und ZEOS) ist es auch unterschiedlich wie die Daten dann persistent (fix) in die Datenbank gelangen.
Beispiel von mir, das auch die Unterschiede zwischen ZEOS und SQLdb zeigt.

Code: Alles auswählen

  ...    
    SQL := ' INSERT INTO [Data]  ([DateTime],[Source])'+sLineBreak
      +'      VALUES (:SQLDateTime,:SQLSource)';
      //+'END '+sLineBreak;
    aQuery.Active:=False;
    {$ifndef useZEOS}aQuery.Options := [sqoAutoApplyUpdates,sqoAutoCommit];{$endif}
    aQuery.SQL.Clear;
    aQuery.SQL.Add(SQL);
    aQuery.Params.CreateParam(ftDateTime, 'SQLDateTime', ptInput);
    aQuery.ParamByName('SQLDateTime').AsDateTime:= DT;
    aQuery.Params.CreateParam(ftString, 'SQLSource', ptInput);
    aQuery.ParamByName('SQLSource').AsString:= Src;
    try 
     aQuery.ExecSQL;
   {$ifdef useZEOS}aQuery.ApplyUpdates;{$endif}
  except
    on E : Exception do begin
      Debugln({$I %CURRENTROUTINE%} +' Exception =>' + E.Message);
    end;
  end;
  ... 
Dieses Beispiel zeigt auch, das ich die Parameter nicht von der Query erraten lasse, sondern sie selbst setze. Das hat sich für mich ganz einfach stabiler erwiesen, egal ob ZEOS oder SQLdb.
Man beachte dabei das man bei SQLdb die Options setzen muss, während bei ZEOS das ApplyUpdates benötigt wird.
Das angeblich obligate "Refresh" wird bei ZEOS bei meinem Anwendungen nirgends verwendet, kann sein , das das Geschmacksfrage ist.
Zuletzt geändert von af0815 am Fr 11. Nov 2022, 18:27, insgesamt 1-mal geändert.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

oleg
Beiträge: 28
Registriert: So 6. Okt 2019, 17:04
OS, Lazarus, FPC: Win10Pro-(Laz 2.2.0 - FPC 3.2.0)-Rasp4(8GB)+MySQL+GITEA 1.20.2 <-> GIT 2.44.0
Wohnort: Leipzig

Re: Befehl insert

Beitrag von oleg »

af0815 hat geschrieben:
Fr 11. Nov 2022, 18:24
Bei Tips sollte man beachten das es zwischen SQLdb (bei Lazarus dabei) und ZEOS kleine aber feine Unterschiede gibt. Die können durchaus einiges bewirken (auch das gar keine Daten an die DB gehen). Damit sollte man als Fragender auch mal sagen, welche DB-Komponenten man verwendet und auch welche DB.

Joachim verwendet vermutlich SQLdb aus Lazarus. Damit fängt der mit Tips für ZEOS in bestimmten Fällen nichts an.

Je nach DB-Systemen (SQLdb und ZEOS) ist es auch unterschiedlich wie die Daten dann persistent (fix) in die Datenbank gelangen.
Beispiel von mir, das auch die Unterschiede zwischen ZEOS und SQLdb zeigt.
Natürlich spielt das DB-System ein Rolle für die Statements und evt. Einstellungen. Wichtig war hier ein Beispiel für die Parameter zu liefern. Auf jeden Fall kann auch dein Code später gut gewartet werden.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6209
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Befehl insert

Beitrag von af0815 »

Joachim hat auch das Problem gehabt, das seine Daten nicht in der DB landen und das ohne Fehlermeldung.

Und hier ist ein Punkt, wo sich SQLdb und ZEOS unterscheiden. Das wollte ich auch mit dem Beispiel zeigen. Das Beispiel ist aus laufenden Code, der unter beiden Systemen stabil lauffähig ist. Der Code ist stark vereinfacht, da die Fehlerbehandlung hier auf ein einfaches try/except reduziert ist. Das ist schon mal soweit ok, weil man damit auch die Exception Messages auf der Konsole sieht, ohne das die Applikation gleich stirbt. Oft kann man danm gleich nachlesen, was dem SQL Server nicht gefallen hat.

Wenn die Daten nicht in der DB landen, es aber keine Fehlermeldung gibt, so muss man mal Kontrollieren ob der interne Puffer der SQLdb oder ZEOS Komponenten überhaupt in die DB kommen. Es werden ja die Änderungen an einem lokalen Dataset gemacht und erst später in die DB übertragen. Da kann es zu interessamten Effekten kommen, besonders, wenn die DB nicht Single User ist. Deswegen sind die zusätzlichen Zeilen notwendig, das die Daten übertragen werden. Hat mir am Anfang viel Probleme bereitet und kann mir jetzt noch Probleme bereiten in Spezialfällen.
Zuletzt geändert von af0815 am Fr 11. Nov 2022, 19:11, insgesamt 1-mal geändert.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Joachim Raap
Beiträge: 143
Registriert: Mo 30. Mär 2020, 12:37

Re: Befehl insert

Beitrag von Joachim Raap »

ja, ich verwende SQLdb von Lazarus und die heilige Maria (MariaDB) - das kann ich gerade noch beantworten.
Übrigens - nach jedem "speichern" in der Anwendung werden alle Sätze aus der Datenbank gelesen und in einer Listview angezeigt. Der Neue ist auch dabei - allerdings bei Maria nicht zu finden (liegt wohl in irgendeinem Puffer und nicht in der Datenbanktabelle). Aber nach Programmende ist er dann auch für die Listview verschwunden genauso wie direkt in der Tabelle der Datenbank.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6209
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Befehl insert

Beitrag von af0815 »

nimm die Query.Options aus meinem Beispiel rein und probiers nochmals. Sollt dann gehen. Ansonsten fehlt ein Primärschlüssel in der DB, sollte aber bei einem Insert nicht so Probleme machen, sondern eher andere.

Schau dir mal die LazInfos an. Ist zwar angestaubt, aber die Grundlagen haben sich nicht wirklich geändert.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Joachim Raap
Beiträge: 143
Registriert: Mo 30. Mär 2020, 12:37

Re: Befehl insert

Beitrag von Joachim Raap »

ja af0815, da habe ich schon mal drin geschnüffelt ist aber soweit ich es verstanden habe nur für die direkte Datenbankarbeit ausgelegt (aber wohl dennoch hilfreich)
Ich habe mal mit einem kopiertem Code aus meinem "Problemprogramm" für die DB-Verbindung, das Speichern und die DB-Beendigung ein zweites, kleines Programm gebastelt. Im Fall der jetztigen Anwendung wird im Gegensatz zum Hilfsprogramm nicht (sofort) in die DB zurückgeschrieben. In meinem Problemprogramm passiert das erst dann, wenn ich "SQLTransaction1.Commit" ausführe - was in der DB-Beendigungsprocedure enthalten ist - im "Hilfsprogramm" passiert das ohne diesen Aufruf sofort.
Was ich nicht nachvollziehen kann ist, warum es mit dem gleichen Code ein unterschiedliches verhalten ergibt - mal wird sofort zurückgeschrieben und mal nicht (kann man das irgendwie einstellen??).
Gibt es dafür eine (leicht verständliche Erklärung)?
By the way af0815 - mit dem Beispiel für die Parameter komme ich nicht klar; probiere mal das von oleg aus.....

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6209
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Befehl insert

Beitrag von af0815 »

Bei welchen Code von dir wird verzögert geschrieben und bei welchen nicht.
Ein kleines, kompilierbares Programm von dir, wo man beide Varianten verwendet holft bei der Beurteilung.

Generell ist es so, nur manuelle Transaktionen oder nur implizit automatische. Kein Mischen darf da passieren. Mein Beispiel oben verwendet automatische Transaktionen und automatisches ApplyUpdates. Ist für meine normalerweise verwendeten Connections am stabilsten (MS SQL).

Mischt man manuelle Transaktionen im falschen Moment mit Applyupdates, kann die Transaktion gestört werden und du kannst ein Rollback im Hintergrund damit auslösen. Wie gesagt, ohne Code ist das meiste Glaskugellesen. Der Beispielcode von mir läuft seit Jahren auf allen Plattformen. Das ist für mich immer die Basis.

Das mit den Parametern läuft ebenso. Aber es meiner Erfahrung nach nicht ganz egal wie der SQL Text gesetzt wird. Ich verwende hier add eines einzingen String unmittelbar nach dem clear. Machst du es anders könnte der interne SQLAnalysator anspringen und die Paramter bereits automatisch erstellen. Nur hat der sich bei mir schon mal verrechnet. Deswegen erstelle ich die Parameter explizit.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten