segunda-feira, 1 de março de 2010

Curso de Delphi INICIANTES.

Achei um curso interessante então vou compartilhar com a galera:

Módulo 1

http://rapidshare.com/files/331784837/Modulo_1_Parte-01.rar

http://rapidshare.com/files/331801296/Modulo_1_Parte-02.rar

http://rapidshare.com/files/331835959/Modulo_1_Parte-03.rar

http://rapidshare.com/files/331846408/Modulo_1_Parte-04.rar


Módulo 2

http://rapidshare.com/files/331867726/Modulo_2_Parte-01.rar

http://rapidshare.com/files/331875126/Modulo_2_Parte-02.rar

http://rapidshare.com/files/331881975/Modulo_2_Parte-03.rar

http://rapidshare.com/files/331896888/Modulo_2_Parte-04.rar


Módulo 3 CD-1

http://rapidshare.com/files/331921827/Modulo_3_CD-1_Parte-01.rar

http://rapidshare.com/files/331928132/Modulo_3_CD-1_Parte-02.rar

http://rapidshare.com/files/331941135/Modulo_3_CD-1_Parte-03.rar

http://rapidshare.com/files/331946746/Modulo_3_CD-1_Parte-04.rar

http://rapidshare.com/files/331952535/Modulo_3_CD-1_Parte-05.rar


Módulo 3 CD-2

http://rapidshare.com/files/331957850/Modulo_3_CD-2_Parte-01.rar

http://rapidshare.com/files/331969623/Modulo_3_CD-2_Parte-02.rar

http://rapidshare.com/files/331975111/Modulo_3_CD-2_Parte-03.rar

http://rapidshare.com/files/331980301/Modulo_3_CD-2_Parte-04.rar

http://rapidshare.com/files/331991161/Modulo_3_CD-2_Parte-05.rar

http://rapidshare.com/files/331995065/Modulo_3_CD-2_Parte-06.rar

Módulo 4 CD-1

http://rapidshare.com/files/332005477/Modulo_4_CD-1_Parte-01.rar

http://rapidshare.com/files/332015948/Modulo_4_CD-1_Parte-02.rar

http://rapidshare.com/files/332026281/Modulo_4_CD-1_Parte-03.rar

http://rapidshare.com/files/332036860/Modulo_4_CD-1_Parte-04.rar

http://rapidshare.com/files/332044076/Modulo_4_CD-1_Parte-05.rar


Módulo 4 CD-2

http://rapidshare.com/files/332049025/Modulo_4_CD-2_Parte-01.rar

http://rapidshare.com/files/332054681/Modulo_4_CD-2_Parte-02.rar


Módulo 5

http://rapidshare.com/files/332066534/Modulo_5_Parte-01.rar

http://rapidshare.com/files/332072386/Modulo_5_Parte-02.rar

http://rapidshare.com/files/332084086/Modulo_5_Parte-03.rar

http://rapidshare.com/files/332089801/Modulo_5_Parte-04.rar


Módulo 6

http://rapidshare.com/files/332102503/Modulo_6_Parte-01.rar

http://rapidshare.com/files/332107975/Modulo_6_Parte-02.rar

http://rapidshare.com/files/332121341/Modulo_6_Parte-03.rar

http://rapidshare.com/files/332127516/Modulo_6_Parte-04.rar

http://rapidshare.com/files/332132218/Modulo_6_Parte-05.rar


Módulo 7 CD-1

http://rapidshare.com/files/332138636/Modulo_7_CD-1_Parte-01.rar

http://rapidshare.com/files/332151799/Modulo_7_CD-1_Parte-02.rar

http://rapidshare.com/files/332165537/Modulo_7_CD-1_Parte-03.rar

http://rapidshare.com/files/332171428/Modulo_7_CD-1_Parte-04.rar

http://rapidshare.com/files/332173066/Modulo_7_CD-1_Parte-05.rar


Módulo 7 CD-2

http://rapidshare.com/files/332179131/Modulo_7_CD-2_Parte-01.rar

http://rapidshare.com/files/332185090/Modulo_7_CD-2_Parte-02.rar

http://rapidshare.com/files/332191345/Modulo_7_CD-2_Parte-03.rar

http://rapidshare.com/files/332191345/Modulo_7_CD-2_Parte-03.rar

http://rapidshare.com/files/332198021/Modulo_7_CD-2_Parte-04.rar

