PDA

Ver la Versión Completa : Procedimiento almacenado


efelix
17-10-2006, 15:20:32
:confused: Hola a todos. Muchas gracias por este foro. He publicado dos problemas en el foro, debo decir que aún no he resuelto mis problemas pero, muchas gracias por los que responden que siempre aportan algo de interés. Como diecn muchos he pensado bien en está pregunta para que alguién se preocupe en contestarla. El problema es el siguiente: desarrollo una aplicación de bases de datos en delphi 7 y sql server 2000, en ella tengo un formulario donde tengo como controles los siguientes, dos datetimepicker, un dbgrid, un edit, un botón de comando y controles de la paleta ado tales como un ado connection, dos adostored procedure y por supuesto un data source. Hay un procedimiento almacenado donde le paso como parámetro un rango de fecha y debe devolverme las facturas pendientes de pago para ese rango, estos parámetros los paso a través de los datetimepicker, el procedimiento almacenado es el siguiente:
CREATE PROCEDURE spPendientesPago
@FechaRecepcion datetime,
@FechaRecepcion1 datetime

AS
SELECT Facturas.IdFactura, Proveedores.NombreProveedor, Facturas.Descripcion, Facturas.Importe
FROM Facturas INNER JOIN
Proveedores ON Facturas.IdProveedor = Proveedores.IdProveedor
WHERE (Facturas.Aplicada = 0) AND Facturas.FechaRecepcion>=@FechaRecepcion AND Facturas.FechaRecepcion<=@FechaRecepcion1
GO
Esto funciona a la perfección en sql server.
Hay otro procedimiento almacenado que utilizo para que me de el total de las facturas sin pagar según el rango de fechas, tiene la siguiente sintáxis:

CREATE PROCEDURE spImporteTotalporFechas
@Fecha datetime,
@Fecha1 datetime,
@ImporteTotal money OUTPUT
AS
SELECT @ImporteTotal=SUM(Importe)
FROM Facturas
WHERE (Aplicada = 0) AND FechaRecepcion>=@Fecha AND FechaRecepcion<=@Fecha1
GO
el cual también funciona a la perfección en sql server. Ahora en delphi en el código del evento onclick del botón de comando hago esto:

begin
ADOSPPendientesPago.Close;
if DTPFecha2.Date < DTPFecha1.Date then
begin
MessageDlg('La fecha final debe ser superior a la inicial',mterror,[mbok],0);
Exit;
end;
ADOSPPendientesPago.Parameters.ParamByName('@FechaRecepcion').Value := DTPFecha1.Date;
ADOSPPendientesPago.Parameters.ParamByName('@FechaRecepcion1').Value := DTPFecha2.Date;
ADOSPImporteTotal.Parameters.ParamByName('@Fecha').Value := DTPFecha1.Date;
ADOSPImporteTotal.Parameters.ParamByName('@Fecha1').Value := DTPFecha2.Date;
ADOSPImporteTotal.ExecProc;
EditImporteTotal.Text := ADOSPImporteTotal.Parameters.ParamValues['@ImporteTotal'];
ADOSPPendientesPago.Open;
end;

En tiempo de ejecución establexco el rango de fechas le doy al botón y el dbgrid se me llena con las facturas pendientes de pago y en el edit se totaliza el importe total de las facturas sin pagar para el rango de fechas seleccionados. Ahora comienza el problema. En la base de datos en la tabla facturas hay en estos momentos cuatro facturas pendientes de pago, me muestra en el dbgrid solamante tres, y me pone en el edit el importe total de las facturas mostradas según el rango de fechas, me excluye una factura, por ejemplo las fechas de estas facturas son desde el 10/04/2006 hasta 16/04/2006, la factura del del 10/04/2006 no la muestra en el dbgrid y por supuesto el procedimiento almacenado que tiene el parámetro de salida pone nada más el importe total de las mostradas en el dbgrid. Repito esto funciona perfectamente bien en sql server 2000, es decir los procedimientos almacenados los he probado y están bien. Otra curiosidad en tiempo de diseño situo un dbgrid le pongo directamente el valor a los parámetros, es decir el rango de fechas y funciona el dbgrid muestra las cuatro facturas pendientes de pago, pero ne tiempo de ejecución no. Además cuando en tiempo de ejecución las dos fechas las pongo iguales me da el siguiente error 'exception in class EVariantTypeCastError with message could no convert variant of type (null) into type (string)', el cursor se detiene en la parte del código donde le asigno a la propiedad text del edit el parámetro de salida del segundo procedimiento almacenado. No se ya que hacer. Espero me puedan ayudar, acepto cualquier sugerencia, por eso mando el código para que lo vean y me diagn donde puede estar el problema. Muchas gracias.

poliburro
17-10-2006, 17:07:59
Ok hay dos pequeños errores en tu código,

