Procedure com Returns

Firebird

24/11/2012

Olá Pessoal, sou novato na área
gostaria que me ajudasse como executar uma procuedure com return no delphi
usando os componentes
SqlStoreProc dbexpress
DataSetProvider
ClientDataSet
DataSource
Firebird 2.1
delphi7

SEGUE A PROCUEDURE
create procedure CAIXA (
INICIO date,
FIM date)
returns (
DATA date,
RESUMO_MOV_MES varchar(50),
VALOR numeric(9,2),
SALDO numeric(9,2),
TIPO char(1),
HISTORICO VARCHAR(50))
as
declare variable SALDO_ANT_CREDITO numeric(9,2);
declare variable SALDO_ANT_DEBITO numeric(9,2);
BEGIN

/*Agora recuperamos a soma dos valores dos creditos anteriores ao
periodo informado*/
SELECT COALESCE(SUM(CX.VL_CREDITO),0)
FROM TB_CAIXA_TX_ADM CX
WHERE (CX.DT_MOV < :INICIO) AND (CX.TP_MOV = ''C'')
INTO :SALDO_ANT_CREDITO;

/*Primeiro recuperamos a soma dos valores dos debitos anteriores ao
periodo informado para posteriormente calcularmos nosso saldo inicial*/
SELECT COALESCE(SUM(CX.VL_DEBITO),0)
FROM TB_CAIXA_TX_ADM CX
WHERE (CX.DT_MOV < :INICIO) AND (CX.TP_MOV = ''D'')
INTO :SALDO_ANT_DEBITO;

/*Caso não haja lancamentos anteriores, a variavel ficara no estado NULL,
como no SQL qualquer operação matemática feita com valores NULL sempre
resulta em NULL, temos que verificar isso e atribuir 0.00 na variavel nula
para que forneça o resultado esperado. Isse será feito pela função COALESCE() */
DATA = :INICIO - 1;
RESUMO_MOV_MES = ''SALDO ANTERIOR'';
VALOR = 0;

/*Inicializando a variavel que armazenara o saldo final
com o valor do saldo anterior*/
SALDO = (SALDO_ANT_CREDITO - SALDO_ANT_DEBITO);

/*Por questões "estéticas" não queremos ter valores negativos no campo valor,
sendo assim, se o saldo anterior é negativo, devemos informar que o lançamento é
de débito e tornar o valor do saldo positivo, caso contratio informamos que o
lançamento é de crédito.*/
IF (:VALOR < 0) THEN
BEGIN
TIPO = ''D'';
VALOR = VALOR * -1;
END
ELSE
TIPO = ''C'';

SUSPEND; /*Retornando a primeira linha (registro) com o saldo anterior
o comando a seguir seleciona os registros dentro do periodo informado
buscando na tabela de contas a pagar*/

DATA = :INICIO;
WHILE (:DATA <= :FIM) DO
BEGIN
TIPO = ''D''; /*Estamos recuperando débitos*/
FOR SELECT CX.DT_MOV, CX.DESCRICAO,CX.NR_DOC, CX.VL_DEBITO
FROM TB_CAIXA_TX_ADM CX
WHERE (CX.DT_MOV = :DATA)
AND (CX.TP_MOV = ''D'')
AND COALESCE(CX.VL_DEBITO,0) > 0
INTO :DATA, :HISTORICO, :RESUMO_MOV_MES, :VALOR
DO
BEGIN
/*Subtraimos o valor do lançamento do saldo final*/
RESUMO_MOV_MES = :RESUMO_MOV_MES;
VALOR = :VALOR;
SALDO = SALDO - VALOR;

/*O suspend a seguir retorna uma "linha" contendo os campos
data, historico, tipo e valor que tem seus valores armazenados
nas variáveis de mesmo nome*/
SUSPEND;
END

TIPO = ''C''; /*Estamos recuperando créditos*/
/*seleciona os registros dentro do periodo informado
buscando na tabela de contas a receber*/
FOR SELECT CX.DT_MOV, CX.DESCRICAO, CX.NR_DOC, CX.VL_CREDITO
FROM TB_CAIXA_TX_ADM CX
WHERE (CX.DT_MOV = :DATA)
AND (CX.TP_MOV = ''C'')
AND COALESCE(CX.VL_CREDITO,0) > 0
INTO :DATA, :HISTORICO, :RESUMO_MOV_MES, :VALOR
DO
BEGIN
/*Adicionamos o valor do lançamento ao saldo final*/
SALDO = SALDO + VALOR;
RESUMO_MOV_MES = :RESUMO_MOV_MES;
VALOR = :VALOR;