http://rapidshare.com/files/332200920/Modulo_7_CD-2_Parte-05.rar



Módulo 10 CD-1

http://rapidshare.com/files/332275150/Modulo_10_CD-1_Parte-01.rar

http://rapidshare.com/files/332281875/Modulo_10_CD-1_Parte-02.rar

http://rapidshare.com/files/332288168/Modulo_10_CD-1_Parte-03.rar

http://rapidshare.com/files/332296958/Modulo_10_CD-1_Parte-04.rar

http://rapidshare.com/files/332301113/Modulo_10_CD-1_Parte-05.rar


Módulo 10 CD-2

http://rapidshare.com/files/332307856/Modulo_10_CD-2_Parte-01.rar

http://rapidshare.com/files/332314358/Modulo_10_CD-2_Parte-02.rar

http://rapidshare.com/files/332320933/Modulo_10_CD-2_Parte-03.rar

http://rapidshare.com/files/332327730/Modulo_10_CD-2_Parte-04.rar

http://rapidshare.com/files/332331259/Modulo_10_CD-2_Parte-05.rar



Módulo 11

http://rapidshare.com/files/332337628/Modulo_11_Parte-01.rar

http://rapidshare.com/files/332344382/Modulo_11_Parte-02.rar

http://rapidshare.com/files/332351009/Modulo_11_Parte-03.rar

http://rapidshare.com/files/332355173/Modulo_11_Parte-04.rar

Módulo 12

http://rapidshare.com/files/332362261/Modulo_12_Parte-01.rar

http://rapidshare.com/files/332369391/Modulo_12_Parte-02.rar

http://rapidshare.com/files/332376408/Modulo_12_Parte-03.rar

http://rapidshare.com/files/332383065/Modulo_12_Parte-04.rar

http://rapidshare.com/files/332383531/Modulo_12_Parte-05.rar

Módulo 13

http://rapidshare.com/files/332390321/Modulo_13_Parte-01.rar

http://rapidshare.com/files/332406352/Modulo_13_Parte-02.rar

http://rapidshare.com/files/332412388/Modulo_13_Parte-03.rar

http://rapidshare.com/files/332423137/Modulo_13_Parte-04.rar

http://rapidshare.com/files/332427139/Modulo_13_Parte-05.rar

Módulo 14

http://rapidshare.com/files/332432715/Modulo_14_Parte-01.rar

http://rapidshare.com/files/332438041/Modulo_14_Parte-02.rar

http://rapidshare.com/files/332454280/Modulo_14_Parte-03.rar

http://rapidshare.com/files/332459231/Modulo_14_Parte-04.rar

http://rapidshare.com/files/332468736/Modulo_14_Parte-05.rar

Módulo 15

http://rapidshare.com/files/332474077/Modulo_15_Parte-01.rar

http://rapidshare.com/files/332487626/Modulo_15_Parte-02.rar

http://rapidshare.com/files/332492464/Modulo_15_Parte-03.rar

http://rapidshare.com/files/332505118/Modulo_15_Parte-04.rar

http://rapidshare.com/files/332505868/Modulo_15_Parte-05.rar


Video Aula SQL com DELPHI

Bom pessoal estou postando uns video interessante que achei na internet.
Então vamos compartilhar.

http://www.megaupload.com/?d=GZ9VRTU1
http://www.megaupload.com/?d=LLJMTHDI

[]´s

Firebird Arquivo INI

Vou falar hoje sobre um problema que todos já passaram ou vão passar, problemas com rede interna e seu sistema.
Você desenvolve seu sistema para rodar na faixa de ip 192.168.0.1, mas no seu cliente esse ip e totalmente diferente, ai o que ocorre problemas com a conexão com o banco de dados.
Para resolver isso irei mostrar aqui como solucionar a conexão com o banco de dados utilizando o arquivo INI.
Inicie um novo projeto e verifique seu codigo fonte ira mostrar algo como isso:

program Project1;

uses
Forms,
Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Vamos modificar essas linhas para que seu sistema possa encontrar o caminho do banco de dados independente de onde o mesmo esteja.

program Project1;

uses
Forms,
Windows,
dialogs,
IniFiles,
SysUtils,
uPRINCIPAL in 'uPRINCIPAL.pas' {frmPRINCIPAL},
uDM_BASE in 'uDM_BASE.pas' {DM_BASE: TDataModule},
uDM_CONEXAO in 'uDM_CONEXAO.pas' {DM_CONEXAO: TDataModule},


