AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Delphi ADODataset Insert Update

ADODataset Insert Update

Ein Thema von gro · begonnen am 8. Feb 2006 · letzter Beitrag vom 16. Feb 2006
Antwort Antwort
gro

Registriert seit: 9. Jul 2004
Ort: Kärnten
17 Beiträge
 
Delphi 10.3 Rio
 
#1

ADODataset Insert Update

  Alt 8. Feb 2006, 13:23
Datenbank: DB2 • Version: V8 • Zugriff über: ADO
Folgendes Problem:

Ich verwende 2 ADOConnections + ADODatasets um von einer Sourcetabelle in eine Targettabelle Daten zu schaufeln.
In der Targettabelle befinden sich aber bereits Daten (gleicher Primarykey) die in der Sourcetabelle bereits vorhanden sind. Wenn nun solch ein Datensatz gefunden wurde sollte auf diesen ein Update gemacht werden.

Meine Lösung:

TargetTable, SourceTable und TargetUpdate sind ADODatasets


Delphi-Quellcode:
TRY
  TargetTable.Insert;
  for iFieldCount := 0 to SourceTable.FieldCount - 1 do begin
    szFieldname := SourceTable.Fields[iFieldCount].FieldName;
    TargetTable.FieldByName(szFieldname).Value :=
           SourceTable.FieldByName(szFieldname).Value;
  end;
  TargetTable.Post; // wenn record vorhanden wird hier eine exception geworfen
EXCEPT
  on e: Exception do begin
    TargetTable.Cancel;

    // alle indexfelder in UPDATESQL befüllen.
    // Die Stringliste aIndexFields und der SQL-Query wird mit einer eigenen Routine befüllt
    TargetUpdate.Active := FALSE;
    for iCount := 0 to aIndexFields.Count - 1 do begin
      szFieldname := aIndexFields[iCount];
      TargetUpdate.Parameters.ParamByName(szFieldname).Value := SourceTable.FieldByName(szFieldname).Value;
    end;
          
    TargetUpdate.Active := TRUE;
    TargetUpdate.Edit;
    for iFieldCount := 0 to SourceTable.FieldCount - 1 do begin
      szFieldname := SourceTable.Fields[iFieldCount].FieldName;
      TargetUpdate.FieldByName(szFieldname).Value := SourceTable.FieldByName(szFieldname).Value;
    end;
    TargetUpdate.Post;
  end;
END;
Dies funktioniert alles recht schön und fast vernünftig.
ABER die Performanze ist dabei unterm Hund da bei jeden Update ein Select ausgeführt wird.
Vergleich bei 15000 Datensätzen
Nur Insert 95 Secunden
Mit Update 920 Sekunden

Nun meine Frage: Wie kann ich den ADODataset TargetTabel so positionieren, das er nach der Exception des Inserts/Post auf den richtigen Datensatz positioniert ist. BZW. wenn ich das TargetTable.Cancel weglasse, wie kann ich den Datensatz danach trotzdem aktualisieren, denn ohne TargetTable.Cancel ist die TargetTable ja richtig positioniert. Wenn ich jetz mit TargetTable.Edit und anschliesendem TargetTable.Post versuche diesen Record upzudaten bekomme ich eine Fehlermeldung (Duplicat Rows) Was mache ich hier falsch?

Mfg Pit und danke im Voraus
Peter (EDV = Ende der Vernunft)
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#2

Re: ADODataset Insert Update

  Alt 13. Feb 2006, 20:55
Deine Art, die Daten rüber zu schaufeln, ist zwar ADO-Konform, aber eben lahm. Um das schnell(er) zu machen, fallen mir 3 Dinge ein:
1. Transaktionen verwenden
2. SQL-Kommandos selber basteln.
3. Einen Index auf den Primary Key der Target-Tabelle

Zu 2 solltest Du abhängig davon, ob der PK vorhanden ist, oder nicht eine INSERT oder UPDATE Anweisung aufbauen, deren WHERE-Klausel nur die Primary Key Bedingung enthält. Also ungefähr so:
SQL-Code:
UPDATE Target
  SET Field1 = <Value1>,
      Field2 = <Value2>,
      ....
WHERE IDField = <ID>
bzw.
SQL-Code:
INSERT INTO Target
  (IDField, Field1, Field2 ....)
VALUES
  (<ID>, <Value1>, <Value2> ...)
Mit ADO sind die vom Provider generierten SQL-Kommandos alles Andere als optimal. Schau Dir die mal an.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
gro

