Diseño de la base de datos: cálculo del saldo de la cuenta

¿Cómo diseño la base de datos para calcular el saldo de la cuenta?

1) Actualmente calculo el saldo de la cuenta de la tabla de transacciones En mi tabla de transacciones tengo “descripción” e “importe”, etc.

Luego sumría todos los valores de “cantidad” y eso resolvería el saldo de la cuenta del usuario.


Le mostré esto a mi amigo y me dijo que no era una buena solución, ¿cuando mi base de datos crezca va a disminuir? Dijo que debería crear una tabla separada para almacenar el saldo calculado de la cuenta. Si lo hiciera así, tendré que mantener dos tablas, y es arriesgado, que la tabla de saldo de la cuenta no esté sincronizada.

¿Cualquier sugerencia?

EDITAR : OPCIÓN 2: ¿debo agregar una columna adicional a mis tablas de transacciones “Balance”? ahora no necesito pasar por muchas filas de datos para realizar mi cálculo.

Ejemplo John compra $ 100 de crédito, la deuda $ 60, luego agrega $ 200 de crédito.

Cantidad $ 100, Balance $ 100.

Monto: $ 60, saldo $ 40.

Cantidad $ 200, Balance $ 240.

Un problema ancestral que nunca se resolvió con elegancia.

Todos los paquetes bancarios con los que he trabajado almacenan el saldo con la entidad de la cuenta. Cálculo sobre la marcha del historial de movimiento es impensable.

El camino correcto es:

  • La tabla de movimientos tiene una transacción de ‘saldo inicial’ para cada cuenta. Lo necesitará dentro de unos años cuando necesite mover movimientos antiguos de la tabla de movimiento activo a una tabla de historial.
  • La entidad de cuenta tiene un campo de saldo
  • Hay un disparador en la tabla de movimientos que actualiza los saldos de las cuentas acreditadas y cargadas. Obviamente, tiene control de compromiso. Si no puede tener un activador, entonces debe haber un módulo único que escriba movimientos bajo control de compromiso
  • Usted tiene un progtwig de “red de seguridad” que puede ejecutar sin conexión, que vuelve a calcular todos los saldos y pantallas (y opcionalmente corrige) los saldos erróneos. Esto es muy útil para las pruebas.

Algunos sistemas almacenan todos los movimientos como números positivos y expresan el crédito / débito invirtiendo los campos de / a o con una bandera. Personalmente, prefiero un campo de crédito, un campo de débito y una cantidad firmada, esto hace que las reversiones sean mucho más fáciles de seguir.

Tenga en cuenta que estos métodos se aplican tanto al efectivo como a los valores.

Las transacciones de valores pueden ser mucho más complicadas, especialmente para acciones corporativas, deberá acomodar una transacción única que actualice uno o más saldos de caja de comprador y vendedor, sus saldos de posición de seguridad y posiblemente el intermediario / depósito.

Debe almacenar el saldo de la cuenta stream y mantenerlo actualizado en todo momento. La tabla de transacciones es solo un registro de lo que sucedió en el pasado y no debe usarse con una frecuencia alta solo para recuperar el saldo actual. Considere que muchas consultas no solo quieren saldos, sino que también quieren filtrar, clasificar y agrupar, etc. La penalización de rendimiento de sumr cada transacción que haya creado en medio de consultas complejas paralizaría incluso una base de datos de tamaño modesto. .

Todas las actualizaciones de este par de tablas deben estar en una transacción y deben garantizar que todo permanezca sincronizado (y la cuenta nunca se sobregire más allá de su límite) o que la transacción retroceda. Como medida adicional, puede ejecutar consultas de auditoría que verifican esto periódicamente.

Una solución común a este problema es mantener (por ejemplo) un saldo de apertura mensual en un esquema de instantáneas. El cálculo del saldo actual se puede hacer agregando datos transaccionales del mes al saldo mensual de apertura. Este enfoque a menudo se toma en los paquetes de cuentas, especialmente en los casos en los que podría tener conversión de moneda y revalorizaciones.

Si tiene problemas con el volumen de datos, puede archivar los saldos anteriores.

Además, los saldos pueden ser útiles para informar si no tiene un almacén de datos externo dedicado o un servicio de informes de gestión en el sistema.

Por supuesto, necesita almacenar su saldo actual con cada fila, de lo contrario, es demasiado lento. Para simplificar el desarrollo, puede usar restricciones, para que no necesite desencadenantes y comprobaciones periódicas de la integridad de los datos. Lo describí aquí. Desnormalización para hacer cumplir las reglas comerciales: correr totales

Tu amigo está equivocado y tienes razón, y te aconsejaría que no cambies las cosas ahora.
Si su db alguna vez se vuelve lento debido a esto, y después de haber verificado todo el rest (indexación adecuada), puede ser útil cierta desnormalización.
Luego puede colocar un campo BalanceAtStartOfYear en la tabla Cuentas y resumir solo los registros de este año (o cualquier enfoque similar).
Pero ciertamente no recomendaría este enfoque por adelantado.

Aquí le gustaría sugerirle cómo puede almacenar su saldo de apertura de una manera muy simple:

  1. Cree una función desencadenante en la tabla de transacciones para que se llame solo después de la actualización o inserción.

  2. Cree una columna con el nombre en la tabla maestra de nomenclatura del saldo de apertura.

  3. guarde su saldo inicial en conjunto en la columna de saldo inicial en la tabla maestra.

  4. ni siquiera necesita usar el lenguaje del lado del servidor use esta matriz de almacenamiento simplemente puede usar funciones de matriz de base de datos disponibles en PostgreSQL.

  5. cuando desee volver a calcular su saldo de apertura en conjunto, simplemente agrupe su tabla de transacciones con la función de matriz y actualice toda la información en la tabla maestra.

He hecho esto en PostgreSQL y estoy trabajando bien.

durante el período de tiempo en que su tabla de transacciones se volverá pesada, entonces puede particionar para su tabla de transacciones sobre la base de la fecha para acelerar el rendimiento. este enfoque es muy fácil y no necesita utilizar ninguna tabla adicional que pueda ralentizar el rendimiento si se une a la tabla porque una tabla menor en la unión le dará un alto rendimiento.

Este es un diseño de base de datos que obtuve con una sola tabla solo para almacenar un historial de operaciones / transacciones. Actualmente funciona como encanto en muchos proyectos pequeños.

Esto no reemplaza un diseño específico. Esta es una solución genérica que podría adaptarse a la mayoría de las aplicaciones.

id : int id de fila estándar

operation_type : int tipo de operación. pagar, cobrar, interesar, etc.

source_type : int desde donde procede la operación. tabla o categoría objective: usuario, banco, proveedor, etc.

source_id : int id de la fuente en la base de datos

target_type : int a qué se aplica la operación. tabla o categoría objective: usuario, banco, proveedor, etc.

target_id : int id del objective en la base de datos

cantidad : valor de precio decimal (19,2 firmado) positivo o negativo por sumdo

saldo_de_tabla : saldo resultante (19,2 firmado) resultante

extra_value_a : decimal (19,2 signed) [esta fue la opción más versátil sin usar el almacenamiento de cadenas] puede almacenar un número adicional: porcentaje de interés, un descuento, una reducción, etc.

created_at : timestamp

Para el tipo_origen y tipo_destino, sería mejor usar una enumeración o tablas appart.

Si desea un saldo en particular, puede consultar la última operación clasificada por created_at descender limit en 1. Puede consultar por origen, destino, tipo de operación, etc.

Para un mejor rendimiento, se recomienda almacenar el saldo actual en el objeto de destino requerido.

Mi enfoque es almacenar los débitos en una columna de débito, crédito en la columna de crédito y, al recuperar los datos, crear dos matrices, matriz de débito y crédito. A continuación, agregue los datos seleccionados a la matriz y haga esto para python:

def real_insert(arr, index, value): try: arr[index] = value except IndexError: arr.insert(index, value) def add_array(args=[], index=0): total = 0 if index: for a in args[: index]: total += a else: for a in args: total += a return total 

entonces

 for n in range(0, len(array), 1): self.store.clear() self.store.append([str(array[n][4])]) real_insert(self.row_id, n, array[n][0]) real_insert(self.debit_array, n, array[n][7]) real_insert(self.credit_array, n, array[n][8]) if self.category in ["Assets", "Expenses"]: balance = add_array(self.debit_array) - add_array(self.credit_array) else: balance = add_array(self.credit_array) - add_array(self.debit_array) 

Respuesta simple: Haz los tres.

Almacenar el saldo actual; y en cada transacción almacenar el movimiento y una instantánea del saldo actual en ese momento. Esto daría algo adicional para conciliar en cualquier auditoría.

Nunca he trabajado en sistemas bancarios centrales, pero he trabajado en sistemas de administración de inversiones, y en mi experiencia así es como se hace.