Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Sql sumar campo sum() (https://www.clubdelphi.com/foros/showthread.php?t=53260)

teclilla 15-02-2008 17:24:54

Sql sumar campo sum()
 
Hola! que tal? Necesito ayuda con el sql, estoy con una aplicacion para elaborar presupuestos a clientes mediante un formulario, tengo la tabla maestra Tpresupuestos y la tabla detalle TPresProdDetalle en la cual voy añadiendo productos para elavorar el presupuesto, esta última tabla contiene un campo 'Importe' que contiene el importe de cada linea de detalle, el total del presupuesto se encuentra en el campo 'SumaTotal' de Tpresupuestos.
Para realizar la suma utilizo una sql :

Select sum(Importe) as ST from presprod where Codpres= :pres

la funcion que ejecuta la sql es:

procedure TFormPresupuestos.CalcularTotal;
var
total: real;
begin
QSuma.Close;
QSuma.Params[0].AsInteger:=TPresupuestosIdpres.AsInteger;
QSuma.Open;
total:=QSumaST.AsFloat;
TPresupuestosSumaTotal.AsFloat:=total;
end;


se llama en los eventos TPresProdDetalleAfterInsert y TPresProdDetalleAfterDelete, es decir cada vez que modificamos el detalle de la factura para que la SumaTotal se actualice.

Mi problema es que se ejecuta todo bien y no obtengo ningun error, pero nunca me realiza la suma, es decir, la suma siempre es cero, aunque solo tenga un articulo, no se si sera la sql, espero que alguien pueda ayudarme.
Gracias.

Caral 15-02-2008 17:40:13

Hola
Acuerdate de usar las etiquetas.;)
Código SQL [-]
Select sum(Importe) as ST from presprod where Codpres= res

Código Delphi [-]
procedure TFormPresupuestos.CalcularTotal;
var
total: real;
begin
QSuma.Close;
QSuma.Params[0].AsInteger:=TPresupuestosIdpres.AsInteger;
QSuma.Open;
total:=QSuma.FileByName('ST').Value;
TPresupuestosSumaTotal.AsFloat:=total;
end;

Saludos

enecumene 15-02-2008 18:21:58

Hola, primero que todo deberias especificar que base de datos utilizas, Access, Mysql que componentes usas ADO, Zeos, BDE, etc., en fin, creo que el codigo debe ser asi:

Si es en Access.

Código Delphi [-]
procedure TFormPresupuestos.CalcularTotal;
var
total: real;
begin
QSuma.Close;
QSuma.Parameters.ParamByName('Pres').Value:=TPresupuestosIdpres.AsInteger;
QSuma.Open;
total:=QSuma.FileByName('ST').Value;
TPresupuestosSumaTotal.AsFloat:=total;
end;

Si es en Mysql con ZEOS u otra base de datos o componentes :

Código Delphi [-]
procedure TFormPresupuestos.CalcularTotal;
var
total: real;
begin
QSuma.Close;
QSuma.ParamByName('Pres').Value:=TPresupuestosIdpres.AsInteger;
QSuma.Open;
total:=QSuma.FileByName('ST').Value;
TPresupuestosSumaTotal.AsFloat:=total;
end;
Saludos.

teclilla 15-02-2008 20:16:56

Hola Caral, :) muchas gracias por tu respuesta, (disculpa por las etiquetas soy nueva en el foro), he cambiado el siguiente codigo :

Código Delphi [-]
total:=QSuma.FieldByName('ST').Value;

y me da el siguiente error:
'Invalid variant type conversion'

:confused:

enecumene 15-02-2008 20:20:28

Hola, tiene que ser asi:

Código Delphi [-]
total:=QSuma.Fields[0].Value;

Saludos.

Caral 15-02-2008 20:22:02

Hola
El campo es Real osea Double.
La suma es double, el nombre del campo es Importe conocido como ST, no veo el error, tal vez asi?
Código Delphi [-]
total:=QSuma.FileByName('Importe').Value;
No se, inténtalo, pero es extraño.
Saludos

teclilla 15-02-2008 21:10:43

Muchas gracias por la respuesta, uso Paradox 7 (disculpad por no haberlo dicho antes), he añadido esto a la función:
Código Delphi [-]
procedure TFormPresupuestos.CalcularTotal;
var
        import, total: real;
begin
        import:=TPresProdDetalle.FieldByName('Importe').asFloat;
        QSuma.Close;
        QSuma.Params[0].AsInteger:=TPresupuestosIdpres.AsInteger;
        QSuma.Open;
        total:=QSuma.FieldByName('ST').Value;
        TPresupuestosSumaTotal.AsFloat:=total;
end;
y ejecuto paso a paso para depurar y resulta que el TPresProdDetalle es tabla detalle y hasta que no confirmo el presupuesto no realizo TPresProdDetalle, no se si el error puede venir por ahí, ya que si pruebo solo con un producto en el detalle el importe que recoge es un numero erroneo, a pesar de que a esta funcion se le llama en el evento TPresProdDetalleAfterInsert, no se si vosotros tendreis alguna idea. Muchas Gracias.

Caral 15-02-2008 21:35:48

Hola
No dices si te da problemas o que problemas te da, cero que no da la informacion?.
Haz este y veras que dato envia:
Código Delphi [-]
procedure TFormPresupuestos.CalcularTotal;
var
        import, total: real;
begin
        import:=TPresProdDetalle.FieldByName('Importe').asFloat;
        QSuma.Close;
        QSuma.Params[0].AsInteger:=TPresupuestosIdpres.AsInteger;
        QSuma.Open;
        total:=QSuma.FieldByName('ST').Value;
        
        ShowMessage(import);
        ShowMessage(total);

        TPresupuestosSumaTotal.AsFloat:=total;
end;
Asi veremos quien es el que tiene la informacion, supongo.
Saludos

teclilla 15-02-2008 22:42:47

import = 0
y genera el error 'Invalid variant type conversion'
Código Delphi [-]
import:=TPresProdDetalle.FieldByName('Importe').asFloat;
        ShowMessage(FloatToStr(import));
        QSuma.Close;
        QSuma.Params[0].AsInteger:=TPresupuestosIdpres.AsInteger;
        QSuma.Open;
        total:=QSuma.FieldByName('ST').Value; //genera el error
        ShowMessage(FloatToStr(import));
        TPresupuestosSumaTotal.AsFloat:=total;
Muchas gracias Caral

Caral 15-02-2008 23:17:37

Hola
Segun me dicen ST tiene un valor NULL, por eso manda el error.
No se a que se debe, se supone que es la suma del campo importe y si este contiene datos no deberia dar ese problema.
Para mi por alguna razon no esta reconociendo ST como un campo.
Quedo un poco corto en la apreciacion del problema, no lo termino de entender.
Espero lo puedas solucionar, o esperar a un maestro, ya vendrán.:)
Saludos

Lepe 16-02-2008 12:06:16

total:=QSuma.FieldByName('ST').AsFloat;

Ya que trabajas con paradox, usa AsFloat, te convertirá el dato NULL por un cero (y no muestra error).

.Value es de tipo Variant, y si no tiene nada asignado o tiene el valor especial NULL, devolverá Unassigned o NULL, y como esos valores no tienen correspondencia con un real, delphi lanza la excepción.

las propiedades Asxxxxx si realizan la conversión.

Por cierto, dale una visual a la ayuda "data types", puede que un Float se más grande que un real, y obtengas errores en ejecución. (Mira el valor máximo que puede guardar cada tipo de dato).

Saludos

Saludos

teclilla 16-02-2008 13:19:36

Muchas gracias lepe, lo he cambiado pero creo que es la sql la que no la realiza bien, ¿como puedo mostrar el resultado de la query por pantalla antes de convertirla a float y asignarla a una variable?
Gracias.

teclilla 16-02-2008 13:27:52

Creo que el tema va por aquí, cuando doy de alta un presupuesto mediante formulario inserto 1 producto, calculo el importe y me da 850,00 y despues calculo el total:
Código Delphi [-]
procedure TFormPresupuestos.CalcularTotal;
var
        total: real;
begin
        QSuma.Close;
        QSuma.Params[0].AsInteger:=TPresupuestosIdpres.AsInteger;
        QSuma.Open;
        ShowMessage(VarToStr(QSumaST.Value)); // me da 0
        total:=QSumaST.AsFloat;
        ShowMessage(FloatToStr(total));
        TPresupuestosSumaTotal.AsFloat:=total;
