PDA

Ver la Versión Completa : Delphi y los procedimientos almacenados


efelix
30-10-2006, 17:29:03
Hola a todos, muchos saludos. Trabajo con delphi 7 y Microsoft Sql Server 2000. Tengo el siguiente procedimiento almacenado:

CREATE PROCEDURE spEdadCuentasporPagar
@Edad int,
@Edad1 int = NULL
AS
IF (@Edad1 IS Null)
begin
SELECT @Edad1 = 0
end
IF (@Edad >= 90)
BEGIN
SELECT IdFactura, Descripcion, IdProveedor, Importe, DATEDIFF(day, FechaRecepcion, GETDATE()) AS Dia, Aplicada
FROM Facturas
WHERE (Aplicada = 0) AND DATEDIFF(day, FechaRecepcion, GETDATE())>=@Edad
END
ELSE
BEGIN
SELECT IdFactura, Descripcion, IdProveedor, Importe, DATEDIFF(day, FechaRecepcion, GETDATE()) AS Dia, Aplicada
FROM Facturas
WHERE (Aplicada = 0) AND DATEDIFF(day, FechaRecepcion, GETDATE())>=@Edad AND DATEDIFF(day, FechaRecepcion, GETDATE())<=@Edad1
END
GO


Que me devuelve un conjunto de registros que cumplen con la condición que lleva implicita el procedimiento. Y tengo otro procedimeinto almacenado construído de la sgte forma:

CREATE PROCEDURE spImporteTotalEdadCuentasxPagar
(@Dias integer,
@Dias1 integer,
@Importe money OUTPUT)
AS
SELECT @Importe=IsNull(Sum(Importe),0)
FROM Facturas
WHERE(Aplicada=0) AND DATEDIFF(day,FechaRecepcion, GETDATE())>=@Dias AND DATEDIFF(day,FechaRecepcion, GETDATE())<=@Dias1
GO


El primer procedimiento me devuelve el conjunto de facturas que están sin pagar dentro del rango de días que se le específique, que puede ser 0-30,30-60,60-90 y mas de 90 días. Y el segundo lo cnstruí con la finalidad de que me devoviera el importe total de las facturas sin pagar. Esto funciona bien en sql server 2000, es decir cada procedimiento por separado lo ejecuto pasandóle los parámetros correspondientes y me dan los resultados deseados. Ahora en delphi tengo un formulario con un ado connection, un ado stored procedure, un dbgrid, tres edit y un botón de comando y por supuesto un data source, a través del siguiento código logro que el dbgrid se me llene con los datos que me devuelve el primer procedimiento almecenado:

begin
ADOSPEdadCuentas.Close;
ADOSPEdadCuentas.Parameters.ParamByName('@Edad').Value := StrToInt(EditEdad2.Text);
if StrToIntDef(EditEdad2.Text,0) = 90 then
begin
ADOSPEdadCuentas.Parameters.ParamByName('@Edad1').Value := VarNull;
end
else
ADOSPEdadCuentas.Parameters.ParamByName('@Edad1').Value := StrToInt (EditEdad1.Text);
ADOSPEdadCuentas.Open;
end;

El segundo procedimiento almacenado lo tengo nada más para que me devuelva el total de las facturas sin pagar, y pienso asignarle el valor de este parámetro a un edit, ahora mi duda es la siguiente puedo manipular ambos procedimientos dentro de las mismas líneas de códigos anteriores?. Puesto como pueden pareciar este segundo procedimiento almacenado tiene un parámetro de salida y para hecerlo tendría que ejecutar el método execpro para que funcione, al menos eso es lo que tengo entendido, el hecho es que se me complica un tanto esto y aveces cuando trato de hacerlo me genera varios errorres. Ojala me hayan enetendido y puedan ayudarme a encontrar una solución. A lo mejor en vez de dos con un solo procedmiento almecenado yo podría resolver esto. Pero hasta el momento no se como hacerlo. Muchas gracias y disculpen mi desconocimiento.