el primero tiene que ver con el manejo de nulos, y es que cuando regresas valores desde el procedimiento almacenado debes tratarlos, por lo que en la parte de la asignación debes hacer lo siguiente


SELECT @ImporteTotal=IsNull(SUM(Importe),0)
FROM Facturas
WHERE (Aplicada = 0) AND FechaRecepcion>=@Fecha AND FechaRecepcion<=@Fecha1

con lo que evitaras el problema de no poder convertir variant null


el segundo error tiene que ver con la manera en que estas manejando el componente, y es que para cuando el procedimiento almacenado solo te devuelve valores a través de los parámetros, unicamente debes invocar a execproc, el llamado que haces a Open esta de mas


suerte

efelix
17-10-2006, 18:15:43
Muchas gracias por tu respuesta, es cierto ya resolví el problema que se me daba con la exception en el tipo de conversión, pero por otra parte no entiendo lo que me explicas, pués el metodo close y open lo uso a modo de refrescamiento de manera tal que si alguién cambia el rengo de fechas y hace click nuevamente se muestren los resultados actualizados para el nuevo rango de fechas. Por otra parte si coemnto la línea dond está el método open no se muestra en el dbgrid el conjunto de resultados, aunque si muestra en el edit el importe total, pero excluyendo una factura que según expliqué aparece comprendida dentro de ese rango, por otra parte si comento la línea del método execproc entonces me genera un error en la línea de la asignación del la propiedad text del edit al parámetro de salida. Te repito muchas gracias por tu respuesta me ha servido de mucho.

poliburro
17-10-2006, 20:31:45
Oks, aclaro un poco el punto.


Cuando tienes un Procedimiento almacenado que solo devolverá datos a través de sus parámetros definidos como OuPut, no necesitas invocar a open,
unicamente basta con ExecProc.

Si tu procedimiento almacenado devuelve uno o varios recorsets, entonces si debes utilizar open.

Ahora que si tu procedimiento almacenado hace una combinación de los casos anteriores entonces si debes usar primero ExecProc para cargar los parámetros de salida y despúes el Open para cargar el dataset.

Suerte

jachguate
17-10-2006, 21:17:19
Hilo movido de "conexión con bases de datos" a "MS SQL Server", por tratarse de un asunto específico de este motor.

Saludos.

efelix
17-10-2006, 21:40:00
poliburro, recuerda que son dos procedimientos almacenados, uno con dos parámetros de entrada, que son los denominados @FechaRecepcion y @FechaRecepcion1, esto lo uso para que me devuelva las facturas pendientes de pago en ese rango de fechas, el otro procedimiento tiene 3 parámetros dos de entrada y uno de salida, los de entrada son @Fecha y @Fecha1 y el de salida @ImporteTotal, si te fijas en el código verás que hay un ADOSPPendientesPago que es un Ado Stored Procedure que hace alusión al primer procedimiento y un ADOSPImporteTotal que hace alusión al otro procedimiento almacenado con los tres parámetros, este último procedimiento lo cree con la finalidad de obtener la suma total de las facturas pendientes de pago según el rango de fechas, si te fijas te darás cuenta que ambos procedimientos en el código delphi yo igualo los parámetros de salida a los valores de la propiedad date de los dos datetimepicker, por eso es que combino losm métodos open para obtener el conjunto de records del primer procedimiento almacenado y el execproc para asignar el valor del parámetro de salida al edit. Pero fijate así como está me funciona la única dificultad es que te repito hay una factura sin pagar con fecha 10/04/2006 que no la muestra en tiempo de ejecución. Yo pongo del 10/04/2006 a 16/06/2006 y me muestra las demas menos esa, sin embargo si pongo un rango de fechas que incluya una el 09/04/2006 a 16/06/2006 si la muestra, y tu viste que los rangos están bien escritos en los procedimientos almacenados. Hermano disculpa tanta molestia, a lo mejor te parezco un latoso, pero esres el qu has contestado a mi inquietud y por eso te respondo. Realmente te pido mi disculpas y gracias nuevamente por dedicar tiempo a a este tema.

poliburro
17-10-2006, 22:13:18
Oks, no te preocupes, y como te decia en el primer post, solo debes tratar los nulos cuando estas devolviendo valores a través de los parámetros.

Mucha suerte amigo.

angelbem
21-11-2007, 17:53:00
Bueno, particularmente no e trabajado mucho con sql, pero por lo que veo en tu codigo, tu parametros son de tipo datetime, y le mandas una fecha de tipo date.

el problema que pasa muchas veces, es por el tipo de dato, date a datetime, en la hora de la comparacion de eso dos tipos de datos pueden variar, como ocurre en tu caso, que no toma la factura de la misma fecha del rango que le colocaste.

bueno pienso que si verificas que los datos que estas comparando son del mismo tipo entonces te arrojaria los datos correctos, puedes darle un format a uno de los dos campos, ya sea el que le mandas por parametro o en la consulta del procedimiento.

Saludos