Registriert seit: 9. Jul 2004
Ort: Kärnten
17 Beiträge
 
Delphi 10.3 Rio
 
#3

Re: ADODataset Insert Update

  Alt 16. Feb 2006, 11:32
Erstmals besten Dank für die rasche Antwort.

Zu 1: Der obige Codeteil ist reduziert auf ein absolutes Minimum. Die einzelnen Inserts/Updates befinden sich innerhalb einer Transaktion. (ADOTargetConnection.BeginTrans und alle 1000 Records ein ADOTargetConnection.CommitTrans) Alle 1000 Records ein Commit ist/war eine Anforderung des Kunden.


Zu 2: Mit dem Dataset "TargetUpdate" wird genau das gemacht. Im Commandtext steht bereits ein SQL wobei sich die WHERE Bedingung aus den Infdexfeldern zusammensetzt.

Dazu kommt noch ein kleines (für mich grosses) Problem: Wenn ich statt eins Datasets einen ADOQuery verwende kann ich in den Blobfelder keine Werte setzen. Sobald ich dieses versuche bekomme ich die Fehlermeldung "Invalid conversation" ???

Dies funktioniert mit BLOB/CLOB Feldern nicht!

Delphi-Quellcode:
  ADODataSet1.First;
  ADOQuery1.SQL.Clear;
  szSql := 'UPDATE schema.table SET ' +
           'FILEDATA = :FILEDATA, DESCRIPTION = :DESCRIPTION ' +
           'WHERE OBJECID = :OBJECTID';

  ADOQuery1.SQL.Add (szSql);
  ADOQuery1.Prepared := TRUE;

  while (ADODataSet1.Eof = FALSE) do begin
    for iCount := 0 to ADODataSet1.FieldCount - 1 do begin
      szField := ADODataSet1.Fields[iCount].FieldName;

      aField := ADOQuery1.Parameters.FindParam(szField);
      if (aField <> nil) then begin
        if (ADODataSet1.Fields[iCount].IsNull = FALSE) then begin
          ADOQuery1.Parameters.ParamByName(szField).Value :=
              ADODataSet1.Fields[iCount].Value;
        end;
      end;
    end;
    ADOQuery1.ExecSQL;
    ADODataSet1.Next;
  end;
Zu 3: Auf allen Tagettabellen sind Indizes vorhanden

-----------------------------------------------------------------------------

Was mir nicht eingeht, ist dass nach einem .INSERT und anschl. .POST die Targettabelle den Cursor auf der richtigen Position stehen hat (und dies auch nach der EXCEPTION DUPLICATE ROWS -803) aber kein Update auf diesen Record danach mehr möglich ist. Wenn ich dieses irgendwie umgehen könnte wäre mein Problem gelöst.

Folgendes könnte ich mir vorstellen. Aber wie?

Delphi-Quellcode:
    // insert versuchen
    aDataSet.Insert;

    // werte eintragen
    // ...

    aDataSet.Post;
  EXCEPT
    on e: exception do begin
      // ??? Was muss man hier machen das das funktioniert???
      aDataSet.Edit;

      // ev. werte nochmals eintragen
      // ...

      aDataSet.Post;
  END;

MfG Pit
Peter (EDV = Ende der Vernunft)
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#4

Re: ADODataset Insert Update

  Alt 16. Feb 2006, 12:13
Hmm....
BLOBS: Mach doch einfach eine Fallunterscheidung: Bei einem Blob verwendest du am besten einen Stream zum kopieren und sonst eben die Variants.

EDIT: Normalerweise sollte es kein Problem sein, bei einem Post-Fehler die Daten nochmals zu editieren, ohne das man irgendwelche Anstrengungen unternehmen muss. Das Dataset ist noch im Edit/Append-Modus, insofern ist der Aufruf vom 2.Edit falsch.
myDataset.Edit;
Delphi-Quellcode:
Try
  myDataSet['Foo'] := Bar;
...
  myDataSet.Post; // <-- peng
Except
  myDataSet.Edit; // <-- Falsch, weil das Dataset noch im Editmodus ist.
  myDataSet['Bar'] := Foo;
  myDataSet.Post;
End;
Versuche doch mal ein myDataSet.Cancel, damit wird der Editmodus verlassen, ohne Änderungen vorzunehmen. Danach kannst Du ja andere Daten reinschreiben...

Was genau steht im TargetUpdate.CommandText drin?
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:30 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf