Doubletten kennzeichnen in den Debitorposten

2. November 2010 12:15

Hallo,

Ich habe per Dataport Zahlungseingänge von Debitoren in ein Fibu-Buchblatt vorgenommen.
Leider existierten vorher vom User erfaßte Fibu-Buchblätter, die teilweise dieselben Daten enthielten.
Nun hat der User sowohl seine, als auch meine importierten Buchblätter mit F11 verbucht.
Nun stellt er fest, dass Zahlungseingänge doppelt drin sind.
Leider weiss weder er noch ich welche Buchblätter von wem erstellt wurden, nur dass die Buchungssätze von 1.1.6..31.12.06 sind.

Ich hab folgenden Code entworfen, der allerdings auf einer NATIVE Server NAV 5.01 Datenbank nach 16 Std. immer noch nicht durchgelaufen ist. Frage, gibt es eine intelligentere, sprich schnellere Möglichkeit Doubletten zu suchen und zu eliminieren? Wenn NAV Arrays mit variablem N unterstützen würde, könnte ich eine verkette Liste implementieren und das Problem schnell lösen. Unter Doubletten verstehe ich Datensätze vom selben Debitor, selber Betrag, versch. Belegnr. (automatisch von NAV gezogen) und gleiches Jahr 2006, gleiches Quartal, aber versch. Monat und versch. Tag.

Ausgedachtes Bsp:
06.10.2006, Zahlung, Debitor 0815, Betrag -512,12€
03.12.2006, Zahlung, Debitor 4711, Betrag -67,50€
10.12.2006, Zahlung, Debitor 4711, Betrag -67,50€
12.12.2006, Zahlung, Debitor 4711, Betrag -67,50€
31.12.2006, Zahlung, Debitor 007, Betrag -11,16€

Mit einer verketteten Liste, könnte ich sehr schnell die Datensätze sortieren und in ein Array mit variabler Länge einlesen und paarweise vergleichen und alle mit gleichem Betrag kennzeichnen:
http://de.wikipedia.org/wiki/Verkettete_Liste

Hier mein Code (10000 bis 69412 ist die Nr. der Debitoren, ich hab FOR-Schleife gewählt, da diese angeblich schneller ist als REPEAT/UNTIL und WHILE/DO, ferner hab ich bei den Deb.Posten nen neuen Schlüssel reingemacht um die Datensätze vorzusortieren):

Code:
CustRec.RESET;
CustLedEntry.RESET;
CustLedEntry2.RESET;

CustRec.SETCURRENTKEY("No.");
CustLedEntry.SETCURRENTKEY("Customer No.","Posting Date","Document Type",Open);
CustLedEntry2.SETCURRENTKEY("Customer No.","Posting Date","Document Type",Open);

CustLedEntry.CALCFIELDS(Amount);
CustLedEntry2.CALCFIELDS(Amount);
 
FOR i := 10000 TO 69412 DO BEGIN // 69412

  CustLedEntry.SETRANGE("Customer No.",FORMAT(i));
  CustLedEntry.SETFILTER("Posting Date",'01.01.2006..31.12.2006');
  CustLedEntry.SETRANGE("Document Type",CustLedEntry."Document Type"::Payment);
  CustLedEntry.SETFILTER(Amount,'<>%1',0.00);

   IF CustLedEntry.COUNT > 0 THEN BEGIN

    IF CustLedEntry.FINDFIRST THEN
      first := CustLedEntry."Entry No.";
    IF CustLedEntry.FINDLAST THEN
      last := CustLedEntry."Entry No.";

    FOR j := first TO last DO BEGIN
      IF CustLedEntry.GET(j) THEN BEGIN
        MyCode := CustLedEntry."Document No.";
           //CustLedEntry.CALCFIELDS(Amount);
           //CustLedEntry2.CALCFIELDS(Amount);
        CustLedEntry2.RESET;
        CustLedEntry2.SETRANGE("Customer No.",CustRec."No.");
        CustLedEntry2.SETFILTER("Posting Date",'01.01.2006..31.12.2006');
        CustLedEntry2.SETRANGE("Document Type",CustLedEntry2."Document Type"::Payment);
        CustLedEntry2.SETRANGE(Amount,CustLedEntry.Amount);

        IF CustLedEntry2.COUNT > 1 THEN BEGIN

          IF CustLedEntry2.FINDFIRST THEN
            first2 := CustLedEntry."Entry No.";
          IF CustLedEntry2.FINDLAST THEN
            last2 := CustLedEntry."Entry No.";

          FOR k := first2 TO last2 DO BEGIN
            CustLedEntry2.GET(k);
            CustLedEntry2.Check := TRUE;
            CustLedEntry2.CheckCode := MyCode;
            CustLedEntry2.MODIFY;
          END; //FOR k :=
        END; //COUNT > 1
      END; //CustLedEntry.GET(j)
    END; //FOR j :=
  END; //COUNT > 0