/*O suspend a seguir retorna uma "linha" contendo os campos
data, historico, tipo e valor que tem seus valores armazenados
nas variáveis de mesmo nome*/
SUSPEND;
END

DATA = DATA + 1;
END

/*Montamos o ultimo "registro" que conterá os valores do saldo FINAL*/
IF (:SALDO < 0) THEN
BEGIN
TIPO = ''D'';
SALDO = SALDO * -1;
END
ELSE
TIPO = ''C'';

DATA = :FIM;
RESUMO_MOV_MES = ''SALDO FINAL'';
VALOR = 0;
SUSPEND;
END

GOSTARIA QUE RETORNASSE ESTE CAMPOS
DATA
RESUMO_MOV_MES
VALOR
SALDO
TIPO
HISTORICO
NO DATASOURCE
RETORNA VAZIO O QUE FAÇO?
GRATO A TODOS QUE COLABORAREM
Márcio Lima

Márcio Lima

Curtidas 0

Respostas

Emerson Nascimento

Emerson Nascimento

24/11/2012

tente com esta versão. note que fiz apenas duas alterações:
1. para melhorar a performance, faço o cálculo dos débitos e dos créditos numa única instrução.
2. atribuí corretamente o conteúdo da variável VALOR.

create procedure CAIXA (
    INICIO date,
    FIM date) 
returns (
    DATA date,
    RESUMO_MOV_MES varchar(50),
    VALOR numeric(9,2),
    SALDO numeric(9,2),
    TIPO char(1),
    HISTORICO VARCHAR(50))
as
declare variable SALDO_ANT_CREDITO numeric(9,2);
declare variable SALDO_ANT_DEBITO numeric(9,2);
BEGIN

    /*Agora recuperamos a soma dos valores dos creditos e dos debitos anteriores
     ao periodo informado, para posteriormente calcularmos nosso saldo inicial*/
    SELECT  SUM(CASE WHEN CX.TP_MOV = 'C' THEN COALESCE(CX.VL_CREDITO,0) ELSE 0 END),
            SUM(CASE WHEN CX.TP_MOV = 'D' THEN COALESCE(CX.VL_DEBITO,0)  ELSE 0 END)
    FROM TB_CAIXA_TX_ADM CX
    WHERE (CX.DT_MOV < :INICIO)
    INTO :SALDO_ANT_CREDITO, :SALDO_ANT_DEBITO;

    /*Caso nao haja lancamentos anteriores, a variavel ficara no estado NULL,
    como no SQL qualquer operacao matematica feita com valores NULL sempre
    resulta em NULL, temos que verificar isso e atribuir 0.00 na variavel nula
    para que forneca o resultado esperado. Isso sera feito pela funcao COALESCE() */
    DATA = :INICIO - 1;
    RESUMO_MOV_MES = 'SALDO ANTERIOR';

    /*Inicializando a variavel que armazenara o saldo final
    com o valor do saldo anterior*/
    SALDO = (COALESCE(SALDO_ANT_CREDITO,0) - COALESCE(SALDO_ANT_DEBITO,0));
    VALOR = SALDO;

    /*Por questoes "esteticas" nao queremos ter valores negativos no campo valor,
    sendo assim, se o saldo anterior for negativo, devemos informar que o lancamento eh
    de debito e tornar o valor do saldo positivo, caso contrario informamos que o
    lancamento eh de credito.*/
    IF (:VALOR < 0) THEN
    BEGIN
        TIPO = 'D';
        VALOR = VALOR * -1;
    END
    ELSE
        TIPO = 'C';

    SUSPEND; /*Retornando a primeira linha (registro) com o saldo anterior
                o comando a seguir seleciona os registros dentro do periodo informado
                buscando na tabela de contas a pagar*/

    DATA = :INICIO;
    WHILE (:DATA <= :FIM) DO
    BEGIN
        TIPO = 'D'; /*Estamos recuperando debitos*/
        FOR SELECT CX.DT_MOV, CX.DESCRICAO, CX.NR_DOC, CX.VL_DEBITO
            FROM TB_CAIXA_TX_ADM CX
            WHERE (CX.DT_MOV = :DATA)
            AND (CX.TP_MOV = 'D')
            AND COALESCE(CX.VL_DEBITO,0) > 0
            INTO :DATA, :HISTORICO, :RESUMO_MOV_MES, :VALOR
        DO
        BEGIN
            /*Subtraimos o valor do lancamento do saldo final*/
            SALDO = SALDO - VALOR;

            /*O suspend a seguir retorna uma "linha" contendo os campos
            data, historico, tipo e valor que tem seus valores armazenados
            nas variaveis de mesmo nome*/
            SUSPEND;
        END

        TIPO = 'C'; /*Estamos recuperando creditos*/
                    /*seleciona os registros dentro do periodo informado
                    buscando na tabela de contas a receber*/
        FOR SELECT CX.DT_MOV, CX.DESCRICAO, CX.NR_DOC, CX.VL_CREDITO
            FROM TB_CAIXA_TX_ADM CX
            WHERE (CX.DT_MOV = :DATA)
            AND (CX.TP_MOV = 'C')
            AND COALESCE(CX.VL_CREDITO,0) > 0
            INTO :DATA, :HISTORICO, :RESUMO_MOV_MES, :VALOR
        DO
        BEGIN
            /*Adicionamos o valor do lancamento ao saldo final*/
            SALDO = SALDO + VALOR;

            /*O suspend a seguir retorna uma "linha" contendo os campos
            data, historico, tipo e valor que tem seus valores armazenados
            nas variaveis de mesmo nome*/
            SUSPEND;
        END

        DATA = DATA + 1;
    END

    /*Montamos o ultimo "registro" que contera os valores do saldo FINAL*/
    IF (:SALDO < 0) THEN
    BEGIN
        TIPO = 'D';
        SALDO = SALDO * -1;
    END
    ELSE
        TIPO = 'C';

    DATA = :FIM;
    RESUMO_MOV_MES = 'SALDO FINAL';
    VALOR = 0;

    SUSPEND;