Lepe
30-10-2006, 19:39:11
No estoy ducho en sqlServer, pero si un procedimiento te devuelve datos (para mostrar en un Grid, por ejemplo, si deseas usar ese mismo componente para llamar al segundo SP tendrás que cerrarlo, configurarlo y abrirlo de nuevo, por tanto pierdes el resultado del grid.

Lo que quiero decir es que debes usar:
- O bien 2 AdoSP.
- O bien abrir primero el que da los totales, guardas el resultado en un Edit (u otro control que no sea de Acceso a datos dbaware), por último lo cierras, modificas las propiedades del AdoSP para llamar al primer SP y dejas abierto dicho SP.


Como verás el segundo método es bastante lioso, y si necesitas solicitar de nuevo los totales, implica doble trabajo, quizás sea más cómodo usar 2 AdoSP.

Saludos

donki
30-10-2006, 19:41:58
Te propongo lo siguiente:

El código del segundo lo añades al primero y lo calculas al principio guardando el valor en @Importe.

Esta variable la añades como una columna añadida más en tus queries siguientes o bien lo pones como parámetro de salida.


Suerte!!!

efelix
01-11-2006, 15:03:00
Lepe te doy las gracias nuevamente por tus rápidas respuesta, seguí tu consejo y agregué al formulario un nuevo ado stored procedure, modifiqué el segundo procedimiento almacenado de la siguiente forma:

CREATE PROCEDURE spImporteTotalEdadCuentasxPagar
(@Dias integer,
@Importe money OUTPUT,
@Dias1 integer = NULL)
AS
IF (@Dias1 IS Null)
begin
SELECT @Dias1=0
end

IF (@Dias>=90)
BEGIN
SELECT @Importe=IsNull(Sum(Importe),0)
FROM Facturas
WHERE(Aplicada=0) AND DATEDIFF(day,FechaRecepcion, GETDATE())>=@Dias AND DATEDIFF(day,FechaRecepcion, GETDATE())<=@Dias1
END
ELSE
BEGIN
SELECT @Importe=IsNull(Sum(Importe),0)
FROM Facturas
WHERE(Aplicada=0) AND DATEDIFF(day,FechaRecepcion, GETDATE())>=@Dias AND DATEDIFF(day,FechaRecepcion, GETDATE())<=@Dias1
END
GO

y en código del evento click del botón de comando pusé lo siguiente:

begin
ADOSPEdadCuentas.Close;
ADOSPEdadCuentas.Parameters.ParamByName('@Edad').Value := StrToInt(EditEdad2.Text);
ADOSPImporteCuentasxPagar.Parameters.ParamByName('@Dias').Value := StrToInt(EditEdad2.Text);
if StrToIntDef(EditEdad2.Text,0) = 90 then
begin
ADOSPEdadCuentas.Parameters.ParamByName('@Edad1').Value := VarNull;
ADOSPImporteCuentasxPagar.Parameters.ParamByName('@Dias1').Value := VarNull;
end
else
ADOSPEdadCuentas.Parameters.ParamByName('@Edad1').Value := StrToInt (EditEdad1.Text);
ADOSPImporteCuentasxPagar.Parameters.ParamByName('@Dias1').Value := StrToInt (EditEdad1.Text);
ADOSPImporteCuentasxPagar.ExecProc;
EditImporte.Text := ADOSPImporteCuentasxPagar.Parameters.ParamValues ['@Importe'];
ADOSPEdadCuentas.Open;
end;

Cuando lo ejecuto, es decir cuando click en el botón de coamando me duveuelve el siguiente mensaje de error, se levanta una excepción en la clase EConvertError with the message is not a valid integer value. He mirado, pero estoy como el pescado en nevera, no encuentro donde está el error. Gracias amigo y disculpa tanta molestia.

efelix
01-11-2006, 15:05:28
Hola, gracias por tu sugerencia, pero no entiendo lo que me dijiste, me gustaría si pudieras fueses un poco mas explicito. Pues todavía tengo lagunas en el trabajo con los procedimientos alamacenados.

donki
02-11-2006, 16:02:12
Por lo que me comentas creo que solo puede ser problema de la linia

EditImporte.Text := ADOSPImporteCuentasxPagar.Parameters.ParamValues ['@Importe'];


Mira de hacer la conversión a mano junto con un try except...

Saludos

Lepe
02-11-2006, 19:07:34
Yo de refilón he visto otro detalle:

else begin
ADOSPEdadCuentas.Parameters.ParamByName('@Edad1').Value := StrToInt (EditEdad1.Text);
ADOSPImporteCuentasxPagar.Parameters.ParamByName('@Dias1').Value := StrToInt (EditEdad1.Text);
end;
ADOSPImporteCuentasxPagar.ExecProc;
EditImporte.Text := ADOSPImporteCuentasxPagar.Parameters.ParamValues ['@Importe'];
ADOSPEdadCuentas.Open;
end;
Aunque el código original está bien identado, falta el begin .. end del else, espero que sea error de copiar y pegar.

Saludos

vinicc
03-11-2006, 18:58:51
:) Hola, a vista de pájaro vi tu sp, muy bueno. hace poco hice uno parecido utilizando un editmask, pero tuve que anteponer un trim para evitar que me diera problemas con un digitador malicioso. posiblemente no sea tu caso pero OJO con eso. (StrToInt(Trim(EditMask1.text)))

