Delphi-PRAXiS
Seite 1 von 5  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi komplexe Berechnungen von abhängigen Datenbankfeldern (https://www.delphipraxis.net/63021-komplexe-berechnungen-von-abhaengigen-datenbankfeldern.html)

Emilio 12. Feb 2006 21:08

Datenbank: DBISAM • Version: 4.21 • Zugriff über: Native

komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hallo Leute,

nachdem ich nun in mehreren Büchern und nach einigen DP-Sitzungen noch weniger schlau bzw. ausreichend verwirrt bin, möchte ich das Problem erstmal grob schildern:

Habe eine Query aus mittlerweile 12 tables und stelle die Werte mit DBLabels dar. Diese Werte werden für weitere Berechnungen, welche zunächst nicht gespeichert werden müssen, benötigt. Und zwar in der Form, dass der User z.B. einen neuen EK-Preis in ein Editfeld einträgt (hab bisher keine schlauere Idee), mittels einer Combobox einen Handlingsaufschlag wählt und damit den EK2 erhält. Dem User soll für den VK ein Vorschlag gemacht werden, den er aber ändern kann. Wenn er dies tut, so soll der Brutto-Preis errechnet werden (in Abhähngigkeit des MwSt-Satzes) und die Felder [Marge€], [Marge%], [Provision] sollen ausgefüllt werden. Jedoch soll der User auch die Möglichleit haben, in letztere Felder Werte seiner Wahl einzutragen und die vorhergehenden sollten errechnet werden. Zu allem Überfluss sollte eine Reihe von Feldern die Veränderungen eines jedes Feldes Alt zu Neu in % ausweisen.
Wichtig zu wissen ist, dass nur neue Datensätz erzeugt werden sollen, also keine Änderungen oder Löschungen.

Ich bekomme das bislang nur hin, in dem ich unter viel Formatierungsaufwand mit den Feldinhalten rechne - scheitere aber an dem Punkt, die neuen Werte so aufzubereiten, dass sie in die Tabelle die es betrifft eingefügt werden können.

Ein DP-Mitglied gab mir die Empfehlung den Rechenkram von der Visualisierung zu trennen - ist bestimmt gut - aber wie? Die neuen Werte müssen doch erst vom User teilweise eingegeben werden und sollen noch vor dem speichern mit allen Folgewerten vorliegen ???

memTable, ParambyName, subquery, Rembrandt?


Mir drehts sich auch schon im Kreis

Kann mir jemand sagen, auf welchen Weg ich mich begeben soll?

Viele Grüße
Emilio

[edit=MrSpock]Titel geändert. Mfg, MrSpock[/edit]

marabu 13. Feb 2006 10:27

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Hallo Emilio,

das römische Imperium ist untergegangen und so führen heute leider nicht mehr alle Wege nach Rom.

Aus dem thread, in dem ich dir den Rat gab alle Rechenvorschriften aus der Benutzerschnittstelle heraus zu halten, kenne ich zumindest eine Rechenvorschrift. Du wirst mehrere benötigen, da du ja von verschiedenen Punkten ausgehen willst.

Prinzipiell musst du fixe (Konstanten) und veränderliche (Variablen) Werte in deinen Berechnungen unterscheiden. Du hattest die Buchstaben a bis m vergeben - ich halte mich hier daran, auch wenn ich eine andere Benennung besser fände. Ich notiere Konstanten mit Großbuchstaben, Variablen mit Kleinbuchstaben.

Deine Rechenvorschrift hatte folgenden Aufbau:

Delphi-Quellcode:
procedure TForm1.cxLookupComboBox1PropertiesCloseUp(Sender: TObject);
var
  a, c, d , e, f , g, h, i, j, k, l, m, n : Double;
  b : Integer;
begin
  a := StrToFloat(cxTextEdit1.Text);
  b := StrToInt(cxLookupComboBox1.Text);
  c := a+(a*b/100);
  d := (a/60*100);
  e := (d-a);
  f := (d-a)*100/d;
  g := (d-c)*StrToFloat(cxDBLabel13.Caption)/100;
  h := (d*116/100);
  i := StrToFloat(cxDBLabel5.Caption);
  j := ((c/i)-1)*100;
  k := StrToFloat(cxDBLabel9.Caption);
  l := ((d/k)-1)*100;
  m := StrToFloat(cxLabel28.Caption);
  n := ((h/m)-1)*100;

  cxLabel14.Caption := Format('EUR ' + '%8.2f', [a+(a*b/100)]);
  cxTextEdit5.Text := Format('EUR ' + '%8.2f', [d]);
  cxTextEdit2.Text := Format('EUR ' + '%8.2f', [e]);
  cxTextEdit3.Text := Format('%5.2f', [f]) + '%';
  cxTextEdit6.Text := Format('EUR ' + '%8.2f', [g]);
  cxTextEdit4.Text := Format('EUR ' + '%8.2f', [h]);
  cxLabel18.Caption := Format('%4.2f', [j]) + '%';
  cxLabel19.Caption := Format('%4.2f', [l]) + '%';
  cxLabel24.Caption := Format('%4.2f', [n]) + '%';
end;
Ich gehe davon aus, dass alle cxTextEdit Eingabefelder darstellen. Aus deinem Code leite ich folgende funktionale Abhängigkeiten ab:

Code:
A=cxTextEdit1
b=cxLookupComboBox1
O=cxDBLabel13
I=cxDBLabel5
K=cxDBLabel9
M=cxLabel28

f_c(A,b)
f_d(A)
f_e(A,d)
f_f(A,d)
f_g(c,d,O)
f_h(d)
f_j(c,I)
f_l(d,K)
f_n(h,M)
Die Funktionen (f_c..f_h,f_j,f_l,f_n) realisierst du im implementation Abschnitt der Unit, in der du deine Rechenvorschriften speicherst. Im interface Abschnitt dieser Unit befinden sich die Funktionen für die Rechenvorschriften. Jede Rechenvorschrift hat eine bestimmte Signatur - das sind die Eingabe- und Ausgabeparameter.

Delphi-Quellcode:
unit CalcMdl;

interface

  procedure CalcRule01(A,I,K,M,O: Extended; b: Integer; var c,d,e,f,g,h,j,l,n: Extended);

implementation

  function f_c(A: Extended; b: Integer): Extended; forward;


function f_c(A: Extended; b: Integer): Extended;
begin
  Result := a + (a * b / 100);
end;


procedure CalcRule01(A,I,K,M,O: Extended; b: Integer; var c,d,e,f,g,h,j,l,n: Extended);
begin
  c := f_c(A, b);
  d := f_d(A);
  e := f_e(A, d);
  f := f_f(A, d);
  g := f_g(c, d, O);
  h := f_h(d);
  j := f_j(c, I);
  l := f_l(d, K);
  n := f_n(h, M);
end;

end.
Das Durchrechnen der Werte als Reaktion auf die Änderung in der ComboBox geschieht dann so:

Delphi-Quellcode:
procedure TForm1.cxLookupComboBox1PropertiesCloseUp(Sender: TObject);
var
  A, c, d , e, f , g, h, I, j, K, l, M, n, O: Extended;
  b : Integer;
begin
  A := StrToFloat(cxTextEdit1.Text);
  I := StrToFloat(cxDBLabel5.Caption);
  K := StrToFloat(cxDBLabel9.Caption);
  M := StrToFloat(cxLabel28.Caption);
  O := StrToFloat(cxDBLabel13.Caption);
  b := StrToInt(cxLookupComboBox1.Text);

  CalcRule01(A, I, K, M, O, b, c, d, e, f, g, h, j, l, n);

  cxLabel14.Caption := Format('EUR ' + '%8.2f', [c]);
  cxTextEdit5.Text := Format('EUR ' + '%8.2f', [d]);
  cxTextEdit2.Text := Format('EUR ' + '%8.2f', [e]);
  cxTextEdit3.Text := Format('%5.2f', [f]) + '%';
  cxTextEdit6.Text := Format('EUR ' + '%8.2f', [g]);
  cxTextEdit4.Text := Format('EUR ' + '%8.2f', [h]);
  cxLabel18.Caption := Format('%4.2f', [j]) + '%';
  cxLabel19.Caption := Format('%4.2f', [l]) + '%';
  cxLabel24.Caption := Format('%4.2f', [n]) + '%';
end;
Das verstehe ich unter Trennung. Beachte auch, dass ich Double durch Extended ersetzt habe - wegen der höheren Rechengenauigkeit. Wenn du alle Berechnungsvorschriften entworfen hast, dann wirst du eventuell feststellen, dass manche Elementarfunktion (f_c, f_d, ...) nur einmal verwendet wird. Es steht dir dann frei solche "internen" Funktionen zu integrieren. Und noch einmal mein Rat über eine Namenskonvention für dein Programm nachzudenken - du wirst es nicht bereuen.

Grüße vom marabu

sakura 13. Feb 2006 11:03

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Hi,

ändere bitte noch den Titel so, dass dieser auch aussagekräftig ist.

Danke,
...:cat:...

Emilio 13. Feb 2006 21:30

Flut v. Rechenvorgängen v. Visualisierung trennen
 
Hi Marabu,

vielen vielen Dank!
Bin dabei Deine Ausführungen umzusetzen (wobei für Dich der Code jetzt verständlicher ist, ist er für mich sehr viel aufwändiger zu lesen - ich tue mich mit der Abstraktion leichter, da ich dann die Rechenformeln leichter formulieren und lesen kann).

Eine Frage zur der Funktion, die Du beispielweise anführst: muss die Deklaration der Funktion nicht im Interface-Abschnitt erfolgen? Wenn nein, warum nicht?

So, jetzt bastel ich erstmal weiter an der "Übersetzung".

Viele Grüße

Emilio

Emilio 13. Feb 2006 21:39

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
@sakura,

:gruebel: wie geht'n das mit dem sräd-Titel ändern?

marabu 13. Feb 2006 21:44

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Hi Emilio,

nur die Rechenvorschriften gehören in den interface Abschnitt, weil sie von außen erreichbar sein müssen. f_c() ist eine rein interne Funktion und gehört deswegen in den implementation Abschnitt. Da ich dort nicht ausschließen kann, dass die Basis-Funktionen sich in unterschiedlicher Reihenfolge gegenseitig rufen, deklariere ich sie zuerst mit der forward Direktive.

Gute Nacht

marabu

PS: du kannst den Titel ändern, wenn du deinen ersten Beitrag bearbeitest.

turboPASCAL 13. Feb 2006 21:44

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Zitat:

Zitat von Emilio
:gruebel: wie geht'n das mit dem sräd-Titel ändern?

Im (Deinem) ersten Beitrag auf Edit klicken und im Titeleditfeld den Titel ändern ;)

Emilio 14. Feb 2006 21:22

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Hi @all,

das mit dem Thema-Titel ändern geht nicht mehr ... vielleicht kann ja einer der Mods eingreifen?

@Marabu,


Zitat:

Zitat von marabu
Hi Emilio,

nur die Rechenvorschriften gehören in den interface Abschnitt, weil sie von außen erreichbar sein müssen. f_c() ist eine rein interne Funktion und gehört deswegen in den implementation Abschnitt. Da ich dort nicht ausschließen kann, dass die Basis-Funktionen sich in unterschiedlicher Reihenfolge gegenseitig rufen, deklariere ich sie zuerst mit der forward Direktive.

Zitat:

Zitat von marabu
Die Funktionen (f_c..f_h,f_j,f_l,f_n) realisierst du im implementation Abschnitt der Unit, in der du deine Rechenvorschriften speicherst. Im interface Abschnitt dieser Unit befinden sich die Funktionen für die Rechenvorschriften. Jede Rechenvorschrift hat eine bestimmte Signatur - das sind die Eingabe- und Ausgabeparameter.

:wiejetzt: Also schreibe ich die anderen Funktionen in ähnlicher Art und Weise in eine neue Unit. In der UnitMain entferne ich das Gerümpel und lasse i.B. die procedure mit der Combobox in derUnitMain stehen? - irgendwie stehe ich doch noch auf dem Schlauch: woher weiß dann die procedure der combobox was von den Rechenvorschriften?

Emilio

marabu 15. Feb 2006 06:06

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Guten Morgen Emilio,

ich unterscheide Berechnungsvorschriften von mathematischen Funktionen. Die Vorschriften müssen in den interface Abschnitt der Unit CalcMdl, weil sie für die ComboBox in deiner MainForm sichtbar sein müssen. Dazu bindest du die Unit CalcMdl per USES in den implementation Abschnitt deiner MainForm ein und schon kannst du aus dem event handler der ComboBox alle Vorschriften aufrufen. Die mathematischen Funktionen (z.B. Berechnung eines Prozentsatzes) werden nur von den Vorschriften benötigt und deshalb im implementation Abschnitt der Unit CalcMdl deklariert.

Du kannst alle Vorschriften und Funktionen in einer einzigen Unit (CalcMdl, dein Kalkulationsmodell) unterbringen. Dein Code wird wohl nie so umfangreich werden, als dass sich eine eigene Unit je Berechnungsvorschrift lohnen wird.

Grüße vom marabu

Emilio 15. Feb 2006 10:22

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Marabu,

Die Calc-Unit habe ich eingebunden - das war kein Thema.

Beim Compilieren erhalte ich nun die Fehlermeldung:

"inkompatible Typen Integer und Extended",

sowie die Fehlermeldung

"nicht genügend wirkliche Parameter"

Der Cursor steht für beide Meldungen in der Zeile

(UnitMain wohlbemerkt): CalcRule01( ...);, welche ich aus Deinem script übernommen habe.

Sollte ich noch ne Kleinigkeit übersehen haben? Die Variablen a (jetzt "ekneu") und b (jetzt "zuschlag") sind als Integer deklariert, in beiden Units.

VG
Emilio


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:52 Uhr.
Seite 1 von 5  1 23     Letzte »    

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