end;
creo que la sql no la realiza bien,
Código SQL [-]
size="1">
Select sum(Importe) as ST from presprod where Codpres= :pres
group by Codpres
en Importe en teoría debe contener 850,00 con lo cual al haber un solo producto este deberia ser el resultado de la query.
Gracias por vuestra ayuda.

Lepe 16-02-2008 13:38:07

El sql ten por seguro que funciona, la función Sum lleva "un par de días inventada" ;).

quizás aun no hayas guardado el presupuesto y por ello el valor de idpres es igual a cero o null.

Ten en cuenta los posibles valores nulos, si existe un importe a Null, la función Sum devuelve null según el standard del SQL.

Saludos

Caral 16-02-2008 14:35:43

Hola
Lo mas seguro es que me equivoque, pero:
1- La sentencia sql seguro la tienes dentro del query y en la pantallita tendras el campo?.
2- Si ves la secuencia que usas, veras que cierras la tabla antes de darle el parametro (QSuma.Close;) eso no es correcto.
Yo lo haria por codigo asi:
Código Delphi [-]
procedure TFormPresupuestos.CalcularTotal;
var
        total: real;
begin
        QSuma.Sql.Text:= 'Select sum(Importe) as ST from presprod where Codpres =  :res group by Codpres ';
        QSuma.Params[0].AsInteger:=TPresupuestosIdpres.AsInteger;
        QSuma.Open;
        ShowMessage(VarToStr(QSumaST.Value));
        total:=QSuma.Files[0].AsFloat;
        ShowMessage(FloatToStr(total));
        TPresupuestosSumaTotal.AsFloat:=total;
end;
Saludos

teclilla 16-02-2008 16:40:56

Siendo que 'presprod' es una tabla detalle de 'presupuestos' con los cual los campos id deben coincidir, ¿estará mal la sql? a la hora de calcular la suma las tablas están en modo appen y no se ha realizado un post por si el usuario no quiere confirmar el presupuesto y desea cancelar. No lanza ningun error y la aplicacion funciona, la suma siempre es 0, pero si que hay un linea (record) con importe 850,00 creo al menos sum deberia ser 850
:confused:
Código SQL [-]
 
Select sum(Importe) as ST from presprod where Codpres= :res
group by Codpres
Muchas gracias.

Lepe 16-02-2008 17:43:11

Cita:

Empezado por teclilla
Siendo que 'presprod' es una tabla detalle de 'presupuestos' con los cual los campos id deben coincidir,

¿Cuando le das valores a presid y a prespod? Porque si usas un autoincrmento, se hará al guardar el registro. Todo lo que hagas antes de guardar, presid y prespod tendrán un cero patatero.

La suma la hace bien, pero no encuentra nada que sumar.

Paradox no copia automáticamente el valor de las claves de la tabla Maestra a la detalle, debes hacerlo tú por código. Me da la impresión de que le das un valor a presid de la tabla maestra, pero no lo asignas a la tabla detalle (codpres).

Saludos

teclilla 16-02-2008 17:56:22

idpre y codpres son de tipo longint, al dar de alta un presupuesto le pongo por codigo el idpres y en la tabla detalle al dar de alta el primer detalle tambien codpres tiene el valor correcto el mismo de idpres (el cual se muestra en el dbgrid) con lo cual esto lo asigna bien a la sql, ¿no será que las dos tablas estan en modo edicion y se deberia haber realizado el post?
:confused: Gracias.

Lepe 16-02-2008 18:04:52

La de detalle debería estar guardada.

Otra posibilidad es usar el evento OnCalcFields mientras se está editando, cambiará inmediatamente los totales.

Saludos

teclilla 16-02-2008 18:21:47

Queria probar esto ultimo que me has comentado, ya que estoy un poco desesperada, ¿podrias indicarme un ejemplo de como usar el evento OnCalcFields?
Muchas gracias por todo.

teclilla 16-02-2008 18:48:45

Creo que he resuelto el tema, me he creado una variable global donde voy guardando los importes de cada linea y mediante codigo los sumo y lo asigno al campo Suma Total del presupuesto de la tabla maestra y funciona de maravilla. Pero ahora tengo otro pequeño problemilla, resulta que si en la tabla detalle introduzco varias lineas de productos, al pasar a la segunda linea me realiza un post de la primera y claro, si el usuario despues de tener rellenado el presupuesto quiere cancelarlo, el presupuesto se cancela de la tabla maestra y la ultima fila de la tabla detalle tambien (es decir, no se graban) pero las anteriores de la tabla detalle si, con lo cual tendria registros en la tabla detalle que no hacer referencia a la tabla maestra, ¿se os ocurre algo?
Muchas gracias por vuestra ayuda. :)