ok.

efelix
03-11-2006, 20:57:48
Muchas gracias a todos por sus respuestas, da cada uno de ustedes he aprendido algunas cosas nuevas. El segundo procedimiento almacenado lo he modificado de la siguiente manera:

CREATE PROCEDURE spImporteTotalEdadCuentasxPagar
(@Dias integer,
@Dias1 integer = NULL,
@Importe money OUTPUT)

AS

IF (@Dias>=90)
BEGIN
SELECT @Importe=IsNull(Sum(Importe),0)
FROM Facturas
WHERE(Aplicada=0) AND DATEDIFF(day,FechaRecepcion, GETDATE())>=@Dias
END
ELSE
BEGIN
SELECT @Importe=IsNull(Sum(Importe),0)
FROM Facturas
WHERE(Aplicada=0) AND DATEDIFF(day,FechaRecepcion, GETDATE())>=@Dias AND DATEDIFF(day,FechaRecepcion, GETDATE())<=@Dias1
END
GO

Para el caso de que se quiera ver el importe total de las facturas com mas de 90 días. El otro procedimiento almacenado (el primero), se ha quedado igual. Ahora que me sucede, vean el código del evento click del botón de coamndo en el formulario:

begin
ADOSPEdadCuentas.Close;
ADOSPEdadCuentas.Parameters.ParamByName('@Edad').Value := StrToInt(Trim(EditEdad2.Text));
ADOSPImporteCuentasxPagar.Parameters.ParamByName('@Dias').Value := StrToInt(Trim(EditEdad2.Text));
if StrToIntDef(EditEdad2.Text,0) = 90 then
begin
ADOSPEdadCuentas.Parameters.ParamByName('@Edad1').Value := VarNull;
ADOSPImporteCuentasxPagar.Parameters.ParamByName('@Dias1').Value := VarNull;
end
else
begin
ADOSPEdadCuentas.Parameters.ParamByName('@Edad1').Value := StrToInt (Trim(EditEdad1.Text));
ADOSPImporteCuentasxPagar.Parameters.ParamByName('@Dias1').Value := StrToInt (Trim(EditEdad1.Text));
ADOSPImporteCuentasxPagar.ExecProc;
EditImporte.Text := ADOSPImporteCuentasxPagar.Parameters.ParamValues ['@Importe'];
ADOSPEdadCuentas.Open;
end;

end;

Recuerden que el segundo procedimiento almacenado es solamente para que me de el total según el rango de edad que haya puesto, bueno esto me funciona perfectamente bien, siempre que en los dos edit ponga valores, exceptuando cuando en el primer edit pongo el valor 90, que solamente debe darme las facturas con mas de 90 días y pasar el valor del parámetro de salida al edit que he establecido para ello, pero no es así, cuando pongo 90 en el primer edit y hago click no se me genera ningún error, pero no me muestra ningún resultado, y el edit donde va a parar el importe total se queda con el valor anterior, por ejemplo si pongo entre 30-60 días me muestra en el dbgrid las faturas pendientes de pago para ese rango y me totaliza en el edit el importe total para este rango, sin embargo cuando pongo 90 en el primer edit y hago click no me muestra nada y se queda en el edit el resultado anterior, y en la base de datos hay 4 facturas con mas de 90 días sin pagar. He chequeado el código varias veces y no veo donde puede estar el problema. Disculpen tanta molestia, espero puedan ayudarme una vez mas.

Lepe
04-11-2006, 14:43:20
Normal, estas 2 líneas tienen que estar fuera del begin.. end (del else) para que siempre se ejecute, sea 30-60, o bien 90, en ambos casos debe ejecutarse:

ADOSPImporteCuentasxPagar.ExecProc;
EditImporte.Text := ADOSPImporteCuentasxPagar.Parameters.ParamValues ['@Importe'];

Creo que estas un poquito espeso (no te ofendas, nos suele pasar mucho a los programadores) :D, una vueltita por el parque suele ayudar ;)

Saludos.

efelix
06-11-2006, 14:48:36
Saludos Lepe, nuevamente te doy las gracias, y esta vez si te pido encarecidamente mil disculpas por molestar tanto, creo que tienes razón en lo que dices que debo darme una vualta por el parque, no te preocupes no me ofendió lo que me dijiste yo se que he molestado bastante. Muchas gracias te las reítero, segui tu consejo y funcionó. A veces la solución la tenemos delante de nosotros pero nos obsecamos y no la vemos, por mi parte te diré que aparte de la programación también soy administrador de red y son dos cosas que demandan mucho de uno y a veces creo que es mucho.Suerte.