Estoy usando PostgreSQL pero creo que la mayoría de los db de gama alta deben tener algunas capacidades similares y, además, que las soluciones para ellos pueden inspirar soluciones para mí, así que no considere esto específico de PostgreSQL.
Sé que no soy el primero en tratar de resolver este problema, así que creo que vale la pena preguntar aquí, pero estoy tratando de evaluar los costos de modelar datos contables de manera que cada transacción sea fundamentalmente equilibrada. Los datos contables son de solo anexo. La restricción general (escrita en pseudocódigo) aquí podría verse más o menos así:
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, tal restricción de verificación nunca funcionará. Funciona por fila y puede verificar toda la base de datos. Por lo tanto, siempre fallará y será lento al hacerlo.
Entonces, mi pregunta es ¿cuál es la mejor manera de modelar esta restricción? Básicamente, he visto dos ideas hasta ahora. Preguntándose si estos son los únicos, o si alguien tiene una mejor manera (aparte de dejarla en el nivel de la aplicación o un proceso almacenado).
- Podría tomar prestada una página del concepto del mundo contable de la diferencia entre un libro de entrada original y un libro de entrada final (diario general vs libro mayor). En este sentido, podría modelar esto como una matriz de líneas de diario adjuntas a la entrada de diario, imponer la restricción en la matriz (en términos de PostgreSQL, seleccionar sum (cantidad) = 0 de unnest (je.line_items). Un disparador podría expandirse y guárdelos en una tabla de elementos de línea, donde las restricciones de columnas individuales podrían aplicarse más fácilmente, y donde los índices, etc. podrían ser más útiles. Esta es la dirección en la que me estoy inclinando.
- Podría intentar codificar un activador de restricción que impondría esto por transacción con la idea de que la suma de una serie de 0 siempre será 0.
Las estoy comparando con el enfoque actual de imponer la lógica en un procedimiento almacenado. El costo de la complejidad se compara con la idea de que la prueba matemática de las restricciones es superior a las pruebas unitarias. El principal inconveniente del n. ° 1 anterior es que los tipos como tuplas son una de esas áreas en PostgreSQL donde uno se encuentra con un comportamiento inconsistente y cambios en las suposiciones regularmente, por lo que incluso espero que el comportamiento en esta área pueda cambiar con el tiempo. Diseñar una futura versión segura no es tan fácil.
¿Hay otras formas de resolver este problema que se escalen hasta millones de registros en cada tabla? ¿Me estoy perdiendo de algo? ¿Hay una compensación que me he perdido?
En respuesta al punto de Craig a continuación sobre las versiones, como mínimo, esto tendrá que ejecutarse en PostgreSQL 9.2 y superior (tal vez 9.1 y superior, pero probablemente podamos seguir con la versión 9.2).
fuente
DELETE
. No sabría lo que es típico o requerido en contabilidad, no es mi área de especialización. Solo trato de proporcionar una solución (IMO bastante efectiva) al problema descrito.La siguiente solución de SQL Server usa solo restricciones. Estoy usando enfoques similares en varios lugares de mi sistema.
fuente
dbo.
y elGO
): sql-fiddleFK_Lines_PreviousLine
restricción de clave externa.