END; //FOR i :=
Zuletzt geändert von Freestyler am 2. November 2010 12:24, insgesamt 1-mal geändert.

Re: Doubletten kennzeichnen in den Debitorposten

2. November 2010 12:24

Lord_British hat geschrieben:(10000 bis 69412 ist die Nr. der Debitoren, ich hab FOR-Schleife gewählt, da diese angeblich schneller ist als REPEAT/UNTIL und WHILE/DO,

Sind denn bei euch die Debitorennummern zwischen 10000 und 69412 lückenlos? Falls nein, macht die FOR-Schleife viele überflüssige Lesezugriffe. Dann wäre es besser, die Debitorentabelle von ... bis ... zu durchlauen.

Re: Doubletten kennzeichnen in den Debitorposten

2. November 2010 12:27

Natalie hat geschrieben:
Lord_British hat geschrieben:(10000 bis 69412 ist die Nr. der Debitoren, ich hab FOR-Schleife gewählt, da diese angeblich schneller ist als REPEAT/UNTIL und WHILE/DO,

Sind denn bei euch die Debitorennummern zwischen 10000 und 69412 lückenlos? Falls nein, macht die FOR-Schleife viele überflüssige Lesezugriffe. Dann wäre es besser, die Debitorentabelle von ... bis ... zu durchlauen.


Nein, sind sie nicht. Hieße das, dass ich mit REPEAT UNTIL NEXT = 0 schneller wäre bei vorherigem CustomerRecord.CALCFIELDS("Saldo(MW)") <> 0 ?

Re: Doubletten kennzeichnen in den Debitorposten

2. November 2010 12:31

Lord_British hat geschrieben:Nein, sind sie nicht. Hieße das, dass ich mit REPEAT UNTIL NEXT = 0 schneller wäre bei vorherigem CustomerRecord.CALCFIELDS("Saldo(MW)") <> 0 ?

Ich wette, ja - aber alle Angaben ohne Gewähr ;-)
Immerhin gibt es in der Debitorenpostentabelle (=Basistabelle für das FlowField) viel mehr Datensätze zu durchsuchen als für die Debitorentabelle.
Ich verzichte grundsätzlich auf jede vermeidbare Berechnung von FlowFields.

Re: Doubletten kennzeichnen in den Debitorposten

2. November 2010 12:39

Natalie hat geschrieben:
Lord_British hat geschrieben:Nein, sind sie nicht. Hieße das, dass ich mit REPEAT UNTIL NEXT = 0 schneller wäre bei vorherigem CustomerRecord.CALCFIELDS("Saldo(MW)") <> 0 ?

Ich wette, ja - aber alle Angaben ohne Gewähr ;-)
Immerhin gibt es in der Debitorenpostentabelle (=Basistabelle für das FlowField) viel mehr Datensätze zu durchsuchen als für die Debitorentabelle.
Ich verzichte grundsätzlich auf jede vermeidbare Berechnung von FlowFields.


Ok, ich hab mir überlegt das ganze auf Basis der Det. Cust. Led. Entries zu machen, weil dort Amount kein Flowfield ist.
Aber IIRC ist die Detaillierte Deb.Posten Tabelle viel umfangreicher als die normale Deb.Posten Tabelle, sprich hat mehr Datensätze und das ganze würde dann länger dauern?

Ferner hab ich eine neue Idee: NAV hat zwar keine Arrays mit variabler Länge, aber man kann Tabellen mit id >= 50.000 erstellen, die ja unendlich viel Datensätze haben können. Ich könnte so eine Tabelle anlegen, zuerst darin alle Debitor No. abspeichert, deren Saldo MW <> 0 ist und mit diesen Nummern über die Deb.Posten (Feld Customer No.) iterieren.

Re: Doubletten kennzeichnen in den Debitorposten

2. November 2010 12:44

Warum so aufwändig?
Lauf mal über die Debitorentabelle und schau mal, obs einen Unterschied macht.

Vielleicht reden wir nicht über das Gleiche:

Code:
CustRec.RESET;
CustLedEntry.RESET;
CustLedEntry2.RESET;

CustRec.SETCURRENTKEY("No.");
CustLedEntry.SETCURRENTKEY("Customer No.","Posting Date","Document Type",Open);
CustLedEntry2.SETCURRENTKEY("Customer No.","Posting Date","Document Type",Open);

CustLedEntry.CALCFIELDS(Amount);
CustLedEntry2.CALCFIELDS(Amount);
 
Cust.SETRANGE("No.", '10000', '69412'); // NEU
Cust.FIND('-'); // NEU
REPEAT // NEU
  CustLedEntry.SETRANGE("Customer No.",Cust."No."); // NEU
  CustLedEntry.SETFILTER("Posting Date",'01.01.2006..31.12.2006');
  CustLedEntry.SETRANGE("Document Type",CustLedEntry."Document Type"::Payment);
  CustLedEntry.SETFILTER(Amount,'<>%1',0.00);

   IF CustLedEntry.COUNT > 0 THEN BEGIN

    IF CustLedEntry.FINDFIRST THEN
      first := CustLedEntry."Entry No.";
    IF CustLedEntry.FINDLAST THEN
      last := CustLedEntry."Entry No.";

    FOR j := first TO last DO BEGIN
      IF CustLedEntry.GET(j) THEN BEGIN
        MyCode := CustLedEntry."Document No.";
           //CustLedEntry.CALCFIELDS(Amount);
           //CustLedEntry2.CALCFIELDS(Amount);
        CustLedEntry2.RESET;
        CustLedEntry2.SETRANGE("Customer No.",CustRec."No.");
        CustLedEntry2.SETFILTER("Posting Date",'01.01.2006..31.12.2006');
        CustLedEntry2.SETRANGE("Document Type",CustLedEntry2."Document Type"::Payment);
        CustLedEntry2.SETRANGE(Amount,CustLedEntry.Amount);

        IF CustLedEntry2.COUNT > 1 THEN BEGIN

          IF CustLedEntry2.FINDFIRST THEN
            first2 := CustLedEntry."Entry No.";
          IF CustLedEntry2.FINDLAST THEN
            last2 := CustLedEntry."Entry No.";

          FOR k := first2 TO last2 DO BEGIN
            CustLedEntry2.GET(k);
            CustLedEntry2.Check := TRUE;
            CustLedEntry2.CheckCode := MyCode;
            CustLedEntry2.MODIFY;
          END; //FOR k :=
        END; //COUNT > 1
      END; //CustLedEntry.GET(j)
    END; //FOR j :=
  END; //COUNT > 0
UNTIL Cust.NEXT = 0; // NEU

Re: Doubletten kennzeichnen in den Debitorposten

2. November 2010 12:55

Wirf doch mal das "CustLedEntry2.RESET;" raus, weil das den Schlüssel wieder auf Standard zurück setzt. Außerdem müsstest du, wenn ich das alles recht verstehe, verhindern, dass schon gecheckte Datensätze nochmal überprüft werden.

Re: Doubletten kennzeichnen in den Debitorposten

2. November 2010 21:45

McClane hat geschrieben:Wirf doch mal das "CustLedEntry2.RESET;" raus, weil das den Schlüssel wieder auf Standard zurück setzt. Außerdem müsstest du, wenn ich das alles recht verstehe, verhindern, dass schon gecheckte Datensätze nochmal überprüft werden.


@McLane + Natalie: ich danke euch sehr, habe euere Vorschläge berücksichtigt und den Code modifiziert und gerade jetzt remote angestoßen.

Re: Doubletten kennzeichnen in den Debitorposten

2. November 2010 23:20

Lord_British hat geschrieben:Nun hat der User sowohl seine, als auch meine importierten Buchblätter mit F11 verbucht.
Nun stellt er fest, dass Zahlungseingänge doppelt drin sind.
Leider weiss weder er noch ich welche Buchblätter von wem erstellt wurden, nur dass die Buchungssätze von 1.1.6..31.12.06 sind.


Darf ich mal einfach blond nachfragen, waurm ihr nicht im Fibu-Journal nachguckt (in dem ja bekanntlich der Buchblattname mitgeführt wird) und das "zuviel gebuchte Journal" dann entsprechend einfach storniert?

VG,
Anke

Re: Doubletten kennzeichnen in den Debitorposten

3. November 2010 01:11

Anke S. hat geschrieben:
Lord_British hat geschrieben:Nun hat der User sowohl seine, als auch meine importierten Buchblätter mit F11 verbucht.
Nun stellt er fest, dass Zahlungseingänge doppelt drin sind.
Leider weiss weder er noch ich welche Buchblätter von wem erstellt wurden, nur dass die Buchungssätze von 1.1.6..31.12.06 sind.


Darf ich mal einfach blond nachfragen, waurm ihr nicht im Fibu-Journal nachguckt (in dem ja bekanntlich der Buchblattname mitgeführt wird) und das "zuviel gebuchte Journal" dann entsprechend einfach storniert?

VG,
Anke


Jo, du darfst:

Wir wissen beide nicht mehr welches der ca. 300 zuletzt gebuchten Fibu-Journale das "richtige" ist.

Wir haben dummerweise die Buchblätter etwas "blond" nummeriert à la ZE-001 .. ZE-300 (um ein Fantasie-Bsp zu liefern, in Wirklichkeit heißen sie anders, aber dennoch genauso ähnlich)

Jedes Fibu-Buchblatt hatte mehrere Tausend Zeilen. Da ist manuelle Suche aussichtslos, es sei denn man hat unendlich viel Zeit :-)

Es sind einige wenige Überschneidungen (Beträge), die aber über alle Fibu-Buchblätter verteilt waren und nun in gebuchter Form nur über Massendatenverarbeitung gefunden werden können.

Wenn es 10 Fibu-Journale mit jeweils 100 Datensätze wären, könnten wir auch mit bloßem Auge die Doubletten erkennen und die Sachposten "stornieren".

Und selbst wenn es nur 10 Journale wären, möchte der User ungern komplette Journale stornieren, da die meisten Daten korrekt sind.

Man müßte neu anfangen, das ganze nochmals aus Excel zu importieren und müßte dann die Doubletten zwischen verbuchten Debitorenposten und befüllten Buchblättern suchen.

Das wäre keine echte Erleichterung.

Der Ersteller der ursprünglichen Exceldatei kann/will auch nicht nach Doubletten suchen.

Deshalb muss das ganze per C/AL-Programmierung gelöst werden. Morgen früh werde ich wissen, ob 12 Std. Code-Durchlauf gereicht haben.

Hätte der User den SQL-Server, hätt ich das ganze per TSQL-Abfrage und INNER JOIN in -sagen wir mal- 15 Min abgefrühstückt.