END
GOSTEI 0
Márcio Lima

Márcio Lima

24/11/2012

Emerson Obrigado Pela Dica. Mais acho que não expliquei melhor o que eu quero.
O que eu quero é executar esta procedure no delphi passando os parametros Inicio e Fin
e ao executar me mostrar o resultado em um DataSource.
Entendeu?
GOSTEI 0
Claudia Nogueira

Claudia Nogueira

24/11/2012

Não sou muito expert no assunto, mas como quase ninguém respondeu vou tentar ajudar.
Você criou uma procedure selecionável, então você não pode usar o SqlStoreProc e sim o SQLQuery.

Teria que ligar o DataSetProvider no SQLQuery e marcar a opção poAllowCommandText do DataSetProvider = True.
Feito isso você liga o ClienteDataSet no DataSetProvider e onde você quiser executar você faria mais ou menos assim:

ClientDataSet1.Close;
ClientDataSet1.CommandText := 'SELECT * FROM CAIXA(:INICIO,:FIM)';
ClientDataSet1.Params[0].AsDateTime := DataInicial;
ClientDataSet1.Params[1].AsDateTime := DataFinal;
ClientDataSet1.Open;



Algumas pessoas podem criticar essa forma, mas é a única que eu sei.
Se não servir, aí posta novamente que alguém com mais conhecimento provavelmente vai te ajudar.
GOSTEI 0
Márcio Lima

Márcio Lima

24/11/2012

Amiga. Obrigado por tentar me ajudar mas nas resolveu o meu problema.
Grato
GOSTEI 0
Claudia Nogueira

Claudia Nogueira

24/11/2012

Hum que pena, mas fala por que não fumciou. Antes de responder eu testei.
GOSTEI 0
Márcio Lima

Márcio Lima

24/11/2012

Não me retornou como queria, se você executar a procedure no banco de dados me retorna como eu quero,
e no delphi não. Será que consegui te explicar?
grato
GOSTEI 0
Claudia Nogueira

Claudia Nogueira

24/11/2012

Eu entendi o que você quer, mas olha só, quando uma procedure do Firebird tem que retornar algum valor você não usa:

EXECUTE PROCEDURE CAIXA(:INICIO,:FIM)


e sim:

SELECT * FROM CAIXA(:INICIO,:FIM)


Estou me baseando que a procedure se chama CAIXA conforme você postou.

Faz direto no banco de dados esses dois procedimentos e veja a diferença.
Enquanto o EXECUTE PROCEDURE retorna algo como:

------ Procedure executing results: ------
Resultado

O SELECT * FROM CAIXA(:INICIO,:FIM) retorna realmente as linhas.

Por isso ao usar o SQLQuery no lugar do SQLStoredProc1.
GOSTEI 0
Márcio Lima

Márcio Lima

24/11/2012

Amiga show de bola viu, funcionou legal.
eu estava executando a procedure por isso retornava com erro
e passando o select funcionou.
GOSTEI 0
Márcio Lima

Márcio Lima

24/11/2012

MUITO OBRIGADO VIU!!!
GOSTEI 0
Claudia Nogueira

Claudia Nogueira

24/11/2012

Fico feliz!
As vezes não consigo explicar direito.
Por isso quando eu começo responder, os tópicos ficam muito grandes.

MUITO OBRIGADO VIU!!!
GOSTEI 0
POSTAR