Ich verwende PostgreSQL, aber ich bin der Meinung, dass die meisten Top-End-Datenbanken über ähnliche Funktionen verfügen müssen. Außerdem können Lösungen für sie zu Lösungen für mich inspirieren. Betrachten Sie diese nicht als PostgreSQL-spezifisch.
Ich weiß, dass ich nicht der erste bin, der versucht, dieses Problem zu lösen, und daher ist es meiner Meinung nach sinnvoll, hier nachzufragen, aber ich versuche, die Kosten für die Modellierung von Buchhaltungsdaten so zu bewerten, dass jede Transaktion im Grunde genommen ausgewogen ist. Die Abrechnungsdaten können nur angehängt werden. Die allgemeine Einschränkung (in Pseudocode geschrieben) könnte hier ungefähr so aussehen:
CREATE TABLE journal_entry (
id bigserial not null unique, --artificial candidate key
journal_type_id int references journal_type(id),
reference text, -- source document identifier, unique per journal
date_posted date not null,
PRIMARY KEY (journal_type_id, reference)
);
CREATE TABLE journal_line (
entry_id bigint references journal_entry(id),
account_id int not null references account(id),
amount numeric not null,
line_id bigserial not null unique,
CHECK ((sum(amount) over (partition by entry_id) = 0) -- this won't work
);
Offensichtlich wird eine solche Prüfbedingung niemals funktionieren. Es funktioniert pro Zeile und überprüft möglicherweise die gesamte Datenbank. So wird es immer scheitern und langsam dabei sein.
Meine Frage ist also, wie diese Einschränkung am besten modelliert werden kann. Grundsätzlich habe ich mir bisher zwei Ideen angesehen. Ich frage mich, ob dies die einzigen sind oder ob jemand einen besseren Weg hat (außer es der App-Ebene oder einem gespeicherten Prozess zu überlassen).
- Ich könnte mir eine Seite aus dem Konzept der Buchhaltungswelt über den Unterschied zwischen einem Buch mit ursprünglicher Erfassung und einem Buch mit endgültiger Erfassung (Hauptbuch vs. Hauptbuch) ausleihen. In dieser Hinsicht könnte ich dies als Array von Journalzeilen modellieren, die an den Journaleintrag angehängt sind, die Einschränkung für das Array erzwingen (in PostgreSQL-Begriffen wählen Sie sum (amount) = 0 aus unnest (je.line_items). Ein Trigger könnte expandieren und Speichern Sie diese in einer Werbebuchungstabelle, in der einzelne Spalteneinschränkungen einfacher durchgesetzt werden können und Indizes usw. nützlicher sind.
- Ich könnte versuchen, einen Einschränkungsauslöser zu codieren, der dies pro Transaktion erzwingt, mit der Idee, dass die Summe einer Reihe von Nullen immer 0 sein wird.
Ich wäge diese gegen den aktuellen Ansatz der Durchsetzung der Logik in einer gespeicherten Prozedur. Die Komplexitätskosten werden gegen die Idee abgewogen, dass der mathematische Nachweis von Einschränkungen Unit-Tests überlegen ist. Der Hauptnachteil von # 1 oben ist, dass Types as Tupel einer der Bereiche in PostgreSQL ist, in denen es zu inkonsistenten Verhaltensweisen und regelmäßigen Änderungen der Annahmen kommt, und ich würde sogar hoffen, dass sich das Verhalten in diesem Bereich im Laufe der Zeit ändern könnte. Das Entwerfen einer zukünftigen sicheren Version ist nicht so einfach.
Gibt es andere Möglichkeiten, um dieses Problem zu lösen, das sich auf Millionen von Datensätzen in jeder Tabelle skalieren lässt? Vermisse ich etwas? Gibt es einen Kompromiss, den ich verpasst habe?
Als Reaktion auf Craigs unten stehenden Punkt zu Versionen muss dies mindestens auf PostgreSQL 9.2 und höher (vielleicht 9.1 und höher, aber wahrscheinlich können wir mit Straight 9.2 weitermachen) ausgeführt werden.