Datenbank : Teil 1 erstellen einer DB

  • Moin

    Ich habe eine Datenbank erstellt, nach derzetig besten Wissen.

    Dazu habe ich jetzt 2 Fragen. :/

    Die Datenbank (in Folge genannt: DB) ist wie folgt aufgebaut:
    Erklärung:
    "Datensatz" NUMERIC NOT NULL, ; 999 : 1, 2, 3, ...... 10, 11, 12, ...... 100, 101, 102
    Spaltenname ; Datentyp und Extra's wie "NOT NULL" ; Format; Beispiele

    Spoiler anzeigen

    CREATE TABLE "HaSpBu" (
    "Datensatz" NUMERIC NOT NULL, ; 999 : 1, 2, 3, ...... 10, 11, 12, ...... 100, 101, 102
    "Lfd. Nr." NUMERIC NOT NULL, ; dreistellig : 001, 002, 003, ... Fortlaufend +1
    "Datum" TEXT NOT NULL, ; MM.JJJJ : 01.2025, 02.2025, ... Fortlaufend +1 Monat

    "Einnahmen_Lohn1" INTEGER, ; 99.999,00 : 1200,00
    "Einnahmen_Lohn2" INTEGER, ; 99.999,00 : 250,00
    "Einnahmen_WGP" INTEGER, ; 99.999,00 : 150,00
    "Einnahmen_LMP_VM" INTEGER, ; 99.999,00 : 60,00
    "Einnahmen_Extra" INTEGER, ; 99.999,00 : 40,00
    "Ausgaben_Miete" INTEGER, ; 99.999,00 : -500,00
    "Ausgaben_Strom" INTEGER, ; 99.999,00 : -100,00
    "Ausgaben_Bank" INTEGER, ; 99.999,00 : -10,05
    "Ausgaben_RuBe" INTEGER, ; 99.999,00 : -20,00
    "Ausgaben_LMP" INTEGER, ; 99.999,00 : -300,00
    "Ausgaben_DuS" INTEGER, ; 99.999,00 : -100,00
    "Ausgaben_frei1" INTEGER, ; 99.999,00 : -150,00
    "Ausgaben_frei2" INTEGER, ; 99.999,00 : -000,00
    "Ausgaben_Extra" INTEGER, ; 99.999,00 : -000,00
    "Gesamteinnahmen" INTEGER, ; 99.999,00 : 1700,00
    "Gesamtausgaben" INTEGER, ; 99.999,00 : 1480,00
    "Kto_Saldo" INTEGER, ; 99.999,00 : 220,00

    "Eingang_Sparbuch" INTEGER, ; 99.999,00 : 100,00
    "Ausgang_Sparbuch" INTEGER, ; 99.999,00 : -75,00
    "Saldo_Sparbuch" INTEGER, ; 99.999,00 : 25,00
    "Verwendungszweck" TEXT, ; Textfeld : € 75,- für X, Y, Z
    "Kuerzel" TEXT, ; ABC123 : SWF, MIE, ...

    "Jahr" NUMERIC, ; JJJJ : 2024, 2025, ...
    "Halbjahr" NUMERIC, ; 1 : 1 oder 2
    "Jahresdrittel" NUMERIC, ; 1 : 1 oder 2 oder 3
    "Quartal" NUMERIC, ; 1 : 1 oder 2 oder 3 odr 4
    "Tage" NUMERIC, ; 11 : 1, 2, 3, ... ... 31

    "Tagessatz" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_1" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_2" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_3" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_4" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_5" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_6" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_7" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_8" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_9" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_10" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_11" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_12" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_13" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_14" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_15" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_16" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_17" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_18" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_19" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_20" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_21" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_22" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_23" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_24" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_25" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_26" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_27" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_28" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_29" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_30" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_31" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_Gesamt" INTEGER, ; 999,99 : 254,91
    "Anzahl_Tageseintraege" NUMERIC, ; 11 : 1, 2, 3, ... ... 31
    "Kalendertage_Tagesdurchschnitt" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "Kalendertage_Wochendurchschnitt" INTEGER, ; 99,99 : 25,00, 13,84, 3,66, ...
    "LMP +" INTEGER, ; 99,99 : 25,25, 13,84, 63,66, ...
    "LMP Scheine" INTEGER, ; 99,99 : 25,00, 10,00, 60,00, ...
    "LMP Muenzen" INTEGER, ; 99 : 0,25, 0,84, 3,66, ...
    PRIMARY KEY("Datensatz")
    )

    1. Frage:
    Ist die oben erstellt DB richtig?

    2. Frage:
    Die 1. - 3. Spalten erklären sich meine ich selber
    Die 4. - 20. Spalte sind das "Haushaltsbuch"
    Die 21. - 25. Spalte sind das "Sparbuch"
    Die 26. - 30. Spalte sind Aufteilungen Jahr / Halbjahr / Jahresdrittel / Quartal / Tage
    Die 31. - 69. Spalte sind das "Tagesverbrauchjournal & Auswertung

    Wäre es hier sinnvoller
    Spalte 4-20 in eine Tabelle (Haushaltsbuch),
    Spalte 21-25 in eine weitere Tabelle (Sparbuch),
    Spalte 26-30 in eine weitere Tabelle (Aufteilung),
    Spalte 31-69 in eine weitere Tabelle (Tagesverbrauch u. Auswertung)
    zu erstellen und wenn, wie mache ich das?

    3. Frage:
    Ich habe Daten, die nur einmal bestehen, also nicht jeden Monat. Zum Beispiel in der Spalte "Kto_Saldo" wird ein Startwert benötig. Weil gerechnet wird:
    1. Monat : Kto_Saldo = Startwert + Gesamteinnahmen - Gesamtausgaben
    Folgemonate: Kto_Saldo = Kto_Saldo vom Vormonat + Gesamteinnahmen - Gesamtausgaben
    Wäre es hier möglich diese Daten auch in die bzw. in eine weitere Tabelle speichern?

    Es treten bestimmt noch weitere / neue Fragen auf, aber Schritt-für-Schritt, denn ich soll es ja auch verstehen.


    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    k3mrwmIBHejryPvylQSFieDF5f3VOnk6iLAVBGVhKQegrFuWr3iraNIblLweSW4WgqI0SrRbS7U5jI3sn50R4a15Cthu1bEr

  • Ist die oben erstellte DB richtig?

    Die Frage sollte wohl eher lauten : Ist die erstellte DB praktikabel und flexibel für Erweiterungen ?

    Da Du alle Felder (auch berechnete) in 'nur' eine Tabelle packst (hier : "HaSpBu"), würde ich sagen - Nein.

    Man kann gar nicht oft genug betonen, wie wichtig ein 'durchdachtes' Datenbankdesign in der Entstehungsphase für den weiteren Verlauf eines Projektes ist. Daher würde ich diesem Bereich die nötige Aufmerksamkeit schenken, auch wenn man (speziell Du ;)) gerne sofort loslegen möchte(st).

    1. Berechnete Felder wie z.B. "Gesamteinnahmen" und "Gesamtausgaben" würde ich nicht als Datenfelder in einer Tabelle speichern, da sie jederzeit per SQL-Abfrage ermittelt werden können.

    2. Ein wesentlicher Punkt ist die Nutzung von "Untertabellen". Nehmen wir mal den Bereich Ausgaben. Statt :

    "Ausgaben_Miete" , "Ausgaben_Strom", "Ausgaben_Bank" usw. erstellt man z.B. eine Untertabelle (tblAusgabenTyp). Diese kannst Du später beliebig erweitern, ohne neue Felder in Deiner "Haupttabelle hinzuzufügen.

    P.S. : Der Einsatz von Tools wie z.B. sqlitestudio wäre eine hilfreiche Ergänzung.

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

    Einmal editiert, zuletzt von Musashi (26. April 2025 um 18:58) aus folgendem Grund: typo

  • das Zauberwort hier ist "Normalisierung" ;)

    besser gesagt: die 3. Normalform ist Standard

    MfG Schnuffel

    "Sarkasmus ist die niedrigste Form des Witzes, aber die höchste Form der Intelligenz."
    Val McDermid

    ein paar Infos ...

    Wer mehr als "nur" Hilfe benötigt, kann sich gern im Forum "Programmieranfragen" an uns wenden. Wir helfen in allen Fällen, die die Forenregeln zulassen.

    Für schnelle Hilfe benötigen wir ein ausführbares Script ("as is"), dass wir als Demonstration des Problems testen können. Wer von uns erwartet ein Teilscript erstmal lauffähig zu bekommen, der hat
    1. keine wirkliche Not
    2. keinen Respekt vor Menschen die ihm in ihrer Freizeit Ihre Hilfe anbieten
    3. oder ist einfach nur faul und meint wir coden das für ihn

    In solchen Fällen erlaube ich mir, die Anfrage einfach zu ignorieren. ;)

    Man möge mir verzeihen, wenn ich nicht perfekten und ideal lesbaren Code zur Verfügung stelle.
    Ich möchte Hilfe zur Selbsthilfe leisten und denke dass eine gewisse Transferleistung erwartet werden kann.

  • Ich hab mal was gebastelt ;)

    Zuallererst: Alle deine Infos lassen sich recht kurz zusammenfassen: Geld wird einem Konto hinzugefügt oder abgezogen.

    Alles andere sind Infos, die du aus den Daten herausfinden (berechnen) willst.

    Dafür schaut man sich mal an, welche Daten denn wirklich von dir vorgegeben sind, die nicht allgemein gültig sind oder berechnet werden können.
    Das sind einmal die Konten (accounts) sowie die Transaktionen auf den accounts (ein/auszahlungen).
    Also brauchen wir eine Tabelle für die Accounts und eine für die Transaktionen.
    Transaktionen haben als Info: Zeitpunkt, Die Änderung (+-), eine kurze Beschreibung und einen Verwendungszweck.

    Meine Tabellen sehen also so aus:

    Accounts
    id - primary key, wird automatisch erzeugtname - Name des Kontos
    Bookings
    id - primary key, wird automatisch erzeugtaccount - (id aus Accounts)time - zeit als unixepochchange - (Änderung in cent)short_desc - Kurze Beschreibungpurpose - der Verwendungszweck

    Diese werden in SQLite so angelegt:

    Deine Daten können dann mit folgendem hinzugefügt werden:

    Alles andere wird mit SQL ausgerechnet.
    Für den Startwert, den du angibst kannst du einfach eine weitere Transaktion in Bookings hinzufügen, die den StartWert auf das Konto überweist, e.g. : INSERT INTO Bookings (account, time, change, short_desc) VALUES (1, unixepoch("2000-01-01 00:00:00"), 5000000, "Initiale 50000");


    Und damit du ein Beispiel hast, hab ich mal alle Daten aus deinem Post, die irgendwie errechnet werden können als Ausgabe vorbereitet, du kannst einfach die passenden Zeilen aus/einkommentieren und dir die Abfragen anzeigen lassen.
    Dabei sind zwei Zeilen (41, 46), in denen Daten zum Testen im Zeitraum 2024.01.01 bis 2025.12.28 generiert werden. Besonders das Löschen der alten Tabellen nimmt etwas Zeit ein, also nach dem ersten ausführen am besten die beiden Zeilen auskommentieren.
    _SQLite_ExecCatchErr($hDB, $sSQLReset, False, True)
    _fillWithExampleData($hDB)
    Die SQL-Abfragen sind sehr schnell, wenn das ausführen also mehr als 1 bis 2 Sekunden dauert liegt es daran.

    Ich hoffe das hilft dir weiter, bzw. gibt dir einen kleinen Anstoß.

  • Moin Moin.

    Musashi, Schnuffel:
    Danke, sehe ich mir an.
    Tool, wie oben vorgeschlagen gerade installiert (SQLiteStudio-3.4.17-windows-x64-installer).

    Kanashius: Kannst Du mir die DLL zur Verfügung stellen? Danke !!!!

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    k3mrwmIBHejryPvylQSFieDF5f3VOnk6iLAVBGVhKQegrFuWr3iraNIblLweSW4WgqI0SrRbS7U5jI3sn50R4a15Cthu1bEr

    Einmal editiert, zuletzt von Alina (28. April 2025 um 15:07)

  • hmm, 2038 ist das Ende einer Epoche. Die "unixepoch()". Verwenden Sie also YYYYMMDDHHNNSS. Es sollte es zukunftssicher machen. Auch leichter zu lesen. Meine 2 Cent Weisheit

  • 2038 findet nur der Überlauf statt wenn 32 Bit-Integer zur Speicherung verwendet werden.
    SQLite entscheidet aufgrund des Bereiches eines Wertes selbstständig ob es diesen als 32 Bit oder 64 Bit Integer abspeichert.
    Im Fall von Unix-Timestamps > 2147483647 (2038-01-19 03:14:07) wechselt SQLite also automatisch auf 64 Bit und daher gibt es da kein Problem.

    Die Funktion unixepoch() ist in SQLite folgendermaßen definiert:

    Hier sieht man schön, dass der Returnwert der Funktion ein 64 Bit Integer ist. Ein Überlaufproblem wird also nicht auftreten.

    Auch die strftime-Funktion ist davon nicht betroffen wie man leicht selbst testen kann:

    SQL
    SELECT
      CAST(strftime('%s', '2038-01-19 03:14:07', 'utc') AS INTEGER) AS vorher,
      CAST(strftime('%s', '2038-01-19 03:14:08', 'utc') AS INTEGER) AS nachher,
      CAST(strftime('%s', '2099-01-01 03:14:07', 'utc') AS INTEGER) AS zukunft;
  • Moin zusammen.

    Ich habe die DB von Kanashius  im SQLiteStudio geöffnet. Ich muss da erst einmal durchblicken. Bis jetzt habe ich einige Fragen.


    Erst einmal werde ich meine riesige Tabelle durch mehrere kleine Tabellen "ersetzen".
    Wenn ich die fertig habe, werde ich die DB, zur Beurteilung, evtl. Berichtigungen und für die nächsten Schritte posten.

    "Schritt-für-Schritt" oder mit einem "Lächeln" auch "SQLite-für-......." genannt.

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    k3mrwmIBHejryPvylQSFieDF5f3VOnk6iLAVBGVhKQegrFuWr3iraNIblLweSW4WgqI0SrRbS7U5jI3sn50R4a15Cthu1bEr

  • Moin zusammen.

    Hatte die letzte Zeit zu viel zu tun.

    Ich habe jetzt eine DB erstellt und arbeite mit dem "SQLiteStudio".
    In der Anlage meine erstellte DB mit paar Beispieldaten und einer ersten Abfrage.

    Bei den Spaltennamen gibt es am Ende "_(F)". Das bedeutet, das ich meine, das diese Spalten, berechnenbar sind und gelöscht werden können.

    Soweit und nun eine erste BITTE. Hat jemand Zeit, sich die erstellte Datenbank anzusehen?

    Dann habe ich noch Fragen zur Datenerfassung.
    1.) Kann man es ändern, das man das Datum wie folgt setzt kann: streiche YYYY.MM.DD ; setzte DD.MM.YYYY (Reihenfolge verändern)
    2.) Kann man es ändern, das man Beträge wie folgt setzten kann: streiche 10.00 ; setzte 10,00 (ersetzte Punkt durch Komma


    db_ahl.zip


    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    k3mrwmIBHejryPvylQSFieDF5f3VOnk6iLAVBGVhKQegrFuWr3iraNIblLweSW4WgqI0SrRbS7U5jI3sn50R4a15Cthu1bEr

  • Hi Alina,

    Ich hab das ganze diesmal auch in eine SQLite Datenbank geschrieben.
    Nur den Tagesverbrauch hab ich weggelassen, da ich den noch nicht wirklich verstanden habe (ist das ein Durchschnitt nach Monatstag? weil es ist kein Datum dabei um einen bestimmten Monat anzugeben).

    Achte auch darauf, dass ich nicht nur die Tabellen angelegt habe, sondern auch einige Views als Beispiel zur Datenabfrage.
    Die Views können wie Tabellen auch in SQL-Abfragen verwendet werden.

    Was das Datum und die Beträge angeht: Lass sie als YYYY-MM-DD und 10.0 in der Datenbank. Das sind die Internationalen Standards, die SQLite automatisch erkennt und verwendet. Ansonsten kann bei den SQLite Operationen (Wie Summe (SUM), Durchschnitt (AVG), Runden (ROUND),...) und den Vergleichen für die Abfragen einiges schief gehen.

    Mach erst alles in SQLite und am Ende baust du dir die Deutsche Variante daraus (In SQL oder AutoIt, je nachdem, wie es besser passt).

    Ein Beispiel für SQLite: SELECT ID, Account, AccountName, Type, TypeName, strftime('%d.%m.%Y %H:%M:%S', Time) as TimeDE, REPLACE(CAST(Change as text), '.', ',') as ChangeDE FROM CombinedBalanceForCalculations

    Edit: Hab die Datenbank noch mit mehr Beispieldaten befüllt (2024/2025) und die Saldo Views überarbeitet, um nicht nur die Veränderung, sondern auch den aktuellen Stand mit auszugeben (z.B. SaldoBefore, SaldoAfter für jeden Monat)