Lepe 16-02-2008 18:55:58

Antes de borrar un registro en la maestra, evento beforedelete, haces que el usuario confirme el borrado y lanzas una sql:
Código SQL [-]
delete from prespod where codpres= :res

Saludos

Caral 16-02-2008 19:07:14

Hola
Perdón que me meta pero no os parece que estáis matando moscas a cañonazos?.:confused::D
Lo que se pretende es hacer una suma de un campo de una tabla y mostrar el resultado.
La tabla Presupuesto va adquiriendo los datos segun se van introduciendo y el campo importe es el que se suma.
Cual es el asunto de fondo, por que hacer una variable que despues se tendra que borrar.
La verdad no entiendo cual es el problema que a mi corto parecer y conocimiento deberia de ser simple.
Me lo podeis explicar, sinceramente no entiendo.
En tal caso en vez de un cañon no es mejor un misil.:D:D
Saludos

teclilla 16-02-2008 19:34:14

El problema es que al estar las tablas en modo edicion y no haber realizado un post, no realiza la sql
Código SQL [-]
Select sum(Importe) as ST from presprod where Codpres= :res
group by Codpres
sino, no entiendo porque el resultado siempre es cero

Caral 16-02-2008 19:46:36

Hola
Cita:

Escrito por ti:

Hola! que tal? Necesito ayuda con el sql, estoy con una aplicacion para elaborar presupuestos a clientes mediante un formulario, tengo la tabla maestra Tpresupuestos y la tabla detalle TPresProdDetalle en la cual voy añadiendo productos para elavorar el presupuesto, esta última tabla contiene un campo 'Importe' que contiene el importe de cada linea de detalle, el total del presupuesto se encuentra en el campo 'SumaTotal' de Tpresupuestos.
Para realizar la suma utilizo una sql :
La tabla Presupuestos tiene los datos, osea que ya estan ahi.
La tabla PresProdDetalle va capturando los datos, osea que tambien estan ahi, si no fuera asi entonces no iría añadiendo nada, o no?.

Para añadir datos se tiene que insertar (NO editar) y hacer el post.

Sigo sin entender.
Saludos

teclilla 16-02-2008 20:15:33

Si es cierto, pero si entonces ¿cual es la explicacion de que la suma de importe siempre se cero? los codigos tanto de presupuesto como del detalle estan bien y he comprobado que no son nulos. Necesito que realice la suma para que el presupuesto tenga un total, y no se la razon de porqué siempre es 0.

Lepe 16-02-2008 22:53:12

teclilla, ¿no tendrás activada en el inspector de objetos la propiedad Cache updates en alguna tabla ¿no?

Por otra parte, se me ha escapado el tema de FlushBuffers, lo siento.

En todas tus tablas, en el evento AFTERPOST añade:
Código Delphi [-]
tablaQuesea.FlushBuffers;
Para que todo cambio hecho, se grabe inmediatamente a las tablas. Ahora mismo, puede pasar algunos segundos /minutoas hasta que se graben físicamente los registros, y ahí puede estar el problema, la suma se hace antes de que estén grabados.

... Se me agotan las ideas :confused:

Bien es verdad que se podía usar el evento OnChange del campo Bimponible y allí realizar todas las operaciones, incluso modificar el total de la tabla maestra, pero quizás se forme un lío de eventos (la tabla detalle se modifica a sí misma que provoca otro cambio Onchange, y además modifica la tabla Maestra, ummm, mejor por SQL :D.

Saludos

teclilla 17-02-2008 18:50:15

No, no tengo activada la opción Cache Updates en ninguna tabla, y sigo sin entender porque no realiza la suma, así que de momento lo dejare con la variable global, ya que necesito avanzar en el programa. Si despues tengo algun problema seguiré investigando y si averiguo lo que es, os avisaré en seguida. Muchas gracias por vuestra ayuda.
Muy agradecida, teclilla.


La franja horaria es GMT +2. Ahora son las 00:47:54.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi