DataSet Only - Hilfe bei Modelierung und Anzeige der Daten für Umsätze und Lieferzeiten

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von DerSmurf.

    DataSet Only - Hilfe bei Modelierung und Anzeige der Daten für Umsätze und Lieferzeiten

    Guten Morgen
    Wie viele wissen bin ich gerade dabei mein VBA Programm in ein VB.Net Programm umzuwandeln.
    Nun bin ich an der Speicherung meiner Bestellungen, mit Lieferdatum, und Rechnugnsinfos angekommen.
    Hierzu habe ich ein Bild angehangen, wie das vorher in Excel ausgesehen hat und bisher (noch unformatiert) in VB.Net
    In meinem DataSet gibt es DTSupplier und DTOrder. Diese haben eine Verknüpfung, damit ich Bestellungen pro Lieferant speichern kann.
    Das funktioniert hervorragend.
    Nun möchte ich noch die Lieferzeit (Datum Lieferungserhalt - Bestelldatum) sowie den Jahresumsatz darstellen.
    Hierzu reicht es glaube ich, wenn ich die DTSupplier und eine Spalte für durchschnittliche Lieferzeit, und eine Spalte für den Gesamtumsatz pro Jahr ergänze.
    In Excel erledige ich die Anzeige der Lieferzeit, sowie des Umsatzes mit Formeln, das geht ja hier nun nicht.

    Hier nun meine Fragen zur LIeferzeit:
    Sollte ich die DTOrders um eine Spalte für Lieferzeiten ergänzen und hier bei jedem Eintragen einer Bestellung, bzw. Rechnung die Tage speichern?
    Die DTSUpplier Lieferzeitspalte könnte ich dann zu einer errechneten Spalte machen und hier den Durchschnitt anzeigen.
    Das Ergebnis stelle ich dann in einem Label dar.
    Hier bin ich mir nicht ganz sicher, ob errechnete Spalten in größeren Datensätzen noch in Ordnung sind.
    Alternativ könnte ich die Lieferzeit in DTSupplier, ja auch nach jedem speichern einer Rechnung per Code neu berechnen.
    Hier möchte ich wissen, welcher der beiden Wege besser ist, oder ob es evtl. noch einen besseren gibt.

    Zum Umsatz:
    Hier weiß ich nicht so recht, wie ich vorgehen soll.
    In Excel habe ich einfach eine entsprechende Formel für die Jahresumsätze, die ich per Makro beim anlegen einer neuen Firma da reinschreibe:
    =SUMMENPRODUKT((JAHR(TabelleFirmaname[Datum])=F2)*(TabelleFirmaname[Net19]+TabelleFirmaname[Net7]))
    Bei jedem Start des Programmes prüfe ich auf neues Jahr (die aktuelle Jahreszahl habe ich im Blatt Einstellungen gespeichert), wenn ein neues Jahr ist, werden Jahreszahl und Jahreszahl - 1 an die Stellen die jetzt mit "2019" und "2018" beschriftet sind geschrieben. Die Umsatzformel ändert sich dann automatisch.

    So ein Jahreswechselmakro könnte ich mir ja in VB.Net auch schreiben und wenn ein neues Jahr ist, eine neue Spalte in DTSUpplier anlegen Umsatz2020 z.B.
    Allerdings habe ich keine Ahnung, wie ich dann ein "Umbinding" meines Umsatzlabels von Umsatz2019 auf Umsatz2020 hinbekomme.
    Und ich weiß auch nicht, wie ich die Daten in die Spalte Umsatz2019 bekomme. Eine berechnete Spalte, mit Prüfung ob Datum zwischen 1.1.2019 und 31.12.2019?
    Bilder
    • DataSet.png

      24,51 kB, 420×741, 86 mal angesehen
    • VBA.png

      71,18 kB, 1.083×725, 93 mal angesehen
    • VBAForm.png

      52,41 kB, 1.086×613, 87 mal angesehen
    • VBNET Form.png

      31,78 kB, 1.095×606, 91 mal angesehen

    DerSmurf schrieb:

    Hier bin ich mir nicht ganz sicher, ob errechnete Spalten in größeren Datensätzen noch in Ordnung sind.
    Probier es aus und berichte. Mach z.B. ein paar Messungen mit 100000 (?) Testdatensätzen, bei denen keine berechnete Spalte dabei ist und das gleiche in dunkelorangeblau mit der berechneten Spalte. Oder taste Dich mit kleinen Testdatensatzmengen an die Zahl ran, ab der es performancetechnisch relevant wird. Versuch macht kluch.

    DerSmurf schrieb:

    Alternativ könnte ich die Lieferzeit in DTSupplier, ja auch nach jedem speichern einer Rechnung per Code neu berechnen.
    Würde ich aus zwei Gründen nicht machen - ist aber auch abhängig davon, wie wichtig diese Info für Dich und eventuelle weitere Entscheidungen ist. 1. Gehen Daten verloren, wenn Du quasi nur einen Mittelwert speicherst (so klang es zumindest, dass Du das vorhast). 2. Wenn ein Lieferant seine Lieferzeiten verbessern sollte, wird es ggf. ewig brauchen, bis Du das im Durchschnitt siehst.

    DerSmurf schrieb:

    eine neue Spalte in DTSUpplier anlegen Umsatz2020
    Nein. Das kommt einer Änderung des Datenmodells gleich. Vielleicht wäre es aber eine Option, 5-10 Spalten anzulegen, die beschriftet sind mit z.B. UmsatzDiesesJahr, UmsatzVorEinemJahr, UmsatzVorZweiJahren, ... - also eine Relativbezeichnung. Ist natürlich abhängig davon, ob Du die alten Daten ewig & 5 Tage behalten willst. Oder noch besser Leg doch einfach ne neue Tabelle an: Umsätze. Da kommen dann als Spalten rein: ID, SupplierID, Jahr und Umsatz.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Huhu.
    Ja eine neue DataTable mit den Umsätzen ist wohl das beste.
    Jedoch interessieren mich die alten Umsätze. Also es muss schon das Jahr gespeichert werden.
    Aber es wäre doch bei einer neuen DTUmsätze mit Spalten "Jahr" und "Umsatz" und Verweis auf die DTSupplier kein Problem, beim ersten Programmstart im neuen Jahr eine neue DataRow mit Jahreszahl und Umsatz anzulegen.
    Die Frage ist nur, wie erzuege ich per Code eine errechnete Spalte und wie stelle ich es an, dass mir auf der Form im angehängten Bild der Umsatz von diesem und letztem Jahr angezeigt wird.

    DerSmurf schrieb:
    Alternativ könnte ich die Lieferzeit in DTSupplier, ja auch nach jedem speichern einer Rechnung per Code neu berechnen.

    VaporiZed schrieb:


    Würde ich aus zwei Gründen nicht machen - ist aber auch abhängig davon, wie wichtig diese Info für Dich und eventuelle weitere Entscheidungen ist. 1. Gehen Daten verloren, wenn Du quasi nur einen Mittelwert speicherst (so klang es zumindest, dass Du das vorhast). 2. Wenn ein Lieferant seine Lieferzeiten verbessern sollte, wird es ggf. ewig brauchen, bis Du das im Durchschnitt siehst.


    Ich verstehe den Unterschied nicht. Wenn ich es beim Eintragen einer Lieferung errechne wäre es wie folgt:
    BstDatum 01.01.2019 / Lieferung 03.01.2019 / Lieferzeit 2 Tage
    BstDatum 10.01.19 / Lieferung 18.01.19 / Lieferzeit 8 Tage
    In DTSupplier lege ich nun eine berechnete Spalte an die mir die Summe der Lieferzeiten errechnet (2+8) und teile diese durch die Menge an Einträgen 10/2 = durchschnittliche Lieferzeit 5 Tage.
    Mir fällt nichts ein, wie ich diesen Wert (mit den gegebenen Daten) genauer errechnen kann.
    Wenn es ohne viel Aufwand möglich ist - gerne, aber generell nutze ich diese Info nicht wirklich. Also ich mache davon nichts abhängig.
    Es geht nur darum eine wirklich ungefähre Ahnung zu haben, wann die Ware denn eintrifft. Die Lieferzeit im Schnitt anzugeben ist eh so eine Sache, da diese teils recht stark schwankt - aber für ungefähr isses ok. Und in der Praxis (mache es so seid Einführung meines VBA Programms 2016) auch auf 1 bis 2 Tage genau (was mir ausreicht).
    In meinem VBA Programm wird mir zum Beispiel auf der "Start Seite" angezeigt, von welchen Firmen Lieferungen offen sind und in wie vielen Tagen (und daraus errechnet an welchem Datum) die Ware eintrifft.
    Aber wie gesagt, ganz ganz ungefähr reicht mir vollkommen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „DerSmurf“ ()

    ich täte empfehlen, bevor du weiter machst, die Benamungen zu korrigieren.
    Entferne die sinnlosen 'DT'-Prefixe. Prefixe sind dazu da, durch Unterschiedlichkeit ansonsten gleichartiges zu gruppieren.
    In einem Dataset gibts aber nur DataTables, daher gäbe es nur den einen Prefix 'DT', und weils nur einen gibt, kann nichts unterschieden werden - also Prefix sinnlos und weg damit.
    Dann bename deine Entitäten Singular.
    Der Name einer Tabelle wird zu Code generiert, der ein einzelnes Element darstellt.
    Etwa aus DTOrders entstünde DTOrdersRow.
    Was soll das sein, ein DTOrdersRow?
    Es handelt sich doch um eine(!) Bestellung, dann soll es auch so heissen. Nenne die Tabelle 'Order', und du erhälst im Code die Klasse 'OrderRow', und das heist so wie was es ist.
    Nenne die Tabelle nicht plural 'Orders', weil dann bekommst du 'OrdersRow', und das würde heissen, mehrere Bestellungen.
    Es ist aber eine Bestellung.

    Tabelle DTAddressBook ist noch krasser. Es sind doch keine Addressbücher in der Tabellle!
    Es sind Personen, mit Name, Vorname, Telefon, Email.
    Also nenne die Tabelle 'Person', damit die Datensätze denn auch so heissen, wie was sie sind.

    Mitte Lieferzeit habich nicht recht verstanden, was du wolle. Eigentlich auch ein Benamungsproblem, weil was du Lieferzeit nennst, scheint mir eine Durchschnitt-Lieferzeit mehrerer Lieferungen zu sein - das wäre ja was genz anderes.
    Also ist es wirklich das, was du wolle? Die DurchschnittsLieferzeit der Bestellungen eines Lieferanten?
    Hallo lieber @ErfinderDesRades
    Danke fürs "einmischen"
    Ich habe meine Benamung so gewählt, dass der Name dem entspricht, was im DataTable gespeichert wird.
    Das DT kommt wohl noch aus VBA Zeiten, wo ich es mir (wegen weniger umfangreicher IDE) zur Gewohnheit gemacht habe, immer ein Präfix zu setzen.
    Aber auf jedenfall Danke für den Tipp - die Benamung meines DataSets entspricht nun deiner Empfehlung.
    Allerdings ist das Umbenennen von DataTables der letzte Müll - muss nun manuell alle Bindings neu setzen.
    Aber naja, besser jetzt als später...

    Zur Lieferzeit (und hoffentlich dann im Anschluss auch zum Umsatz), hier ist meine Excel Formel (siehe Excel Bild oben) aus meinem bisherigen Excel Programm.
    =WENNFEHLER(TEXT((SUMME(TabelleFirmaname[Lieferung])-SUMMEWENN(TabelleFirmaname[Lieferung];">0";TabelleFirmaname[Bestellung]))/(ZÄHLENWENN(TabelleFirmaname[Lieferung];">0"));"0,0")&" Tage";"keine Lieferung")
    genau das möchte ich.
    Wenn dir diese Formel nichts sagen sollte, hier mein Erklärungsversuch:
    Ich möchte die Durchschnittliche Lieferzeit eines Lieferanten für alle Bestellungen angeben.
    Also einfach die Differenz zwischen Bestelldatum und Lieferdatum für alle Bestellungen geteilt durch die Menge der Bestellungen.
    Zum Beispiel:
    BestelldatumLieferdatum
    01.01.1904.01.19
    01.02.1908.02.19

    Lieferzeit Bestellung1 = 3 Tage
    Lieferzeit Bestellung2 = 7 Tage
    Zusammen 10 Tage / geteilt durch 2 Lieferungen = Durchschnittlich 5 Tage
    Also du möchtest eine Spalte

    Quellcode

    1. Suppliers.DeliverDurationAverage
    schaffen.
    Mit berechneten Spalten wäre das eiglich schön machbar - v.a. könnte man diese direkt und datengebunden in DGVs anzeigen.
    Leider kann die Syntax berechneter Spalten nicht mit Date und Timespan rechnen - rechnen kann sie nur mit Zahlen.

    Ich sehe da 2 Lösungswege:
    1. Man ersetzt in Order das OrderDate(Date) - DeliverDate(Date) - konzept durch OrderDate(Date) - DeliverDuration(Double).
      Dann kann eine berechnete Spalte DeliverDurationAverage(Double) formulieren.
    2. Man belässt es beim DeliverDate(Date) und fügt in Supplyer auch eine AverageSpalte ein.
      Im Gui behilft man sich dann mit einer ungebundenen ReadOnly-Spalte im DGV, und im DGV_CellFormatting-Event muss dann der gewünschte Wert aus den Daten erst berechnet werden.
    Ja, genau diese Spalte möchte ich erstellen.
    Dein erster Lösungsweg kommt nicht in Frage, da ich nun seid 3 Jahren Bestelldatum und Lieferdatum in meine Excelform schreibe, tue ich mich mit einer solchen Änderung schwer.
    Deinen zweiten Lösungsweg verstehe ich nicht ganz. Meinst du hier evtl. anstelle von Supplier.AverageColumn, Order.AverageColumn?

    Es gibt zum Eintragen der Daten nur eine einzige Möglichkeit - den speichern Button der Form.
    Nun werden die Daten validiert und geprüft, was überhaupt eingegeben wurde (z.B. nur Lieferdatum).
    Erst danach erfolgt die Speicherung im DataSet.
    Wäre es unter diesen Voraussetzungen nicht am einfachsten, wenn ich die Spalten Order.DeliverDuration(Int32) und Supplier.DeliverDurationAverage(double) anlege?
    Die Order.DeliverDuration kann ich beim eintragen des Lieferdatums errechnen. So habe ich für jede Bestellung die Lieferzeit in Tagen.
    Aus Supplier.DeliverDurationAverage mache ich dann eine berechnete Spalte, um den Durchschnitt anzeigen zu lassen.
    Diese kann ich dann in der GUI bequem - datengeunden - als Label anzeigen.
    Danke @VB1963 für den Tipp. Das werde ich sicher mal brauchen :o)

    Hier in meinem konkreten Beispiel ist es aber so, dass sich die Order.DeliverDuration ja (in der Regel) nicht ändert und es kein Problem darstellt, diesen Wert per Code im DataSet zu speichern.
    Aus diesem Grund wollte ich mir die (meiner Ansicht nach) unnötige berechnete Spalte sparen.
    Dann würde nur die Supplier.DeliverDurationAverage berechnet sein.
    Oder spricht etwas gegen dieses Vorgehen?
    1)
    jo - kann man machen.
    Also eine Logik bauen, die beim Setzen der DeliveryDate die DurschnittsDeliverDuration des verknüpften Suppliers aktualisiert.
    Weil ich gehe davon aus, dass das DeliveryDate einer Bestellung erst nachträglich gesetzt werden kann, weil beim Erstellen der Bestellung ist ja noch nicht geliefert - oder?

    2)

    DerSmurf schrieb:

    Deinen zweiten Lösungsweg verstehe ich nicht ganz. Meinst du hier evtl. anstelle von Supplier.AverageColumn, Order.AverageColumn?
    Ich meine gar keine AverageColumn, jedenfalls nicht im Dataset.
    Ich meine auch keine Order.AverageColumn, weil ein Order hat ja nur eine DeliveryDuration - davon den Mittelwert bilden wäre ja Quatsch.
    Sondern der Supplier.AverageDuration-Wert wird nur für die Anzeige im dgvSupplier ausgerechnet, und zwar im dgvSupplier_Formatting-Event.
    Nochmal: Der Supplier.AverageDuration wird nur für das dgv berechnet, er wird nirgends gespeichert. Wird nur berechnet, wenn das dgvSupplier ihn anzeigen will.
    Das ist eine etwas spezielle Technik, kann sein, dassde davon noch nix gehört hast.

    Mir täte 2) besser gefallen, weil bei 1) kann doch iwann mal wie Teufel will auftreten, dass eine Bestellung hinzukommt, oder gelöscht wird, und dass dann der Durchschnitt nicht mitgepflegt wird.
    Bei 2) besteht in dieser Hinsicht keinerlei Gefahr.
    Na aber es gibt keine SupplierDgv zur Anzeige.
    Die Durchschnittliche Lieferzeit gebe ich mit einem Label wieder.
    Aber ich verstehe dein 1) nicht.
    Das gibt doch nicht mein Vorgehen aus meinem Post wieder.
    Ich Pflege ja den Durchschnitt nicht selbst im dataset.
    Sondern: wann immer sich orderdate, oder deliverydate ändern, was ausschließlich über Buttons passiert, speichere oder ändere ich die Lieferzeit in tagen im Order datatable. Denn das dataset kann ja nicht mit Datumswerten rechnen.
    In der Supplier Datatable gibt es dann die berechnete Spalte deliverytimeaverage.
    Expression = Avg(child(fk_beziehungsname).deliveryduration)
    Habe den genauen Namen nicht im Kopf, aber du verstehst schon.
    Dieser Wert hat dann ein Binding an mein Label.
    Ich verstehe nicht, wie ich hier Gefahr Laufe, dass der Durchschnitt nicht mitgepflegt wird

    Wenn ich es mache wie in deinem 2) beschrieben, muss ich doch Code schreiben um den Schnitt auszurechnen und mein datatable mit einer Schleife durchlaufen . Was doch umständlicher ist. Oder hab ich da einen Denkfehler?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „DerSmurf“ ()