dedlfix: Tabellenstrukturen für Haushaltsbuch gesucht

Beitrag lesen

Tach!

Du meinst also, Ausagben sind dadurch gekennzeichnet, dass es sich beim Betrag um eine negative Zahl handelt. Meine Überlegung war, dass ich mir dann zB. alle Ausgaben einer bestimmten Kategorie in einem bestimmten Zeitraum ausgeben lassen kann. SELECT ... WHERE cashflow = 1. Aber natürlich erreiche ich das auch mit einem SELECT ... WHERE betrag < 0. War das so gemeint von Dir?

Exaktamente.

Den Kontostand extra zu führen ist nicht notwendig, der ergibt sich aus der Summe der Buchungsbeträge (mit ihren Vorzeichen). Da stocke ich jetzt etwas mit meinem Verständnis. Wenn ich soetwas wie eine Start-Übersichtsseite mit den Kontoständen all meiner Konten haben möchte, dann ist das mit der "Kontostand"-Spalte eine Abfrage eines einzigen Feldes. Ansonsten wäre ich gezwungen, bei 5 Konten 5 mal die komplette Datenbank durchlaufen zu lassen und mir sämtliche Buchungswerte zusammenzählen zu lassen.

SELECT SUM(Amount) FROM Transactions GROUP BY ID_Account;

Dazu noch die Account-Tabelle joinen für den Namen des Kontos und in meinem Datenmodell die Splitbuchungen ausklammern.

Das ist doch über-performancelastig und kompliziert. Oder denkst Du da an einen völlig anderen Weg, den aktuellen Stand ausgeben zu lassen ohne einer eigenen "Kontostand"-Spalte?

Bei 15000 Transaktionsdatensätzen kann ich da keine Verzögerung spüren.

Das hat sogar den Vorteil, dass Fehler auffallen. Dann stimmt nämlich die selbst berechnete Summe nicht mit dem Kontostand überein. Ich würde ja den Kontostand nicht manuell eintragen. Bei der Speicherung einer neuen Transaktion würde ich einfach den aktuellen Kontostand aufrufen, entsprechend summieren oder subtrahieren und den neuen Wert wieder speichern. Da kann es nicht zu Fehlern kommen. Also noch fehlt mir das verständnis, wieso die "Kontostand"-Spalte nicht gut ist. Ich bitte um weitere Aufklärung und Hilfestellung!

Nimm den Fall, dass du gerade alle Buchungen vom letzten Kontoauszug eingetragen hast. Dabei hast du dich bei einem Betrag vertippt (Vorzeichen oder Wert). Das merkst du bei der (Zwischen)Summenbildung nicht, sondern erst nach Abschluss aller Einträge, weil du auf dem Kontoauszug auch keine Zwischensummen sondern nur den alten und neuen Stand stehen hast. Jetzt korrigierst du die eine Transaktion/Buchung und musst dann noch mit dem Differenzbetrag zwischen fehlerhafter und korrigierter Buchung/Transaktion die Kontosumme ausgleichen. Das ist nun nicht gerade ein Akt, aber trotzdem zusätzlicher Code statt einfach nur einer einfachen Datensatzänderung.

Das hab ich bei mir nicht extra sondern in der Transaktionentabelle drin. Die sieht so aus: Die von Dir gepostete Tabellenerstellung habe ich bei mir lokal via phpMyAdmin laufen lassen und mir die entstandene Tabelle genauer angesehen. Nach längerer Zeit denke ich, dass ich Dein System zum größten Teil verstanden habe. Aber nur, um das abzuckecken:

Deine Spalte "ID_Account" bezeichnet die ID des Kontos, das bei dieser Transaktion beteiligt ist. Festgelegt durch die IDs in der Tabelle "Accounts" (oder wie immer auch bei Dir bezeichnet.) Richtig? Und ich nehme an, Deine Spalte "ID_Payee" bezeichnet bei Dir das, was ich als "Finanzpartner" definiert habe, also die gegenseite der Finanztransaktion. Richtig?

Beides richtig.

Was ich am wenigsten verstehe, ist die Spalte "Sort":

Sort bekommt bei Bedarf eine Nummer, um Buchungen (=Transaktionen) eines Tages definiert anordnen zu können. Das ist nur Optik und kann auch wegbleiben. Dazu kann ich mir absolut nichts vorstellen. Meinst Du, dass da temporär etwas in dieser Spalte gespeichert wird und nach einer Berechnung/Ausgabe wieder gelöscht wird? Kannst Du das praktisch irgendwie erläutern?

Per Definition liegen die Datensätze in einer Tabelle in einer beliebigen Reihenfolge, selbst wenn das DBMS praktisch die Reihenfolge in der physischen Ordnung nimmt. Man sortiert also nach Datum und bekommt alle Datensätze vom selben Tag theoretisch in einer beliebigen Reihenfolge angezeigt. Das kann einem egal sein, aber wenn man gern die Reihenfolge wie auf dem Kontoauszug haben möchte, dann reicht das Datum allein nicht. Eine gefakte Uhrzeit hinzuzufügen ist nicht die beste Idee. Außerdem kann es vorkommen, dass ich eine Buchung einzutippen übersehe und sie erst nach ein paar anderen nachtrage. Die steht dann zwar zu dem Datum aber irgendwo am Ende, der Buchungen dieses Tages. Die Alternativen, die Danach-Datensätze zu löschen und alle in der richtigen Reihenfolge wieder einzugeben oder gar IDs umzuschreiben oder eine physische Umsortierung, sind keine. Wenn ich also Wert auf eine bestimmte Reihenfolge innerhalb eines Tages lege, dann brauch ich ein weiteres Sortierkriterium. Und das gibt mir die Sort-Spalte. »ORDER BY Date, Sort« Es ist wesentlich einfacher bei ein paar Datensätzen ein paar Zahlen in ein Feld einzutragen oder dort ein paar Änderungen vorzunehmen. Sie müssen ja auch nur relativ zum Tag vergeben werden (oder zur Split-Buchung). Meist bleibt Sort leer, wenn es nur eine Buchung am Tag ist oder eine weitere Sortierung mir nicht notwendig erscheint. Alles in allem ist Sort also ein Kriterium zu einer feineren Sortierung. Und vermutlich entspricht das auch gar nicht buchhalterischen Kriterien (besonders die erwähnten Korrekturen beim Vertippen), aber ich halte ja kein Buch sondern nur die Übersicht in meinen privaten Finanzen auf einem für mich brauchbaren Niveau.

Ich werde komplett auf die Tabelle "Interne Umbuchungen" verzichten und das so wie Du lösen. Dazu habe ich mir auch schon Gedanken gemacht. [...] Mit $id  =  $db -> lastInsertId() bekomme ich nach dem Speichern der ersten Buchung die ID, verwende diese dann als Wert für die ReferenceID bei der Speicherung der 2. Buchung, bekomme hier wiederum mit $id  =  $db -> lastInsertId() zur ID und mit einem SET ... WHERE ID = ... wird dieser Wert dann noch bei der ersten Buchung als ReferenceID nachgetragen. Das gefällt mir!

Mir nicht so sehr, aber unter den gegebenen Umständen lässt sich das nicht viel anders machen. Wenn man im Fehlerfall keine halben Sachen im DBMS stehen haben will, sollte man den Vorgang (erster Eintrag, zweiter Eintrag, zweite ID beim ersten nachtragen) zumindest als eine Transaction (im DBMS-Sinne, nicht im finanziellen) ausführen.

Andere DBMSe haben kein Auto-Increment, dessen Wert erst nachher zur Vefügung steht. Die haben dafür Sequenzen. Das sind unabhänig laufende Zahlenhochzähler (und ebenfalls session- und nebenläufigkeitsproblemfrei). Die befragt man vor dem Insert nach zwei neuen Werten und macht die beiden Inserts gleich mit den richtigen Werten. Oder man erzeugt eindeutige IDs gleich ganz selbst (GUID/UUID).

Wovon Du mich nicht überzeugt hast, ist Dein Zusammenschluss von Einzelbuchungen und Splitbuchungen. Für mich ist das einfach nicht das Selbe. Wenn ich beim Aldi 1 Banane, 1 Joghurt und 1 Wurst kaufe, dann bezahle ich ja an der Kasse nicht 3 Mal hintereinander jedes einzelne Produkt extra. Es gibt einen Bezahlvorgang. Das, was ich als Transaktion bezeichne. Diese Transaktion hat einen Empfänger, ein Datum und einen Gesamtbetrag. Um welche Produkte es sich dabei genau gehandelt hat und was die Preise dieser Einzelprodukte waren, ist wieder eine andere Sache. Dafür die Buchungstabelle, die die Splitrechnungen aufzeigt. Hier wiederum ist für mich der Empfänger und das Datum uninteressant, da durch die ReferenceID der Bezug zur Gesamtrechnung ja gegeben ist. Ich kann mich einfach nicht damit anfreunden, das in eine einzige Tabelle zu stecken. Nicht, weil es mir technisch zu kompliziert wäre oder ich Dein Konzept nicht verstehe, sondern weil ich einfach 2 verschiedene Dinge darin sehe und mich dagegen sträube, die in einen Topf zu werfen. Findest Du das wirklich so schlimm/falsch?

