Autor |
Beitrag |
colaka
      
Beiträge: 200
Erhaltene Danke: 4
Win XP, W7
Delphi 2005 Prof.
|
Verfasst: 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:
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); 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); Rest := copy(Rest, length(Artikelnummer)+2, (length(Rest)-length(Artikelnummer))); Rest := copy(Rest, 0, POS(Tr,Rest)-1); Artikelpreis := round(StrToFloat(Rest)*100); 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
      

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)
|
Verfasst: 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.
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:
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 
      
Beiträge: 200
Erhaltene Danke: 4
Win XP, W7
Delphi 2005 Prof.
|
Verfasst: 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
      

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)
|
Verfasst: So 24.01.10 12:55
colaka hat folgendes geschrieben : |
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.
colaka hat folgendes geschrieben : |
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:
Delphi-Quelltext 1: 2: 3: 4:
| type TArtikelPreis=record ArtikelNr: integer; ArtikelPreis: integer; end; |
dann ein Array
Delphi-Quelltext 1:
| ArtikelPreise: array [0..60000] of 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
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 
      
Beiträge: 200
Erhaltene Danke: 4
Win XP, W7
Delphi 2005 Prof.
|
Verfasst: 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
      

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)
|
Verfasst: 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
Delphi-Quelltext 1: 2:
| Query:=TQuery.Create(Form); Query.DatabaseName:='Database.db'; |
2. Tabelle sortieren
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
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| 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:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| 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 
      
Beiträge: 200
Erhaltene Danke: 4
Win XP, W7
Delphi 2005 Prof.
|
Verfasst: 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
      

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)
|
Verfasst: Mo 25.01.10 09:19
colaka hat folgendes geschrieben : |
"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 
      
Beiträge: 200
Erhaltene Danke: 4
Win XP, W7
Delphi 2005 Prof.
|
Verfasst: 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
|
|
|