Mahlzeit,
mal was zwischendurch, wenn mal wer Zeit hat.
Gegeben sei eine XML-Vorlage, die in etwa so aussieht:
XML-Daten
1: 2: 3: 4: 5: 6: 7:
| ... <columns> <column fieldname="bla" function="average" /> <column fieldname="blubb" function="sum" /> ... </columns> ... |
Außerdem haben wir ein ClientDataset, welches für jeden column-Knoten aus dem XML eine Spalte enthält und mit einigen hundert oder tausend Datensätzen befüllt ist.
Nun geht es darum, die angegebene Aggregatfunktion auf die Spalte anzuwenden. Mögliche Funktionen sind average, sum, min, max. Es ist ein Minimum von 0 für jede Spalte vorauszusetzen.
Die erste Idee war, einfach eine 2. Abfrage zu bauen und den Datenbankserver die Aggregate berechnen zu lassen, das geht aber nicht, da nach der Abfrage, aber vor der Berechnung noch Datensätze konsolidiert werden.
Nun kommt meine zweite und aktuelle Idee zum tragen, die da wäre das Dataset für jede Spalte, die eine Aggregatfunktion hat, einmal komplett durchzulaufen und zu berechnen. Die Berechnungen sähen wie folgt aus:
max (min entsprechend andersrum):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| function GetMax(ADataset : TClientDataSet; AFieldName : String) : double; begin Result := 0; ADataset.first; while not ADataset.eof do begin if ADataSet.FieldByName(AFieldName).asFloat > Result then Result := ADataSet.FieldByName(AFieldName).asFloat; ADataset.next; end; end; |
sum:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function GetSum(ADataset : TClientDataSet; AFieldName : String) : double; begin Result := 0; ADataset.first; while not ADataset.eof do begin Result := Result + ADataSet.FieldByName(AFieldName).asFloat; ADataset.next; end; end; |
average:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| function GetAvg(ADataset : TClientDataSet; AFieldName : String) : double; var cnt : Integer; sum : float; begin Result := 0; cnt := 0; sum := 0; ADataset.first; while not ADataset.eof do begin if not ADataSet.FieldByName(AFieldName).isNull then begin inc(cnt); sum := sum + ADataSet.FieldByName(AFieldName).asFloat; end; ADataset.next; end; Result := sum / cnt; end; |
Auch wenns noch nicht umgesetzt ist, so weiss ich doch, dass es nicht besonders schnell sein wird.
Nun die Preisfrage
Hat wer eine Idee, die Berechnung schneller durchzuführen?
Viel Spass

Bravery calls my name in the sound of the wind in the night...