{$R *.res}

var
vArqIni:TIniFile;
Caminho:string;

begin
Application.Initialize;
Application.CreateForm(TDM_CONEXAO, DM_CONEXAO);
Application.CreateForm(TDM_BASE, DM_BASE);
// Application.CreateForm(TfrmINICIO, frmINICIO);
Caminho:='DIGITE AQUI O CAMINHO';
DM_CONEXAO.conexao.Close;
if not(FileExists(extractfilepath(ParamStr(0))+'Automacao.ini') ) then
begin
ShowMessage('Arquivo de Configurações do Banco de Dados Não Encontrado!');
vArqIni := TIniFile.Create(extractfilepath(ParamStr(0))+'Automacao.ini');
try
DM_CONEXAO.conexao.ConnectionName:='BANCO';
vArqIni.WriteString('BANCO','database',Caminho);
DM_CONEXAO.conexao.Params.Values['DataBase'] :=Caminho;
finally
vArqIni.Free;
end;
end;
try
vArqIni := TIniFile.Create(extractfilepath(ParamStr(0))+'Automacao.ini');
DM_CONEXAO.conexao.ConnectionName:='BANCO';
Caminho :=vArqIni.ReadString('BANCO','database',Caminho);
DM_CONEXAO.conexao.Params.Values['DataBase'] :=Caminho;
finally
vArqIni.Free;
end;
try
DM_CONEXAO.conexao.Connected:=True;
Application.Title := 'NOME DA APLICACAO';
Application.CreateForm(TfrmPRINCIPAL, frmPRINCIPAL);
Application.Run;
except
Application.MessageBox( 'Não foi possivel se conectar com o banco de dados.' + #13 +
'verifique se o arquivo de configuração está configurado, ' + #13 +
'ou se o servidor firebird está instalado em seu sistema.' + #13 +
'Verifique tambem se o Usuario secundario esta cadastrado.' + #13 +
'Entre em contato com suporte para esclarecer qualquer dúvida.',
'Error Interno', mb_ok + mb_IconError );
Application.Terminate;
end;
Feito isso agora simplesmente crie um arquivo na raiz do seu sistema chamado "Automacao.ini".
No conteudo do arquivo de ini coloque as seguintes linhas:

[BANCO]
database=IP DO SERVIDOR:C:\caminho do seu banco de dados\base.fdb
Pronto agora e so modificar o arquivo "INI" com o local onde esta salvo o banco de dados e correr para o abraço.
Qualquer duvida e so entrar em contato.

[]´s








domingo, 28 de fevereiro de 2010

Programando em InterBase e Firebird

Criação de stored procedures e triggers

Um dos recursos mais importantes de um sistema gerenciador de banco de dados é sem dúvida nenhuma sua capacidade de executar procedimentos internos e de disparar ações baseadas em eventos ocorridos em uma tabela – são as stored procedures e os triggers. Como não poderia deixar de ser, o InterBase e o Firebird (IB/FB) suportam bem ambos os recursos, fornecendo comandos especiais para serem utilizados nesses casos.

Indo além, o IB/FB permite que você use stored procedures como fonte de dados, ou seja, como se fossem tabelas do banco. São as select stored procedures (que chamaremos de "selecionáveis"). Além disso, a possibilidade de utilizar UDFs (funções definidas pelo usuário) aumenta ainda mais o poder e a funcionalidade das stored procedures e triggers.

Estrutura e criação de uma stored procedure

O comando utilizado para a criação de uma stored procedure (SP) é o CREATE PROCEDURE. Uma SP tem duas partes: cabeçalho e corpo. No cabeçalho, temos a definição do nome da SP, parâmetros de entrada (caso existam) e parâmetros de saída (caso a SP retorne valores). O corpo contém declarações de variáveis e comandos a serem executados. A estrutura é definida da seguinte maneira:

CREATE PROCEDURE nome_procedure (

PARAMETRO1 TIPO, /* lista de parâmetros de entrada */

PARAMETRO2 TIPO)

RETURNS (

RESULTADO1 TIPO, /* lista de parâmetros de saída */

RESULTADO2 TIPO)

AS

DECLARE VARIABLE VAR1 TIPO;

