TSQLQuery sowohl SELECT als auch INSERT

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

TSQLQuery sowohl SELECT als auch INSERT

Beitrag von pschoett »

Hallo allerseits,
ich habe wohl eine Anfängerfrage, weil (Un)verständnisfrage zu TSQLQuery.

Ein TSQLQuery hat ja die Eigenschaften SQL für Select und DeleteSQL,InsertSQL,UpdateSQL. Wenn ich im TSqlQuery sowohl für SQL.Text als auch für InsertSQL.Text ein Statement mit Parameter hinterlege, wie kann dann entscheiden welches der Statements ich ausführe?

Code: Alles auswählen

 
With SqlQuery1 do
begin
  SQL.Text := 'SELECT id, name FROM tabelle WHERE name= :parName' ;
  InsertSQL.Text := 'INSERT INTO tabelle (name) VALUES (:parName)' // "id" ist autoincrement und muss nicht manuell gesetzt werden
 
  // Jetzt schreibe ich den Parameter
  Params.ParamByName('parName').AsString := 'meinName';
 
  // Was passiert jetzt? Wird ein neuer Record erstellt oder/und wird der Record zu :parName angezeigt?
  ExecSQL;
  SQLTransaction.Commit;
end;

Meine Frage ist, wie ich entscheide, wann ich Daten abrufen und wann ich Daten schreiben möchte.

Gruß,
Peter

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von mse »

DeleteSQL, InsertSQL und UpdateSQL werden von der ApplyUpdates() Prozedur verwendet, SQL von ExecSQL() und Active:= true.
Wenn du Daten nicht via ApplyUpdates() sondern eine eigene Operation in die DB schreiben möchtest, solltest du <connection>.executedirect() oder eine zusätzliche query-Komponente verwenden. Vermutlich gibt es auch eine tsqlstatement Komponente ohne den Datencursor overhead.

pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von pschoett »

Vielen Dank für deine Antwort.

Laut dem Wiki-Artikel Working with TSQLQuery verstehe ich, dass SQLQuery.ApplyUpdates die insert/delete/update-Statements in die DB schreibt?
<connection>executedirect() entspricht meiner Variante "ExecSQL; Transaction.Commit" oder?

Welchen Grund gibt es denn zwei TSQLQueries, eines für SELECT und eines für INSERT/UPDATE/DELETE, zu verwenden?

Peter

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von mse »

pschoett hat geschrieben:Laut dem Wiki-Artikel Working with TSQLQuery verstehe ich, dass SQLQuery.ApplyUpdates die insert/delete/update-Statements in die DB schreibt?

Ja, wobei die insert/delete/update-Statements normalerweise automatisch generiert werden. "InsertSQL.Text := '<The Insert Statement>';" ist nur für Spezialfälle, z.B. Updaten von joins notwendig.
<connection>executedirect() entspricht meiner Variante "ExecSQL; Transaction.Commit" oder?

Mit "<connection>.executedirect()" meine ich "<connection>.executedirect('<Dein insert/delete/update-Statement>',...)".
"Transaction.Commit;" ist zusätzlich notwendig.
In deinem Fall macht "ExecSQL;" etwa "<connection>.executedirect(''SELECT id, name FROM tabelle WHERE name= :parName',...)"
Welchen Grund gibt es denn zwei TSQLQueries, eines für SELECT und eines für INSERT/UPDATE/DELETE, zu verwenden?

Das frage ich mich auch. :-)
Die Methode weitere "TSQLQuery" zum insert, delete und update zu verwenden stammt möglicherweise aus der Zeit als es noch kein TSQLStatement gab.
In MSEgui habe ich zusätzlich "tmsesqlquery.onapplyrecupdate" um komplizierte und unübliche update-Vorgänge abzuwickeln.

pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von pschoett »

Die Dokumentation von Lazarus ist ja schon recht schwierig zu durchblicken.
wobei die insert/delete/update-Statements normalerweise automatisch generiert werden

Insert erklärt sich über ein Beispiel im Wiki Artikel. Dort wird die Methode 'appendrecord' genannt:

Code: Alles auswählen

 tsqlquery1.appendrecord(['XXXX', 'description']) 
tsqltransaction1.commit;

Die Methoden Delete und Edit (anstelle 'Update table') beziehen sich immer auf den aktuellen Record. Gibt es Methoden, bei denen ich zusätzlich den Record wählen kann, a la 'where id=4711' oder muss ich eine zusätzliche Bedingung über ein eigenes SQL-Statement wählen oder mit der Methode ExecuteDirect() ausführen?

Bzgl <connection>executedirect() hätte ich den Wiki Artikel genauer durchlesen sollen, denn dort steht es auch genauso.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von mse »

Am besten beschreibst du einmal deine konkrete Aufgabe.

pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von pschoett »

Konkrete Aufgabe ist eine Import-Schnittstelle von einer sich immer noch in Verwendung befindenden FoxPro Datenbank per ODBC-Schnittstelle nach MySQL. Dabei kann ich nicht 1zu1 kopieren, sondern bau die Datenstrukturen für die Zieltabellen um.

Ich frage hier so detailiert nach, um die für mich optimale Möglichkeit für Lazarus und DB zu finden.

Ich habe gerade in Lazarus mit TSQLQuery.AppendRecord() erste Versuche gestartet und erhalte bereits beim Kompilieren die Fehlermeldung:

Code: Alles auswählen

unit1.pas(310,90) Error: Wrong number of parameters specified for call to "AppendRecord"

Das verstehe ich jetzt nicht. Ich habe zwei AppendRecord-Versuche gestartet.
1) In TSQLQuery habe ich keine Parameter definiert und es wird AppendRecord(value1, value2, ..., value#) ausgeführt mit exakt für jedes Tabellenfeld ein value# in genau der richtigen Reihenfolge.
2) In TSQLQuery habe ich genau zwei Parameter definiert und es wird AppendRecord(value1,value2) ausgeführt mit den richtigen Werten für die beiden Parameter.
Aber in beiden Fällen nennt der Compiler die obige Fehlermeldung.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von mse »

TSQLQuery wie auch die MSEgui tmsesqlquery als auch die ZEOS query Komponenten machen vereinfacht folgendes:

- Wird "active:= true" gesetzt wird das "SQL" statement ausgeführt (normalerweise ein SELECT statement) und die vom Server zurückgelieferten Daten in einem Puffer gespeichert.
- Diese Daten im Puffer können nun mit den normalen TDataset Operationen (Insert, Append, Delete, Edit, Post) verändert werden. Dabei wird von allen geänderten Records eine Kopie des Originalzustandes zurückbehalten.
- ApplyUpdates() sendet die Änderungen zur Datenbank, die Originalkopien werden zur Auswahl der zu ändernden records im Server herangezogen.
- Um die Transaktion abzuschliessen muss <transaction>.Commit() aufgerufen werden.

Vermutlich wirst du die FoxPro Daten in ein sqlquery laden, die records durchgehen und in ein zweites mit MySQL verbundenes sqlquery übertragen. tsqlquery.appendrecord() sollte dazu geeignet sein. Eine andere Möglichkeit ist append()/post(). <MySQL query>.ApplyUpdates() überträgt die Daten zum MySQL-Server, <MySQL transaction>.commit() schliesst die Übertragung ab.
Ich frage hier so detailiert nach, um die für mich optimale Möglichkeit für Lazarus und DB zu finden.

Wahrscheinlich ist es nicht notwendig, die FoxPro Daten alle im Speicher zu halten. In MSEgui würde ich vermutlich ein tsqlresult verwenden, welches wesentlich weniger overhead hat.
Ich habe gerade in Lazarus mit TSQLQuery.AppendRecord() erste Versuche gestartet und erhalte bereits beim Kompilieren die Fehlermeldung:
unit1.pas(310,90) Error: Wrong number of parameters specified for call to "AppendRecord"

Wie sieht dein AppendRecord() Aufruf exakt aus?

pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von pschoett »

mse hat geschrieben:Wie sieht dein AppendRecord() Aufruf exakt aus?

Das hier wird nicht kompiliert:

Code: Alles auswählen

AppendRecord( DModul1.qMAXAuftrag.fieldbyname('nummer').Value,
    DModul1.qMAXAuftrag.fieldbyname('datum').Value,
    DModul1.qMAXAuftrag.fieldbyname('kndnr').Value,
    ...
    AnsiToUtf8(DModul1.qMAXAuftrag.fieldbyname('frei_c10').Value),
    AnsiToUtf8(DModul1.qMAXAuftrag.fieldbyname('frei_m01').Value) );

Habe ich jedoch ein Insert-Statement in SQL.Text mit Parametern eingetragen, so wird das erfolgreich kompiliert und erfolgreich ausgeführt:

Code: Alles auswählen

   ParamByName('parfrei_c10').Value:=AnsiToUtf8(DModul1.qMAXAuftrag.fieldbyname('frei_c10').Value);
   ParamByName('parfrei_m01').Value:=AnsiToUtf8(DModul1.qMAXAuftrag.fieldbyname('frei_m01').Value);
   ExecSQL;
   DModul1.SQLTransOdbc.Commit;

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von mse »

appendrecord() ist so definiert:

Code: Alles auswählen

 
procedure TDataSet.AppendRecord(const Values: array of const);
 

also:

Code: Alles auswählen

 
AppendRecord([ DModul1.qMAXAuftrag.fieldbyname('nummer').Value,
    DModul1.qMAXAuftrag.fieldbyname('datum').Value,
    DModul1.qMAXAuftrag.fieldbyname('kndnr').Value,
    ...
    AnsiToUtf8(DModul1.qMAXAuftrag.fieldbyname('frei_c10').Value),
    AnsiToUtf8(DModul1.qMAXAuftrag.fieldbyname('frei_m01').Value)] );
 

pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von pschoett »

Danke, genau das habe ich gerade auch herausgefunden :)
und natürlich kompiliert dann auch alles richtig.

pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Re: TSQLQuery sowohl SELECT als auch INSERT

Beitrag von pschoett »

Meine Unwissenheit treibt mich noch in den Wahnsinn :(
AppenRecord lässt sich jetzt kompilieren, aber nicht ausführen. Ich erhalte den Fehler:

Code: Alles auswählen

EDatabaseError: query1: More fields specified then really exist

Allerdings sind genau die Felder in AppendRecord eingetragen, die in der MySQL Tabelle existieren. Die MySQL Tabelle hat auch kein Autoinkrement Indexfeld, das nur von MySQL gefüllt wird. Insofern benötige ich wieder Hilfe.

Anscheinend ist die Fehlermeldung aber nicht wirklich aussagekräftig, da der Fehler auch kommt, wenn ich einen Record mit nur drei neuen Feldern mit AppendRecord hinzufügen will.

Antworten