Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Beim Einlesen doppelte Datensätze (PK) verhindern (https://www.delphipraxis.net/154243-beim-einlesen-doppelte-datensaetze-pk-verhindern.html)

nachtstreuner 2. Sep 2010 16:01

Datenbank: MSSQL • Version: server • Zugriff über: ADO

Beim Einlesen doppelte Datensätze (PK) verhindern
 
Hallo zusammen,

ich möchte eine CSV Datei einlesen, Felder (EAN = Primary Key), Art-Nr usw..
Das Einlesen klappt wunderbar. Bis es zu einer Primary Key Verletzung kommt, dadurch wird das weitere Einlesen verhindert !

Wie kann ich nun dem Programm sagen, das es bei soch einer Konstellation diesen Satz überspringen soll und mit dem nächsten Datensatz der CSV weitermachen soll ?

Delphi-Quellcode:
while memo1.Lines.Count <> i do begin
   sTEXT := memo1.Lines[i];
   Liste := EXPLODE(';',sTEXT);
   // Daten Speichern
   IF (sTEXT <> '') and (LISTE[0] <> 'EAN_NR') then
      begin
      // SATZ_SPEICHERN; //
      with ADOQueryMetro do begin

        if AdoConnectionMetro.Connected = false then begin
          try
           AdoConnectionMetro.ConnectionString := ProvString;
           //'Provider=SQLOLEDB.1;Password=Eisenach09!;Persist Security Info=True;'+
          // 'User ID=sa;Initial Catalog=METRO;Data Source=METROSQL\SQLEXPRESS';
           AdoConnectionMetro.Connected := true;
           AdoQueryMetro.Active := true;
          except
           on E : Exception do begin
            MELDUNG := 'VERBINDUNGSFEHLER : '+ E.Message;
            writelog;
            FEHLER := 1;
            application.Terminate;
            form1.Close;
            ABORT;
            EXIT;
           end;
          end;

        end;
        //Showmessage('Kein Fehler'); // weiter
        //Showmessage(Liste[0]);
        try

          ADOQueryMetro.SQL.Clear;
          ADOQueryMetro.SQL.Text := 'INSERT into PRODUKTE (EAN_NR, ART_BEZ_ALTERN, '+
            'PWHG, PWG, PWUG, KZ_WERB) '+
            'VALUES (:sEAN_NR, :sART_BEZ_ALTERN, :sPWHG, :sPWG, :sPWUG, :sKZ_WERB)';
          ADOQueryMETRO.Parameters.ParamByName('sEAN_NR').Value := LISTE[0];
          ADOQueryMETRO.Parameters.ParamByName('sART_BEZ_ALTERN').Value := LISTE[5];
          ADOQueryMETRO.Parameters.ParamByName('sPWHG').Value   := LISTE[7];
          ADOQueryMETRO.Parameters.ParamByName('sPWG').Value    := LISTE[8];
          ADOQueryMETRO.Parameters.ParamByName('sPWUG').Value   := LISTE[9];
          ADOQueryMETRO.Parameters.ParamByName('sKZ_WERB').Value := LISTE[10];
          //------------------------

          ADOQueryMETRO.ExecSQL;
         except
           on E : Exception do begin
            MELDUNG := 'Doppelter Datensatz(EAN) : ' + LISTE[0] +' | ' +E.Message;
            Showmessage(MELDUNG);

            writelog;


           end;

        end;
      end;



   end;

   i := i +1;
//   memo1.Lines.Delete(0);
end;
MELDUNG := 'Es wurden ['+ IntToStr(i) + '] Zeilen verarbeitet...';
WRITELOG;
:roll: Grüße vom nachtstreuner

mkinzler 2. Sep 2010 16:05

AW: Beim Einlesen doppelte Datensätze (PK) verhindern
 
Würde sich ja ein Merge anbieten

shmia 2. Sep 2010 16:19

AW: Beim Einlesen doppelte Datensätze (PK) verhindern
 
Hier erst mal ein paar Tipps:
1.) bitte den Code, der die Verbindung zur Datenbank herstellt in eine eigene Methode verschieben.
Delphi-Quellcode:
procedure TForm1.ConnectToDatabase;
begin
  if not AdoConnectionMetro.Connected then
  begin
    AdoConnectionMetro.ConnectionString := ProvString;
    //'Provider=SQLOLEDB.1;Password=Eisenach09!;Persist Security Info=True;'+
    // 'User ID=sa;Initial Catalog=METRO;Data Source=METROSQL\SQLEXPRESS';
    AdoConnectionMetro.Connected := true;
  end;
end;
Diese Methode wird einmal VOR der Schleife aufgerufen
2.) Das SQL für die Query wird ebenfalls nur einmal vor der Schleife aufrufen
Delphi-Quellcode:
ADOQueryMetro.SQL.Text := 'INSERT into PRODUKTE (EAN_NR, ART_BEZ_ALTERN, '+
 'PWHG, PWG, PWUG, KZ_WERB) '+
 'VALUES (:sEAN_NR, :sART_BEZ_ALTERN, :sPWHG, :sPWG, :sPWUG, :sKZ_WERB)';