DECLARE VARIABLE VAR2 TIPO;

<... Outras declarações de variáveis ...>

BEGIN

<... Corpo da stored procedure (comandos) ...>

END

Estrutura e criação de um trigger

Semelhante a uma stored procedure, um trigger também possui um cabeçalho e um corpo. No cabeçalho definimos a tabela à qual o trigger está associado e o tipo de evento que irá dispará-lo (veja os eventos suportados na Tabela 1). O corpo do trigger contém a declaração de variáveis e comandos a serem executados. Veja sua estrutura:

CREATE TRIGGER nome_trigger FOR nome_tabela

ACTIVE evento POSITION posição

AS

DECLARE VARIABLE VAR1 TIPO;

DECLARE VARIABLE VAR2 TIPO;

<... Outras declarações de variáveis ...>

BEGIN

<... Corpo do trigger (comandos)...>

END

Em triggers (mas não em SPs) é possível utilizar as variáveis de contexto NEW e OLD, que representam respectivamente os valores atuais e os anteriores dos campos da tabela em questão. Na Tabela 1, temos as situações onde cada variável de contexto pode ser utilizada. Você pode ter vários triggers definidos para um mesmo evento. Eles serão executados na seqüência definida pelo valor da cláusula POSITION.

Nota: se o valor de uma variável NEW for alterado em um evento Before Insert ou Before Update, esse valor não é refletido em triggers criados para o mesmo evento. Sendo assim, se por exemplo uma variável New.campo1 tiver seu valor original 0 alterado para 1, outros triggers definidos para o mesmo evento continuarão enxergando o valor 0.

Tabela 1. Eventos e variáveis de contexto

Evento

Momento em que é disparado

Variáveis de contexto

Before Insert

Antes de uma inserção

New

After Insert

Após uma inserção

New*

Before Update

Antes de uma atualização

New e Old

After Update

Após uma atualização

New* e Old

Before Delete

Antes de uma exclusão

Old

After Delete

Após uma exclusão

Old

* Alterar os valores das variáveis nesses eventos não causará qualquer efeito prático.

A linguagem de SPs e triggers

Os bancos InterBase e Firebird suportam uma linguagem própria para a construção de triggers e stored procedures. Basicamente, os mesmos comandos se aplicam tanto a triggers como a SPs, salvo em poucas exceções. A seguir, mostro um resumo da sintaxe e da forma de uso dos principais comandos da linguagem de SPs e triggers do IB/FB.

Variáveis

As variáveis têm papel fundamental nas stored procedures e triggers. Pode-se definir e utilizar variáveis de qualquer tipo de dado suportado no IB/FB, exceto os tipos ARRAY e BLOB. Variáveis no IB/FB são sempre locais, ou seja, são visíveis somente dentro da SP ou trigger em que foram criadas. Valores são atribuídos a variáveis usando o operador de atribuição "=":

Variável = Valor;

Aqui, Valor pode conter um valor imediato (1, 2, 'A' etc.), o resultado de uma expressão (como x/y+2), ou até mesmo chamadas a UDFs. Note o “;” obrigatório no final da sentença, semelhante ao Pascal.

Importante: referências a variáveis e parâmetros devem ser precedidas por um “:” (dois-pontos).

Comentários

Comentários em SPs e triggers são delimitados por /* e */. Por exemplo:

IF (new.status = ‘A’) THEN /* Verificar se foi aprovado */

Blocos

Um bloco é uma seqüência de comandos e instruções delimitados por BEGIN e END. Como em Delphi, um bloco pode conter outros blocos. No Firebird e no InterBase, os blocos devem terminar com um END seguido do terminador. O terminador é definido com o comando SET TERM. No exemplo da Listagem 1, o terminador foi definido como sendo o acento circunflexo (^).

EXCEPTION

O comando EXCEPTION gera uma exceção previamente definida pelo usuário (a definição é feita usando o comando CREATE EXCEPTION). A sintaxe básica é a seguinte:

EXCEPTION nome;

A exceção a ser gerada é definida em nome. Quando o comando EXCEPTION é executado, ele termina a execução da SP ou do trigger e desfaz todas as operações executadas anteriormente por eles. O tratamento de exceções pelo usuário pode ser feito usando comandos WHEN...DO (veja adiante). Por exemplo:

CREATE EXCEPTION estoque_negativo