Deine Tabellenaufteilung geht anders an die Sache ran. Weil es eine Kategorisierung nur in den Buchungen, nicht aber bei den Transaktionen gibt, gehe ich davon aus, dass zu jeder Transaktion mindestens ein Buchungsdatensatz angelegt wird (oder mehrere wenn es sich um eine Splitbuchung handelt). In dem steht dann kategorisiert und/oder als Text (Feld dafür fehlt noch) was du gekauft hast. Das kann man so machen und ist genauer betrachtet vermutlich sogar besser als mein System. Ich nehme an, ich hab bei meinem Modell zuerst in Einzelbuchungen gedacht und dann den Split-Teil hinzugefügt. Das System entstand ja auch schon vor vielen Jahren und Erfahrungen.

Jetzt muss ich nochmal nachdenken, wie Umbuchungen in das getrennte System zu integrieren wären. Die ReferenzId ist für Splitbuchungen überflüssig, weil die Zuordnung bereits über die Transaktionsfremdschlüssel in den Buchungen gegeben ist. Das heißt, sie wird nur noch für den nicht so häufigen Fall der Überweisungen zwischen zwei Konten benötigt. Als Alternative zur zusätzlichen, meist leeren Spalte fällt mir da grad nur eine Zuordnungstabelle ein. Aber letztere wirft weitere Fragen auf. a und b seien zwei zusammenhängende Transaktionen. Macht man nun nur a-b-Datensätze, die auch b-a-Datensätze sein können, je nachdem von welcher Transaktionsseite man schaut? Oder macht man jeweils zwei Datensätze, einmal a-b und einmal b-a? Das ist redundant, aber der Vorteil ergibt sich beim Suchen. Da gibt es nämlich das Problem, dass man von einer Transaktion ausgehend in beiden Spalten nachsehen muss, ob deren ID eingetragen ist und dann in der jeweils anderen den Partner findet. Man weiß es ja nicht, ob man den a- oder den b-Teil der Umbuchung vorliegen hat. Wobei, hmm, das Vorzeichen des Betrages könnte ein Hinweis sein. Das wiederum steht aber nur bei den Buchungen (siehe etwas weiter unten). - Vermutlich ist es doch einfacher, eine zusätzliche ReferenceID-Spalte zu nehmen, auch wenn man da das AutoIncrement-ID-Problem hat.

Recht hast Du natürlich damit, dass die Gesamtvermögensberechnungen auf Grund der Transaktionen, also der Hauptrechnungen durchgeführt werden.

Mir ist erst in dieser Antwort klar geworden, wie du die Transaktionen und Buchungsdaten aufteilen willst. (Ich würde es sicher nicht als Buchung (das ist ja quasi synonym zu Transaktion) sondern als Posten oder Details, auf jeden Fall aber englisch benennen.) Es kann jedenfalls sein, dass ich dir nun Vorschläge mache, die anders sind als die vorherigen.

Was du bei deiner Aufteilung nicht brauchst, ist eine Betragsspalte bei den Transaktionen. Die wäre nur doppelt und bringt keinen wirklichen Vorteil gegenüber einem SUM() der zugehörigen Buchungen (über Gruppierung oder Correlated Subquery berechnet).

Beachte auch, als Spaltentyp für die Beträge DECIMAL und nicht FLOAT zu verwenden, sonst gibt es den bekannten und befürchteten Ärger mit ungenauer Abbildbarkeit von Nachkommastellen im Dualsystem (à la 1 - 0.1 = 0.89999999).

Ich weiß jetzt nicht genau, was Du damit meinst, aber ich habe hier beim Mitlesen im Forum schon ein paar Mal mitbekommen, dass es bei Verwendung von FLOAT Probleme gibt. Wenn ich mich richtig erinnere, auch ber der Berechnung von Mittelwerten oder Ähnlichem. Danke für den Hinweis, dann verwende ich DECIMAL! (Nur so nebenbei: Wenn es mit FLOAT so viele Fälle gibt, die Probleme machen, wann verwendet man es dann denn auf jeden Fall statt dem DECIMAL? Irgend eine Daseinsberechtigung muss es ja haben?!)

Die genauen Unterschiede stehen sicher irgendwo zum Nachlesen (Wikipedia oder ähnlich). Float ist besser an das Dualsystem angepasst. Das Dezimalsystem auf einem Dualsystem abzubilden verschenkt Platz und passt nicht direkt in die Rechnerarchitektur. Meist ist es nicht wichtig, wie genau eine Zahl an der drölften Stelle ist, nur der Anfang und der Exponent für die Größenordnung zählt. Deshalb sind die Ungenauigkeiten von Float kein Beinbruch. Beim Geld aber hört die Freundschaft auf und da muss es präzise zugehen, auch wenn die Dualsystemprozessoren dabei mehr Ressourcen verbrauchen.

dedlfix.