3.) Du fängst ja schon Fehler beim Einfügen mittels try..except ab.
Nur bringt das wenig, wenn du die Fehlermeldung mit ShowMessage() gleich anzeigst.
Stellt dir vor, es sind 100 doppelte Datensätze in der CSV-Datei - viel Spass beim OK-klicken.8-)

4.) die Zeile
Delphi-Quellcode:
AdoQueryMetro.Active := true;
komplett löschen. Bei einem SQL-Insert macht dies keinen Sinn; es stört eher.

nachtstreuner 2. Sep 2010 17:58

AW: Beim Einlesen doppelte Datensätze (PK) verhindern
 
Viele Dank erstmal für die Antworten,

mit dem MERGE muss ich mich erstmal beschäftigen.

Die Tips von shmia habe ich beherzigt und auch so im unten stehenden Code eingefügt :

Allerdings schreibt er mir jetzt keinen einzigen Datensatz in die DB,
Stattdessen erhalte ich folgende Meldung aus dem Protokoll :

02.09.2010 18:59:08 Es werden [15668] Zeilen verarbeitet !
02.09.2010 18:59:18 Doppelter Datensatz(EAN) : 1215126156152 | Ungültige Autorisierungsangabe
02.09.2010 18:59:24 Doppelter Datensatz(EAN) : 1233567891012 | Ungültige Autorisierungsangabe
02.09.2010 18:59:29 Doppelter Datensatz(EAN) : 1234567890128 | Ungültige Autorisierungsangabe
02.09.2010 18:59:36 Doppelter Datensatz(EAN) : 1472583691477 | Ungültige Autorisierungsangabe

und das obwohl ich vor dem Start die Tabelle geleert habe.

Hier nochmal der geänderte Code :
Code:
//==============================================================================
// Verbindung zur Datenbank herstellen
//==============================================================================
procedure TForm1.ConnectToDatabase;
begin
  if not AdoConnectionMetro.Connected then
  begin
    AdoConnectionMetro.ConnectionString := ProvString;
    //'Provider=SQLOLEDB.1;Password=*******;Persist Security Info=True;'+
    // 'User ID=sa;Initial Catalog=METRO;Data Source=METROSQL\SQLEXPRESS';
    try
      AdoConnectionMetro.Connected := true;
     // ADOQueryMETRO.Active := true;
    except
      on E : Exception do begin
            MELDUNG := 'VERBINDUNGSFEHLER : '+ E.Message;
            writelog;
            FEHLER := 1;
            application.Terminate;
            form1.Close;
            ABORT;
            EXIT;
      end;
    end;
  end;
end;
//==============================================================================
// Verarbeitung starten
//==============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  i : integer;
  liste    : TStringDynArray;
  sTEXT,DATNAME    : string;
  test : variant;
