Estou usando o PostgreSQL, mas acho que a maioria dos bancos de dados de ponta precisa ter recursos semelhantes e, além disso, que as soluções para eles podem inspirar soluções para mim, então não considere isso específico para o PostgreSQL.
Sei que não sou o primeiro a tentar resolver esse problema, então acho que vale a pena perguntar aqui, mas estou tentando avaliar os custos de modelagem de dados contábeis, de modo que todas as transações sejam fundamentalmente equilibradas. Os dados contábeis são apenas anexados. A restrição geral (escrita em pseudo-código) aqui pode parecer aproximadamente:
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
);
Obviamente, essa restrição de verificação nunca funcionará. Ele opera por linha e pode verificar o banco de dados inteiro. Por isso, sempre falha e demora a fazê-lo.
Então, minha pergunta é qual é a melhor maneira de modelar essa restrição? Até agora, olhei basicamente duas idéias. Pensando se esses são os únicos ou se alguém tem uma maneira melhor (exceto deixá-lo no nível do aplicativo ou em um processo armazenado).
- Eu poderia pegar emprestada uma página do conceito do mundo contábil da diferença entre um livro de entrada original e um livro de entrada final (diário geral versus contabilidade). Nesse aspecto, eu poderia modelar isso como uma matriz de linhas de diário anexadas à entrada do diário, impor a restrição na matriz (em termos do PostgreSQL, selecione sum (amount) = 0 da unnest (je.line_items). salve-os em uma tabela de itens de linha, na qual restrições de colunas individuais poderiam ser aplicadas com mais facilidade e onde índices etc. poderiam ser mais úteis.
- Eu poderia tentar codificar um gatilho de restrição que aplicaria isso por transação, com a ideia de que a soma de uma série de 0s sempre será 0.
Eu os estou comparando com a abordagem atual de impor a lógica em um procedimento armazenado. O custo da complexidade está sendo pesado contra a ideia de que a prova matemática de restrições é superior aos testes de unidade. A principal desvantagem do nº 1 acima é que tipos como tuplas são uma daquelas áreas do PostgreSQL em que se depara com comportamentos inconsistentes e mudanças nas suposições regularmente e, portanto, eu espero que o comportamento nessa área possa mudar com o tempo. Projetar uma versão futura segura não é tão fácil.
Existem outras maneiras de resolver esse problema que escalarão até milhões de registros em cada tabela? Estou esquecendo de algo? Existe uma troca que eu perdi?
Em resposta ao ponto de Craig abaixo sobre as versões, no mínimo, isso terá que ser executado no PostgreSQL 9.2 e superior (talvez 9.1 e superior, mas provavelmente podemos seguir com o 9.2).