Sto usando PostgreSQL ma immagino che la maggior parte dei db di fascia alta debba avere alcune funzionalità simili e, inoltre, che le soluzioni per loro possano ispirare soluzioni per me, quindi non considerare questo specifico di PostgreSQL.
So di non essere il primo a cercare di risolvere questo problema, quindi immagino che valga la pena chiedere qui, ma sto cercando di valutare i costi della modellizzazione dei dati contabili in modo tale che ogni transazione sia sostanzialmente bilanciata. I dati contabili sono solo appendici. Il vincolo generale (scritto in pseudo-codice) qui potrebbe apparire approssimativamente come:
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
);
Ovviamente un tale vincolo di controllo non funzionerà mai. Funziona per riga e potrebbe controllare l'intero db. Quindi fallirà sempre e sarà lento nel farlo.
Quindi la mia domanda è qual è il modo migliore per modellare questo vincolo? Finora ho praticamente esaminato due idee. Mi chiedo se questi sono gli unici o se qualcuno ha un modo migliore (oltre a lasciarlo al livello di app o ad un proc memorizzato).
- Potrei prendere in prestito una pagina dal concetto del mondo contabile della differenza tra un libro di entrata originale e un libro di entrata finale (giornale generale vs libro mastro). A questo proposito, potrei modellarlo come un array di righe di giornale associate alla voce di journal, applicare il vincolo sull'array (in termini PostgreSQL, selezionare sum (amount) = 0 da unest (je.line_items). Un trigger potrebbe espandersi e salvali in una tabella degli elementi pubblicitari, in cui i vincoli delle singole colonne potrebbero essere applicati più facilmente e dove gli indici ecc. potrebbero essere più utili. Questa è la direzione in cui mi sto appoggiando.
- Potrei provare a codificare un trigger di vincolo che lo imponga per transazione con l'idea che la somma di una serie di 0 sarà sempre 0.
Li sto valutando rispetto all'attuale approccio di applicazione della logica in una procedura memorizzata. Il costo della complessità viene valutato rispetto all'idea che la prova matematica dei vincoli è superiore ai test unitari. Il principale svantaggio del n. 1 sopra è che i tipi come tuple sono una di quelle aree di PostgreSQL in cui si incontrano comportamenti inconsistenti e cambiano assunzioni regolarmente e quindi spero persino che i comportamenti in quest'area possano cambiare nel tempo. Progettare una versione futura sicura non è così semplice.
Esistono altri modi per risolvere questo problema che scaleranno fino a milioni di record in ogni tabella? Mi sto perdendo qualcosa? C'è un compromesso che mi sono perso?
In risposta al punto di Craig che segue sulle versioni, almeno, questo dovrà essere eseguito su PostgreSQL 9.2 e versioni successive (forse 9.1 e versioni successive, ma probabilmente possiamo procedere con le versioni 9.2).