Datenbankmodell für Haushaltsbuch

Dsimon24

Lieutenant
Registriert
Aug. 2016
Beiträge
595
Hallo zusammen,

da mir noch ein paar Skills im Bereich der Datenbanken fehlen, eigne ich mir gerade welche an.
Dabei habe ich zum Testen mal ein Haushaltsbuch entworfen. Leider komme ich da nicht so
recht weiter. Vielleicht kann mich einer auf den richtigen Weg bringen!?

Neben normalen Buchungen (Eingänge/Ausgänge) gibt es auch vorgemerkte Buchungen,
die jeden Monat (z.B. über einen Cron) ausgeführt werden.

Dazu habe ich die Tabellen 'buchungen_vorgemerkt' sowie 'buchungen_ausgefuehrt'
erstellt. Wird eine vorgemerkte Buchung einmal im Monat ausgeführt, erscheint
diese in die entsprechende Tabelle. Ich verweise in der entsprechenden Tabelle
dann auf die Tabelle, in dieser sich die vorgemerkten Buchungen befinden.

Wie gehe ich aber vor, wenn sich bei einer vorgemerkten (also regelmäßigen Buchung) gelegentlich der
Betrag ändert. Bspw. kostet ein Handyvertrag 44€ im Monat. Wenn ich aber im Juli 10 SMS versende, sind
es weitere 1,90€ für diesen Monat (Das würde ich dann durch eine Anpassung der über den Cron erzeigten
Buchung realisieren). Und wie schaut es mit Buchungen aus, die nicht vorgemerkt wurden. Bspw. Auto
gewaschen - also nicht regelmäßig. Wie binde ich diese Dinge am saubersten mit ein?

Ich hoffe, ich konnte mein Problem recht klar darstellen und freue mich auf Tipps.

VG, David
 

Anhänge

  • buchungen_db.png
    buchungen_db.png
    14,3 KB · Aufrufe: 575
Also die "Buchungen vorbemerkt" sind in dem System vorhanden und werden durch einen Cronjob dann automatisch zum passenden Zeitraum gebucht?

So wie es auf dem Bild für mich aussieht ist die Beziehung auf der falschen Seite, du hast ja bei "Buchung ausgeführt" eine ID auf "Buchung vorbemerkt". Das heißt im Umkehrschluss, dass deine ausgeführte Buchung ja nur 1 Eintrag haben kann mit einer Beziehung zu nur einer "Buchung vorbemerkt" und damit könntest du das auch gleich alles in eine Tabelle klatschen mit einem Status.


Natürlich willst du mehrere Buchungen zu einer ausgeführten Buchung haben, wie du schon sagtest sowas wie:

  • Handyvertrag Grundgebühr
  • SMS 1€
  • SMS 1€
  • Auslandsanruf 2.50€


dann solltest du lieber bei "Buchung vorbemerkt" eine referenz zur "Buchung ausgeführt" haben.
Und jetzt wo ich das so schreibe finde ich die Namensbezeichnung der Tabellen auch irgendwie nicht richtig :D
 
cppnap schrieb:
Also die "Buchungen vorbemerkt" sind in dem System vorhanden und werden
durch einen Cronjob dann automatisch zum passenden Zeitraum gebucht?

Genau.

In vorgemerkt sind dann die Buchungen bspw:
Handyvertrag, 44€ start: 01.01.2019 ende: 31.12.2021.

Diese Vorlage erzeigt dann jeden Monat die entsprechende Buchung.
Die erstellte Buchung kann ich dann bei Bedarf anpassen, wenn es auf
der Rechnung doch teurer geworden ist. Dann müsste die Richtung
der Beziehung doch eigentlich doch richtig sein, oder?

Aber für Buchungen, die nicht aus der Tabelle der vorgemerkten
Buchungen stammen, brauche ich dann noch ne dritte Tabelle?
 
Dafür gibt's viele verschiedene Lösungen, und jede hat ihre eigenen Vor- und Nachteile - wie eigentlich immer in der Informatik :D

Erst mal das wichtigste an deiner Datenbank: Die Tabelle mit den ausgeführten Buchungen. Die Daten darin müssen um jeden Preis (pun intended) stimmig sein.

Für deine Daueraufträge gilt das nicht unbedingt. Da gibt's nun verschiedene Möglichkeiten. Z.B.

  • Eine saubere Lösung wäre: Wenn sich der Betrag ändert, dann duplizierst du den Dauerauftrag. Der alte geht dann nur noch bis "jetzt" und der neue startet "ab jetzt". Die einzelnen Aufträge lassen sich dann natürlich noch untereinander verknüpfen, damit man später darstellen kann, wer wie wann wo was daran geändert wurde. So kann man dann auch z.B. einstellen, dass der Dauerauftrag (als er angelegt wurde) 10€ beträgt, diesen Monat sind's 15€, und ab nächsten Monat geht's mit 12€ weiter bis in alle Ewigkeit.
  • Quick and Dirty wäre: Einfach den Betrag im Dauerauftrag überschreiben. Dann kann man allerdings nur noch an den ausgeführten Buchungen sehen, wann sich der Dauerauftrag (ungefähr) geändert hat. Und man kann keine "einmaligen" Änderungen machen, die ab nächsten Monat automatisch wieder zurückgesetzt werden.
 
Also erstmal würde man sich eine Entität Buchung erstellen.
Deine Entität ist Käse

Eine Buchung hat eine
Id kontoid - konto ist auch eine Entität, datum betrag

Konto hat id nr name ..... was du noch willst

Desweiteren schreibt man sowas in Englisch...das machts später einfacher.

Wenn du 1.90 mehr bezahlen musst sind das in deinem system 2 Buchungen

Bzw theoretisch sogar viel mehr.

Jede sms bekommt eine Buchung.

Da das alles nicht so einfach ist und du ja wissen willst wohin das alles gehört brauchst du eine neue Entität Vorgang.

Id, name, Beschreibung, Buchungen[] da du Buchungen nicht als Array referenzieren kannst brauchst du eine neue tabelle

Vorgang_buchung

Mit id, vorgangsid, buchubgsid

Damit wird dann jede Buchung nit einem vorgang verknüpft

Dann hast du den Vorgang Handyvertrag
Mit allen Buchungen die dazu gehöhren.

Das eigendlich relativ simpel.

Man kann noch schatten und systembuchungen vornehmen, oft aus Performance und Statistik zwecken. Brauchst du aber sicher nicht.

Z.b. willst du ja wissen für was du dein geld bei ikea bezahlt hast nicht nur Buchung ikea.. über 2000 euro
 
Es geht in die Richtung die blackbirdone auch vorgibt...
Mit der richtigen Datenbank gehen auch Arrays, aber in der Regel will man das nicht. ;)

Grundsätzlich sind weitere Tabellen sinnvoll (wie die angedeutete "kategorie" Tabelle).
Ähnlich kann man auch eine Tabelle mit möglichen Vorgängen erstellen, die erweitert wird, wenn ein noch nicht vorhandener Vorgang hinzukommt.
Dort kann man auch eine Spalte aufnehmen, in der man angibt in welchen Intervallen der Vorgang typsicherweise vorkommt ("wöchentlich", "monatlich", "quartal", "halbjährlich", etc. und im Zweifel, "unregelmäßig"). Die Liste der Intervalle wird wie die Kategorie" wieder in eine eigene Tabelle mit ID und Bezeichnung gepackt (alternativ wäre auch ein Enum-Typ der Datenbank möglich: https://www.postgresql.org/docs/current/functions-enum.html).

Tabelle "vorgang"; Spalten: "vorgang_id", "bezeichnung", "intervall_id",...
Tabelle "intervall"; Spalten: "intervall_id", "bezeichnung",...


Statt in jeder Tabelle eine "id" Spalte zu führen, empfehle ich hier direkt immer schon den Tabellennamen als Prefix voranzustellen (wie oben ersichtlich).
Damit ist die Spaltenbezeichnung in der Tabelle identisch zu der in der Referenz in der mit der ID darauf verwiesen wird.
Das erleichtert einem das Lesen und es hilft Tools Verbindungen zwischen den Tabellen zu erkennen, wenn man vergessen hat die entsprechenden Fremdschlüsselbeziehungen zu definieren (z. B. SchemaSpy kann diese dann als "implizite" Verbindungen erkennen und stellt diese mit einer gestrichelten Linie dar - siehe Beispiel: http://www.jmdb.de/content/eng/dbschema/dbschema.html ; Anm: Hier wurde die Verbindung nicht vergessen, sondern die IMDb Daten sind fehlerhaft/unvollständig, so dass keine FOREIGN KEY Constraints erstellt werden konnte und daher die Verbindung immerhin als gestrichelte Linie dargestellt werden kann).
 
Ich stimme @blackbirdone und @xmarsx dahingehend zu, dass das aktuelle Design der Datenbank unzureichend ist. Es wäre in der Tat sinnvoller, eine Tabelle für Buchungen zu erstellen und in diesen dann einen Status bzw das Ausführungsdatum festzuhalten. Im vorliegenden Design sind eben diese Eigenschaften einfach nur in eine andere Tabelle ausgelagert. Bei der Normalisierung einer Datenbank nimmt man alle Eigenschaften, die nicht auf das primäre Attribut des Eintrags bezogen sind, in eine separate Tabelle.

Ein Beispiel dafür wäre eine Person (Primärattribut) sowie dessen Wohnort und die dazugehörige Postleitzahl. Letztere ist nicht von der Person abhängig, sondern vom Wohnort (oder andersherum, Ort von der PLZ) und somit gehört die Relation Wohnort <> PLZ in eine eigene Tabelle und eben nicht in die Personentabelle. Das Geburtsdatum wiederum hängt direkt von der Person ab und gehört demnach ebenfalls in die Personentabelle.
 
Eine bewährte Vorgehensweise bei der Erstellung eines ersten Datenbankdesigns ist folgendes:
Man schreibt sein Vorhaben als Text in (vernünftigen) Sätzen vollständig auf. Also zum Beispiel:

Ich möchte ein Haushaltsbuch führen. Darin werden Buchungen erfasst. Eine Buchung kann den Status "durchgeführt, vorgemerkt oder ausgeführt" haben. usw. usw. usw.

Wenn der Text fertig ist geht man bei und fummelt sich alle Hauptwörter heraus. Das wäre vom obigen Beispiel:

Haushaltsbuch
Buchungen
Status

Das sind dann schon mal die ersten relevanten Entitäten. Diese verwendet man dann in ein ER-Diagramm nach Chen und verbindet diese mit den Verben aus dem Text. Beispiel:

Haushaltsbuch - erfasst - Buchungen
Buchungen - haben - Status

Dann kann man im Anschluss mit der Kardinalität weiter machen, das ganze dann in ein Relationenmodell überführen, ich benutze dafür meistens die UML-Notation, teilweise leicht abgewandelt.
Dabei gilt es die dritte Normalform zu berücksichtigen. Da verstößt dein Design aus dem Eingangspost schon gegen, da das Attribut "Betrag" und die Entität "Buchungen" nicht eindeutig nur von sich selbst und seinen Schlüsselattributen abhängig ist. Betrag gibt es in zwei Entitäten, die einen ähnlichen Zweck haben. Wenn man sich aber an die oben stehende Vorgehensweise hält legt man schon automatisch den Grundstein dafür (eindeutige Entitäten), dass die 3NF eingehalten wird (wenn man das Vorhaben sauber beschreibt und das Design sauber durchführt)

Grüße
 
Zurück
Oben