Autotosumas Parciales en Formulario Access
Me he enganchado con esto que creo que es sencillo pero no lo consigo. Mi versión de Access es : Microsoft® Access® 2016 MSO (versión 2301 compilación 16.0.16026.20002) de 64 bits
Es una Tabla en la que quiero que conforme vaya introduciendo los datos de Importe, me vaya haciendo la suma del Saldo del campo anterior más el valor del nuevo importe.
La Tabla se llama "T Datos". Los campos serían [DESCRIPCION] [IMPORTE] [SALDO]
He utilizado en el campo [SALDO] "Valor Predeterminado" la expresión: =Suma([IMPORTE])+2675,41
(Nota: 2675,41 es el valor inicial en el primer registro del campo [SALDO])
Y con esta expresión me devuelve la Suma de TODOS los valores de [IMPORTE] en cada registro. El mismo valor siempre. Y quisiera que en [SALDO] mantuviera el valor que se de en cada registro y que el siguiente fuera la suma de ese [SALDO] más el nuevo [IMPORTE].
EJ: [DESCRIPCION] [IMPORTE] [SALDO]
Apunte Inicio 0 2675,41
Apunte 2 100 2775,41
Apunte 3 200 2975,41
etc......
Esto me iría bien ponerlo en el Formulario como Procedimiento de Evento "al actualizar" o "al salir" del campo [IMPORTE]
3 Respuestas
En un informe se hace con mucha facilidad, pero en un formulario no es lo mas optimo, si acaso es ...¿imprescindible? Mejor en una consulta (que será el nuevo origen de datos del formulario, la tabla + el dato calculado).
Para que funcione de forma optima se necesita un dato que implique un orden creciente (no es imprescindible que sea correlativo solo que sea creciente).
Como saldo no se toma 'el campo anterior', se toma la suma del campo importe desde su inicio (cero o el saldo anterior) hasta el campo actual (la referencia creciente).
En la consulta se genera el nuevo campo así:
Saldo: DSum("Importe", "[aqui la tabla]", "[CampoCreciente] <= " & [CampoCreciente])
Solo un comentario: el saldo será real y si se modifica un valor se recalcula, la suma la hace 'registro a registro' para obtener el dato (se repetirá tantas veces como datos tenga la tabla).
Por alusiones:
La ventaja de hacer el calculo en una consulta, (el mismo calculo) es que el formulario 'pesa menos' y los datos se visualizaran en cuanto se guarde el registro.
Solo hay que verificar ambos métodos y quedarse con el que se considere mas idóneo (sobre todo al recorrer el formulario).
Una tabla con estos campos:
Id (autonumérico)
Fecha (fecha/hora)
Descripción (texto)
Importe (moneda)
La consulta (en formato SQL)
SELECT Diario.Fecha, Diario.Descripcion, Diario.Importe, DSum("Importe","Diario","Id <=" & [id]) AS Saldo
FROM Diario;
Un formulario basado en esa consulta y el campo saldo se actualizará en cuanto se guarde el registro.
Como 'SALDO' es un campo calculado, no es manipulable ni en la consulta ni el formulario (se le puede desactivar su propiedad 'punto de tabulación' para facilitar la entrada de datos).
- Compartir respuesta
En las tablas no puedes hacerlo, pero me parece descabellado que se diga que en los formularios no se debe. Los formularios se diseñaron como una forma cómoda de meter datos en las tablas. Para poder ver resultados en una consulta previamente tienes que haber metido datos en una tabla, y ¿por qué esperar si puedo verlos en el mismo momento que introduzco los datos?.
Por ejemplo, si tengo la tabla
Y con ella construyo un formulario, da igual único o continuo pero de esta forma se ve mejor
Anoto un valor en Valor1. Puedes ver que el cursor aún está en el control. Cuando pulso Enter
Me anota el primer saldo, y no tengo que tener en cuenta nada. Anoto otro valor y al pulsar Enter
Y así...
Y sólo con decirle, en el evento Después de actualizar del cuadro de texto Valor1
Private Sub Valor1_AfterUpdate() DoCmd.RunCommand acCmdSaveRecord Saldo = DSum("valor1", "tabla1") End Sub
Y me va dejando la tabla como
Pues si que funciona, mira
Al pulsar Enter
Y el código es el que te dije
Private Sub Importe_AfterUpdate() DoCmd.RunCommand acCmdSaveRecord Grupo4 = DSum("importe", "T Datos") End Sub
Lo que no sé si en las propiedades del cuadro de texto Importe-Eventos-Después de actualizar has puesto el cursor en el rectángulo blanco que hay a su derecha y al pulsado el botón de tres puntos(...) y en la ventana que se abre has seleccionado Generador de código.
No se. Algo hay que no cuadra. He repasado el código y he puesto lo mismo.
Y el resultado es que no da ningún valor. La celda queda en blanco.
El nombre del campo donde debe ir el Saldo parcial es "GRUPO4"
Chico, tienes que perdonar el retraso, pero esta página no avisa de la petición de ampliación de respuestas.
Si tengo el formulario, al que sólo le he puesto dos campos de la tabla, y en vista diseño selecciono el control Importe y en sus propiedades-eventos pongo el cursor en el rectángulo de la derecha del evento Después de actualizar, me aparecen una punta de flecha y un botón de tres puntos. Si "despliego" la punta de flecha, me aparece Procedimiento de evento, lo selecciono y luego pulso el botón de los tres puntos(puedes ver que el cursor está a la derecha de Después de actualizar)
Entonces se abrirá el editor de VB, y entre Private Sub... y end sub es donde escribo
Con lo que a medida que voy metiendo datos en el formulario
Muchas gracias por la ayuda.
Esta opción de código que me dices es la que ya tengo puesta y, efectivamente, me va haciendo la suma conforme meto datos nuevos en el campo Importe.
Para que te hagas una idea, en el ejemplo que me has puesto arriba, si tu en el 2º campo que me has puesto, cambias el valor -333,00€ por otro distinto, ya no te mantiene el saldo bien.
Mi problema es que los datos me aparecen desordenados en el tiempo y si después de introducir el dato y que me haga la suma bien, procedo a reordenar la tabla por la Fecha del Valor, los resultados de la columna GRUPO4 (que en realidad es el SALDO) no quedan ordenados ni son correctos.
Para poder tenerlo bien tengo que borrar todos los valores desde el nuevo que quiero meter en su orden de fecha y volver a escribir todo.
Esta acción con Excel como ejemplo, sería: si tienes columnas A (Importe) y B (Saldo), la fórmula sería B2= B1+A2; B3=B2+A3; B4=B3+A4; etc. de forma que no sumara los valores del campo "IMPORTE" sino que tomara el último valor de la columna "GRUPO4" y le sumara el siguiente de la columna "IMPORTE". Así, cada vez que introduzca un nuevo valor, cuando se muestre en el Formulario ordenado por fecha del dato, me haga siempre la suma del saldo en ese Registro a esa fecha.
Tú dirás ¿y por qué no lo haces en Excel? Pues porque en Excel, meter los datos y hacer las operaciones es fácil, pero extraer diferentes consultas por fechas, conceptos, suma de conceptos, etc es más complicado o muy difícil.
Gracias por tu atención.
Te pongo a continuación tres capturas del Formulario para intentar explicar mejor lo que digo.
Tener en cuenta que el Formulario está basado en una Consulta que ORDENA los datos por el campo FECHA, así que cada vez que se cierra y se vuelve a abrir se reordenan todos los registros.
CAPTURA 01: Los datos conforme los voy introduciendo. Los apuntes son correlativos conforme van apareciendo. Las fechas son de cada apunte, no tienen por qué ser correlativas. El saldo está correcto porque va calculando conforme se va introduciendo el dato en IMPORTE.
Aquí el SALDO final es 0. SALDO CORRECTO
CAPTURA 02: Esta es la vista del Formulario tras cerrarlo y volverlo a abrir. Los registros se han reordenado según el criterio de la Consulta por FECHA. Los valores de IMPORTE son correctos pero el SALDO es incorrecto. No ha hecho la suma del valor de IMPORTE más el último valor de SALDO y el resultado en el último registro no es correcto.
Aquí el SALDO final es 500. SALDO INCORRECTO
CAPTURA 03: Esta es una captura de datos "forzada" para que se vean cuál debería ser el comportamiento del Formulario tras cerrar y volver a abrir. En esta vista se ve que las fechas son correlativas independientemente del momento de introducción del Apunte y el SALDO es correcto en todos los Registros.
Aquí el SALDO final es 0. SALDO CORRECTO
Esta última es la acción que necesito en la acción "Después de actualizar" del campo "IMPORTE" para que me ofrezca siempre el SALDO correcto en cada Registro y al Final.
Gracias de nuevo
Voy a tratar de ser lo más sencillo posible. Si tengo el formulario Tabla1 con
Voy a cambiarle el valor del registro de 100 euros
Puedes ver que el cursor aún está en 50,50. Si pulso el botón
En este caso, pero se podría hacer de otras formas, pero me gusta ver, si son muchos registros como se va desplazando por lo registros actualizando valores, el código del botón es
Private Sub Comando7_Click() Dim i As Integer DoCmd.GoToRecord , , acFirst For i = 1 To Me.Recordset.RecordCount Grupo4 = DSum("importe", "tabla1", "idmov <=" & Me.IdMov & "") DoCmd.GoToRecord , , acNext Next End Sub
No sería necesario que se viera el Idmov, pero lo pongo para que dé una idea.
Y el código del evento Después de actualizar del cuadro de texto Importe lo dejo como
Private Sub Importe_AfterUpdate() DoCmd.RunCommand acCmdSaveRecord Grupo4 = DSum("importe", "tabla1", "idmov<=" & Me.IdMov & "") End Sub
La instrucción del botón también te serviría en caso de que decidieras eliminar un registro.
Hola Julián. Gracias por la última información.
Esa solución estaría bien si no modificara el orden del "IdMov" o como lo quieras llamar. Pero es que el orden de ese valor va a cambiar cada vez que cierre y abra el formulario ya que está ordenado por FECHA DEL VALOR y ese valor no tiene por qué coincidir con el momento de la inserción del registro. Por lo tanto se va a volver loco buscando el IdMov anterior menor ya que estarán desordenados.
Pregunto: Esa misma función que me has puesto, ¿se puede usar aplicándosela al campo FECHA en vez de al campo IdMov?
Es que en tu ejemplo no figura el campo FECHA y es el que uso para ordenar los datos.
La cosa sería que el campo SALDO diera el resultado del Registro en el que está, independientemente de su orden de IdMov
Por lo que se ve en la imagen, la fecha contable es la misma para todos los registros, por tanto no la puedes usar como diferenciador de los registros. Pero el primer campo de la izquierda, si guarda un orden. Vamos a suponer que se llama NumOrden. En la instrucción, donde yo pongo IdMov tu puedes poner NumOrden.
No. Fíjate bien. No son la misma fecha.
Son fechas distintas, alguna se repite, pero son distintas.
Al reordenar por fecha todo el saldo se corrompe porque mantiene el valor a pesar de haber cambiado de orden.
Había mirado la primera imagen en la que todos tenían la misma fecha. Tal como la tienes, hay fechas que se repiten, por lo que no puedes usar
<= fecha
Para ello, si tengo tu tabla, le añado un campo auxiliar llamado Orden
Con ella construyo un formulario, donde no sería necesario que se viera el control Orden, pero lo dejo a la vista.
Cuando abro el formulario
En el evento Al cargar del formulario le digo
Private Sub Form_Load() Me.RecordSource = "select * from Ftabla1 order by fecha" Dim i As Integer DoCmd.GoToRecord , , acFirst For i = 1 To Me.Recordset.RecordCount Orden = Me.CurrentRecord DoCmd.RunCommand acCmdSaveRecord Saldo = DSum("importe", "ftabla1", "fecha<=#" & Me.Fecha & "# and orden <=" & Me.Orden & "") DoCmd.GoToRecord , , acNext Next End Sub
Es decir, que el origen de registros del formulario sean aquellos de la tabla ordenados por fecha. Después le digo que se vaya al primer registro, y que al control Orden le asigne el valor del registro en que está en ese momento, y que a su vez me calcule el saldo. Que repita el proceso hasta el final del formulario.
Con lo que si modificas algún valor o eliminas algún registro, cada vez que abras el formulario te "recalculará" todo. El saldo correcto lo tendrás siempre en el formulario no en la tabla, ya que en ella están ordenado por entrada no por fecha.
Yo he puesto como nombre a la tabla el nombre que he visto en el formulario, pero si la tabla se llama de otra forma, por ejemplo, Alumnos tienes que escribirlo como
Me.recordsource="select * from alumnos order by fecha"
Bueno, pues parece que hemos acertado. He hecho varias pruebas y parece que responde bien. He creado una macro asignada a un botón "al hacer click" para que cierre y abra el formulario y así se actualice. .
Una duda, en el campo "ORDEN" donde pongo el numero correlativo de registro, ¿lo tengo que poner a mano o puede ser que se actualice automáticamente a un +1 sobre el último existente?
Ah! y MUCHÍSIMAS GRACIAS por todo el trabajo que has hecho y el tiempo que me has dedicado.
No tienes que hacer nada, observa que la instrucción está en el evento al cargar del formulario. Por tanto, cada vez que abras el formulario ejecuta la instrucción. Pero también, con la tabla abierta, puedes decirle que te ordene de menor a mayor el campo Orden, con lo cual también tendrás en la tabla el saldo correcto en el último registro.
No. Lo que pregunto es si el campo ORDEN puede ser auto numérico.
Por no tener que escribir yo el número
Autonumérico no debe ser, ya que cuando declaras un campo autonumérico pierdes el control sobre él y si eliminas un registro, el autonumérico te marcaría que hay, por ejemplo, 15 registros cuando en realidad hay 14.
Pero, si te has fijado en el código, no hay que escribir nada en Orden. El valor lo coge automáticamente a medida que vas rellenando registros en el formulario.
- Compartir respuesta
Estoy de acuerdo con Julián el indicado es un formulario y es la solución y TOTALMENTE descabellado el concepto de Enrique, este señor siempre repite una respuesta o copia parte de una respuesta de otro, si no da una respuesta con solo texto "cantinflesco"
¡Gracias!
Pues he aplicado el Procedimiento de evento en "despues de actualizar" del campo "IMPORTE" .
Esto he escrito:
Private Sub IMPORTE_AfterUpdate()
DoCmd.RunCommand acCmdSaveRecord
GRUPO4 = DSum("IMPORTE", "T Datos")
End Sub
Y no me funciona. Como resultado me da el campo vacío.
Recuerdo:
Campo "IMPORTE" es donde está el apunte de la cantidad
Campo "GRUPO4" es donde debe aparecer la suma continua.
"T Datos" es el nombre de la Tabla.
¿He hecho algo mal?
¿Pudiera tener algo que ver en que no de resultados el que los "Tipos de Datos" en la Tabla están puestos como "Moneda" ?
¿Deberían ser "Número"?
Si puede envíeme la base de datos con información ficticia a [email protected] y trato de colaborarle.
- Compartir respuesta