Dado que Access no tiene funciones de ventana como PostgreSQL, hay que usar un truco con subconsultas correlacionadas o aprovechar el motor de SQL para acumular datos por producto y fecha.
Supuestos:
Tienes algo como:
TblProductos
IDProducto (clave primaria)
NombreProducto
TblDetalleMov
IDMov (clave primaria)
IDProducto (foránea a tblProductos)
FechaMov
Cantidad (positiva para ingreso, negativa para salida)
Objetivo
Agregar un campo Saldo a la consulta C_DetalleMov que muestre el acumulado histórico de cada producto ordenado por fecha.
Solución:
Usar una subconsulta correlacionada
La forma más efectiva en Access es usar una subconsulta en SQL. Aquí tienes un ejemplo:
SELECT
D1. IDProducto,
D1. FechaMov,
D1. Cantidad,
(
SELECT SUM(D2.Cantidad)
FROM tblDetalleMov AS D2
WHERE D2.IDProducto = D1.IDProducto
AND D2.FechaMov <= D1.FechaMov
AND (D2.IDMov <= D1.IDMov OR D2.FechaMov < D1.FechaMov)
) AS Saldo
FROM tblDetalleMov AS D1
ORDER BY D1. IDProducto, D1. FechaMov, D1.IDMov;
Explicación
Esta subconsulta suma todas las cantidades de movimientos anteriores o iguales (por fecha e ID) al movimiento actual.
El AND D2.IDMov <= D1. IDMov OR D2. FechaMov < D1. FechaMov asegura que si hay varios movimientos el mismo día, se use el IDMov como criterio secundario para evitar duplicación en el saldo.
Consideraciones:
Si tienes muchos datos, esta consulta puede volverse lenta, ya que Access recalcula el saldo para cada fila.
Para mejorar rendimiento, puedes usar consultas de acción para almacenar saldos en una tabla intermedia, actualizándolos cuando sea necesario.
Alternativa con VBA (si lo necesitas)
Si el rendimiento es crítico o necesitas mayor control, puedes hacerlo con código VBA recorriendo los datos y actualizando un campo Saldo en una tabla.
Aquí tienes una solución con VBA en Access para calcular el saldo acumulado por producto y guardarlo en una tabla.
Supuestos de estructura:
Tabla de movimientos: tblDetalleMov
IDMov (clave primaria, autonumérico)
IDProducto (clave foránea)
FechaMov (fecha del movimiento)
Cantidad (positiva = ingreso, negativa = salida)
Saldo (nuevo campo a actualizar)
Campo Saldo ya existe en tblDetalleMov. Si no existe, agrégalo:
Tipo: Número (doble)
Nombre: Saldo
Código VBA para calcular y actualizar el saldo acumulado
Sub CalcularSaldoAcumulado()
Dim db As DAO.Database
Dim rsProductos As DAO.Recordset
Dim rsMovimientos As DAO.Recordset
Dim saldo As Double
Dim strSQL As String
Set db = CurrentDb
' Obtener todos los productos
Set rsProductos = db.OpenRecordset("SELECT IDProducto FROM tblProductos", dbOpenSnapshot)
Do While Not rsProductos.EOF
saldo = 0
' Obtener los movimientos para el producto actual, ordenados por fecha e IDMov
strSQL = "SELECT * FROM tblDetalleMov " & _
"WHERE IDProducto = " & rsProductos!IDProducto & " " & _
"ORDER BY FechaMov, IDMov"
Set rsMovimientos = db.OpenRecordset(strSQL, dbOpenDynaset)
Do While Not rsMovimientos.EOF
saldo = saldo + rsMovimientos!Cantidad
rsMovimientos.Edit
rsMovimientos!Saldo = saldo
rsMovimientos.Update
rsMovimientos.MoveNext
Loop
rsMovimientos.Close
rsProductos.MoveNext
Loop
rsProductos.Close
Set rsMovimientos = Nothing
Set rsProductos = Nothing
Set db = Nothing
MsgBox "Saldos acumulados actualizados correctamente.", vbInformation
End Sub
Cómo usarlo:
Abre el Editor de VBA (Alt + F11).
Inserta un módulo nuevo (Insert > Module).
Pega el código anterior.
Cierra el editor.
En Access, ejecuta la macro desde la ventana de macros o el panel de VBA (F5 en el módulo).
Verifica que el campo Saldo en tblDetalleMov se haya actualizado correctamente.