"O estoque deve ser maior que zero";

...

IF (New.estoque < style="">THEN

EXCEPTION estoque_negativo;

Nota: o Firebird 1.5 traz a possibilidade de gerar exceções dinâmicas; com essa versão, você não precisa criar uma exceção antes de gerá-la.

EXECUTE PROCEDURE

O comando EXECUTE PROCEDURE permite chamar stored procedures de dentro de triggers ou SPs. As chamadas podem ser recursivas (o limite é de mil níveis de recursão). Caso a procedure sendo chamada tenha parâmetros de entrada ou de saída, estes devem ser informados obrigatoriamente.

A sintaxe para esse comando é a seguinte (as partes entre colchetes são opcionais):

EXECUTE PROCEDURE nome [parametros_entrada] [parametros_saida];

Veja um exemplo de chamada:

DECLARE VARIABLE Produto CHAR(4);

DECLARE VARIABLE CustoMedio NUMERIC(9,2);

...

produto = ‘0001’;

EXECUTE PROCEDURE CalculaCustoMedio:Produto

RETURNING_Values:CustoMedio;

IF...THEN...ELSE

A condição em um IF deve sempre estar entre parênteses. Como de costume, o ELSE é executado quando a condição avaliada for falsa. Você também pode utilizar blocos de código dentro de IFs (veja o exemplo na Listagem 1) e IFs aninhados. Um exemplo:

if (:status = 1) then

:desc_status = 'OK';

else

:desc_status = 'FALHOU';

Nesse exemplo, observe que diferentemente do Pascal, onde o “;” pode determinar o final de um if, no IB/FB isso não acontece.

POST_EVENT

POST_EVENT faz com que seja enviado um evento do servidor para todas as aplicações que estejam registradas para receber esse evento. A sintaxe é a seguinte:

POST_EVENTnome_do_evento’ | campo_de_uma_tabela;

Após a aplicação cliente receber a notificação de que o evento foi disparado, ela pode realizar ações como atualizar os dados, replicar alguma informação em outro banco etc.

SELECT...INTO

Você também pode executar SELECTs que retornem no máximo uma linha a partir de SPs ou triggers e armazenar o resultado em uma variável ou parâmetro. Na Listagem 1, um SELECT desse tipo é usado para recuperar os valores dos débitos e créditos dos lançamentos anteriores para posteriormente calcular o saldo inicial.

Nota: até o InterBase 6, a única maneira de se garantir que um SELECT retornaria apenas uma linha era usando funções de agregação, como o SUM, COUNT, MAX etc. No Firebird 1.0 você pode garantir isso usando a cláusula “FIRST 1” do SELECT e no InterBase 6.5 ou 7.0 usando “ROWS 1”.

EXIT e SUSPEND

Os comandos EXIT e SUSPEND só podem ser usados em SPs e funcionam de maneira diferente de acordo com o tipo de stored procedure. Veja as diferenças na Tabela 2 (adaptada do manual "Language Reference" do InterBase 6).

Tabela 2. Funcionamento de EXIT e SUSPEND

Tipo de SP

SUSPEND

EXIT

END final

SP selecionável

Suspende a execução da procedure até que o próximo FETCH seja recebido e retorna os valores de saída

Vai para o END final

Retorna o controle para a aplicação e altera SQLCODE para 100, significando que não há mais registros a serem retornados

SP executável

Vai para o END final (não é recomendado seu uso nesse tipo de SP)

Vai para o END final

Retorna os valores e devolve o controle para a aplicação

WHEN...DO

WHEN..DO é o comando responsável pelo tratamento de erros em SPs e triggers. Quando um erro é gerado, as ações executadas dentro do bloco BEGIN-END atual são desfeitas e um WHEN é procurado. Caso não seja encontrado um WHEN dentro do bloco atual, o servidor volta um nível na cadeia de blocos BEGIN-END à procura desse comando e assim por diante. Se um WHEN for encontrado, a ação (ou bloco de ações) definida por ele é executada e o fluxo retorna para o bloco BEGIN-END onde foi encontrado. Caso nenhum WHEN seja encontrado, todas as ações executadas pela SP são desfeitas.

Os erros que podem ser capturados pelo WHEN são EXCEPTIONs, SQLERRORs (erros de SQL), GDSERRORs (erros do IB/FB) e ANY (qualquer um dos anteriores). Veja um exemplo do uso do WHEN na Listagem 2.

WHILE…DO

O WHILE é o único comando de loop genérico disponível para SPs e triggers, mas é suficiente para executar praticamente todo tipo de loop necessário. A Listagem 2 contém um exemplo de uso do WHILE.

Listagem 2. Stored procedure para elevar um número a uma potência

CREATE PROCEDURE POWER (

NUMERO NUMERIC(9,2),

EXPOENTE INTEGER)

RETURNS (

RESULTADO NUMERIC(15,2))

AS

DECLARE VARIABLE CONTADOR INTEGER;

BEGIN

resultado = -1; /* Em caso de erro, retorna -1 */

/* A rotina só funciona para expoentes positivos */

IF (:expoente <>THEN

EXCEPTION exp_negativo;

contador = 0;

resultado = 1;

WHILE (:contador <:expoente) DO

BEGIN

resultado = resultado * numero;

contador = contador + 1;

/* Caso ocorra algum erro (como um overflow, retorna -1) */

WHEN ANY DO

BEGIN

resultado = -1;

EXIT;

END

END

END

^

FOR SELECT...DO

O FOR SELECT é um dos comandos mais importantes em SPs e triggers. Permite que você abra um cursor unidirecional e percorra os dados retornados pelo SELECT. Nesse tipo de SELECT, é exigido o uso da cláusula INTO para receber os dados dos campos especificados. Essa é a única forma de se trabalhar com cursores de dentro de SPs e triggers.

A Listagem 1 usa dois loops FOR SELECT para percorrer as tabelas de débito e crédito retornando os registros desejados e incrementando o valor do saldo final. Esses loops alimentam algumas das variáveis de saída da procedure (que serão retornadas quando for executada).

Stored procedures selecionáveis

O suporte a stored procedures selecionáveis é um dos recursos mais poderosos do IB/FB. Com ele você pode utilizar uma stored procedure como fonte de dados para os seus SELECTs, como se a SP fosse uma tabela do seu banco de dados.

O efeito é o mesmo de ter uma “tabela virtual” montada com informações vindas de uma ou mais tabelas do banco de dados, sendo que essas informações podem ser transformadas, calculadas etc. para montar a tabela.

Para demonstrar o uso desse tipo de stored procedure, criei um exemplo simples de um fluxo de caixa, onde temos uma tabela para contas a receber e outra para contas a pagar. A intenção é que possamos obter dados para o fluxo de caixa em determinado período, ordenado por data, listando os lançamentos e seus tipos (débitos e créditos), incluindo o saldo inicial (antes do período informado) e o saldo final. O código da SP pode ser visto na Listagem 1. O script para a criação do banco de dados está disponível para download no site da Revista. Na seção seguinte, explico cada parte do código.

Listagem 1. Stored procedure para um fluxo de caixa

CREATE PROCEDURE CAIXA (

INICIO DATE,

FIM DATE)

RETURNS (

DATA DATE,

HISTORICO VARCHAR(30),

VALOR NUMERIC(9,2),

TIPO CHAR(1))

AS

DECLARE VARIABLE SALDO_ANT_CREDITO NUMERIC(9,2);

DECLARE VARIABLE SALDO_ANT_DEBITO NUMERIC(9,2);

DECLARE VARIABLE SALDO_FINAL NUMERIC(9,2);

begin

/* Recupera a soma dos débitos anteriores ao período informado */

SELECT sum(ap.valor)

FROM apagar ap

WHERE (ap.data <:inicio)

INTO:saldo_ant_debito;

/* Recupera a soma dos créditos anteriores ao período informado */

SELECT sum(ar.valor)

FROM areceber ar

WHERE (ar.data <:inicio)

INTO:saldo_ant_credito;

/* Trata nulos */

IF (:saldo_ant_credito IS NULL) THEN

saldo_ant_credito = 0.00;

IF (:saldo_ant_debito IS NULL) THEN

saldo_ant_debito = 0.00;

data =:inicio - 1;

historico = 'SALDO ANTERIOR';

valor = (saldo_ant_credito - saldo_ant_debito);

/* Trata valores negativos */

IF (:valor <>THEN

BEGIN

tipo = 'D';

valor = valor * -1;

END

ELSE

BEGIN

tipo = 'C';

END

SUSPEND;

/* Retorna a primeira linha com o saldo anterior */

saldo_final = valor;

/* Seleciona os registros dentro do período informado

buscando na tabela de contas a pagar */

tipo = 'D'; /* Estamos recuperando débitos */

FOR SELECT ap.data, ap.historico, ap.valor

FROM apagar ap

WHERE (ap.data BETWEEN:inicio and:fim)

INTO:data,:historico,:valor

DO

BEGIN

saldo_final = saldo_final - valor;

/* O suspend a seguir retorna uma linha contendo os campos

data, histórico, tipo e valor */

SUSPEND;

END

tipo = 'C'; /* Estamos recuperando créditos */

/* Seleciona os registros dentro do período informado

buscando na tabela de contas a receber */

FOR SELECT ar.data, ar.historico, ar.valor

FROM areceber ar

WHERE (ar.data BETWEEN:inicio and:fim)

INTO:data,:historico,:valor

DO

BEGIN

saldo_final = saldo_final + valor;

/* O suspend a seguir retorna uma linha contendo os campos

data, historico, tipo e valor */

SUSPEND;

END

/* Montamos a última linha, com os valores do saldo final */

data =:fim;

historico = 'SALDO FINAL';

tipo = 'C';

valor = saldo_final;

SUSPEND;

END

^

Análise da stored procedure

A stored procedure CAIXA tem como parâmetros de entrada as datas de início e final do período que desejamos visualizar e, como parâmetros de saída, os “campos” da nossa “tabela virtual” (data, historico, valor e tipo). Como vimos anteriormente, essas informações são definidas no cabeçalho da SP:

CREATE PROCEDURE CAIXA (

INICIO DATE,

FIM DATE)

RETURNS (

DATA DATE,

HISTORICO VARCHAR(30),

VALOR NUMERIC(9,2),

TIPO CHAR(1))

Em seguida definimos duas variáveis numéricas que armazenarão os totais de débitos e créditos anteriores ao período informado, para que possamos então calcular o saldo anterior, além de uma terceira variável (saldo_final), para armazenar o saldo final do período:

DECLARE VARIABLE SALDO_ANT_CREDITO NUMERIC(9,2);

DECLARE VARIABLE SALDO_ANT_DEBITO NUMERIC(9,2);

DECLARE VARIABLE SALDO_FINAL NUMERIC(9,2);

O próximo passo é obter os valores para o cálculo do saldo anterior. Usamos dois SELECTs com a função SUM para totalizar os lançamentos (débitos e créditos) anteriores à data inicial:

SELECT SUM(ap.valor)

FROM apagar ap

WHERE (ap.data <:inicio) INTO:saldo_ant_debito;

SELECT SUM(ar.valor)

FROM areceber ar

WHERE (ar.data <:inicio) INTO:saldo_ant_credito;

A seguir devemos verificar se as variáveis são nulas (isso ocorrerá se não houver nenhum lançamento anterior ao dia inicial). Como você sabe, NULL dentro de qualquer cálculo matemático faz com que o resultado da operação também seja NULL, o que pode fazer com que o saldo anterior fique incorreto. Sendo assim, checamos se alguma das variáveis possui valor NULL. Caso positivo, atribuímos a ela o valor zero:

IF (:saldo_ant_credito IS NULL) THEN

saldo_ant_credito = 0.00;

IF (:saldo_ant_debito IS NULL) THEN

saldo_ant_debito = 0.00;

O próximo passo é montar a primeira linha do resultado da nossa SP, contendo os dados do saldo anterior. Definimos o parâmetro data como o dia anterior à data inicial informada, depois descrevemos o histórico como sendo “SALDO ANTERIOR” e calculamos o saldo com base nas variáveis anteriormente calculadas.

Para não mostrar valores negativos no resultado, verificamos se o saldo anterior é negativo; de for, o convertemos para um valor positivo. Nesse caso o lançamento é feito como débito, caso contrário, lançamos como crédito.

data =:inicio - 1;

historico = 'SALDO ANTERIOR';

valor = (saldo_ant_credito - saldo_ant_debito);

IF (:valor < 0) THEN

BEGIN

tipo = 'D';

valor = valor * -1;

END

ELSE

BEGIN

tipo = 'C';

END

SUSPEND;

A linha contendo o SUSPEND fará com que a nossa SP devolva o primeiro registro com os valores atribuídos aos parâmetros de saída. O processamento da stored procedure continua a partir dali assim que ela recebe uma requisição de fetch da aplicação cliente.

Seguindo a seqüência, devemos inicializar a variável saldo_final com o saldo anterior obtido:

saldo_final = valor;

O próximo passo é recuperar os lançamentos no período informado. Primeiramente, vamos percorrer a tabela de contas a pagar. Ela fornece os lançamentos de débito, portanto devemos alterar o parâmetro tipo para “D” (débito). Feito isso, usamos um FOR SELECT para varrer todos os registros dentro do período especificado, armazenando os valores dos campos data, historico e valor nos respectivos parâmetros de saída que formarão uma linha da “tabela virtual”. Note que dentro do loop atualizamos o saldo final com base no campo valor do registro que está sendo percorrido.

Obtidos todos os dados necessários, precisamos pedir à SP que retorne um novo registro para a aplicação, chamando mais uma vez SUSPEND. Note que para cada linha percorrida pelo FOR SELECT, teremos um SUSPEND retornando uma linha do resultado. Depois repetimos o processo para a tabela de contas a receber, alterando tipo para “C” (crédito) e somando os valores ao saldo final, em vez de subtraí-los. A seqüência pode ser observada no seguinte código:

tipo = 'D';

FOR SELECT ap.data, ap.historico, ap.valor

FROM apagar ap

WHERE (ap.data BETWEEN:inicio AND:fim)

INTO:data,:historico,:valor

DO

BEGIN

saldo_final = saldo_final - valor;

SUSPEND;

END

tipo = 'C';

FOR SELECT ar.data, ar.historico, ar.valor

FROM areceber ar

WHERE (ar.data BETWEEN:inicio AND:fim)

INTO:data,:historico,:valor

DO

BEGIN

saldo_final = saldo_final + valor;

SUSPEND;

END

Agora só nos resta retornar um registro contendo nosso saldo final. Montamos o registro com bases nos dados já coletados, como pode ser visto a seguir:

data =:fim;

historico = 'SALDO FINAL';

tipo = 'C';

valor = saldo_final;

SUSPEND;

Chamando a procedure

Uma stored procedure selecionável pode ser chamada em um SELECT como se fosse uma tabela comum do banco de dados. Veja um exemplo de chamado à nossa SP:

SELECT * FROM CAIXA ('15.1.2003','1.3.2003')

ORDER BY data

Note que as datas do período estão sendo passadas usando “.” ao invés da tradicional “/”. O ponto diz ao IB/FB que a data está sendo passada no formato dia/mês/ano. Se fosse usado “/”, deveria usar o formato americano mês/dia/ano. Na Figura 1 podemos ver um exemplo de resultado desse comando.

Figura 1. Resultado de SELECT sobre a procedure selecionável CAIXA

Exemplo com triggers

Para exemplificar o uso de um trigger, veremos como criar um campo “auto-incremento” no IB/FB (na verdade estamos simulando um campo auto-incremento, visto que esse tipo de dado não é suportado o IB/FB).

Para que possamos fazer isso, devemos primeiramente criar um generator, que nada mais é do que um contador interno de 64 bits dentro do banco. Para isso usamos o comando CREATE GENERATOR, como em:

CREATE GENERATOR GEN_APAGAR_ID;

Agora que temos o generator criado, o que precisamos fazer é definir um trigger no evento Before Insert (ou seja, antes que uma inserção aconteça), que irá incrementar o nosso contador e atribuir o valor dele ao nosso campo "auto-incremento". Verifique o código:

CREATE TRIGGER APAGAR_BI_BI FOR APAGAR

ACTIVE BEFORE INSERT POSITION 0

AS

BEGIN

IF (NEW.ID IS NULL) THEN

NEW.ID = GEN_ID(GEN_APAGAR_ID,1);

END

^

No exemplo, ID é o campo auto-incremento e só recebe um valor caso já não tenha sido inicializado. Isso permite uma flexibilização que não ocorre no tipo auto-incremento real encontrado no Paradox, por exemplo. Dessa maneira, podemos forçar um registro a ter um determinado ID simplesmente atribuindo um valor a ele antes de confirmar as mudanças no registro. O trigger irá detectar que o campo não está nulo e portanto não incrementará o generator.

Nota: GEN_ID é uma função interna do servidor que incrementa um generator e retorna o novo valor.