begin
  try
    memo1.Clear;
    memo1.Lines.LoadFromFile(FILEPFAD +'\'+ FileDat);
    MELDUNG := FilePFAD + '\' + FileDat + ' ... eingelesen';
    WRITELOG;
  except
    MELDUNG := '[FEHLER:] Konnte CSV Datei nicht öffnen ...';
    WRITELOG;
    Application.Terminate;

  end;

  I := 0;
  MELDUNG := 'Es werden ['+IntToStr(memo1.Lines.Count)+'] Zeilen verarbeitet !';
  Writelog;
  ADOQueryMetro.SQL.Clear;
  ADOQueryMetro.SQL.Text := 'INSERT into PRODUKTE (EAN_NR, ART_BEZ_ALTERN, '+
            'PWHG, PWG, PWUG, KZ_WERB) '+ //, WERB_ID, WERB_ZEITR_VON, WERB_ZEITR_BIS, '+
            //'BAS_GROESSE, UWD_MASSENEINHEIT_SL, VK_PREIS_BR, VK_PREIS_ALT_BR, '+
            //'VK_PREIS_WERB_BR, GRUNDPREIS_BR, GRUNDPREIS_ALT_BR, GRUNDPREIS_WERB_BR, '+
            //'AKTIONSBEGINN, AKTIONSENDE) ' +
            'VALUES (:sEAN_NR, :sART_BEZ_ALTERN, :sPWHG, :sPWG, :sPWUG, :sKZ_WERB)';



  while memo1.Lines.Count <> i do begin
   sTEXT := memo1.Lines[i];
   Liste := EXPLODE(';',sTEXT);

   // Daten Speichern
   IF (sTEXT <> '') and (LISTE[0] <> 'EAN_NR') then
     begin
      // SATZ_SPEICHERN; //
       ADOQueryMETRO.Parameters.ParamByName('sEAN_NR').Value := LISTE[0];
       ADOQueryMETRO.Parameters.ParamByName('sART_BEZ_ALTERN').Value := LISTE[5];
       ADOQueryMETRO.Parameters.ParamByName('sPWHG').Value   := LISTE[7];
       ADOQueryMETRO.Parameters.ParamByName('sPWG').Value    := LISTE[8];
       ADOQueryMETRO.Parameters.ParamByName('sPWUG').Value   := LISTE[9];
       ADOQueryMETRO.Parameters.ParamByName('sKZ_WERB').Value := LISTE[10];
       //------------------------
       try
         ADOQueryMETRO.ExecSQL;
       except
           on E : Exception do begin
            MELDUNG := 'Doppelter Datensatz(EAN) : ' + LISTE[0] +' | ' +E.Message;
           Showmessage(MELDUNG);

            writelog;

           end;
       end
   end;
   i := i +1;
   //   memo1.Lines.Delete(0);
  end;

  MELDUNG := 'Es wurden ['+ IntToStr(i) + '] Zeilen verarbeitet...';
  WRITELOG;
  DATNAME := leftstr(dateToStr(date),2)+midstr(dateToStr(date),4,2)+
   leftstr(TimeToStr(time),2)+midstr(timeToStr(time),4,2)+
   midstr(timeToStr(time),7,2)+'.CSV';
  //   movefile(PChar(FILEPFAD+ '\' + FileDat),PChar(sichPFAD+'\'+DATNAME));
   MELDUNG := FILEPFAD + '\' + FileDat+' nach '+ sichPfad + '\'+DATNAME+' verschoben !!';
   //frmLOGBUCH.memo.Lines.Add('c:\wa_order.txt nach c:\sich_order\'+DATNAME+' verschoben !!');
   writelog;
  MELDUNG := 'VERARBEITUNG abgeschlossen !! - Keine FEHLER !';
  WRITELOG;
//Form1.close;
end;
:pale:

rapante 2. Sep 2010 18:19

AW: Beim Einlesen doppelte Datensätze (PK) verhindern
 
Wo rufst du denn deine Connect-Procedure auf?

nachtstreuner 2. Sep 2010 18:48

AW: Beim Einlesen doppelte Datensätze (PK) verhindern
 
Hallo Rapante,

in der ersten Procedure im String 'ProvString'

Der connect funktioniert ja, sonst hätte ich dort schon eine Fehlermeldung bekommen.

:?

nachtstreuner 2. Sep 2010 18:57

AW: Beim Einlesen doppelte Datensätze (PK) verhindern
 
Hallo Rapante,

das war von mir eine Falschmeldung !!!
Habe ganz übersehen, nach dem füllen des Strings 'ProvString' die Prozedur ConnectToDatabas aufzurufen.
Jetzt funktiniert zumindest das wegschreiben in die Tabelle.

In der CSV Datei die ich einlese, befindet sich eine doppelte EAN-Nummer, dieses wird in der Tabelle in das Primary Key Feld EAN_NR geschrieben, nach 50000 Datensätzen bekomme ich dann die Fehlermeldung

[Window Title]
Metro

[Content]
Doppelter Datensatz(EAN) : 3073780993654 | Verletzung der PRIMARY KEY-Einschränkung 'PK__PRODUKTE__3A831F4D7F60ED59'. Ein doppelter Schlüssel kann in das dbo.PRODUKTE-Objekt nicht eingefügt werden

[OK]


Da das Einlesen später autom. ohne Benutzerreaktion nachts eingelesen werden soll, frage ich mich, wie ich diese Fehlermeldung abfangen kann, den doppelten EAN-Code(Satz) überspringe und mit dem nächsten Satz weitermache...

rapante 2. Sep 2010 19:11

AW: Beim Einlesen doppelte Datensätze (PK) verhindern
 
Lass doch einfach das showmessage weg und schreib stattdessen die Fehlermeldung in dein Logfile.

scrat1979 2. Sep 2010 19:14

AW: Beim Einlesen doppelte Datensätze (PK) verhindern
 
Ich würde entweder alle EAN in eine Liste schreiben (IntegerList) und prüfen, ob sie dort bereits existiert

ODER

Vor dem INSERT mit "COUNT * .... WHERE EAN = ...." prüfen, ob Datensätze mit der EAN vorhanden sind

nachtstreuner 2. Sep 2010 21:05

AW: Beim Einlesen doppelte Datensätze (PK) verhindern
 
Danke an alle für Eure Tips,

ich habe es jetzt so gemacht wie Rapante vorgeschlagen hat, SHowmessage ausschalten und stattdessen den doppelten EAN-code in das Logfile eintragen, da hat man gleich noch einen Nachweis für den Ersteller der CSV datei, aus diesen Info´s kann er dann Massnahmen ergreifen, um doppelte EAN Codes zu vermeiden.

Nachdem Einlesen wird also ein Mail generiert und an den Lieferanten der CSV zurückgeschickt, dieser kann sie dann bearbeiten.

Danke nochmal an alle. Problem gelöst und dies wie immer sehr schnell.

mfg
nachtstreuner


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:50 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz