Autor Beitrag
colaka
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 200
Erhaltene Danke: 4

Win XP, W7
Delphi 2005 Prof.
BeitragVerfasst: So 24.01.10 09:29 
Hallo,

ich möchte aus einer Textdatei den Preis auslesen, um ihn in meine Artikeltabelle zu übernehmen. Das habe ich mit dem folgenden Code gemacht:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
procedure TForm2.Button1Click(Sender: TObject);
var
  Tr : Char;
  d : TextFile;
  Zeile, Rest, Artikelnummer  : String;
  Artikelpreis : Integer;
begin
  Tr := ';';
  assignFile(d, ExtractFilePath(ParamStr(0))+ '519786_CustSpecific_20100123.txt');
  Reset(d);                   // Datei öffnen
  Gauge.Visible := true;
  Gauge.ForeColor := $0099EE;
  Gauge.Progress := 0;
  Gauge.MaxValue := FileSize(d);
  ReadLn(d,Zeile);
  while not EOF(d) do
  begin
    ReadLn(d,Zeile);
    Rest := copy(Zeile, POS(Tr, Zeile)+1, length(Zeile)-7);
    Artikelnummer := copy(Rest, 0, POS(Tr,Rest)-1);
//    Label1.Caption := Artikelnummer;
    Rest := copy(Rest, length(Artikelnummer)+2, (length(Rest)-length(Artikelnummer)));
    Rest := copy(Rest, 0, POS(Tr,Rest)-1);
    Artikelpreis := round(StrToFloat(Rest)*100);  // kalkuliert wird in Cent
//    Label2.Caption := IntToStr(Artikelpreis);
//    label3.Caption := Zeile;
    Table1.Locate('BestNr', Artikelnummer, []);
    Table1.Edit;
    Table1Preis.AsInteger := Artikelpreis;
    Gauge.Progress := FilePos(d);
    Application.ProcessMessages;
  end;
  Table1.Post;
  CloseFile(d);
end;


Das Ganze funktioniert zwar, doch da es sich um ca. 60.000 Artikel handelt, und ich anschließend auf die gleiche Art auch noch den Artikelbestand aus einer anderen Textdatei einlesen muß, dauert es ziemlich lange (geschätzte 30 Minuten). Deshalb habe ich die Frage an die Experten:
Könnte man das vielleicht irgendwie beschleunigen?

Der Aufbau der Textdatei sieht so aus:
Cust_id;Matnr;CustBestPrice;Currency_code;Surcharge
519786;1000039;410,36;EUR;0,00
519786;1000180;26,50;EUR;0,00
519786;1000181;9,64;EUR;0,00
519786;1000186;2304,78;EUR;0,00
519786;1000193;222,11;EUR;0,00
519786;1000209;24,00;EUR;0,00
usw.

Ich bin für jeden Vorschlag dankbar.
Gruß Ebi
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: So 24.01.10 10:51 
Soweit ich das sehe, ist der Locate-Befehl die Schwachstelle. Du könntest z.B. alle Artikelpreise erstmal in ein Array speichern und am Ende die Tabelle einmal komplett durchlaufen und die Preise setzen (kommt drauf an wieviele Artikel da drin sind und wieviele davon du verändern willst).

Application.ProcessMessages bremst definitv auch.

*stöber*
*such*
*wart*
*grübel*

Achja, da ists ja.

Ich hab das auch mal gemacht, und hab mich gewundert warum der Datenbank-Import so langsam ist. Ich habs dann wie ich gerade sehe durch Table.Filter ersetzt.

ausblenden Delphi-Quelltext
1:
2:
Table.Filter:='ID = 5230';
Table.Filtered:=True;


Das .Post hab ich übrigens in die Schleife mit rein, trau der Sache sonst nicht.

Edit:
Achja, das mit dem ProcessMessages hab ich so gemacht:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
  if ModalForm<>nil then
    begin
      C:=GetTickCount;
      if (C>=LastUpdate+100)and(ModalForm.Showing) then
        begin
          ModalForm.SetFocus;
          Application.ProcessMessages;
          LastUpdate:=C;
        end;
    end;

(vom Prinzip her wird halt nur maximal alle 0.1 sec ein Update gemacht.)

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
colaka Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 200
Erhaltene Danke: 4

Win XP, W7
Delphi 2005 Prof.
BeitragVerfasst: So 24.01.10 12:42 
Hallo,

ich habe das mit dem Filter probiert, aber das dauert ungefähr 3 mal solange wie meine ursprüngliche Lösung.

Den Vorschlag mit dem Array habe ich leider nicht kapiert, aber es sind ca. 60.000 Artikel und ich muß alle Preise ersetzen. In der Tabelle befinden sich Listenpreise, die ich durch meine kundenspezifischen Preise ersetzen muß.

Könntest Du mir vielleicht ein kurzes Beispiel geben, wie das mit dem Array gehen soll?

Außerdem habe ich soeben festgestellt, daß mein Programm nach dem Ersetzen der Preise ca. 50% mehr Speicherplatz belegt als vorher. Wie kann denn das sein?

Danke Ebi
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: So 24.01.10 12:55 
user profile iconcolaka hat folgendes geschrieben Zum zitierten Posting springen:

ich habe das mit dem Filter probiert, aber das dauert ungefähr 3 mal solange wie meine ursprüngliche Lösung.
...
Außerdem habe ich soeben festgestellt, daß mein Programm nach dem Ersetzen der Preise ca. 50% mehr Speicherplatz belegt als vorher. Wie kann denn das sein?

Hmm. Am besten du kommentierst mal abwechselnd Teile aus (Locate, Schreiben in die DB, ...) und dann siehst du prima, was wirklich die Zeit beansprucht und den Speicher braucht.

user profile iconcolaka hat folgendes geschrieben Zum zitierten Posting springen:

Den Vorschlag mit dem Array habe ich leider nicht kapiert, aber es sind ca. 60.000 Artikel und ich muß alle Preise ersetzen. In der Tabelle befinden sich Listenpreise, die ich durch meine kundenspezifischen Preise ersetzen muß.

Könntest Du mir vielleicht ein kurzes Beispiel geben, wie das mit dem Array gehen soll?

Hmm, 60.000...ob das in ein Array passt...

Also vom Prinip:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
type TArtikelPreis=record
  ArtikelNr: integer;
  ArtikelPreis: integer;
end;

dann ein Array
ausblenden Delphi-Quelltext
1:
ArtikelPreise: array [0..60000of TArtikelPreis;					

Jetzt so im nachhinein wird mir irgendwie klar, dass es damit nicht schneller gehen wird, wenn dann müsste man das array dann noch sortieren nach der Artikelnr oder so :P

Edit:
In deinem Beispiel ist die Liste schon nach ArtikelNr sortiert...ist das immer so? dann wärs noch einfacher

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
colaka Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 200
Erhaltene Danke: 4

Win XP, W7
Delphi 2005 Prof.
BeitragVerfasst: So 24.01.10 13:05 
Hallo,

ja, das ist schon das Locate, das die Zeit beansprucht. Aber mit dem Filter dauerts erst recht ewig. Das Programm läuft schon eine halbe Stunde und ist erst bei 27%.

Die txt-Datei ist schon nach Artikelnummern sortiert, aber meine Tabelle nicht. Wie könnte man es denn dann vereinfachen?

Danke Ebi
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: So 24.01.10 14:04 
Also wenn die Datei sortiert ist und die Tabelle nicht, würd ichs mal so probieren:

1. Query erstellen
ausblenden Delphi-Quelltext
1:
2:
Query:=TQuery.Create(Form);
Query.DatabaseName:='Database.db';


2. Tabelle sortieren
ausblenden Delphi-Quelltext
1:
2:
3:
4:
Query.SQL.Clear;
Query.SQL.Add('Select ArtikelNr,ID FROM Database ORDER BY ArtikelNr');
Query.Active:=True;
Query.First;


3. Einlesen
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
//ArtikelNr und ArtikelPreis aus Datei lesen
while Query.FieldByName(ArtikelNr).AsInteger<ArtikelNr do
  Query.Next;
if Query.FildByName(ArtikelNr).AsInteger<>ArtikelNr then
  ShowMessage('Artikel '+inttostr(ArtikelNr)+' nicht in DB')
else
  begin
     Table1.First;
     while Table1.FieldByName('ID').AsInteger<Query.FildByName('ID').AsInteger do
       Table1.Next;
     if Table1.FieldByName(ArtikelNr).AsInteger<>Query.FildByName('ID').AsInteger then
       ShowMessage('Artikel '+inttostr(ArtikelNr)+' nicht in DB - eigentlich nicht möglich, da ID ja im Query')
     else
       Table1.FieldByName('ArtikelPreis').AsInteger:=ArtikelPreis;
   end


Damit würdest du dir das Locate oder Filtern sparen...hierbei muss die Tabelle allerdings nach ID sortiert sein...

Code ist ungetestet

Edit:
mir ist grad aufgefallen, dass ist auch nicht so das wahre...bin irgendwie unkreativ heute

Konnte man nicht auch in einem Query schreiben? Glaube schon, dann könntest du den ganzen Table-Bereich weglassen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
//ArtikelNr und ArtikelPreis aus Datei lesen
while Query.FieldByName(ArtikelNr).AsInteger<ArtikelNr do
  Query.Next;
if Query.FieldByName(ArtikelNr).AsInteger<>ArtikelNr then
  ShowMessage('Artikel '+inttostr(ArtikelNr)+' nicht in DB')
else
  Query.FieldByName('ArtikelPreis').AsInteger:=ArtikelPreis;
Query.Post;

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
colaka Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 200
Erhaltene Danke: 4

Win XP, W7
Delphi 2005 Prof.
BeitragVerfasst: Mo 25.01.10 08:22 
Hallo,

das mit der Query scheint mir doch der beste Weg zu sein. Deshalb habe ich Deinen Code ausprobiert, doch dabei erscheint die Fehlermeldung: "Eine Datenmenge, die nur zum Lesen geeignet ist, kann nicht verändert werden".

Wie kann man denn mit einer Query den Preis überschreiben?

Danke Ebi
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: Mo 25.01.10 09:19 
user profile iconcolaka hat folgendes geschrieben Zum zitierten Posting springen:

"Eine Datenmenge, die nur zum Lesen geeignet ist, kann nicht verändert werden".


Hmm, das geht wohl nicht per Query...es gibt zwar auch Write Befehle für SQL aber...

www.delphipraxis.net/post161366.html
Die lösen es per Index...eigentlich ist deine ArtikelNr ja auch sowas wie ein Index (nur einmal, ein integer).
Alternativ könnte man evtl auch in den Table.Filter sowas wie order by unterbringen.

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
colaka Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 200
Erhaltene Danke: 4

Win XP, W7
Delphi 2005 Prof.
BeitragVerfasst: Mo 25.01.10 21:33 
Hallo,

ich habe jetzt die Tabelle umgestellt und die Artikelnummer zum Primärindex gemacht. Damit werden die 60.000 Datensätze in etwa 1 Minute aktualisiert.

Danke Ebi