Você está na página 1de 139

ClientDataSet

com
DBExpress e Firebird

Mdulo II
Explorando o Banco de Dados

Por Eduardo Rocha


eduardo@edudelphipage.com.br
www.edudelphipage.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Sumrio
Preparando o ambiente........................................................................................... 3
Migrando o banco de Paradox para Firebird ........................................................... 7
Utilizando Alias para conexo com o banco de dados .......................................... 20
Utilizando a funo COALESCE do Firebird ......................................................... 24
Utilizando a funo NULLIF do Firebird ................................................................ 26
Utilizando a funo CASE do Firebird ................................................................... 27
Utilizando domnios no banco de dados................................................................ 29
Utilizando o ISQL para criao e manipulao do banco de dados ...................... 33
Realizando Backups e Restores no Banco de Dados ........................................... 37
Criando e utilizando UDF's.................................................................................... 39
Uma viso geral sobre Stored Procedures............................................................ 46
Criando e implementando Stored Procedures....................................................... 49
Criando Stored Procedures no IBExpert ............................................................... 64
Utilizando Stored Procedures no Delphi................................................................ 69
Trabalhando com Stored Procedures que no retornam valores .......................... 70
Trabalhando com Stored Procedures que retornam um registro........................... 73
Trabalhando com Stored Procedures que retornam mais de um registro ............. 76
Executando a Stored Procedure que gera Exception............................................ 79
Criando e implementando Triggers ....................................................................... 82
Criando Triggers no IBExpert ................................................................................ 86
Utilizando Triggers no Delphi ................................................................................ 95
Criando e definindo Views................................................................................... 100
Criando e utilizando Views no IBExpert .............................................................. 104
Relatrios Mestre/Detalhe com performance ...................................................... 111
Criando Relatrio Mestre/Detalhe utilizando NestedDataSet .............................. 113
Criando o Relatrio utilizando Joins .................................................................... 122
Instalando e utilizando driver DBExpress de terceiros ........................................ 130
Trocando a senha do usurio SYSDBA .............................................................. 136

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

-2-

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Preparando o ambiente
Em quase todos os tpicos da apostila utilizaremos o IBExpert e o Delphi, portanto, sugiro j
deixarmos preparada a conexo com o banco de dados atravs do IBExpert e o projeto bsico no
Delphi contendo apenas um formulrio e um data module principal j conectado com o banco,
assim quando entrarmos nos tpicos no precisaremos nos preocupar com estes detalhes.

Criando a pastas
No CD temos duas pastas chamada Diversos e Projeto, copie-as para C:\CursoClientDataSet2.
A estrutura de diretrios dever ficar da seguinte forma:

Figura 1 Estrutura de diretrios


Na pasta Projeto tem tudo o que foi feito ao longo do curso, caso queira seguir passo a passo
desde o incio, sugiro que deixe apenas os arquivos abaixo excluindo os demais.
cliente.*
exemplo.fdb
vendedor.*

Figura 2 Excluindo arquivos da pasta projeto e deixando apenas o bsico

Criando a conexo no IBExpert


O instalador do IBExpert est disponvel na pasta Diversos, portanto, caso no tenha instalado
ainda aproveite este momento para realizar esta tarefa.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

-3-

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Estando com o IBExpert instalado em sua mquina, execute-o e logo em seguida acesse o menu
Database->Register Database.

Figura 3 Acessando o item de menu Register Database


Ser exibida a seguinte janela:

Figura 4 Registrando o banco no IBExpert


No entrarei em detalhes sobre o registro do banco no IBExpert, pois isso j foi abordado no
primeiro mdulo deste curso, portanto, vamos apenas preencher os campos da seguinte forma:
Server: Local
Server Version: Firebird 1.5
Database File: C:\CursoClientDataSet2\Projeto\exemplo.fdb
Database Alias: VideoAulaCds2
User Name: SYSDBA
Password: masterkey
Charset: WIN1252

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

-4-

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 5 Preenchendo os dados para registrar o banco de dados no IBExpert


Aps o preenchimento devemos clicar no boto Register para confirmar.
Em seguida podemos visualizar a conexo registrada no IBExpert conforme demonstra a figura a
seguir:

Figura 6 Banco de Dados registrado no IBExpert

Preparando o projeto no Delphi


Abra o Delphi e inicie uma nova aplicao.
Salve o projeto como CursoCds2.dpr em C:\CursoClientDataSet2\Projeto e o formulrio
principal salve como ufrmPrincipal.pas.
Adicione um data module ao projeto, nomeie como dmPrincipal e salve-o com o nome
udmPrincipal.pas.
No datamodule adicione um componente TSqlConnection e ajuste as seguintes propriedades:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

-5-

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

TSQLConnection
Name: SqlConPrincipal
LoginPrompt: False
DriverName: Interbase
Params:
DataBase: c:\CursoClientDataSet2\projeto\exemplo.fdb
Dialect: 3
Charset: WIN1252
No evento OnCreate do datamodule adicione o seguinte cdigo:
procedure TdmPrincipal.DataModuleCreate(Sender: TObject);
begin
SqlConnPrincipal.Connected := True;
end;

Agora no formulrio principal adicione a unit udmPrincipal na clusula uses:


implementation
uses
udmPrincipal;
...

Agora v ao menu Project->Options e na aba Forms ajuste o Auto-create forms e Available


forms da seguinte forma:

Figura 7 Ajustando o Auto-Create forms do projeto


Definimos esta ordem para que ao iniciar a aplicao, j crie automaticamente o DataModule e o
formulrio principal.
Confirme clicando no boto OK e logo em seguida salve o projeto.
Pronto, agora podemos fechar o Delphi e partir para os prximos tpicos.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

-6-

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Migrando o banco de Paradox para Firebird


A migrao poderia ser feita de modo manual gerando scripts SQL do banco para criao e
insero dos dados, porm isso daria muito trabalho. Temos uma ferramenta gratuita no mercado
chamada IBDataPump que nos permite fazer esta migrao de forma bastante simples. Esta
ferramenta possui custo apenas para aquisio do cdigo fonte ou suporte que so opcionais. A
mesma pode ser baixada diretamente do site:
http://www.clevercomponents.com/products/datapump/ibdatapump.asp
O mais interessante que aps baix-la no necessrio instalar, apenas executar o utilitrio.
Outro aspecto importante desta ferramenta que ela nos permite fazer qualquer migrao de
dados que suporte ADO, BDE e ODBC (DBbase, Paradox, Access, MSSQL, Sybase, Oracle, DB2
entre outros).
Para demonstrao utilizaremos duas tabelas paradox que acompanham o projeto e migraremos
para o banco Firebird.

Partindo para prtica


Para podermos migrar as tabelas paradox precisamos primeiramente criar um alias, pois o
IBDataPump precisa do alias para selecionarmos nosso banco de origem, portanto, v at o BDE
Administrator e crie um alias com o nome MigracaoParadox apontando para o diretrio em que
esto as tabelas paradox: C:\CursoClientDataSet2\Projeto, conforme demonstra a figura a seguir:

Figura 1 - Criando o alias MigracaoParadox no BDEAdministrator


Em seguida execute o IBDataPump.exe e a seguinte tela ser exibida.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

-7-

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 2 - Tela inicial do IBDataPump


O processo de migrao deve ser feito em 2 etapas: primeiro criamos o banco em seguida
migramos os dados.

Criando o Banco de Dados


No campo Source Database Properties selecione a opo BDESource.
Em seguida no campo Source DB selecione o alias que criamos: MigracaoParadox.
Perceba que ao selecionar, o boto Build SQL Script exibido, veja na figura abaixo:

Figura 3 - Selecionando o banco de origem


Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

-8-

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Agora podemos clicar no boto Build SQL Script e a seguinte tela ser exibida:

Figura 4 - Tela para gerar o Script de criao do banco


Nesta tela podemos ajustar diversos parmetros para converso dos tipos de campos, nome de
tabelas, Charset entre outros detalhes.
Em nosso exemplo ajustaremos o caminho onde o script ser gerado para
C:\CursoClientDataSet2\diversos\script_migracao.sql, o caminho onde o banco ser criado
C:\CursoClientDataSet2\diversos\testemigracao.fdb e tambm o Charset para WIN1252 por
recomendao para compatibilidade com caracteres acentuados.
Veja a seguir como ficaro os ajustes:

Figura 5 - Ajustando os parmetros para migrao do banco


Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

-9-

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Agora basta clicarmos no boto Start e o script para criao do banco de dados ser gerado no
caminho informado. Note que ser exibida uma mensagem de concluso.

Figura 6 Mensagem de concluso da gerao do script


Confirme clicando no boto OK.
Em seguida ser aberto automaticamente o bloco de notas com o contedo do script gerado.

Figura 7 Bloco de notas sendo aberto automaticamente com o script


Podemos fechar o bloco de notas, pois utilizaremos o prprio IBExpert para executar este script.
Neste momento podemos fechar tambm a tela do IBDataPump clicando no boto Close.
Agora abra o IBExpert e v at o menu Tools e clique na opo Script Executive...

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 10 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 8 - Acessando a opo de menu Tools->Script Executive


Em seguida ser exibida a tela para execuo de scripts.
Clique no boto LoadFromFile conforme demonstra a seta em destaque (na imagem acima) para
carregarmos o arquivo que contm o script de criao do banco que geramos anteriormente em
C:\CursoClientDataSet2\diversos\script_migracao.sql.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 11 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 9 - Carregando o arquivo de Script

Figura 10 Abrindo o script de migrao

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 12 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 11 - Script de criao do banco carregado


Aps termos carregado o script precisamos apenas execut-lo clicando no boto Run conforme
demonstra a figura a seguir:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 13 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 12 - Executando o script para criao do banco


Neste momento j temos o banco de dados criado na mesma estrutura das tabelas em Paradox, o
que precisamos fazer agora executar o prximo passo que a migrao dos dados.

Migrando os dados
Abra novamente o IBDataPump e vamos ajustar os parmetros para indicar que agora queremos
migrar os dados das tabelas paradox para o nosso banco recm criado em Firebird, portanto
devemos ajustar os seguintes parmetros:
Source Database Properties: BDESource
Source DB: MigracaoParadox
Destination DB: C:\CursoClientDataSet2\Diversos\TESTEMIGRACAO.FDB (este foi o arquivo
criado na execuo do script que vimos anteriormente)
CharSet: WIN1252
Os ajustes devero ficar igual figura a seguir:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 14 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 13 - Ajustando o IBDataPump para fazermos a migrao dos dados


Depois de ajustar os parmetros podemos partir para o 2.o passo clicando na aba Step 2
localizada na parte superior da tela conforme demonstra a seta na figura anterior.
Veja a seguir a tela a ser exibida ao clicar:

Figura 14 - Step2 do IBDataPump


Nesta tela criamos os vnculos entre as tabelas de origem e destino, ou seja, aqui informamos que
os dados da tabela X sero enviados para tabela Y, assim como seus respectivos campos.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 15 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Pode ficar tranqilo que o IBDataPump j possui um recurso que faz este vnculo automaticamente
analisando os nomes e tipos de campos de origem procurando-os na tabela de destino e fazendo o
vnculo automaticamente.
Antes de tudo, precisamos trazer as definies das tabelas de origem e destino, para isso
devemos clicar no boto Get Definitions. Ao clicar neste boto, teremos o seguinte resultado:

Figura 15 - Carregando as definies das tabelas de origem e destino


No lado esquerdo so exibidas as tabelas de destino e do lado direito as tabelas de origem.
Para fazermos os vnculos manualmente poderamos arrastar as tabelas do lado direito at o lado
esquerdo, fazendo a respectiva associao e o mesmo poderamos fazer para os campos, mas
isso no necessrio. Como criamos o banco de destino com a mesma estrutura do banco de
origem ento basta clicarmos no boto Build Relations e o IBDataPump realizar todos os
vnculos automaticamente.
Veja a seguir o resultado aps ter clicado no boto Build Relations.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 16 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 16 - Criando o relacionamento entre as tabelas de origem e destino

Figura 17 Vnculos feitos automaticamente aps ter clicado em Build Relations


Note na primeira coluna as setas do lado esquerdo e direito indicando destino e origem. O que
est em azul a origem, por exemplo, o campo CLI_CODIGO (em preto) possui um destaque do
seu lado direito em azul com a palavra CLI_CODIGO, isso significa que este campo receber o
valor do campo CLI_CODIGO da tabela de origem, o mesmo conceito se aplica s tabelas.
Neste momento j podemos partir para o ltimo passo clicando na aba Step 3. Ao clicar ser
exibida a seguinte tela:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 17 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 18 - Step3 do IBDataPump


Nesta tela clicamos no boto Start para iniciar o processo de migrao. Ao clicar ser exibida a
seguinte mensagem:

Figura 19 Mensagem exibida ao clicar no boto start.


Esta mensagem apenas um alerta informando que o banco est no modo ForcedWrites e por
este motivo o processo poder demorar, mas no h problemas, podemos confirmar clicando no
boto YES.
Ao final ser exibida uma mensagem informando que a migrao foi executada com sucesso.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 18 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 20 Mensagem confirmando que o script foi executado com sucesso

Concluso
Nosso objetivo neste captulo foi explicar passo a passo o processo de migrao de um banco
Paradox para Firebird, porm sabemos que o IBDataPump possui muitos parmetros que podem
ser configurados na migrao e vale a pena explor-los para extrair ao mximo seus recursos e,
alm disso, nos permite migrarmos dados de outros bancos de dados.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 19 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Utilizando Alias para conexo com o banco de dados


Um recurso muito interessante que surgiu na verso 1.5 do Firebird e acrescentou mais uma
segurana a possibilidade de utilizarmos um alias para conexo com o banco de dados
representando o path do arquivo FDB.
A segurana est no fato de ocultarmos o caminho do banco na string de conexo substituindo
pelo alias, desta forma evitamos que intrusos vejam o caminho do banco para executar alguma
tarefa maliciosa.
A idia criarmos um alias no servidor apontando para o caminho do banco e na aplicao
utilizamos este alias.
O arquivo que contm a definio dos aliases chama-se aliases.conf e est localizado na raiz do
diretrio de instalao do Firebird, por exemplo:
C:\Arquivos de programas\Firebird\Firebird_1_5\aliases.conf

Veja abaixo o que temos neste arquivo:

Figura 1 Contedo original do arquivo aliases.conf


Cada alias criado em uma linha na seguinte estrutura:
Nome do alias = caminho do banco

Definindo um alias
O exemplo abaixo define um alias com o nome SisExemploAlias apontando para o banco
c:\sistema\exemploalias.fdb.
SisExemploAlias = c:\sistema\exemploalias.fdb

Perceba que definimos apenas o caminho fsico do banco e no informamos o IP ou nome da


mquina, isso ser informado na string de conexo.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 20 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Exemplo de utilizao do alias na aplicao


Supondo que o servidor onde o Firebird est instalado esteja com o IP 192.168.0.1 e utilizando o
protocolo padro TCP para conexo com o banco, a string de conexo seria:
No utilizando o alias:
192.168.0.1:c:\sistema\exemploalias.fdb

Utilizando o alias:
192.168.0.1:SisExemploAlias

Note que utilizando alias ocultamos o caminho do banco, esta a grande vantagem.

Partindo para prtica


V at a pasta C:\Arquivos de programas\Firebird\Firebird_1_5 e abra o arquivo aliases.conf
em algum editor de texto.
Inclua a seguinte linha no arquivo:
ExemploAlias = c:\CursoClientDataSet2\projeto\exemplo.fdb

O arquivo dever ficar da seguinte forma:

Figura 2 Modificando o arquivo aliases.conf do Firebird


Salve o arquivo e feche-o. Neste momento j temos o alias, portanto iremos testar a partir de uma
aplicao no Delphi.
Abra o Delphi e inicie uma nova aplicao:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 21 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 3 Criando uma nova aplicao no Delphi


Insira o componente SQLConnection e ajuste a propriedade DriverName para Interbase.

Figura 4 Definindo o driver interbase para conexo


Em seguida, clique na propriedade Params e no parmetro Database informe:
localhost:ExemploAlias

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 22 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 5 Ajustando o parmetro Database para utilizar o Alias


Confirme e faa o teste ativando a propriedade Connected do componente.
Em nosso exemplo utilizamos localhost por estarmos executando o teste na prpria mquina que
possui o servidor Firebird instalado, mas em um ambiente Client/Server, onde o Firebird estaria em
outra mquina substituiramos o localhost pelo endereo IP do servidor.

Concluso
Neste captulo abordamos a utilizao de alias para conexo com o banco de dados a fim de
obtermos uma segurana a mais, porm no podemos esquecer que outros aspectos de
segurana tambm so importantes e no devem ser esquecidos como por exemplo, a prpria
restrio de acesso ao arquivo FDB e a pasta onde o Firebird est instalado.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 23 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Utilizando a funo COALESCE do Firebird


A funo COALESCE no especfica do Firebird, ela faz parte do padro SQL92, porm s foi
implementada a partir da verso 1.5.
Esta funo retorna o primeiro valor no nulo de uma lista de valores, isto muito til em
casos onde precisamos retornar valor X se no for nulo ou Y se o valor X for nulo.
Vamos analisar um exemplo prtico:
Imagine que temos uma tabela de produtos com dois campos de valores, um representando o
preo de venda padro e outro promocional. Nossa regra seria: se tiver um preo promocional,
dever ser visualizado este preo, caso contrrio o preo padro.
Pensando nisso, logo poderamos imaginar:
- Vamos criar um campo calculado no ClientDataSet e fazer a verificao, se tiver valor no campo
promocional, exibimos este campo, caso contrrio exibimos o valor padro.
Certamente isso funcionaria, porm se precisssemos fazer isso diretamente no banco?
Para este caso utilizamos a funo COALESCE diretamente no SELECT. Vejamos um exemplo:
SELECT
COALESCE(PROD_VALORPROMO, PROD_VALOR, 0) AS PRECO
FROM
PRODUTO

A funo COALESCE recebe N parmetros e retorna o primeiro valor no nulo seguindo a


seqncia da esquerda para direita.
Neste exemplo a funo verificar se o campo PROD_VALORPROMO nulo, se no for retornar
este valor, caso contrrio, verificar o prximo campo (PROD_VALOR), se no for nulo retornar o
valor deste campo, se for nulo seguira a seqncia de verificao at encontrar um valor no nulo.
Se todos forem nulos, retornar o valor do ltimo parmetro da lista, neste exemplo retornaria o
valor 0 (zero).
A deciso se isto deve ser feito diretamente no SELECT ou em um campo calculado depender
muito da situao, porm existe um caso em que a utilizao da funo COALESCE muito
importante. Por exemplo, imagine que precisamos fazer um SELECT exibindo o valor dos produtos
subtraindo seu desconto:
SELECT
PROD_VALOR - PROD_DESCONTO
FROM
PRODUTO

Esta query funcionar perfeitamente desde que um dos campos PROD_VALOR e PROD_DESCONTO
no sejam nulos em nenhuma situao, pois se em algum registro um dos campos forem nulos, a
operao retornar NULL, ao contrrio do que muitos imaginam um valor NULO no considerado
ZERO, qualquer operao com NULO resulta em NULL.
Utilizando a funo COALESCE isto pode ser resolvido facilmente:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 24 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


SELECT
COALESCE(PROD_VALOR,0) - COALESCE(PROD_DESCONTO,0)
FROM
PRODUTO

Desta forma antes de ser efetuada a operao os campos sero analisados e se algum deles for
NULL ser substitudo (apenas na operao) pelo valor zero, em seguida a operao realizada
com base nestas substituies e no teremos mais o problema de retornar NULL na operao.

Concluso
Neste captulo podemos perceber o quanto simples a utilizao da funo COALESCE e ao
mesmo tempo o quanto ela pode ser importante em determinadas situaes.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 25 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Utilizando a funo NULLIF do Firebird


Esta funo utilizada para retornar NULL quando os dois valores passados no parmetro
forem iguais e quando forem diferentes ser retornado o valor do primeiro parmetro. Vejamos um
exemplo:
SELECT
PROD_VALOR,
NULLIF(PROD_VALORPROMO,PROD_VALOR) AS PRECOPROMO
FROM
PRODUTO

Neste exemplo ser retornado NULL quando o campo PROD_VALORPROMO for igual ao campo
PROD_VALOR, quando forem diferentes ser retornado o valor do campo PROD_VALORPROMO, pois
o primeiro da lista.
Poderamos aplicar esta funo em um UPDATE, por exemplo. Imagine que precisamos definir
NULL para o campo PROD_VALORPROMO quando o mesmo for igual ao campo PROD_VALOR,
neste caso podemos fazer da seguinte forma:
UPDATE PRODUTO SET PROD_VALORPROMO = NULLIF(PROD_VALORPROMO, PROD_VALOR);

Concluso
A utilizao da funo NULLIF em um primeiro momento pode no parecer ser to til, mas vale a
pena sabermos de sua existncia, pois certamente em algumas situaes sua utilizao ser de
grande importncia.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 26 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Utilizando a funo CASE do Firebird


A funo CASE bastante semelhante ao comando CASE que utilizamos no Delphi ou mais
precisamente na linguagem Pascal.
Sua funo retornar valores com base em condies. Um exemplo prtico de utilizao aquele
caso onde temos uma tabela de produtos e possumos um campo que representa o Tipo de
Produto onde armazenamos apenas um cdigo como D=DVD, L=LIVRO e assim por diante. Se
precisssemos exibir uma coluna com a descrio do Tipo de Produto, como faramos?
Logo poderamos pensar em criar um campo calculado no ClientDataSet de modo que verificasse
o campo Tipo de Produto e retornasse a respectiva descrio. Isto funciona perfeitamente, mas
podemos fazer isso diretamente no banco de dados atravs da utilizao da funo CASE no
SELECT.
Vejamos um exemplo:
SELECT
PROD_DESCRICAO,
CASE PROD_TIPO
WHEN 'D' THEN 'DVD'
WHEN 'L' THEN 'LIVRO'
WHEN 'I' THEN 'INSTR. MUSICAIS'
ELSE
'PRODUTO DESCONHECIDO'
END AS PROD_TIPO
FROM
PRODUTO

Podemos perceber que a estrutura semelhante ao CASE do Pascal. Esta funo analisar o valor
do campo PROD_TIPO e retornar a descrio de acordo com o seu valor.
Existe uma outra forma de utilizarmos o comando CASE, vamos analisar o exemplo a seguir e logo
entenderemos as diferenas.
SELECT
PROD_DESCRICAO,
CASE
WHEN (PROD_TIPO = 'D') THEN 'DVD'
WHEN (PROD_TIPO = 'L') THEN 'LIVRO'
WHEN (PROD_TIPO = 'I') THEN 'INSTR. MUSICAIS'
WHEN (PROD_TIPO IS NULL AND PROD_ATIVO <> 'S') THEN 'PRODUTO INATIVO'
WHEN (PROD_TIPO IS NULL) THEN 'TIPO NAO DEFINIDO'
ELSE
'TIPO DESCONHECIDO'
END AS PROD_TIPO
FROM
PRODUTO

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 27 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Analisando esta segunda forma, notamos uma diferena, podemos fazer qualquer tipo de
comparao com qualquer campo inclusive verificando se o mesmo nulo, enquanto que na
primeira forma isso no possvel e fazemos a comparao em apenas um campo.

Concluso
Com a utilizao da funo CASE podemos evitar criar campos calculados na aplicao e, alm
disso, pode nos beneficiar em outros aspectos, por exemplo, podemos fazer um agrupamento por
este campo, ordenaes, etc.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 28 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Utilizando domnios no banco de dados


A utilizao de domnios no banco de dados extremamente importante principalmente quando
pensamos em ganho de tempo na manuteno do banco em situaes onde precisamos alterar
estruturas de campos.
Por exemplo, muito comum existncia de tabelas de Clientes, Fornecedores, Transportadoras,
etc, e sempre utilizamos um campo Razo Social para todos estes casos, e na criao da tabela
especificamos o tamanho do campo para cada tabela. Imagine que amanh percebemos que o
campo Razo Social est muito curto e precisamos ajustar, o que teremos que fazer verificar
todas a tabelas que possuem o campo Razo Social e alterar o tamanho do campo para cada
tabela.
Podemos resolver esta situao facilmente utilizando domnios. Em nosso exemplo, criaramos um
domnio chamado DOM_RAZAO_SOCIAL especificando seu tipo como VARCHAR(50), e na criao
das tabelas, indicaramos que os campos Razo Social so do tipo DOM_RAZAO_SOCIAL. Quando
precisarmos alterar o tamanho ou tipo dos campos Razo Social das tabelas, alterarmos apenas o
DOMINIO e conseqentemente todos os campos que o utilizam, sero modificados.

Partindo para prtica


Utilizaremos como exemplo nossa tabela de produtos que possui dois campos representando
valores, este outro caso muito comum de criarmos um domnio representando valores, portanto,
criaremos da seguinte forma:
CREATE DOMAIN DOM_VALOR NUMERIC(9,2);

A instruo SQL acima criar um domnio chamado DOM_VALOR sendo do tipo NUMERIC(9,2).
Agora vamos alterar a estrutura da nossa tabela definindo que os campos PROD_VALOR e
PROD_VALORPROMO utilizaro o domnio.
Caso estivssemos apenas adicionando um campo seria simples:
ALTER TABLE PRODUTO ADD NOVO_CAMPO DOM_VALOR;

Note que logo aps o nome do campo, ao invs de especificarmos que o campo do tipo
NUMERIC definimos que o mesmo do tipo DOM_VALOR.
Em nosso exemplo estaremos alterando campos j existentes, por isso teremos um pouco mais de
trabalho. Podemos exclu-los e cri-los novamente ou alter-los pelo IBExpert que o mesmo j
executa uma instruo SQL para alterar os campos sem ter de recri-los.
Utilizando a primeira opo faramos da seguinte forma:
/* recriando o campo PROD_VALOR */
ALTER TABLE PRODUTO DROP PROD_VALOR;
ALTER TABLE PRODUTO ADD PROD_VALOR DOM_VALOR;
/* recriando o campo PROD_VALORPROMO */
ALTER TABLE PRODUTO DROP PROD_VALORPROMO;
ALTER TABLE PRODUTO ADD PROD_VALORPROMO DOM_VALOR;

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 29 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Se preferir, poder optar pela segunda alternativa utilizando o IBExpert, portanto, com o IBExpert
aberto e conectado no banco de dados, clique na opo Tables na rvore selecionando a tabela
PRODUTO e clique com o boto direito do mouse acessando o item de menu Edit Table...

Figura 1 Editando a tabela de Produto


Sero exibidos todos os campos da tabela de produtos.

Figura 2 Campos da tabela de produtos.


Selecione o campo PROD_VALOR e de um duplo clique.
Ser exibida uma janela para podermos definir o domnio do campo.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 30 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 3 Alterando o tipo do campo para utilizar o domnio


Nesta tela clique no ComboBox de Domnios (Domain) e selecione o domnio que criamos:
DOM_VALOR.
Em seguida basta clicar no boto OK e outra tela ser exibida:

Figura 4 Confirmando a utilizao do domnio no campo


Este seria o SQL que deveramos utilizar para alterarmos um campo definindo que o mesmo
dever utilizar um domnio.
Agora clique no boto Commit e o campo ser alterado conforme podemos observar na lista de
campos a seguir:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 31 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 5 Lista de campos atualizada com o campo PROD_VALOR utilizando o domnio


Repita o mesmo procedimento para o campo PROD_VALORPROMO para que ambos possam estar
utilizando o domnio.
Depois disso se precisar alterar a estrutura do domnio poderamos executar a seguinte instruo
SQL e todos os campos que utilizarem o domnio sero alterados:
ALTER DOMAIN DOM_VALOR TYPE NUMERIC(10,2);

Executando a instruo acima comprovamos que os campos que utilizam o domnio tiveram sua
estrutura modificada, ou seja, a propriedade Size passou para 10:

Figura 6 Campos alterados automaticamente aps a modificao da estrutura do domnio

Concluso
Neste captulo vimos que a utilizao de domnios simples e ao mesmo tempo extremamente
importante permitindo-nos alterarmos a estrutura dos campos facilmente e com maior segurana.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 32 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Utilizando o ISQL para criao e manipulao do banco


de dados
No primeiro mdulo deste curso vimos como criar e manipular um banco de dados atravs do
IBExpert. Tudo se torna simples quando temos uma ferramenta visual, mas se um dia precisarmos
criar ou manipular um banco de dados em um cliente onde no tivesse o IBExpert nem mesmo
Internet para baix-lo, como faramos? E se estivssemos em um ambiente Linux?
Resolvemos isso facilmente utilizando o ISQL que um utilitrio que j acompanha o Firebird,
executado pelo prompt e sua verso para Linux idntica verso para Windows. Com este
utilitrio criamos e manipulamos o banco de dados atravs da sua janela de linha de comando.
Vamos exemplificar utilizando-o para criar um banco de dados e em seguida manipul-lo.

Partindo para prtica


Atravs
do
prompt
de
comando
programas\Firebird\Firebird_1_5\bin

at

diretrio:

C:\Arquivos

de

Estando neste diretrio, digite a seguinte linha de comando:


isql -user sysdba -pass masterkey

Ao pressionar ENTER, ser exibida a janela de linha de comando do ISQL:

Figura 1 - ISQL sendo executado no prompt de comando


Para criamos um banco utilizamos o comando CREATE DATABASE seguido do caminho:
CREATE DATABASE c:\CursoClientDataSet2\Projeto\NovoBanco.fdb;

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 33 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


No esquea de colocar ; (ponto-e-vrgula) ao final da linha, isso o que indica o trmino de um
comando. Aps ter digitado a linha acima, aperte o ENTER para executar este comando.

Figura 2 - Banco sendo criado pelo ISQL


Neste momento j temos o banco de dados criado, agora podemos executar as instrues SQL
para criar as tabelas.
Vamos criar apenas uma tabela para demonstrarmos sua utilizao.
Digite o seguinte comando SQL:
CREATE TABLE CLIENTE (CLI_ID INTEGER NOT NULL PRIMARY KEY, CLI_NOME VARCHAR(50));

Aperte o ENTER em seguida digite a linha abaixo:


INSERT INTO CLIENTE VALUES (1, CLIENTE 1);

Aperte o ENTER e digite:


COMMIT;

Em seguida pressione ENTER para confirmar o ltimo comando, veja abaixo como ficou nossa
seqncia de comandos executados:

Figura 3 - Criando a tabela de cliente e inserindo dados


Agora que j temos a tabela criada e com um registro inserido, podemos visualizar os dados
executando um SELECT:
Digite a seguinte linha no prompt:
SELECT * FROM CLIENTE;

Pressione ENTER e ser exibido o seguinte resultado:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 34 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 4 - Executando um SELECT para visualizar os dados da tabela


Note que podemos executar qualquer instruo SQL neste prompt, ou seja, podemos manipular o
banco de dados por completo.
O ISQL possui alguns comandos em particular que podem ser visualizados digitando HELP na linha
de comando:

Figura 5 - Executando o comando HELP


Temos diversos comandos que podemos utilizar no ISQL, um comando importante de ser
comentado o SHOW que nos permite visualizar informaes de diversos objetos como cita o help:
banco, tabelas, procedures, etc.
Por exemplo, para visualizarmos a estrutura da tabela CLIENTE utilizamos a seguinte linha de
comando:
SHOW TABLE CLIENTE;

Ao pressionar ENTER teremos o seguinte resultado:

Figura 6 - Exibindo informaes de uma tabela

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 35 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Para sair do ISQL basta digitar:
EXIT;

Em seguida pressionar ENTER para confirmar.


Todos os SQL acima foram executados no banco em que criamos, pois logo aps a criao do
banco ficamos conectados no mesmo, porm podemos entrar no ISQL e conectar em um banco de
dados j existente da seguinte forma:
Entramos no ISQL atravs da linha de comando j demonstrada:
isql user SYSDBA pass MASTERKEY

Em seguida, no prompt do ISQL utilizamos o comando CONNECT informando o caminho do banco,


por exemplo:
CONNECT "C:\CursoClientDataSet2\projeto\exemplo.fdb";

Figura 7 Conectando em um banco j existente


Neste momento estamos conectados ao banco C:\CursoClientDataSet2\projeto\exemplo.fdb e
agora podemos executar SQL's, visualizar tabelas, etc.
Para sair utilizamos o mesmo comando EXIT.

Concluso
Apesar de termos ferramentas visuais que auxiliam na manipulao do banco podemos perceber o
quanto o ISQL pode ser til em momentos que no temos estas ferramentas disponveis
principalmente quando estamos em um ambiente Linux. Vale a pena explorar o ISQL para saber
de todos seus recursos que certamente sero importantes em momentos como este.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 36 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Realizando Backups e Restores no Banco de Dados


Todos ns sabemos da importncia que realizar backups constantes do banco de dados. Para
realizarmos backups do banco Firebird no recomendvel apenas copiar o arquivo FDB, muito
mais seguro fazer um backup atravs do utilitrio que acompanha o Firebird chamado GBAK.
Quando realizamos um backup atravs do GBAK ele faz uma compactao do banco e exclui
linhas de registros no mais utilizveis, conseqentemente ao final teremos um arquivo menor
inclusive na restaurao.
recomendvel tambm utilizarmos os processo de backup e restore quando precisamos transferir
o banco de dados de uma mquina para outra, ou at mesmo de uma verso do banco para outra.
Como sabemos, os utilitrios que acompanham o Firebird no possuem uma IDE, portanto o
GBAK utilizado tambm atravs do prompt de comando.
Vamos realizar um backup e logo em seguida um restore do banco de dados para visualizarmos na
prtica esse processo.

Partindo para prtica


No prompt de comando v at o diretrio de instalao do Firebird e entre na pasta bin. Em nosso
exemplo ser:
C:\Arquivos de programas\Firebird\Firebird_1_5\bin

Nesta pasta digite a seguinte linha de comando:


gbak -USER SYSDBA -PASS masterkey c:\CursoClientDataSet2\Projeto\exemplo.fdb
C:\CursoClientDataSet2\Projeto\exemplo.bak

Figura 1 - Realizando o Backup do Banco de Dados


O que passamos como parmetro para o GBAK o nome do usurio e a senha, logo em seguida
informamos o banco de origem e o caminho de destino onde ser gerado o backup.
Ao executar podemos verificar que em C:\CursoClientDataSet2\Projeto foi gerado o arquivo de
backup exemplo.bak .
Vamos agora executar um restore do banco de dados utilizando o exemplo.bak
Estando na pasta bin do Firebird, digite a seguinte linha de comando:
gbak -c -USER SYSDBA -PASS masterkey c:\cursoclientdataset2\projeto\exemplo.bak
c:\cursoclientdataset2\projeto\exemplo_restaurado.fdb

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 37 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 2 - Executando um Restore do Banco


A diferena ao executarmos o GBAK para restore que passamos o parmetro c indicando que
o banco dever ser criado a partir do arquivo exemplo.bak.
Podemos executar um restore fazendo um replace no banco ao invs de um create, neste caso
utilizaramos o parmetro r ao invs do c, porm particularmente falando prefiro utilizar o
parmetro c que cria o banco do zero ao invs de sobrescrev-lo.

Concluso
O gbak possui muitas opes de parmetros que podem ser exploradas, demonstramos aqui a
forma mais simples que j o suficiente para utilizarmos no dia-a-dia nos permitindo realizar
backups e restore de forma segura.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 38 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando e utilizando UDF's


Muitos podem j ter ouvido falar em UDF, mas talvez poucos exploraram ou conheceram o poder
que pode nos trazer dependendo de como utilizamos.
UDF (User Defined Functions) so funes definidas pelo usurio para serem utilizadas no banco
de dados.
Por exemplo, no Delphi podemos criar uma funo que recebe N parmetros e retorna um
determinado valor. Com UDF podemos fazer o mesmo, ou seja, criamos uma funo que recebe
alguns parmetros e nos retorna um determinado valor, porm esta funo seria utilizada no banco
de dados, por exemplo, em um SELECT, em uma Stored Procedure, etc.
Vejamos um exemplo prtico para entendermos melhor:
SELECT
CALCULA_VALOR(PROD_VALOR, PROD_DESCONTO)
FROM
PRODUTO

A funo CALCULA_VALOR no existe no Firebird, ela seria uma funo que poderamos ter criado
em uma UDF e utilizada em um SELECT.
A criao de uma UDF resume em gerarmos uma DLL com as funes que gostaramos de utilizar.
A criao desta biblioteca pode ser feita em qualquer linguagem que gere uma biblioteca
compartilhada, no caso do ambiente Windows seria a DLL e no Linux um Shared Object.
Depois de criada a UDF devemos registrar as funes, assim poderemos utiliz-las livremente em
SELECTs, UPDATEs, SPs, etc.
Algumas regras devem ser obedecidas ao criarmos uma UDF, vejamos algumas:
- S permitido ter no mximo 10 parmetros
- Os tipos de dados devem ser somente aqueles suportados pelo Firebird
- O retorno da funo dever ser um tipo de dado natural da linguagem C
Existem outras regras mais detalhadas e tcnicas no que diz respeito a tratamento de strings, j
que precisamos garantir que elas sejam thread safe.
Neste captulo demonstraremos dois exemplos de funes utilizando inteiros e strings que o mais
comum, porm outros exemplos podem ser obtidos na Internet com mais detalhes, por exemplo,
em casos de utilizao de blobs entre outros.
Antes de partimos para prtica, vamos apenas explicar como seria a declarao de uma UDF no
Firebird.
Para registrarmos uma funo utilizamos o comando DECLARE EXTERNAL FUNCTION.
Vejamos um exemplo de uma UDF j existente no Firebird:
DECLARE EXTERNAL FUNCTION rtrim
CSTRING(255)
RETURNS CSTRING(255) FREE_IT
ENTRY_POINT 'IB_UDF_rtrim' MODULE_NAME 'ib_udf';

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 39 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Aps o comando DECLARE EXTERNAL FUNCTION temos o nome da funo a ser registrada,
neste caso rtrim, logo em seguida so declarados os tipos de parmetros que esta funo
recebe, no caso apenas um parmetro do tipo CSTRING(255). Logo aps declarado o tipo de
retorno (RETURNS) sendo CSTRING(255). A declarao FREE_IT indica que o Firebird dever
liberar a memria alocada dinamicamente, isto utilizado sempre que retornamos strings. Aps o
ENTRY_POINT declarado o nome da funo contida na biblioteca, neste caso a funo
IB_UDF_rtrim e ao final temos o nome da biblioteca que contm as funes, neste caso chama-se
ib_udf.
Na indicao do nome do arquivo recomendvel que no seja declarado a extenso, pois assim
no teramos problemas se migrssemos o servidor de um ambiente Windows para Linux ou viceversa, pois no Windows o servidor Firebird estaria utilizando a extenso .dll e no Linux .so. Outro
detalhe importante que no precisamos informar o path completo da biblioteca, pois a mesma
dever estar dentro da pasta UDF do Firebird.
Um outro exemplo de UDF utilizando mais de um parmetro de entrada:
DECLARE EXTERNAL FUNCTION substr
CSTRING(255), SMALLINT, SMALLINT
RETURNS CSTRING(255) FREE_IT
ENTRY_POINT 'IB_UDF_substr' MODULE_NAME 'ib_udf';

Um exemplo que no retorna string:


DECLARE EXTERNAL FUNCTION tan
DOUBLE PRECISION
RETURNS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'IB_UDF_tan' MODULE_NAME 'ib_udf';

Neste ltimo exemplo podemos perceber que no foi utilizado o FREE_IT, pois no est sendo
retornado um tipo string. Foi utilizado tambm o BY VALUE indicando que o tipo de retorno por
valor e no por referncia.

Excluindo o registro de uma UDF


Para excluirmos o registro de uma UDF utiliza-se o comando DROP EXTERNAL FUNCTION e logo
aps informamos o mesmo nome indicado no registro, por exemplo:
DROP EXTERNAL FUNCTION CALCULA_VALOR

Partindo para prtica


Vamos agora criar nossa UDF no Delphi e logo aps registraremos e utilizaremos no Firebird.
Abra o Delphi e clique no Menu File->New->Other...
Na tela exibida escolha a opo DLL Wizard.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 40 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 1 - Criando uma nova DLL


Ao confirmar j vamos gravar o projeto
C:\CursoClientDataSet2\Projeto\UDF.

com

nome

exemplo_udf.dpr na

pasta

Neste momento j podemos dar incio criao das nossas funes, porm antes vamos criar uma
nova unit para centralizarmos e ficar mais organizado. V at o menu File->New->Unit e logo em
seguida salve a unit como uFuncoes.pas.
Agora vamos implementar duas funes:
function calcula_valor(Valor: PDouble; Desconto: PDouble): Double; cdecl; export;
function primeiro_nome(nome: pchar): pchar; cdecl; export;

A unit final dever ficar da seguinte forma:


unit uFuncoes;
interface
function calcula_valor(Valor: PDouble; Desconto: PDouble): Double; cdecl; export;
function primeiro_nome(nome: pchar): pchar; cdecl; export;
implementation
function calcula_valor(Valor: PDouble; Desconto: PDouble): Double;
begin
Result := Valor^ - Desconto^;
end;
function primeiro_nome(nome: pchar): pchar;
var
iPos: Integer;
begin
iPos := Pos(#32, Pchar(nome));
if iPos = 0 then iPos := Length(Pchar(nome));
Result := Pchar(Copy(Pchar(nome), 1, iPos));
end;
initialization
IsMultiThread :=

true;

end.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 41 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


O objetivo da primeira funo apenas retornar o valor fazendo a subtrao entre os dois valores
passados no parmetro. Utilizaremos esta funo para calcular o valor do produto, onde
passaremos o valor e o desconto como parmetros.
A segunda funo retornar o primeiro nome utilizando como base o caractere #32 (espao) a
partir da string passada como parmetro. Utilizaremos esta funo para retornar o primeiro nome
do produto.
O que h de diferente nas declaraes a utilizao das diretivas cdecl e export ao final das
funes, isto dever ser sempre utilizado para podermos exportar a funo e utilizar banco de
dados.
Perceba tambm que utilizamos os tipos PChar e PDouble ao invs do tipo String ou Double,
isso tambm necessrio, devemos utilizar ponteiros para os respectivos tipos de dados.
Poderamos utilizar descritores que nos permite trabalhar com qualquer tipo de dado, inclusive
possibilitando o tratamento de valores nulos. No entraremos em detalhes sobre descritores, pois
tornaria este captulo muito extenso e complexo, porm na Internet, em diversos sites e na
Firebase (www.firebase.com.br) temos bastante artigos sobre este assunto.
A ltima observao que utilizamos a declarao IsMultiThread ao final da unit de modo que
o gerenciador de memrias possa trabalhar com threads.
Depois de declarado e criado as funes, precisamos export-las, portanto fazemos isso no
Source do Projeto. Clique no menu Project->View Source, ser exibido o cdigo fonte do projeto
conforme demonstra figura a seguir:

Figura 2 - Cdigo fonte do projeto


Devemos alterar o cdigo do projeto incluindo as seguintes linhas antes do begin:
exports
calcula_valor,
primeiro_nome;

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 42 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Devemos informar quais funes queremos exportar para podermos registr-las no banco Firebird,
pois poderamos ter outras funes apenas para auxlio, portanto, no precisariam ser exportadas.
O cdigo final do projeto dever ficar da seguinte forma:

Figura 3 - Exportando as funes a serem utilizadas


Agora j podemos compilar o projeto para que seja gerada a DLL.
O prximo passo ser copiar a DLL para o diretrio de UDF's do Firebird, portanto em nosso
exemplo
copiaremos
a
DLL
exemplo_udf.dll
para
C:\Arquivos
de
programas\Firebird\Firebird_1_5\UDF

Figura 4 Copiando a dll para o diretrio UDF do Firebird


O ltimo passo registr-la, para isso devemos executar as seguintes instrues SQL:
DECLARE EXTERNAL FUNCTION CalculaValor
DOUBLE PRECISION, DOUBLE PRECISION
RETURNS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'calcula_valor' MODULE_NAME 'exemplo_udf';
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 43 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


DECLARE EXTERNAL FUNCTION primeironome
CSTRING(255)
RETURNS CSTRING(255) FREE_IT
ENTRY_POINT 'primeiro_nome' MODULE_NAME 'exemplo_udf';

Estas instrues SQL's podero ser executadas no IBExpert atravs do menu Tools->Script
Executive... conforme demonstra figura a seguir:

Figura 5 Executando as instrues SQL para registrar as funes


Para fins didticos o nome da funo declarada no banco (aps o FUNCTION) diferente do nome
da funo que criamos no Delphi (declarada aps o ENTRY_POINT). Estes nomes poderiam ser
iguais, apenas foi exemplificado desta forma para demonstrar que no obrigatrio registrar a
funo com o mesmo nome.
Depois de executada as instrues, j podemos realizar os testes utilizando as funes em um
SELECT:
SELECT
PROD_DESCRICAO,
PROD_VALOR,
PROD_DESCONTO,
PrimeiroNome(PROD_DESCRICAO),
CalculaValor(PROD_VALOR, PROD_DESCONTO)
FROM
PRODUTO

Figura 6 Analisando o resultado com o uso das funes

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 44 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Note que no grid temos os dados do produto e o resultado das funes PrimeiroNome (pegando
o primeiro nome do produto) e CalculaValor (valor do produto - desconto) da UDF.

Concluso
A utilizao de UDF's pode nos trazer grandes benefcios j que muitas rotinas que as vezes
precisamos no esto disponveis no Firebird, mas podem ser criadas no Delphi e utilizadas no
banco. Apenas devemos prestar bastante ateno ao utilizarmos UDFs principalmente quando o
assunto strings para no termos problemas de gerenciamento de memria.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 45 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Uma viso geral sobre Stored Procedures


At este momento trabalhamos com todas as regras de negcio diretamente na aplicao, nossa
proposta agora criar as regras de negcio no banco de dados atravs da utilizao de Stored
Procedures e Triggers.
O objetivo deste captulo explicar o que uma Stored Procedure e quando devemos utiliz-la
para que logo em seguida possamos demonstrar como criamos, implementamos e utilizamos no
ambiente Delphi com o ClientDataSet em conjunto com a DBExpress.

O que uma Stored Procedure?


Antes de tudo, para no ficar repetitivo citar Stored Procedure, em alguns casos estarei
abreviando para SP, ok?
Stored Procedures so rotinas armazenadas no banco de dados podendo ser disparadas pelo
banco ou por aplicaes e so executadas atravs de SELECTs quando retornam valores ou
atravs de um EXECUTE PROCEDURE quando no retornam valores.
A estrutura de uma SP um pouco semelhante a uma procedure do Delphi, ou mais precisamente,
da linguagem Pascal, onde temos um cabealho informando os parmetros de entrada e sada e o
corpo contendo sua implementao, sendo utilizado para isso uma linguagem especfica (PSQL).
Na implementao de uma SP podemos criar variveis, executar instrues SQL's, chamar outras
SP's, varrer dados de uma tabela, executar clculos, atualizar registros, etc.
Uma Stored Procedure pode executar determinadas tarefas e tambm retornar valores, estas SP's
so chamadas de Stored Procedures Selecionveis.

Vantagens

Aplicaes mais leves


Reduo de trfego em rede
Regras de negcio centralizadas no banco
Compartilhamento das regras para outras aplicaes
Ganho de performance na execuo de processos

Desvantagens
Citar as desvantagens algo bastante complicado, pois por experincia prpria e opinio particular
no vejo nenhuma desvantagem em sua utilizao, apenas devemos estar cientes de algumas
questes:

Stored Procedures so dependentes do banco, isso significa que uma troca de banco de
dados implicar em uma grande manuteno.

Utilizando SPs os processos estaro centralizados no servidor, isso quer dizer que
devemos investir mais em hardware na mquina onde estar o servidor de banco de dados.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 46 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Quando utilizar uma SP?


No existe uma regra para isso, devemos analisar caso a caso e verificar se determinado processo
seria possvel ser rodado diretamente no banco ou parte dele passando parmetros, por exemplo.
Vamos analisar uma situao onde a utilizao de uma SP seria mais eficiente que um processo
sendo executado na aplicao.
Imagine que voc tenha uma aplicao que precise atualizar uma lista de preo de produtos e este
processo envolve analisar alguns dados do produto e com base nisso atualizar seu valor.
Se optssemos por fazer isso na aplicao, poderamos fazer de algumas formas:

Utilizando o ClientDataSet:
Montaramos uma query que retornaria todos os produtos, abriramos o ClientDataSet ligado a esta
query, faramos uma varredura em todos produtos analisando cada um e logo em seguida
editaramos o registro no ClientDataset e gravaramos.

Utilizando Querys
Abririamos uma Query com todos os produtos, faramos um loop analisando cada produto e logo
em seguida executaramos uma outra query atualizando o preo do produto com base nos dados
analisados.
Nestes dois casos podemos perceber que um trfego em rede ser gerado, pois seremos
obrigados a carregar todos os produtos que precisamos alterar, pois dependemos das informaes
de cada produto para podermos alterar seu preo.

Utilizando uma SP
Ao utilizarmos uma SP podemos fazer esta varredura de produtos diretamente no servidor de
banco de dados sem a necessidade de trafegar os registros pela rede. No Delphi apenas
executaramos a Stored Procedure e todo processo seria executado no servidor.
Podemos perceber que neste caso a utilizao de uma SP muito mais eficaz que a execuo do
processo na aplicao.

Uma outra vantagem de SP interessante


Podemos implementar uma SP que apenas executa determinadas instrues SQL no banco de
dados, mesmo no havendo trfego teramos uma performance melhor do que executar estas
instrues diretamente pela aplicao.
Isso ocorre pelo seguinte fato: quando a aplicao executa uma query no banco, o servidor tem a
responsabilidade de analisar o SQL, verificar se est tudo correto, fazer um parser, fazer um plano
de execuo etc. Utilizando SP este processo realizado apenas uma vez no momento em que
criamos a SP no banco, depois de armazenada podemos executar e este trabalho no ser mais
necessrio. Obviamente que em aplicaes pequenas no notaremos tanta diferena, somente em
um ambiente onde h um grande nmero de querys sendo executadas a todo instante.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 47 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


- Legal, ento a utilizao de SP sempre ser mais eficaz, ento devo fazer tudo atravs de SP,
largar de vez o ClientDataSet, etc?
- Calma, no bem por este caminho
- Ser que vale a pena tanto trabalho para coisas mais simples?
Algumas pessoas so viciadas em SPs e acabam utilizando inclusive em casos de cadastros de
registros no banco. No precisamos chegar a este ponto, podemos continuar a utilizar o
ClientDataSet tranqilamente, j que ele nos traz grandes benefcios e facilidades, na maioria dos
casos o ideal utilizarmos as SP's para regras de negcios (processos) e em alguns casos para
querys mais complexas ou que so executadas a todo instante.
Um fato que no devemos esquecer a questo de performance do servidor, pois utilizando SP
todo processo estar centralizado, portanto muito importante que haja um bom investimento de
hardware no servidor.

Utilizar SP (regras no banco) ou aplicaes multicamadas


Este um assunto que gera muitas dvidas e muito difcil decidir qual o melhor caminho, pois
temos diversas vantagens e desvantagens comparando cada um desses.
Sempre que me perguntam digo que depende muito do caso, por exemplo, se voc no pensa em
trocar de banco de dados, por que no usar SPs centralizando as regras no banco? Mas e se voc
pensa em trocar, ser que valeria a pena fazer tudo no banco?
Como nosso foco neste momento a utilizao de SP, gostamos e confiamos no FB e no
pretendemos mudar ento iremos falar de SP e numa prxima oportunidade falaremos de
Aplicaes multicamadas. O objetivo ao longo do curso demonstrar as metodologias e
tecnologias e a partir disso termos conhecimentos suficientes para decidirmos o que melhor para
ns.

Concluso
Neste captulo abordamos a teoria sobre Stored Procedures citando vantagens, desvantagens e
casos de uso recomendados para sua utilizao. A seguir abordaremos a prtica demonstrando
como criamos e implementamos Stored Procedures no Firebird.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 48 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando e implementando Stored Procedures


A criao de uma Stored Procedure feita atravs do comando CREATE PROCEDURE onde
informamos o nome da SP, os parmetros de entrada, e no caso de uma SP selecionvel, os
parmetros de retorno.
Vejamos um exemplo de uma SP no selecionvel, ou seja, que no retorna valores:
CREATE PROCEDURE SP_AJUSTA_VALORES
(INDICE_AJUSTE FLOAT, CATEGORIA INTEGER)
AS
BEGIN
/* aqui vem a implementao */
END

Neste exemplo declaramos uma Stored Procedure com o nome SP_AJUSTA_VALORES recebendo
dois parmetros de entrada: INDICE_AJUSTE do tipo FLOAT e CATEGORIA do tipo INTEGER.

Executando a Stored Procedure


Para executarmos uma Stored Procedure utilizamos o comando EXECUTE PROCEDURE. Utilizando
como exemplo a SP criada anteriormente, executaramos da seguinte forma:
EXECUTE PROCEDURE SP_AJUSTA_VALORES(10,1);

Note que passamos os parmetros logo aps o nome da procedure separando-os com vrgula,
muito semelhante ao que fazemos no Delphi.

Excluindo uma Stored Procedure


A excluso de uma SP feita atravs do comando DROP PROCEDURE.
DROP PROCEDURE SP_AJUSTA_VALORES;

Alterando uma Stored Procedure


Para alterarmos a implementao ou cabealho de uma Stored Procedure, utilizamos o comando
ALTER PROCEDURE NOME_DA_PROCEDURE e logo aps informamos os parmetros de entrada,
sada e a implementao como se estivssemos criando do zero, a diferena que ao invs de
estarmos utilizando CREATE PROCEDURE estaremos utilizando o ALTER PROCEDURE.
ALTER PROCEDURE SP_AJUSTA_VALORES
(INDICE_AJUSTE FLOAT, CATEGORIA INTEGER, NOVO_PARAMETRO INTEGER)
AS
BEGIN
/* aqui vem a NOVA implementao */
END

At poderamos dropar a SP e criar novamente, mas isso no seria possvel caso a mesma esteja
sendo utilizada (executada) por outra SP ou Trigger.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 49 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando uma Stored Procedure Selecionvel (que retorna valores)


SET TERM ^;
CREATE PROCEDURE SP_AJUSTA_VALORES_COM_RETORNO
(INDICE_AJUSTE FLOAT, CATEGORIA INTEGER)
RETURNS
(QTDE_PRODS_ATUALIZADOS INTEGER)
AS
BEGIN
QTDE_PRODS_ATUALIZADOS = 10;
SUSPEND;
END
^
SET TERM ; ^

Neste segundo exemplo declaramos a SP utilizando o RETURNS indicando que temos parmetros
de retorno, neste caso temos apenas um: QTDE_PRODS_ATUALIZADOS. Poderamos ter mais
parmetros de retorno, bastaria separ-los por virgula da mesma forma que feita para os
parmetros de entrada.
Note que neste caso utilizamos dois novos comandos: SET TERM e SUSPEND, para no complicar
o meio de campo agora , explicarei isso mais adiante.

Executando uma Stored Procedure Selecionvel


Para

extrairmos os valores retornados por uma SP utilizamos SELECT * FROM


NOME_DA_PROCEDURE como se ela fosse uma tabela, onde os parmetros de sada sero retornados

como campos.
No exemplo da SP criada anteriormente, executaramos da seguinte forma:
SELECT * FROM SP_AJUSTA_VALORES_COM_RETORNO(10,1);

Executando
esta
instruo
ser
retornado
um
registro
contendo
o
campo
QTDE_PRODS_ATUALIZADOS (parmetro de retorno definido na SP) com valor igual a 10 conforme
implementamos na SP. Se tivssemos dois parmetros de retorno, por exemplo, seriam
retornados 2 campos no SELECT, e assim por diante, como dito, todos parmetros de sada da SP
so retornados como campos no SELECT. Mais adiante veremos como retornar mais de um
registro.

Criando uma Stored Procedure que executa outra Stored Procedure


possvel uma Stored Procedure executar outra SP, para isto utilizamos o comando EXECUTE
PROCEDURE.
SET TERM ^;
CREATE PROCEDURE SP_EXEC_OUTRA_SP
AS
BEGIN
/* aqui poderamos ter outros cdigos...*/
EXECUTE PROCEDURE SP_AJUSTA_VALORES(10,1);
END
^
SET TERM ; ^
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 50 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Este um exemplo de uma SP executando outra SP que no retorna valores, no caso de SPs
selecionveis utilizamos outro comando que veremos mais adiante.

Implementando uma SP
Em linguagens de programao temos declaraes de variveis, ifs, fors, whiles, etc e na
implementao de uma SP tambm contamos com isso. Veremos agora como aplicamos nas SPs.

Comentrios
Da mesma forma que utilizamos comentrios em instrues SQL, podemos utilizar tambm em
SPs utilizando a mesma regra:
/* exemplo de um comentrio
podendo estar em mais de uma linha
*/

No firebird 1.5 podemos ter comentrios de apenas uma linha utilizando o sinal --- comentrio de uma linha

Particularmente prefiro utilizar a primeira opo que o padro SQL.

Set Term
Como vimos na criao da Procedure SP_AJUSTA_VALORES_COM_RETORNO, tivemos que utilizar
o comando SET TERM, agora vamos entender a razo disto.
O comando SET TERM determina o terminador SQL. O terminador o que indica o final de um
comando SQL e o padro o ; (ponto-e-vrgula).
Agora que vem o problema:
Se utilizarmos este terminador na implementao da SP, como indicaremos ao banco o incio e fim
do nosso comando CREATE PROCEDURE j que temos um ponto-e-vrgula aparecendo antes do
final deste comando?
O servidor ir achar que seu comando CREATE PROCEDURE termina no primeiro terminador
(ponto-e-vrgula) que ele encontrar, e isso no est correto!
Ento o que fazemos algo bem simples:
Definimos um novo terminador (SET TERM ^ ;) logo no incio dizendo que no utilizaremos o
terminador padro para criar a SP e sim um novo que no caso o ^ (acento circunflexo), ao final
terminamos o comando CREATE PROCEDURE com este novo terminador (END ^) e voltamos o
terminador padro ponto-e-vrgula (SET TERM ; ^).
Desta forma ao executarmos o comando CREATE PROCEDURE o servidor saber que o final deste
comando ser ao encontrar o caractere ^ (acento circunflexo).

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 51 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Note que o SET TERM utilizado no incio diferente do utilizado no fim. No incio indicamos o novo
terminador (^) e finalizamos o comando com o terminador padro (ponto-e-vrgula). Ao final
definimos o terminador anterior (ponto-e-vrgula) e finalizamos o comando com o terminador atual
(^).

Declarao de variveis
Podemos declarar qualquer tipo de varivel desde que seja um tipo de dados suportado pelo
Firebird. A declarao feita atravs do comando DECLARE VARIABLE, vejamos um exemplo:
DECLARE VARIABLE QTDE INTEGER;

Neste caso estamos declarando uma varivel do tipo INTEGER.


Na implementao de uma SP as declaraes de variveis so feitas aps o AS e antes do BEGIN:
SET TERM ^;
CREATE PROCEDURE EXEMPLO (VALOR NUMERIC(9,2))
AS
DECLARE VARIABLE NOME VARCHAR(50);
DECLARE VARIABLE IDADE INTEGER;
BEGIN
/* implementao da SP */
END
^
SET TERM ; ^

Acessando e atribuindo valores a variveis ou parmetros


Diferente da linguagem pascal que atribumos valores com := em PSQL utilizamos apenas o sinal
de = para atribuio:
BEGIN
VALORFINAL = VALOR DESCONTO;
END

Existe uma outra forma de fazermos referncia a uma varivel ou parmetro utilizando o sinal :
(dois pontos) antes do nome. Veja o exemplo abaixo e logo em seguida vamos entender a
diferena:
BEGIN
VALORFINAL = :VALOR - :DESCONTO
END

Utilizamos esta forma para indicar que queremos fazer acesso ao parmetro ou varivel ao invs
de um campo da tabela.
Exemplo:
Na implementao da SP poderamos ter um SELECT da seguinte forma:
SELECT * FROM PRODUTO WHERE PROD_CODIGO = CODIGO

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 52 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Se utilizarmos desta forma o servidor entendera que voc est tentando retornar o produto cujo
valor da coluna PROD_CODIGO seja igual ao valor da coluna CODIGO. No isso que gostaramos,
queremos que retorne o produto cujo valor da coluna PROD_CODIGO seja igual ao valor do
parmetro CODIGO. Neste caso utilizamos o sinal de dois pontos antes do nome do parmetro
para o servidor saber que CODIGO um parmetro e no uma coluna.
Ento o correto seria utilizar da seguinte forma:
SELECT * FROM PRODUTO WHERE PROD_CODIGO = :CODIGO

IF/ELSE
A regra para utilizao do IF simples, basta que a condio esteja entre parnteses:
IF (:VALOR = 1) THEN
BEGIN
CONDICAO = VERDADEIRA;
END
ELSE
BEGIN
CONDICAO = FALSA;
END

ou
IF (:VALOR = 1) THEN
CONDICAO = VERDADEIRA;
ELSE
CONDICAO = FALSA;

Podemos perceber que semelhante linguagem Pascal, diferenciando apenas que quando
utilizamos o BEGIN/END no ltimo END no temos o ponto-e-vrgula, e quando no utilizamos
BEGIN/END a linha aps o IF deve ser terminada com ponto-e-vrgula.
Vale lembrar que neste exemplo a utilizao do : (dois pontos) para fazer referncia varivel
opcional.

LOOPS
A nica forma que temos para fazer um loop atravs do comando WHILE. No temos o comando
FOR, na realidade at existe, porm utilizado para percorrer os registros de uma tabela. Veremos
sua utilizao mais a seguir, vamos agora verificar como a sintaxe para utilizao do WHILE:
CONTADOR = 1
WHILE (:CONTADOR < 10) DO
BEGIN
CONTADOR = :CONTADOR + 1;
END

Vale lembrar que neste exemplo a utilizao do : (dois pontos) para fazer referncia varivel
tambm opcional.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 53 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

SELECT...INTO
Atravs do comando SELECT...INTO podemos armazenar em variveis valores de campos
obtidos de SELECTs que retornam apenas um registro.
Vejamos um exemplo
SET TERM ^ ;
CREATE PROCEDURE SP_EXEMPLO_SELECT_INTO(CODIGO INTEGER)
AS
DECLARE VARIABLE VALOR NUMERIC(9,2);
DECLARE VARIABLE PROMOCAO NUMERIC(9,2);
BEGIN
SELECT
PROD_VALOR,
PROD_VALORPROMO
FROM
PRODUTO
WHERE
PROD_CODIGO = :CODIGO
INTO
:VALOR,
:PROMOCAO;
IF (:PROMOCAO>0) THEN
UPDATE PRODUTO SET PROD_VALOR = :PROMOCAO WHERE PROD_CODIGO = :CODIGO;
END
^
SET TERM ; ^

Analisando esta SP passo a passo, feito um SELECT na tabela PRODUTO extraindo os campos
PROD_VALOR e PROD_VALORPROMO e seus valores so armazenados nas variveis VALOR e
PROMOCAO na respectiva ordem. Note que utilizamos o sinal de dois pontos para fazer referncia
s variveis.
Ao final verificado o valor da varivel PROMOCAO e caso seja maior que zero, atualizado a
tabela PRODUTO.
Ser muito comum a utilizao do SELECT...INTO para podermos avaliar valores de campos e
tomar determinadas decises.
Cuidado com SELECTs que podem retornar mais de um registro!
Note que nosso SELECT retorna apenas um registro, por esta razo conseguimos utiliz-lo no
comando SELECT...INTO armazenando os dados retornados em variveis. Se tirssemos a
condio WHERE ou colocssemos outra condio que resultasse em mais um registro, teramos a
seguinte mensagem de erro sendo exibida ao executar esta SP:

Figura 1 Erro exibido quando utilizamos selects que retornam mais de um registro

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 54 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Para armazenarmos em variveis dados de mais de um registro utilizamos o FOR
SELECT...INTO que veremos a seguir.

FOR SELECT...INTO
O comando FOR SELECT...INTO muito semelhante ao SELECT...INTO que vimos
anteriormente, a diferena que ele nos permite trabalhar com SELECTs que retornam mais de
um registro, ou seja, podemos percorrer as linhas resultadas do SELECT e em cada ciclo
armazenamos os valores dos campos em variveis da mesma forma que fazemos no
SELECT..INTO e executamos tarefas dentro do bloco BEGIN/END.
importante sabermos que a leitura dos registros feita de forma unidirecional, ou seja,
percorremos apenas para frente, no temos a possibilidade de voltar o cursor.
Vamos verificar um exemplo para entendermos melhor:
SET TERM ^;
CREATE PROCEDURE CALCULA_TOTAL_PRODUTOS
RETURNS
( VALOR_TOTAL NUMERIC(9, 2) ) AS
DECLARE VARIABLE CODIGO INTEGER;
DECLARE VARIABLE VALOR NUMERIC(9,2);
BEGIN
VALOR_TOTAL = 0;
FOR
SELECT
PROD_CODIGO,
PROD_VALOR
FROM
PRODUTO
INTO
:CODIGO,
:VALOR
DO
BEGIN
VALOR_TOTAL = :VALOR_TOTAL + :VALOR;
END
SUSPEND;
END
^
SET TERM ; ^

Neste exemplo ser realizada uma varredura em todos registros retornados pelo SELECT e para
cada registro os valores dos campos sero armazenados nas variveis (informadas aps o INTO)
declaradas na respectiva ordem.
No bloco BEGIN/END fazemos o tratamento necessrio para cada registro. Neste exemplo
estamos totalizando os valores dos produtos na varivel VALOR_TOTAL (que na realidade um
parmetro de retorno da SP), para isso incrementamos utilizando como base a varivel VALOR que
estar com o valor do produto naquele ciclo.
O comando SUSPEND necessrio neste caso por se tratar de uma SP que retorna valor. A seguir
ser explicada melhor sua utilizao.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 55 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

SUSPEND
A utilizao do SUSPEND necessria quando utilizamos SP's que retornam valores. Sua funo
suspender a execuo da SP retornando os valores e continuar a SP (do ponto em que parou)
quando o prximo FETCH for requisitado.
No exemplo anterior utilizamos o SUSPEND ao final da SP, pois aps termos percorrido os registros
retornamos o valor contido na varivel VALOR_TOTAL.

Retornando mais de um registro em SP selecionvel


interessante entendermos bem o conceito do SUSPEND, pois isso que nos permitir retornar
mais de um registro em uma SP selecionvel.
Com base no que comentamos sobre o comando SUSPEND, vamos analisar o que aconteceria se
utilizssemos este comando mais de uma vez na SP:
SET TERM ^ ;
CREATE PROCEDURE SP_TESTE_SUSPEND
RETURNS
(CAMPO1 INTEGER, CAMPO2 INTEGER)
AS
BEGIN
CAMPO1 = 1;
CAMPO2 = 2;
SUSPEND;
CAMPO1 = 10;
CAMPO2 = 20;
SUSPEND;
END
^
SET TERM ; ^

Ao executarmos esta SP atravs de um SELECT * FROM SP_TESTE_SUSPEND teramos como


retorno exatamente 2 registros, pois executamos o SUSPEND duas vezes.
Acho que agora ficou mais claro como ele funciona
Ento com isso j podemos imaginar como poderamos retornar N registros atravs de um loop
com o comando WHILE ou atravs de um FOR SELECT...INTO. Vamos analisar os dois
exemplos:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 56 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Retornando com While
SET TERM ^;
CREATE PROCEDURE SP_TESTE_SELECIONAVEL_WHILE
RETURNS (
VALOR_RETORNO INTEGER
)
AS
DECLARE VARIABLE CONTADOR INTEGER;
BEGIN
CONTADOR = 0;
WHILE (:CONTADOR < 10) DO
BEGIN
VALOR_RETORNO = :CONTADOR;
CONTADOR = :CONTADOR + 1;
SUSPEND;
END
END
^
SET TERM ; ^

Executaramos esta SP utilizando:


SELECT * FROM SP_TESTE_SELECIONAVEL_WHILE

Como retorno teramos 10 registros com a coluna VALOR_RETORNO contendo valores de 0 a 9,


pois estamos preenchendo este parmetro de sada com o valor da varivel CONTADOR.
Retornando com FOR SELECT...INTO
SET TERM ^;
CREATE PROCEDURE SP_TESTE_SELECIONAVEL_FORSELECT
RETURNS (
VALOR_RETORNO NUMERIC(9,2)
)
AS
DECLARE VARIABLE VALOR NUMERIC(9,2);
BEGIN
FOR
SELECT
PROD_VALOR
FROM
PRODUTO
INTO
:VALOR
DO
BEGIN
VALOR_RETORNO = :VALOR * 1.10;
SUSPEND;
END
END
^
SET TERM ; ^

Executaramos esta SP da seguinte forma:


SELECT * FROM SP_TESTE_SELECIONAVEL_FORSELECT

Note que em cada ciclo, ou seja, dentro do bloco BEGIN/END alimentamos o valor do parmetro
de retorno e executamos o SUSPEND para que o registro seja retornado.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 57 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Como resultado teremos todos registros da tabela PRODUTO com uma coluna VALOR_RETORNO
contendo o valor do produto com 10% de acrscimo.

LEAVE
O comando LEAVE nos permite interromper um loop gerado por um WHILE, FOR SELECT...INTO
ou FOR EXECUTE...INTO (veremos mais adiante). A utilizao deste comando simples:

Utilizando em um While
CONTADOR = 1;
WHILE (:CONTADOR < 10) DO
BEGIN
IF (:CONTADOR = 5) LEAVE;
CONTADOR = :CONTADOR + 1;
END

Utilizando em um FOR SELECT...INTO


FOR
SELECT
PROD_VALOR
FROM
PRODUTO
INTO
:VALOR
DO
BEGIN
IF (:VALOR=200) LEAVE;
END

EXECUTE STATEMENT
O comando EXECUTE STATEMENT nos permite executar uma instruo SQL montada
dinamicamente. Vejamos o exemplo a seguir:
SET TERM ^;
CREATE PROCEDURE SP_ATUALIZA_CAMPO_TABELA
(
TABELA VARCHAR(10),
CAMPO VARCHAR(10),
VALOR VARCHAR(20)
)
AS
BEGIN
EXECUTE STATEMENT 'UPDATE ' || TABELA || ' SET ' || CAMPO || ' = ''' || VALOR
|| '''';
END
^
SET TERM ; ^

Perceba que montamos a instruo SQL dinamicamente com base nos parmetros passados para
a SP e logo em seguida executamos atravs do EXECUTE STATEMENT.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 58 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Note tambm que foi necessrio concatenar a string, para isso utilizamos o sinal de dois pipe || que
o utilizado em SQL.
Poderamos utilizar esta SP da seguinte forma:
EXECUTE PROCEDURE SP_ATUALIZA_CAMPO_TABELA('PRODUTO', 'PROD_DESCRICAO', 'TESTE');

Vale lembrar que este exemplo apenas para fins didticos, sabemos que sua execuo
atualizaria o campo PROD_DESCRICAO de todos os registros da tabela PRODUTO, algo que no
vivel, seria recomendvel a utilizao de uma clusula WHERE.

EXECUTE STATEMENT...INTO
Este comando uma unio do EXECUTE STATEMENT e SELECT...INTO, pois nos permite
montar um SELECT dinamicamente armazenando os valores dos campos em variveis.
Vejamos um exemplo:
SET TERM ^;
CREATE PROCEDURE SP_EXEMPLO_EXECUTE_STAT_INTO (
CAMPO VARCHAR(20),
CODIGO INTEGER)
RETURNS (
VALOR_CAMPO VARCHAR(50))
AS
BEGIN
EXECUTE STATEMENT 'SELECT ' || CAMPO || ' FROM PRODUTO WHERE PROD_CODIGO = ' ||
:CODIGO INTO :VALOR_CAMPO;
SUSPEND;
END
^
SET TERM ; ^

Exemplo de utilizao:
SELECT * FROM SP_EXEMPLO_EXECUTE_STAT_INTO('PROD_DESCRICAO', 10);

Como retorno teramos a descrio do produto de cdigo 10.

FOR EXECUTE STATEMENT...INTO


Este comando uma unio do EXECUTE STATEMENT e FOR SELECT...INTO, pois nos permite
montar um SELECT (que retorna mais de um registro) dinamicamente armazenando os valores
dos campos em variveis.
Vejamos um exemplo:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 59 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


SET TERM^;
CREATE PROCEDURE SP_RETORNA_CAMPO_TABELA(TABELA VARCHAR(20),
CAMPO VARCHAR(20))
RETURNS (VALOR_CAMPO VARCHAR(50))
AS
BEGIN
FOR EXECUTE STATEMENT
' SELECT ' || CAMPO || ' FROM ' || TABELA
INTO
:VALOR_CAMPO
DO
BEGIN
SUSPEND;
END
END
^
SET TERM ; ^

Poderamos utilizar esta SP da seguinte forma:


SELECT * FROM SP_RETORNA_CAMPO_TABELA('PRODUTO', 'PROD_DESCRICAO');

Assim estaramos retornando o campo PROD_DESCRICAO de todos registros tabela PRODUTO.

EXCEPTION
Na implementao de uma Stored Procedure ou Trigger podemos gerar exceptions em
determinadas situaes. Por exemplo, em uma Trigger antes da incluso de um registro,
poderamos verificar determinadas condies e caso no atenda, geramos uma exception
anulando a respectiva incluso e uma mensagem definida por ns seria exibida para o usurio, a
mesma idia poderia ser feita em uma SP barrando a execuo do processo em determinada
situao.
Podemos tambm verificar se alguma exceo foi gerada e com isso tomar outras decises, como
por exemplo, logar o erro em uma tabela, ou at mesmo ignorar caso necessrio.
Para gerarmos uma exception precisamos antes cri-la, para isso utilizamos o comando CREATE
EXCEPTION:
CREATE EXCEPTION NOME_DA_EXCEPTION 'MENSAGEM DE ERRO';

Para gerarmos a exception utilizamos:


EXCEPTION NOME_DA_EXCEPTION

At a verso 1.0 do Firebird tnhamos que criar uma exception para cada mensagem de erro. Na
verso 1.5 podemos criar a exception com a mensagem de erro padro ou em branco e ao chamla passamos outra mensagem, exemplo:
EXCEPTION NOME_DA_EXCEPTION 'MINHA MENSAGEM DE ERRO'

Vejamos um exemplo de utilizao em uma SP:


CREATE EXCEPTION VALOR_NEGATIVO Valor negativo;

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 60 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


CREATE PROCEDURE TESTE_EXCEPTION(VALOR INTEGER)
AS
BEGIN
IF (:VALOR < 0) THEN
EXCEPTION VALOR_NEGATIVO;
END

Se executarmos esta procedure utilizando EXECUTE PROCEDURE TESTE_EXCEPTION(-1) seria


gerada a mensagem de erro: Valor negativo.
Poderamos ento personalizar a mensagem da seguinte forma:
CREATE PROCEDURE TESTE_EXCEPTION_2(VALOR INTEGER)
AS
BEGIN
IF (:VALOR < 0) THEN
EXCEPTION VALOR_NEGATIVO 'Valor negativo: ' || Valor;
END

Perceba que agora est sendo informada uma mensagem de erro especfica ao gerar a exception
concatenando com o valor passado no parmetro, logo, se executarmos esta SP utilizando o
comando: EXECUTE PROCEDURE TESTE_EXCEPTION_2(-1) teramos a seguinte mensagem de
erro: Valor negativo: -1.

EXCEPTION Tratando erros


Podemos verificar se alguma exception foi gerada de vrias formas:

Utilizando WHEN SQLCODE...DO


Atravs do comando WHEN SQLCODE...DO tratamos uma exception especfica (gerada pelo
banco) atravs do SQLCODE, onde XXX o cdigo de erro.
WHEN SQLCODE XXX DO
BEGIN
/* aqui vem o tratamento */
END

Neste exemplo verificamos se ocorreu algum erro de cdigo (SQLCODE) XXX, caso tenha
ocorrido, as instrues existentes no bloco BEGIN/END sero executadas.
Utilizando WHEN GDSCODE...DO
Semelhante ao bloco acima, atravs do comando WHEN GDSCODE...DO podemos verificar
tambm uma exception especfica, (gerada pelo banco), porm utilizando o GDSCODE, onde em
XXX informamos uma constante, por exemplo, foreign_key ou o prprio cdigo de erro.
WHEN GDSCODE XXX DO
BEGIN
/* aqui vem o tratamento */
END

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 61 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Em documentaes do Firebird existem as mensagens de erros com suas respectivas descries,
navegando pela Internet achei um PDF que documenta estas mensagens com os respectivos
cdigos SQLCODE, GDSCODE e suas constantes:
http://firebird.sourceforge.net/doc/contrib/fb_1_5_errorcodes.pdf
Uma observao importante descrita na prpria documentao existente no Firebird
(README.context_variables), quando utilizamos WHEN SQLCODE...DO a varivel SQLCODE
contm valor e GDSCODE fica com valor zero e quando utilizamos WHEN GDSCODE...DO a varivel
GDSCODE contm valor e SQLCODE fica com valor zero, portanto, se precisar avaliar o cdigo de
erro dentro do tratamento, utilize a prpria varivel informada no WHEN.
Utilizando WHEN ANY...DO
Com a utilizao do comando WHEN ANY...DO podemos tratar qualquer exception, independente
do erro e se foi gerada pelo banco ou por ns.
WHEN ANY DO
BEGIN
/* aqui vem o tratamento */
END

Neste caso, poderamos avaliar o cdigo de erro dentro do bloco BEGIN/END utilizando apenas a
varivel SQLCODE, pois a varivel GDSCODE estaria com valor zero, vejamos um exemplo:
WHEN ANY DO
BEGIN
IF (SQLCODE=-803) THEN
BEGIN
/* tratando o erro -803 */
END
END

importante saber que as variveis SQLCODE e GDSCODE s possuem valores dentro do bloco de
tratamento, fora do bloco ambas sempre estaro com valor zero.

Gerando a exception novamente


Quando utilizamos um dos blocos acima, o que estamos fazendo na realidade segurando a
exception, semelhante ao que acontece quando utilizamos try/except no Dephi, portanto,
podemos soltar a exception novamente aps fazermos o tratamento especfico, para isso
utilizamos o comando EXCEPTON dentro do bloco:
WHEN ANY DO
BEGIN
/* aqui vem o tratamento */

/* gerando a exception novamente */


EXCEPTION;
END

Utilizamos como exemplo o bloco WHEN ANY DO, mas poderamos utilizar qualquer um dos blocos
demonstrados anteriormente.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 62 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Independentemente se iremos segurar ou soltar a exception, importante sabermos que o
conceito semelhante ao que temos em Delphi utilizando o try/except, ou seja, se segurarmos a
exception quem originou a execuo do processo no saber do erro e continuar a execuo dos
processos seguintes, caso contrrio, se soltarmos a exception, sero cancelados todos os
processos executados anteriormente.

Concluso
Neste captulo foram abordados os principais comandos utilizados na implementao de Stored
Procedures, porm existem comandos mais avanados nos permitindo realizar outras tarefas como
controle de transao, cursores, etc, no so comuns de serem utilizados, mas vale a pena
explor-los depois de praticado bastante o bsico.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 63 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando Stored Procedures no IBExpert


Estaremos criando 4 exemplos de Stored Procedures: a primeira executar uma atualizao no
banco de dados, a segunda retornar apenas um registro, a terceira retornar mais de um registro
e a ltima ira gerar uma exception para visualizarmos o erro no Delphi.
Vale lembrar que poderamos criar as Stored Procedures em outras ferramentas, mas utilizaremos
o IBExpert pelo fato de j utilizarmos ao longo do curso.

Partindo para prtica


Execute o IBExpert e abra a conexo com o nosso banco de dados.
Depois de conectado, v at o menu Tools->Script Executive.

Figura 1 Acessando o item de menu Script Executive


No editor de script coloque o seguinte cdigo:
SET TERM ^ ;
CREATE PROCEDURE SP_ATUALIZA_VALORES (
INDICE FLOAT)
AS
BEGIN
UPDATE PRODUTO SET PROD_VALOR = PROD_VALOR * ( 1 + (:INDICE / 100));
END^
SET TERM ; ^

Em seguida clique no boto Run para executar o script conforme demonstra a figura a seguir:

Figura 2 Criando a Stored Procedure SP_ATUALIZA_VALORES no IBExpert


Aps a criao a SP j estar disponvel para ser utilizada, inclusive podemos visualiz-la no
IBExpert:
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 64 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 3 - Visualizando a Stored Procedure no IBExpert


Se clicarmos com o boto direito do mouse, temos opes de criar, editar ou excluir uma Stored
Procedure.

Figura 4 - Opes existentes no IBExpert para manipulao de Stored Procedures


Podemos editar a Stored Procedure clicando no item de menu Edit Procedure... e a seguinte tela
ser exibida:

Figura 5 Editando a Stored Procedure


Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 65 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Note que por padro exibida apenas a implementao da Stored Procedure, para visualizarmos
inclusive o cabealho devemos clicar no boto Lazy mode conforme demonstra a figura a seguir:

Figura 6 Clicando no boto Lazy Mode para visualizar inclusive o cabealho da Stored Procedure
Caso queira voltar ao modo anterior, basta clicar novamente no boto Lazy mode.
Nesta tela podemos alterar a implementao da SP e para confirmar clicamos no boto Compile
Procedure conforme demonstra a figura:

Figura 7 Clicando no boto Compile Procedure para confirmar a alterao


Ao clicar neste boto, ser exibida uma outra janela:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 66 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 8 Confirmando a alterao da Stored Procedure


Para confirmar basta clicar no boto Commit e as alteraes sero comitadas no banco de dados.
Note que nesta tela exibido o script necessrio para alterao da SP, portanto, poderamos
alterar uma Stored Procedure manualmente executando este script.
Vale lembrar que poderamos criar nossa Stored Procedure atravs do item de menu New
Procedure onde seria exibida a mesma tela da figura 5 e poderamos informar os parmetros de
entrada e sada pela IDE do IBExpert, apenas teramos que codificar a implementao da Stored
Procedure.
Antes de partimos para o Delphi, vamos aproveitar e criar as demais Stored Procedures que
propomos no incio para realizao de testes.
Portanto, repita os procedimentos de criao de Stored Procedures vistos anteriormente utilizando
os seguintes scripts:
SET TERM ^ ;
CREATE PROCEDURE SP_RETORNA_MAIOR_VALOR (INDICE FLOAT)
RETURNS
(MAIOR_VALOR NUMERIC(9,2))
AS
BEGIN
UPDATE PRODUTO SET PROD_VALOR = PROD_VALOR * ( 1 + (:INDICE / 100));
SELECT
MAX(PROD_VALOR)
FROM
PRODUTO
INTO
:MAIOR_VALOR;
END^
SET TERM ; ^

O objetivo desta Stored Procedure alm de atualizar os valores dos produtos com base no ndice
passado no parmetro, tambm retornar um registro com o maior valor existente na tabela de
produtos.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 67 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Agora vamos criar a 3.a Stored Procedure responsvel por retornar mais de um registro:
SET TERM ^ ;
CREATE PROCEDURE SP_RETORNA_VALOR_AJUSTADO (INDICE FLOAT)
RETURNS
(CODIGO INTEGER,
VALOR NUMERIC(9,2))
AS
BEGIN
FOR
SELECT
PROD_CODIGO,
PROD_VALOR
FROM
PRODUTO
INTO
:CODIGO,
:VALOR
DO
BEGIN
VALOR = :VALOR * (1 + (INDICE/100));
SUSPEND;
END
END^
SET TERM ; ^

Nesta SP estamos percorrendo a tabela de produtos e retornando o valor ajustado com base no
ndice passado no parmetro. Ser neste caso que utilizaremos o componente SQLQuery no
Delphi para extrair os registros desta Stored Procedure, enquanto que nas duas SP's criadas
anteriormente utilizaremos o componente SQLStoredProc.
E por ltimo criaremos nossa SP que ir gerar uma exception para visualizarmos o erro no Delphi:
CREATE EXCEPTION EXCEPTION_GENERICA '';
SET TERM ^;
CREATE PROCEDURE SP_TESTE_EXCEPTION_PRODUTO(CODIGO INTEGER)
AS
BEGIN
INSERT INTO PRODUTO (PROD_CODIGO) VALUES (:CODIGO);
WHEN SQLCODE -625 DO
BEGIN
EXCEPTION EXCEPTION_GENERICA 'ERRO AO INSERIR O PRODUTO COM VALOR NULO';
END
WHEN ANY DO
BEGIN
EXCEPTION EXCEPTION_GENERICA 'ERRO DESCONHECIDO:' || SQLCODE;
END
END
^
SET TERM ; ^

Concluso
Notamos que o IBExpert at possui alguns recursos na IDE para criao e edio de Stored
Procedures, porm o trabalho maior est na implementao, algo que ele no pode nos ajudar
muito, por esta razo optamos por utilizar a execuo de scripts diretamente.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 68 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Utilizando Stored Procedures no Delphi


Em nossos exemplos estaremos utilizando os componentes da DBExpress, at mesmo porque o
foco do curso, porm vale lembrar que poderamos utilizar qualquer engine de acesso, como ADO,
BDE, etc.
Para executarmos Stored Procedures que no retornam valores ou que retornam no mximo
um registro, utilizamos o componente TSQLStoredProc, no qual informamos o nome da Stored
Procedure na propriedade StoredProcName e na propriedade Params definimos os parmetros
de entrada e sada. Feito isto, executamos a SP chamando o mtodo ExecProc do componente e
no caso de SPs que retornam um registro, avaliamos os parmetros de sada.
J no caso de SPs que retornam mais de um registro, utilizamos qualquer componente que
execute querys, como por exemplo, no caso da DBExpress, o SQLQuery e o TSQLDataSet. Na
propriedade
onde
informamos
a
query,
fazemos
um
SELECT
*
FROM
NOME_STORED_PROCEDURE passando os parmetros de entrada. importante saber que este
modelo poderia ser aplicado tambm com SPs que retornam apenas um registro.

Partindo para prtica


Chega de teoria e vamos implementar nossa aplicao em Delphi para fazer uso das SPs,
portanto, esteja com o projeto aberto e vamos seguir os passos dos prximos captulos que foram
divididos para um melhor entendimento.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 69 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Trabalhando com Stored Procedures que no retornam valores


No datamodule principal adicione um componente TSQLStoredProc localizado na paleta
dbExpress:

Figura 1 Adicionando o componente TSQLStoredProc ao datamodule


Ajuste as seguintes propriedades do componente:

TSQLStoredProc
Name: sspAtualizaValores
SqlConnection: SqlConnPrincipal
StoredProcName: SP_ATUALIZA_VALORES
Obs: Note que a propriedade StoredProcName um ComboBox que deveria listar o nome das
Stored Procedures existentes no banco de dados. Neste caso no est sendo exibido devido a um
bug :( da DBExpress, infelizmente s exibido os nomes quando utilizamos uma conexo
nomeada, ou seja, quando utilizamos a propriedade ConnectionName do componente
SQLConnection. Mas isto no um problema para ns, pois temos a possibilidade de digitar o
nome da Stored Procedure diretamente na propriedade.
Como esta Stored Procedure recebe parmetros, devemos ento ajustar a propriedade Params do
componente, porm temos a vantagem desta propriedade j ser preenchida no momento em que
informamos o nome da SP na propriedade StoredProcName do componente SQLStoredProc,
mas importante confirmarmos para ver se est tudo ok, portanto vamos clicar na propriedade
Params e a seguinte janela ser exibida:

Figura 2 Verificando a propriedade Params do componente sspAtualizaValores


Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 70 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Note que temos apenas um parmetro, o mesmo definido na Stored Procedure sendo do tipo
entrada (propriedade ParamType = ptInput). Se necessrio, poderamos alterar, excluir ou incluir
parmetros nesta tela, porm no necessrio, pois como vimos, os parmetros so carregados
automaticamente.
Neste momento o componente j est configurado para ser utilizado, precisamos apenas executlo, faremos isso atravs do formulrio principal.
Abra o formulrio principal e insira um boto ajustando as seguintes propriedades:

TButton
Name: btnExeSP1
Caption: Exec. SP_ATUALIZA_VALORES
No evento OnClick do boto insira o seguinte cdigo:
procedure TfrmPrincipal. btnExeSP1Click(Sender: TObject);
begin
dmPrincipal.sspAtualizaValores.ParamByName('INDICE').AsFloat := 10;
dmPrincipal.sspAtualizaValores.ExecProc;
end;

Entendendo o cdigo
Na primeira linha definimos o valor do parmetro INDICE para 10 em seguida executamos a Stored
Procedure chamando o mtodo ExecProc do componente. s isso que precisamos fazer, muito
simples .

Testando aplicao
Se rodarmos a aplicao e clicarmos neste boto, a Stored Procedure ser executada recebendo o
parmetro INDICE com o valor igual 10 e atualizar a tabela de produtos aumentado o valor em
10%.
Vamos acompanhar passo a passo.
Primeiro precisamos analisar os dados atuais da tabela de produtos e logo em seguida
executamos a SP e visualizamos os resultados.

Figura 3 Visualizando dados dos produtos no IBExpert antes a execuo da SP


Agora executamos a SP a partir da aplicao.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 71 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 4 Executando a SP a partir da aplicao


Aps a execuo podemos conferir o resultado da atualizao atravs do IBExpert.

Figura 5 Visualizando dados dos produtos no IBExpert aps a execuo da SP


Note que o valor dos produtos teve um acrscimo de 10% aps a execuo da SP.

Concluso
Neste captulo vimos que a execuo de SP's que no retornam registros feita atravs do
componente SQLStoredProc, porm vale lembrar que poderamos executar o comando EXECUTE
PROCEDURE manualmente atravs do componente SQLQuery, neste caso utilizaramos o
comando ExecProc do componente ao invs do comando Open.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 72 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Trabalhando com Stored Procedures que retornam um


registro
A utilizao de Stored Procedures que retornam um registro no difere muito do que vimos
anteriormente, a nica diferena que aps a execuo da Stored Procedure, devemos ler os
parmetros de sada para podermos extrair os valores de retorno.
Insira outro componente TSQLStoredProc no datamodule e ajuste as seguintes propriedades:

TSQLStoredProc
Name: sspRetornaValor
SqlConnection: SqlConnPrincipal
StoredProcName: SP_RETORNA_MAIOR_VALOR
Em seguida clique na propriedade Params para verificar se existem dois parmetros, um de
entrada e outro de sada:

Figura 1 Visualizando os parmetros do componente sspRetornaValor


Note que o parmetro INDICE est com a propriedade ParamType definida como ptInput
(parmetro de entrada) e o parmetro MAIOR_VALOR est definido como ptOutput indicando que
um parmetro de sada, ou seja, o valor de retorno.
Neste momento o componente j est configurado para ser utilizado, precisamos apenas executlo, faremos isso atravs do formulrio principal.
Abra o formulrio principal e insira um boto ajustando as seguintes propriedades:

TButton
Name: btnExeSP2
Caption: Exec. SP_RETORNA_MAIOR_VALOR
No evento OnClick do boto insira o seguinte cdigo:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 73 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


procedure TfrmPrincipal.btnExeSP2Click(Sender: TObject);
begin
dmPrincipal.sspRetornaValor.ParamByName('INDICE').AsFloat := 10;
dmPrincipal.sspRetornaValor.ExecProc;
ShowMessage(dmPrincipal.sspRetornaValor.ParamByName('MAIOR_VALOR').AsString);
end;

Entendendo o cdigo
Nas duas primeiras linhas fizemos o mesmo procedimento aplicado anteriormente, informamos o
valor do parmetro INDICE e logo em seguida executamos a Stored Procedure. A diferena est
na ltima linha, onde obtemos o valor de retorno acessando o parmetro MAIOR_VALOR.
Poderamos ter mais de um valor de retorno, no h diferena, continuaramos obtendo os valores
atravs da funo ParamByName. O que no podemos ter mais de um registro de retorno,
abordaremos este caso no prximo captulo.

Testando aplicao
Vamos executar a aplicao e clicar no boto, a SP atualizar os produtos aumentando os valores
em 10% e resultar o maior valor entre eles.

Figura 2 Executando a SP a partir da aplicao

Figura 3 Aplicao exibindo o resultado da SP com o maior valor dos produtos

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 74 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 4 Analisando a tabela de produtos no IBExpert aps a execuo da SP


Nesta ltima figura pudemos comprovar que os produtos tiveram um acrscimo de 10% com base
nos valores vistos na ltima atualizao e o maior valor entre eles 363,00 que foi exibido na
aplicao.

Concluso
Utilizamos o mesmo componente visto no captulo anterior, mas importante sabermos que
poderamos utilizar uma Query extraindo o valores atravs de um SELECT * FROM
NOME_DA_PROCEDURE, um mtodo que veremos no prximo captulo utilizado para SPs que
retornam mais de um registro.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 75 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Trabalhando com Stored Procedures que retornam mais de um


registro
Como dissemos anteriormente, para trabalharmos com Stored Procedures que retornam mais de
um registro, temos de usar algum DataSet que permita a execuo de Querys, pois faremos um
SELECT em nossa SP como se fosse uma tabela.
Neste caso estaremos utilizando o componente SQLQuery, porm, sabemos que a DBExpress
trabalha com cursores unidirecionais, portanto, para visualizarmos o resultado em um dbgrid, por
exemplo, precisaremos utilizar o ClientDataSet para fazer o cach, da mesma forma que j vimos
com tabelas no primeiro mdulo.
Adicione no datamodule aquele conjunto de componentes que j estamos acostumados:
TClientSataSet + TDataSetProvider + TSqlQuery.
Ajuste as propriedades da seguinte forma:

TSQLQuery
Name: qryRetornaValorAjustado
SQLConnection: SqlConnPrincipal

TDataSetProvider
Name: dspRetornaValorAjustado
DataSet: qryRetornaValorAjustado

TClientDataSet
Name: cdsRetornaValorAjustado
ProviderName: dspRetornaValorAjustado
SQL:
SELECT
*
FROM
SP_RETORNA_VALOR_AJUSTADO(:INDICE)

Note que fizemos um SELECT como se a SP fosse uma tabela. Como a nossa Stored Procedure
exige um parmetro de entrada, ento passamos este parmetro no SQL e conseqentemente
ser criado um parmetro na propriedade Params do componente, portanto devemos ajustar seu
tipo.
Clique na propriedade Params do componente qryRetornaValorAjustado e ajuste as seguintes
propriedades do parmetro:
DataType: ftFloat
ParamType: ptInput

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 76 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 1 Ajustando os parmetros da Query


Agora no formulrio principal insira um boto ajustando as seguintes propriedades:

TButton
Name: btnExeSP3
Caption: Exec. SP_RETORNA_VALOR_AJUSTADO
No evento OnClick do boto insira o seguinte cdigo:
procedure TfrmPrincipal.btnExeSP3Click(Sender: TObject);
begin
dmPrincipal.cdsRetornaValorAjustado.FetchParams;
dmPrincipal.cdsRetornaValorAjustado.Params.ParamByName('INDICE').AsFloat := 10;
dmPrincipal.cdsRetornaValorAjustado.Open;
end;

Entendendo o cdigo
Na primeira linha carregamos para o ClientDataSet os parmetros da Query, em seguida
alimentamos o parmetro INDICE no ClientDataSet com valor 10 para que seja transferido para
Query e conseqentemente enviado para a Stored Procedure e por final, abrimos o
ClientDataSet.
Agora precisamos de um DBGrid para visualizarmos o resultando, portanto insira os seguintes
componentes no formulrio principal ajustando suas respectivas propriedades:

TDataSource
Name: dtsRetornaValorAjustado
DataSet: dmPrincipal.cdsRetornaValorAjustado

TDBGrid
Name: dbgrdSpRetornaValorAjustado
DataSource: dtsRetornaValorAjustado

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 77 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Pronto, agora podemos executar a aplicao e clicar no boto, logo veremos os registros no
DBGrid. O Resultado ser os produtos com seus valores ajustados, porm no fisicamente,
somente na visualizao.

Testando aplicao

Figura 2 Visualizando o resultado da Stored Procedure SP_RETORNA_VALOR_AJUSTADO a


partir da aplicao
Note os valores dos produtos com acrscimo de 10%, porm isso no foi gravado fisicamente no
banco de dados, apenas um retorno da SP, podemos conferir analisando os dados reais da
tabela atravs do IBExpert:

Figura 3 Visualizando os dados reais da tabela de produtos no IBExpert

Concluso
Podemos perceber que a visualizao de registros retornados por uma SP simples, j que
utilizamos o ClientDataSet da mesma forma que em tabelas. Poderamos utilizar uma Query
diretamente, porm, como sabemos no poderamos utilizar em um DataControl, apenas leramos
os registros para frente, j que a DBEXpress trabalha com cursores unidirecionais.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 78 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Executando a Stored Procedure que gera Exception


Agora vamos executar a 4.a e ltima Stored Procedure que criamos como exemplo na qual gera
uma exception, visualizaremos a mensagem de erro sendo exibida diretamente na aplicao.
Adicione um componente TSQLStoredProc no datamodule principal ajustando as seguintes
propriedades:

TSQLStoredProc
Name: sspTesteException
SqlConnection: SqlConnPrincipal
StoredProcName: SP_TESTE_EXCEPTION_PRODUTO
Agora no formulrio principal, insira um boto ajustando as seguintes propriedades:

TButton
Name: btnExeSP4
Caption: Exec. SP_TESTE_EXCEPTION_PRODUTO
Neste momento j temos tudo pronto para executar os testes, portanto, simularemos 3 testes: O
primeiro tentaremos inserir um produto com cdigo nulo, logo aps um produto com cdigo j
existente e por final um produto com cdigo inexistente, desta forma visualizaremos as mensagens
de erros nos dois primeiros testes e ao final concluiremos inserindo o produto com sucesso.
Para realizarmos o primeiro teste, codifique o evento OnClick do boto da seguinte forma:
procedure TfrmPrincipal.btnExeSp4Click(Sender: TObject);
begin
dmPrincipal.sspTesteException.ParamByName('VALOR').Value := null;
dmPrincipal.sspTesteException.ExecProc;
end;

Testando aplicao

Figura 1 Realizando o primeiro teste

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 79 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 2 Mensagem de erro ao tentar inserir um produto com valor nulo


Note a mensagem de erro sendo a mesma mensagem que definimos na SP no caso de ocorrer um
erro de insero de produto com cdigo nulo.
Agora partiremos para o segundo teste, portanto, ajuste o evento OnClick do boto da seguinte
forma:
procedure TfrmPrincipal.btnExeSp4Click(Sender: TObject);
begin
dmPrincipal.sspTesteException.ParamByName('VALOR').Value := 1;
dmPrincipal.sspTesteException.ExecProc;
end;

Testando aplicao

Figura 3 Erro ao tentar inserir um produto com cdigo j existente


Note a mensagem de erro ao tentarmos inserir um produto com cdigo j existente, o cdigo
SQLCODE -803, poderamos ajustar a SP para comear a tratar este cdigo de erro tambm.
Agora faremos o teste final, onde incluiremos um produto sem gerar exception, portanto, ajuste o
evento OnClick do boto da seguinte forma:
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 80 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


procedure TfrmPrincipal.btnExeSp4Click(Sender: TObject);
begin
dmPrincipal.sspTesteException.ParamByName('VALOR').Value := 100
dmPrincipal.sspTesteException.ExecProc;
end;

Testando aplicao
Rodando a aplicao e clicando no boto o produto ser inserido no banco de dados com sucesso
conforme demonstra a figura a seguir no IBExpert:

Figura 4 Produto inserido com sucesso no banco de dados

Concluso
Podemos perceber que a mensagem de erro definida na exception exibida independentemente
da forma que foi executada a SP, seja diretamente pelo banco atravs do IBExpert, por exemplo,
ou atravs de uma aplicao, desta forma conclumos que no ambiente Delphi no precisamos nos
preocupar com nenhum tipo de codificao especfica.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 81 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando e implementando Triggers


Triggers so gatilhos disparados pelo banco de dados quando algum evento ocorre em alguma
tabela. A utilizao de Triggers nos permite capturarmos estes eventos e fazermos algum tipo de
tratamento.
Os eventos que podemos manipular so:
BeforeInsert: Disparado antes da insero de registros na tabela.
BeforeUpdate: Disparado antes da atualizao de registros na tabela.
BeforeDelete: Disparado antes da excluso de registros na tabela.
AfterInsert: Disparado aps a incluso de registros na tabela.
AfterUpdate: Disparado aps a atualizao de registros na tabela.
AfterDelete: Disparado aps a excluso de registros na tabela
Podemos utilizar Triggers em diversas situaes, por exemplo, poderamos gravar uma data em
um campo da tabela quando a mesma tivesse algum registro modificado simulando um log de
alterao, para isso trataramos o evento BeforeUpdate da tabela.
A linguagem utilizada para codificar uma Trigger a mesma utilizada em SPs (PSQL), apenas
alguns comandos so especficos para SPs.
Vejamos um exemplo de criao de Trigger:
CREATE TRIGGER NOME_DA_TRIGGER FOR NOME_DA_TABELA
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
/* implementacao da Trigger */
END

Analisando a sintaxe
Primeiro executamos o comando CREATE TRIGGER definindo o nome da Trigger, logo aps
informamos o nome da tabela que iremos tratar o evento. Depois indicamos que esta Trigger est
ativa atravs do ACTIVE, pois podemos desativ-la em determinado momento, para isso
utilizaramos o INACTIVE. Em seguida definimos a qual evento esta Trigger est associada, neste
exemplo estamos associando ao evento BEFORE INSERT, alm deste poderia ser um dos
seguintes eventos: BEFORE UPDATE, BEFORE DELETE, AFTER INSERT, AFTER UPDATE,
AFTER DELETE. Por final temos o valor do POSITON igual a zero, no Firebird 1.5 temos a
possibilidade de ter mais de uma Trigger para a mesma tabela e mesmo evento, por este motivo
indicamos o valor do POSITION determinando a ordem de execuo das Triggers para este caso.

Implementao de uma Trigger


Como dissemos, a linguagem para implementarmos uma Trigger a mesma utilizada na
implementao de uma SP, porm temos algumas caractersticas especficas que so aplicadas
somente em Triggers, vejamos:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 82 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Variveis New e Old
Quando implementamos uma Trigger podemos acessar a varivel new e old para verificarmos o
valor do campo antes e aps sua modificao respectivamente e no caso da varivel new
podemos tambm definir um novo valor para o campo dependendo do evento em que estivermos.
Exemplo:
CREATE TRIGGER PRODUTO_BU FOR PRODUTO
ACTIVE BEFORE UPDATE POSITION 0
AS
DECLARE VARIABLE PRODUTO_FOI_ATIVADO CHAR(1);
BEGIN
/* verificando se tornou o produto inativo */
IF (OLD.PROD_ATIVO='S' AND NEW.PROD_ATIVO='N') THEN
BEIGN
NEW.DATA_INATIVO = current_time_stamp;
PRODUTO_FOI_ATIVADO = 'N';
END
ELSE
BEGIN
NEW.DATA_ATIVO = current_time_stamp;
PRODUTO_FOI_ATIVADO = 'S';
END
END

Note que verificamos o valor anterior do campo PROD_ATIVO atravs da varivel OLD e
verificamos o novo valor atribudo utilizando a varivel NEW. Da mesma forma que podemos ler as
variveis OLD e NEW podemos tambm atribuir um novo valor, neste caso utilizamos a varivel NEW.
Foi o que fizemos, aps termos comparado o campo PROD_ATIVO verificando se o produto foi
ativado ou desativado, atribumos um novo valor ao campo DATA_ATIVO ou DATA_INATIVO
atravs da varivel NEW.
Para fins didticos, declaramos uma varivel neste exemplo para demonstrarmos que podemos
utilizar os mesmos conceitos vistos na implementao de uma SP utilizando variveis, loops, ifs,
etc.
Neste exemplo atualizamos um campo da prpria tabela ao qual a Trigger associada, porm
importante sabermos que podemos atualizar campos de outras tabelas, j que somos livres de
executar instrues SQLs na implementao de uma Trigger inclusive os comandos j vistos para
implementao de SPs.

Determinando a varivel correta a ser utilizada de acordo com evento


Apesar de termos disponveis a todo momento as variveis NEW e OLD devemos saber que em
determinado evento a leitura das variveis NEW o OLD no retornaro valores ou a atribuio de
valor a varivel NEW no refletir na tabela, isso varia de acordo com a varivel/evento:
Varivel New
Leitura e Escrita: BeforeInsert, BeforeUpdate
Somente Leitura: AfterInsert e AfterUpdate
Varivel Old
Sempre Somente Leitura: BeforeUpdate, AfterUpdate, BeforeDelete, AfterDelete

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 83 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Associando mais de um evento para mesma Trigger


Na verso 1.5 do Firebird podemos associar mais de um evento para mesma Trigger, por exemplo,
poderamos ter uma Trigger para tratar os eventos Before Update e After Update da tabela. Neste
caso temos 3 variveis para utilizarmos e saber que tipo de vento est ocorrendo naquele instante:
INSERTING, UPDATING e DELETING.
CREATE TRIGGER PRODUTO_BUI FOR PRODUTO
ACTIVE BEFORE UPDATE OR INSERT OR DELETE POSITION 0
AS
BEGIN
IF (inserting) THEN
BEGIN
/* implementacao para o caso de estar ocorrendo um insert */
END
IF (updating) THEN
BEGIN
/* implementacao para o caso de estar ocorrendo um update */
END
IF (deleting) THEN
BEGIN
/* implementacao para o caso de estar ocorrendo um delete */
END
END

Note que na declarao da Trigger definimos o tipo: BEFORE e logo aps os eventos: UPDATE
OR INSERT OR DELETE, isto significa que esta Trigger ser disparada quando acontecer um dos
eventos: BEFORE UPDATE, BEFORE INSERT ou BEFORE DELETE. No seria possvel tratar
dois tipos (BEFORE e AFTER) de eventos ao mesmo tempo, por exemplo, BEFORE UPDATE e
AFTER INSERT, por isso primeiro definimos o tipo se BEFORE ou AFTER e logo aps os
eventos.
Em nosso exemplo associamos a Triggers aos trs eventos, mas vale lembrar que no somos
obrigados a utilizar os trs ao mesmo tempo, poderamos fazer referncia a 2 eventos, por
exemplo.

Alterando uma Trigger


No temos um comando ALTER TRIGGER, portanto, para alterarmos uma Trigger devemos exclua e cri-la novamente.

Excluindo uma Trigger


A excluso de uma Trigger feita utilizando o comando DROP TRIGGER.
DROP TRIGGER PRODUTO_BIU

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 84 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Concluso
Com a utilizao de Trigger podemos centralizar as regras no banco de dados, independente de
quem est fazendo a manuteno na tabela, seja uma aplicao desktop, ou at mesmo uma
aplicao Web, a Trigger ser disparada e suas regras de negcios sero sempre mantidas.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 85 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando Triggers no IBExpert


Para criarmos Triggers atravs do IBExpert, podemos utilizar a opo Script Executive... como
vimos na criao de uma SP ou utilizar a opo especfica para criao de Triggers atravs da IDE.
Como j vimos a primeira opo em Stored Procedures, utilizaremos a segunda opo para fins
didticos, mas ao final veremos o cdigo completo da Trigger.
Como exemplo criaremos uma Trigger para tabela PRODUTO associada ao evento Before Insert e
Before Update, onde estaremos armazenando a data de alterao no campo
PROD_DATAALTERACAO (quando estiver atualizando) e a data de incluso no campo
PROD_DATACADASTRO (quando estiver incluindo).

Partindo para prtica


Abra o IBExpert, em seguida abra a conexo com o nosso banco de dados. V at o menu
Database e clique no item New Triggers...

Figura 1 Selecionando a opo New Trigger do menu Database


A seguinte tela ser exibida:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 86 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 2 Tela de criao de Triggers


Nesta tela devemos informar para qual tabela estaremos criando a Trigger, portanto, na opo For
Table selecione a tabela PRODUTO.

Figura 3 Selecionando a tabela onde ser criada a Trigger


Em seguida devemos informar os eventos que estaremos associando a esta Trigger. Clique no
ComboBox do campo Type selecionando a opo Before em seguida marque os checkboxs
INSERT e UPDATE. Desta forma estamos informando que esta Trigger estar associada aos
eventos BEFORE UPDATE e BEFORE INSERT.

Figura 4 Selecionando os eventos que estaro associados a Trigger


Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 87 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Note que o nome da Trigger no campo Name vai sendo preenchido automaticamente. O padro de
nomenclatura : NOME_DATA_TABELA + _ + EVENTO + POSITION. Onde o EVENTO uma
abreviao, por exemplo, BIU = Before Insert e Update. Se fosse apenas para o evento Before
Insert, por exemplo, seria: BI.
Neste momento j podemos partir para implementao da Trigger. No quadro branco insira o
seguinte cdigo:
IF (INSERTING) THEN
BEGIN
NEW.PROD_DATACADASTRO = CURRENT_TIMESTAMP;
END ELSE
IF (UPDATING) THEN
BEGIN
NEW.PROD_DATAALTERACAO = CURRENT_TIMESTAMP;
END

Figura 5 Implementando a Trigger


Depois de implementado, podemos compil-la clicando no boto Compile.

Figura 6 Clicando no boto Compile para compilar a Trigger


Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 88 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Ao clicarmos neste boto, ser exibida uma janela com uma mensagem de erro em nosso cdigo:

Figura 7 Janela exibida informando erros na implementao da Triggers


Isto acontece pelo fato de o IBExpert no reconhecer as variveis INSERTING, UPDATING e
DELETING, pois foi implementado somente na verso 1.5 do Firebird, portanto, podemos ignorar
esta janela clicando no boto YES para continuar. Assim a seguinte tela ser exibida:

Figura 8 Cogitando a criao da Trigger


Nesta tela basta clicarmos no boto Commit para confirmarmos a criao da Trigger.
Ao confirmarmos voltaremos para tela anterior, assim notaremos a mensagem de erro do IBExpert
informando que no reconheceu a varivel INSERTING.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 89 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 9 IBExpert informando que no reconheceu a varivel INSERTING


Mas como j dissemos, isso no um problema, neste momento j temos nossa Trigger criada
pronta para ser utilizada.
Caso optssemos em executar o script da Trigger diretamente atravs do menu Script Executive,
poderamos utilizar o seguinte cdigo:
SET TERM ^;
CREATE TRIGGER PRODUTO_BIU0 FOR PRODUTO
ACTIVE BEFORE INSERT OR UPDATE POSITION 0
AS
BEGIN
IF (INSERTING) THEN
BEGIN
NEW.PROD_DATACADASTRO = CURRENT_TIMESTAMP;
END ELSE
IF (UPDATING) THEN
BEGIN
NEW.PROD_DATAALTERACAO = CURRENT_TIMESTAMP;
END
END
^
SET TERM ; ^

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 90 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Testando a Trigger
Antes de partirmos para o ambiente Delphi, vamos verificar se nossa Trigger est funcionando
corretamente. Pelo fato de ser disparada pelo banco de dados, qualquer query de atualizao
executada na tabela disparar a Trigger.
No prprio IBExpert entre no SQLEditor teclando F12 ou atravs do menu Tools->SQLEditor. Em
seguida execute a seguinte query:
INSERT INTO PRODUTO (PROD_CODIGO, PROD_DESCRICAO) VALUES (100, 'NOVO PRODUTO')

Figura 10 Incluindo um produto para que a Trigger seja disparada


Em seguida execute um SELECT para verificarmos quais campos foram preenchidos:
SELECT * FROM PRODUTO WHERE PROD_CODIGO = 100

Figura 11 Verificando que o campo PROD_DATACADASTRO foi preenchido automaticamente


pela Trigger
Note que o campo PROD_DATACADASTRO foi preenchido automaticamente pela Trigger, pois
executamos uma incluso. Agora vamos fazer uma alterao neste registro e verificar se o campo
PROD_DATAALTERACAO tambm ser preenchido automaticamente, portanto, execute a seguinte
query:
UPDATE PRODUTO SET PROD_DESCRICAO = 'NOVO PRODUTO ALTERADO' WHERE PROD_CODIGO =
100

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 91 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 12 Atualizando o produto para que a Trigger seja disparada


Em seguida execute um SELECT para verificarmos como esto os campos do produto.
SELECT * FROM PRODUTO WHERE PROD_CODIGO = 100

Figura 13 Verificando que o campo PROD_DATAALTERACAO foi preenchido automaticamente


pela Trigger aps a atualizao
Note que desta vez o campo PROD_DATAALTERACAO foi atualizado, pois fizemos um UPDATE na
tabela e na Trigger havamos implementado uma regra de atualizar este campo quando estiver
ocorrendo uma atualizao.

Alterando uma Trigger


Para alterarmos a implementao de uma Trigger basta acessar o item de menu Edit Trigger no
IBExpert conforme demonstra a figura a seguir:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 92 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 14 Acessando o item de menu para alterar uma Trigger


Em seguida ser exibida a mesma tela que vimos na criao de uma Trigger

Figura 15 Alterando uma Trigger

Portanto, basta alterar o que for necessrio e executar o mesmo procedimento de compilao para
efetivar a alterao.

Excluindo uma Trigger


Utilizando o IBExpert esta tarefa realizada atravs do item de menu Drop Trigger:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 93 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 16 Excluindo uma Trigger

Concluso
O IBExpert possui uma IDE muito interessante que nos permite criar Triggers de forma rpida, mas
interessante estudarmos a sintaxe de criao para eventuais casos onde podemos estar sem
uma ferramenta visual.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 94 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Utilizando Triggers no Delphi


Como vimos no captulo anterior, as Triggers so disparadas pelo prprio banco de dados quando
alguma incluso, alterao ou excluso ocorre na tabela, isso significa que no precisamos utilizar
componentes especiais, basta que o mesmo faa a manuteno na tabela e a Trigger ser
disparada automaticamente pelo banco de dados.
Estaremos utilizando o ClientDataSet para fazermos a manuteno na tabela de produtos, porm
existem algumas dicas que veremos para que possamos visualizar o campo alterado pela Trigger e
evitar problemas comuns quando esquecemos de alguns detalhes na utilizao do ClientDataSet.

Partindo para prtica


Com o projeto aberto, no datamodule principal adicione os seguintes componentes ajustando suas
respectivas propriedades:

TSQLQuery
Name: qryTesteTrigger
SQLConnection: SqlConnPrincipal
SQL: SELECT * FROM PRODUTO
Obs: Sabemos que este tipo de select no recomendvel, utilizaremos apenas para
exemplificao.

TDataSetProvider
Name: dspTesteTrigger
DataSet: qryTesteTrigger

TClientDataSet
Name: cdsTesteTrigger
ProviderName: dspTesteTrigger
No evento OnReconcileError do ClientDataSet, adicione o seguinte cdigo:
procedure TdmPrincipal.cdsTesteTriggerReconcileError(
DataSet: TCustomClientDataSet; E: EReconcileError;
UpdateKind: TUpdateKind; var Action: TReconcileAction);
begin
MessageDlg(E.Message, mtError, [mbOk], 0);
end;

Fazemos isso para visualizarmos as mensagens de erro que acontecero na atualizao da tabela.
Para que o mtodo MessageDlg possa ser utilizado, devemos adicionar a unit Dialogs na
clusula uses do datamodule:
uses
SysUtils, Classes, DBXpress, DB, SqlExpr, FMTBcd, Provider, DBClient, Dialogs;

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 95 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Para facilitar executaremos o mtodo ApplyUpdates e CancelUpdates automaticamente atravs
dos eventos do ClientDataSet, assim evitamos ter que adicionar botes especficos para isso.
Codifique o evento AfterPost da seguinte forma:
procedure TdmPrincipal.cdsTesteTriggerAfterPost(DataSet: TDataSet);
begin
with cdsTesteTrigger do
begin
if ApplyUpdates(0) <> 0 then CancelUpdates;
end;
end;

Para o evento AfterCancel, codifique desta forma:


procedure TdmPrincipal.cdsTesteTriggerAfterCancel(DataSet: TDataSet);
begin
cdsTesteTrigger.CancelUpdates;
end;

O evento AfterDelete codificado da mesma forma que o evento AfterPost:


procedure TdmPrincipal.cdsTesteTriggerAfterDelete(DataSet: TDataSet);
begin
with cdsTesteTrigger do
begin
if ApplyUpdates(0) <> 0 then CancelUpdates;
end;
end;

Ajustando o formulrio principal


Agora vamos ajustar o formulrio principal para que possamos visualizar e fazer as manutenes
dos registros em um dbgrid:
Adicione os seguintes componentes:

TDataSource
Name: dtsTesteTrigger
DataSet: dmPrincipal.cdsTesteTrigger

TDBGrid
Name: dbgrdTesteTrigger
DataSource: dtsTesteTrigger
Adicione tambm um boto para que possamos abrir o ClientDataSet:

TButton
Name: btnAbrirTesteTrigger
Caption: Abrir cdsTesteTrigger
Veja abaixo como ficar a parte do formulrio referente a estes componentes:
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 96 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 1 Preparando o formulrio principal para fazermos os testes da Trigger


Codifique o evento do boto da seguinte forma:
procedure TfrmPrincipal.btnAbrirTesteTriggerClick(Sender: TObject);
begin
dmPrincipal.cdsTesteTrigger.Open;
end;

Neste momento j temos tudo preparado para fazermos manutenes na tabela de produtos, mas
agora vamos falar dos problemas!

Os dois grandes problemas


O campo alterado pela Trigger no atualizado no DBGrid
Se tentarmos inserir um registro pelo DBGrid, perceberemos que o campo PROD_DATACADASTRO
no atualizado na tela, na realidade ele est sendo atualizado sim, porm apenas no banco de
dados e no est sendo refletido no ClientDataSet.

Figura 2 Incluindo um produto e o campo PROD_DATACADASTRO no atualizado no DBGrid


Ao tentar alterar/gravar o registro inserido, aparece a mensagem de erro:
Record not found or changed by another user

Figura 3 Tentando alterar o produto que acabamos de inserir


Este problema conseqncia do problema anterior. Recordando um pouco, lembra que o padro
o ClientDataSet utilizar todos os campos na clusula where para montar a query de
atualizao?
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 97 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Este o problema, aps incluirmos o registro, no banco de dados o campo PROD_DATACADASTRO
est com um determinado valor e no ClientDataSet est nulo, pois o campo atualizado pela Trigger
no foi refletido no ClientDataSet, o componente no sabe deste novo valor, conseqentemente ao
tentarmos alterar este registro o ClientDataSet tentar usar um SQL de atualizao da seguinte
forma:
UPDATE PRODUTO SET ... WHERE ... AND PROD_DATACADASTRO IS NULL

Este registro no ser encontrando no banco de dados, pois ele est com o campo
PROD_DATACADASTRO preenchido, no est nulo como o ClientDataSet acha!
Por este motivo temos a mensagem de erro, pois o ClientDataSet no encontra o registro.

Resolvendo estes problemas, inclusive um outro problema de campos com


valores defaults.
Para resolvermos estes problemas temos algumas sadas:
- Ajustar a propriedade UpdateMode do Provider de modo que utilize apenas a chave primria na
clusula where
- Ajustar a propriedade ProviderFlags dos campos atualizados pela Trigger de modo que no
sejam utilizados na clusula where
- Corrigir o primeiro problema, fazendo com que o ClientDataSet enxergue os valores dos campos
atualizados pela Trigger.
Dentre estas solues, as duas primeiras j vimos como utilizar em captulos anteriores do primeiro
mdulo deste curso, porm ambas resolveriam apenas o erro do registro no localizado, portanto
utilizaremos a terceira opo na qual resolve os dois problemas de uma s vez.

A soluo
Pode no parecer, mas tudo isso por falta de um simples Refresh no ClientDataSet. Aps
chamarmos o mtodo ApplyUpdates basta executarmos o mtodo Refresh e o ClientDataSet ser
refletido com os novos valores atualizados pela Trigger e tudo ser resolvido!
Portanto, ajuste o evento AfterPost do ClientDataSet da seguinte forma:
procedure TdmPrincipal.cdsTesteTriggerAfterPost(DataSet: TDataSet);
begin
with cdsTesteTrigger do
begin
if ApplyUpdates(0) <> 0 then
CancelUpdates
else
Refresh;
end;
end;

Note que apenas inclumos a chamada ao mtodo Refresh caso no tenha ocorrido erros na
atualizao.
Feito isto, podemos testar a aplicao e veremos que o valor do campo atualizado pela Trigger
exibido no DBGrid.
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 98 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Podemos tambm alterar o registro normalmente, pois neste momento o ClientDataSet j sabe o
valor do campo aps o refresh e montar o SQL de atualizao corretamente.

Figura 4 Campos PROD_DATAALTERACAO E PROD_DATACADASTRO sendo refletidos no


ClientDataSet aps incluso e alterao

Por que foi citado: inclusive um outro problema de campos com valores defaults?
Quando utilizamos campos com valores defaults definidos no banco de dados o problema que
vimos anteriormente acontecer da mesma forma, ou seja, o ClientDataSet no saber dos novos
valores atribudos aos campos com valores defaults, conseqentemente no aparecer no DBGrid
e ao tentarmos alterar o registro a mensagem de erro acusando que o registro no foi encontrado
ser exibida tambm pelo mesmo motivo.
Para solucionar este caso simples, basta executarmos o mtodo Refresh da mesma forma que
fizemos anteriormente.

Concluso
Neste captulo percebemos que a utilizao de Triggers no ambiente Delphi no requer
componentes especiais nem programao diferenciada, o nico detalhe sempre chamarmos o
Refresh para que os valores dos campos defaults e atualizados por Triggers possam ser refletidos
no ClientDataSet evitando assim esses problemas.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 99 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando e definindo Views


Views so vises que criamos no banco de dados representando os dados de uma ou mais tabelas
atravs de SELECTs resultando assim em uma tabela virtual.
Imagine aquela situao onde temos um SELECT complexo e em todo momento utilizamos este
SELECT na aplicao. J imaginou ter uma tabela virtual (a VIEW) representando os dados
retornados por este SELECT e depois simplesmente utilizar SELECT * FROM MINHA_VIEW?
- O objetivo principal da utilizao de Views exatamente este!
importante deixar claro que uma View no uma cpia das tabelas envolvidas no SELECT,
apenas uma viso, qualquer alterao, incluso ou excluso efetuada nas tabelas sero refletidas
na View.
Legal, se uma View uma tabela virtual onde posso utilizar SELECT * FROM MINHA_VIEW, poderia
ento atualiz-la?
Views podem ser atualizadas sim, desde que obedeam algumas regras:
- No pode ser uma View que resulta dados de mais de uma tabela
- Campos NOT NULL sem valores padres devero estar na lista de campos da View
- No pode haver campos agregados, subquerys, etc.
Uma outra vantagem interessante que poderamos utilizar Views para limitar o acesso a dados
confidenciais por usurios do banco de dados. Imagine que temos uma tabela de Clientes onde
no gostaramos que determinados usurios do banco de dados tivessem acesso a todos os
dados, neste caso poderamos criar uma View representando parte destes dados e liberaramos o
acesso do usurio somente a esta view e no a tabela inteira de Clientes.

Criando uma View


Na criao de uma View opcional informarmos os campos que sero retornados, vamos ver um
exemplo deste caso:
CREATE VIEW VIEW_EXEMPLO_1 AS SELECT * FROM PRODUTO

Analisando a sintaxe, aps o CREATE VIEW informamos o nome da View e logo aps o AS
informamos o resultado da View atravs de um SELECT.
Neste exemplo a View retornar todos os campos e registros da tabela PRODUTO.
Poderamos utilizar a View da seguinte forma:
SELECT * FROM VIEW_EXEMPLO_1;

Neste SELECT podemos especificar os campos que gostaramos de retornar da View, utilizar
WHERE, JOINS, etc, ou seja, como se VIEW_EXEMPLO_1 fosse realmente uma tabela!
Vejamos agora um caso onde queremos criar uma View que retorne apenas alguns campos da
tabela PRODUTO:
CREATE VIEW VIEW_EXEMPLO_2 AS SELECT PROD_CODIGO, PROD_DESCRICAO FROM PRODUTO
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 100 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Agora se executarmos SELECT * FROM VIEW_EXEMPLO_2 visualizaremos todos os campos da View
e no da tabela PRODUTO, ou seja, teremos como resultado apenas os campos PROD_CODIGO e
PROD_DESCRICAO.
Os nomes dos campos retornados por esta View sero os mesmos nomes especificados no
SELECT, porm, podemos alter-los especificando-os na criao da View:
CREATE VIEW VIEW_EXEMPLO_2A (CODIGO, DESCRICAO) AS SELECT PROD_CODIGO,
PROD_DESCRICAO FROM PRODUTO

Neste exemplo, ao executarmos o SELECT na View, sero retornados os campos PROD_CODIGO e


PROD_DESCRICAO, porm nomeados como CODIGO e DESCRICAO respectivamente.
Podemos tambm limitar os registros que sero retornados, utilizamos para isso uma clusula
WHERE no SELECT:
CREATE VIEW VIEW_EXEMPLO_3 AS SELECT PROD_CODIGO, PROD_DESCRICAO, PROD_TIPO FROM
PRODUTO WHERE PROD_TIPO = 'D'

Neste exemplo podemos executar SELECT * FROM VIEW_EXEMPLO_3 e sero retornados todos
registros da View, no caso todos os produtos cujo campo PROD_TIPO seja igual a D.
At poderamos ser ousados em executar, por exemplo:
SELECT * FROM VIEW_EXEMPLO_3 WHERE PROD_TIPO = 'L'

Apesar de existirem registros na tabela PRODUTO que atendam esta condio, nesta View no
seria retornado, pois ela est limitando os registros com a clusula WHERE PROD_TIPO = 'D'.

Atualizando a View
Como dito no incio, para que uma View seja atualizvel ela dever atender algumas regras, neste
caso a atualizao feita da mesma forma que uma tabela:
UPDATE VIEW_EXEMPLO_3 SET PROD_DESCRICAO = 'PRODUTO 1 ALTERADO' WHERE PROD_CODIGO
= 1

Da mesma forma poderamos utilizar INSERT e DELETE. Reforando mais uma vez, a View no
uma cpia de tabelas, uma viso das tabelas envolvidas no SELECT, portanto, neste caso
estamos alterando fisicamente a tabela PRODUTO, logo podemos executar um SELECT na tabela e
veremos o resultado desta atualizao.
No caso do nosso exemplo VIEW_EXEMPLO_2A onde os campos foram nomeados, a atualizao
feita utilizando os nomes dos campos da VIEW e no da tabela fsica, exemplo:
UPDATE VIEW_EXEMPLO_2A SET DESCRICAO = 'PRODUTO 1 ALTERADO' WHERE CODIGO = 1

Note que utilizamos os campos DESCRICAO, CODIGO e no PROD_DESCRICAO, PROD_CODIGO


que so os campos fsicos da tabela.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 101 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

No permitindo a incluso de registros na View que no atendam ao filtro


Na criao de uma View podemos incluir a constraint WITH CHECK OPTION ao final. Esta constraint
opcional e evita a incluso de registros na View que no atendam ao filtro (WHERE) especificado
no SELECT que foi determinado na View.
Analisando nosso exemplo anterior, onde criamos uma View para retornar os produtos com o
campo PROD_TIPO = D, apesar da limitao feita na clusula WHERE, atravs da View
poderamos incluir um produto com o campo PROD_TIPO <> D, o registro seria adicionado na
tabela PRODUTO, porm no seria visualizado na View justamente devido clusula WHERE estar
limitando:
INSERT INTO VIEW_EXEMPLO_3 (PROD_CODIGO, PROD_DESCRICAO, PROD_TIPO) VALUES (200,
'PRODUTO 200', 'L');

Se utilizssemos a constraint WITH CHECK OPTION na criao da View, ao tentarmos inserir o


produto com o campo PROD_TIPO <> D um erro interno no banco seria gerado anulando a
incluso do registro.
Vejamos um exemplo de View utilizando esta constraint:
CREATE VIEW VIEW_EXEMPLO_4 AS SELECT PROD_CODIGO, PROD_DESCRICAO, PROD_TIPO FROM
PRODUTO WHERE PROD_TIPO = 'D' WITH CHECK OPTION

Se tentarmos inserir um registro com o campo PROD_TIPO = D:


INSERT INTO VIEW_EXEMPLO_4 (PROD_CODIGO, PROD_DESCRICAO, PROD_TIPO) VALUES (100,
'PRODUTO 100', 'D');

Este registro ser incluso na tabela PRODUTO e ser visualizado na View.


Agora se tentarmos inserir um registro com o campo PROD_TIPO <> D:
INSERT INTO VIEW_EXEMPLO_4 (PROD_CODIGO, PROD_DESCRICAO, PROD_TIPO) VALUES (200,
'PRODUTO 200', 'L');

A seguinte mensagem de erro seria exibida:


Operation violates CHECK constraint on view or table VIEW_EXEMPLO_4.
Desta forma o registro no seria incluso.
Vale lembrar que independente da utilizao desta constraint, se tentssemos atualizar ou excluir
um registro que no retornado pela View, mesmo existindo na tabela de produtos, o registro no
seria atualizado nem excludo, alm disso, a mensagem de erro tambm no seria exibida caso
estivssemos utilizando a constraint.

Excluindo e Alterando uma VIEW


A excluso de uma View feita utilizando o comando DROP:
DROP VIEW_EXEMPLO_1

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 102 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


No temos um ALTER VIEW, portanto, para alterarmos uma View temos que excluir e criar
novamente.

Concluso
Neste captulo abordamos a criao de Views assim como suas respectivas vantagens. Estaremos
agora demonstrando sua utilizao diretamente no banco de dados atravs do IBExpert.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 103 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando e utilizando Views no IBExpert


Vimos no captulo anterior para que serve uma View e como criamos. Estaremos agora utilizando o
IBExpert para criamos e executarmos as Views.
Podemos criar as Views executando os scripts vistos anteriormente no editor SQL do IBExpert.
Alm desta opo poderamos utilizar o menu Database->New View ou o item Views na rvore de
opes da conexo, veremos este ltimo caso.
Com o IBExpert aberto e conectado no banco, abra a rvore do lado esquerdo selecionando o item
Views e clique com o boto direito do mouse selecionando o item de menu New View...:

Figura 1 Selecionando o item de menu para criao de uma View


Ao clicar nesta opo, ser exibida a tela para criamos a View:

Figura 2 Tela para criao da View

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 104 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


No lado direito indicado pela seta onde devemos informar o script da nossa View ou substituir os
campos _fields_ _table_name_ _conditions_. Para facilitar estaremos colando nosso script nesta
tela:

Figura 3 Adicionando nosso cdigo para criao da View


Agora s clicar no boto Compile ou apertar CTRL + F9 para que ela seja compilada:

Figura 4 - Clicando no boto compile para compilar a View


Em seguida ser exibida a tela para efetuarmos um Commit:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 105 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 5 Tela para efetuar o Commit na criao da View;


Basta clicar no boto Commit e a nossa View estar criada.
Depois de criada, podemos alter-la ou exclu-la clicando com o boto direito na respectiva View:

Figura 6 - Opes para alterarmos ou excluirmos a View

Criando e realizando testes em outras Views


Repetiremos os procedimentos de criao para as Views abaixo e iremos realizando os testes para
visualizarmos os resultados.
Estaremos utilizando como base 5 produtos da tabela de PRODUTO.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 106 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

1.a View Modelo mais simples


Antes de partir para a criao da 2.a View, vamos realizar um teste na 1.a View.
Caso no tenha criado ainda, utilize o seguinte cdigo:
CREATE VIEW VIEW_EXEMPLO_1 AS SELECT * FROM PRODUTO

Para realizar o teste, execute a seguinte instruo SQL:


SELECT * FROM VIEW_EXEMPLO_1;

Teremos o seguinte resultado:

Figura 7 Visualizando o resultado da 1.a View


Esta View a mais simples, retorna todos os campos e todos os registros da tabela PRODUTO.

2.a View Especificando os campos


CREATE VIEW VIEW_EXEMPLO_2 AS SELECT PROD_CODIGO, PROD_DESCRICAO FROM PRODUTO

Execute a seguinte instruo SQL para o teste:


SELECT * FROM VIEW_EXEMPLO_2;

Figura 8 Visualizando o resultado da 2.a View


Esta View continua retornando todos os registros, porm apenas 2 campos: PROD_CODIGO e
PROD_DESCRICAO.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 107 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

3.a View Nomeando os campos


CREATE VIEW VIEW_EXEMPLO_2A (CODIGO, DESCRICAO) AS SELECT PROD_CODIGO,
PROD_DESCRICAO FROM PRODUTO

Execute a seguinte instruo SQL para o teste:


SELECT * FROM VIEW_EXEMPLO_2A;

Figura 9 Visualizando o resultado da 3.a View


Perceba que esta View tambm retorna os 2 campos, porm nomeados com os nomes indicados
na View.

4.a View Limitando os registros


CREATE VIEW VIEW_EXEMPLO_3
AS
SELECT
PROD_CODIGO,
PROD_DESCRICAO,
PROD_TIPO
FROM
PRODUTO
WHERE
PROD_TIPO = 'D'

Utiliza a seguinte instruo SQL para realizar o teste:


SELECT * FROM VIEW_EXEMPLO_3

Figura 10 Visualizando o resultado da 4.a View


Nesta View j limitamos os registros a serem retornados, neste caso somente produtos cujo campo
PROD_TIPO seja igual a D.
Poderamos aproveitar este momento para realizar o teste de atualizao de uma view:
UPDATE VIEW_EXEMPLO_3 SET PROD_DESCRICAO = 'PRODUTO 1 ALTERADO' WHERE PROD_CODIGO
= 1
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 108 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Aps atualizarmos, podemos verificar a alterao executando um SELECT na View ou na tabela
PRODUTO:
SELECT * FROM VIEW_EXEMPLO_3

Figura 11 Visualizando os registros na View aps o update


SELECT * FROM PRODUTO

Figura 12 Visualizando os registros na tabela de produtos aps o update na View


Podemos notar que o update na view atualizou diretamente a tabela de produto.

4.a View Impedindo a insero de registros no autorizados


CREATE VIEW VIEW_EXEMPLO_4 AS
SELECT
PROD_CODIGO,
PROD_DESCRICAO,
PROD_TIPO
FROM
PRODUTO
WHERE
PROD_TIPO = 'D'
WITH CHECK OPTION

Podemos testar esta view executando a seguinte instruo SQL:


INSERT INTO VIEW_EXEMPLO_4 (PROD_CODIGO, PROD_DESCRICAO, PROD_TIPO) VALUES (200,
'PRODUTO 200', 'L');

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 109 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 13 Mensagem de erro ao tentar inserir um registro que viola a constraint


Note a mensagem de erro sendo exibida, pois estamos tentando inserir um produto com o campo
PROD_TIPO = 'L' e nossa View limita os registros com PROD_TIPO = 'D', logo violamos a
constraint que adicionamos na view: WITH CHECK OPTION.
Agora se tentarmos inserir um produto com o PROD_TIPO = 'D', ser inserido normalmente:
INSERT INTO VIEW_EXEMPLO_4 (PROD_CODIGO, PROD_DESCRICAO, PROD_TIPO) VALUES (200,
'PRODUTO 200', 'D');

Figura 14 Produto inserido diretamente na View

Concluso
Vimos no IBExpert como criamos e utilizamos Views no banco de dados, pudemos notar que a IDE
no nos facilita muito na criao da View, compensa executarmos o script SQL diretamente.
No demonstraremos a utilizao de Views no Delphi, j que utilizada da mesma forma que uma
tabela, ou seja, podemos utilizar os componentes da DBExpress normalmente como j vimos
anteriormente utilizando o conjunto ClientDataSet/Provider/Query para visualizao dos dados,
onde na query teramos, por exemplo, um SELECT * FROM NOME_DA_PROCEDURE.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 110 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Relatrios Mestre/Detalhe com performance


No primeiro mdulo deste curso citei as diferenas entre as formas existentes de se trabalhar com
o ClientDataSet utilizando mestre/detalhe. Conclumos que a forma mais eficaz na grande maioria
dos casos utilizar o modelo NestedDataSet, onde fazemos o relacionamento entre as querys, o
ApplyUpdates feito apenas no ClientDataSet mestre, a atualizao centralizada na mesma
transao, etc.
Por esta razo comum os desenvolvedores acabarem utilizando este mesmo modelo de
relacionamento em relatrios, mas infelizmente no recomendvel em casos onde temos muitos
registros mestres.
Quando utilizamos este modelo, para cada registro mestre executado a query detalhe para
retornar os registros detalhes. Por exemplo, se formos gerar um relatrio contendo 100 pedidos,
teremos uma query sendo executada para extrair os pedidos, e para cada pedido ser executada
outra query para retornar os itens, ou seja, teremos 101 querys sendo executadas, claro que
otimizadas, pois a query detalhe que estar sendo executada com freqncia ser preparada
antecipadamente pela prpria DBExpress ganhando mais performance no servidor.
Por esta razo sugiro desenvolvermos relatrios mestre/detalhe utilizando outra tcnica (joins) um
pouco mais trabalhosa, porm vale a pena, pois para relatrios com muitos registros mestres,
perceberemos a diferena de performance claramente.

Utilizando Joins
A utilizao de joins resume-se em fazermos um SELECT na tabela DETALHE com JOIN na
tabela MESTRE e no gerador de relatrios fazemos uma quebra pela chave primria da tabela
MESTRE, para isto utilizaramos agrupadores nos geradores de relatrios.
Esta tcnica pode ser aplicada em qualquer gerador de relatrio que permita fazer quebras,
agrupamentos, portanto, estaremos utilizando o QuickReport para fins didticos.
Pode parecer um pouco confuso, mas vamos exemplificar aqui uma tabela com poucos registros
para entendermos melhor com seria.
Utilizaramos o seguinte SQL:
SELECT
PED.PED_NUMERO,
PED.PED_VALOR,
PEDITEM.PEDITEM_QTDE,
PEDITEM.PEDITEM_VALUNIT,
PEDITEM.PEDITEM_DESCRICAO
FROM
PEDIDO_ITEM PEDITEM
INNER JOIN PEDIDO PED ON PED.PED_NUMERO = PEDITEM.PED_NUMERO
ORDER BY
PED.PED_NUMERO

O resultado seria:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 111 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 1 Exemplo dos registros


No exemplo acima perceba que as 3 primeiras colunas so referentes aos dados do pedido e as
demais colunas so referentes aos dados dos itens. O pedido nmero 1 tem 2 itens, por isso
visualizamos seus dados repetidos nas duas primeiras linhas (vermelho) e 3 primeiras colunas. O
pedido nmero 2 (azul) tem apenas um item e o Pedido nmero 3 (verde) tem 2 itens.
As cores foram utilizadas para ficar claro que as quebras do relatrio sero feitas desta forma, ou
seja, ser feita uma quebra no pedido nmero 1 sendo visualizado seus 2 itens, outra quebra no
pedido nmero 2 imprimindo apenas seu nico item e por ltimo a quebra no pedido nmero 3
imprimindo seus 2 itens, com isso teremos um efeito de mestre/detalhe.
O segredo do funcionamento a chave que ir fazer a quebra, neste caso, utilizaremos o nmero
do pedido, pois sempre que mudar o nmero, uma nova quebra ser feita dando um efeito de
mestre/detalhe, por este motivo utilizamos o ORDER BY no campo PED_NUMERO para garantir que
os registros sejam ordenados por este campo.
A performance est no fato de executarmos apenas uma query no banco e no mais N querys de
acordo com o nmero de registros mestre para buscar os registros detalhes.

Partindo para prtica


Para que possamos comprovar na prtica a diferena, criaremos o relatrio utilizando os dois
modelos (NestedDataSet e Joins) e ao final ser feita uma comparao demonstrando o arquivo de
log gerado por ambos os modelos.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 112 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando Relatrio Mestre/Detalhe utilizando NestedDataSet


Abra nosso projeto no Delphi.
Clique no menu File->New->Other... na janela que ser exibida, selecione o item Report e
confirme clicando no boto Ok.

Figura 1 Criando um novo Report


Em seguida salve-o como uqrModeloNestedDataSet.pas
Adicione na clusula uses a unit udmprincipal:
...
implementation
uses udmPrincipal;
...

Agora insira os seguintes componentes no QuickReport:

TSQLQuery
Name: qryPedido
SQLConnection: dmPrincipal.SqlConnPrincipal
SQL:
SELECT
PED_NUMERO,
PED_DATA,
PED_VALOR
FROM
PEDIDO

TDataSetProvider
Name: dspPedido
DataSet: qryPedido

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 113 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

TClientDataSet
Name: cdsPedido
ProviderName: dspPedido

TDataSource
Name: dtsLink
DataSet: qryPedido

TSQLQuery
Name: qryPedItem
DataSource: dtsLink
SQLConnection: dmPrincipal.SqlConnPrincipal
SQL:
SELECT
PED_NUMERO,
PEDITEM_DESCRICAO,
PEDITEM_QTDE,
PEDITEM_VALTOTAL
FROM
PEDIDO_ITEM
WHERE
PED_NUMERO = :PED_NUMERO

Agora de um duplo clique no cdsPedido para abrir o FieldsEditor, em seguida clique com o boto
direito do mouse e acesse o item de menu Add fields.

Figura 2 Adicionando os campos ao cdsPedido


Em seguida ser exibida a lista dos campos a serem adicionados.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 114 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 3 Lista de campos a serem adicionados ao cdsPedido


Perceba o campo qryPedidoItem, este ser o nosso NestedDataSet. Confirme clicando no boto
OK.
Agora selecione o componente cdsPedItem e na propriedade DataSetField j temos o
NestedDataSet disponvel, portanto, associe-a com o campo cdsPedidoqryPedidoItem.

Figura 4 Definindo o DataSetField do cdsPedItem


Pronto, neste momento temos nossos ClientDatsSet's interligados de modo a trabalhar com
mestre/detalhe utilizando NestedDataSet.
Agora vamos ajustar o QuickReport.
Selecione o Report e na propriedade Bands ligue a opo HasDetail

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 115 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 5 Ligando a opo HasDetail do QuickReport


Adicione o componente QRSubDetail conforme demonstra a figura a seguir:

Figura 6 Adicionando um QRSubDetail ao QuickReport

Figura 7 Subdetail inserido no relatrio

Selecione o Report e ajuste a propriedade DataSet apontando para cdsPedido.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 116 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 8 Ajustando o DataSet do QuickReport


Agora selecione a banda SubDetail e ajuste o DataSet apontando para cdsPedItem.

Figura 9 Ajustando o DataSet da banda SubDetail


Agora o que resta adicionarmos os QRDBText's na banda Detail ligando-os com o dataset
cdsPedido e Subdetail ligando-os com o dataset cdsPedItem assim como seus respectivos
campos.
O QuickReport dever ficar da seguinte forma:

Figura 10 Report montando com os QRDBText's


Para que cada quebra seja feita em uma pgina, devemos ajustar a propriedade ForceNewPage
da banda Detail, portanto ative esta propriedade.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 117 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 11 Ligando a propriedade ForceNewPage da banda Detail


Aproveite este momento para ajustar o name do QuickReport para qrModeloNestedDataSet.
Para verificar se tudo est funcionando corretamente, abra o cdsPedido atravs da propriedade
Active e faa o mesmo para o cdsPedItem. Em seguida clique com o boto direito do mouse
sobre o QuickReport e clique em Preview.
Dever ser visualizado o relatrio no modelo mestre/detalhe conforme demonstra a figura a seguir:

Figura 12 Preview do Relatrio


Agora vamos colocar uma chamada ao relatrio na tela principal do projeto, porm antes vamos
aproveitar que estamos com o Report aberto e codificar seu evento BeforePrint da seguinte forma:
procedure TqrModeloNestedDataSet.QuickRepBeforePrint(
Sender: TCustomQuickRep; var PrintReport: Boolean);
begin
cdsPedido.Open;
end;

No esquea de desligar a propriedade Active do componente cdsPedido e cdsPedItem.


Abra a unit ufrmPrincipal e na clusula uses adicione a unit uqrModeloNestedDataSet
...
implementation
uses
uqrModeloNestedDataSet;

...
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 118 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Certifique-se de que este Report no est como Auto-Create na aplicao, para verificar, acesse o
menu Project->Options e confira se a paleta Forms est como a figura a seguir, caso no esteja
ajuste-a desta forma:

Figura 13 Ordem de criao dos formulrios


Agora adicione um boto no formulrio principal.

TButton
Caption: Abrir QuickReport 1 Modelo NestedDataSet
Name: btnQrNestedDataSet
Codifique o evento OnClick da seguinte forma:
procedure TfrmPrincipal.btnQrNestedDataSetClick(Sender: TObject);
begin
qrModeloNestedDataSet := TqrModeloNestedDataSet.Create(Self);
try
qrModeloNestedDataSet.PreviewModal;
finally
qrModeloNestedDataSet.Free;
end;
end;

Se rodarmos a aplicao e clicarmos no boto, teremos o mesmo resultado do Preview que


testamos em tempo de projeto no prprio QuickReport.

Fazendo um log das Querys executadas no banco


Faremos um log das querys executadas no banco de dados para que ao final possamos concluir
com as diferenas entre os dois modelos de relatrio, portanto, adicione o componente
SQLMonitor no datamodule principal ajustando as seguintes propriedades:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 119 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

TSQLMonitor
Name: sqlmon
SqlConnection: SqlConnPrincipal
FileName: log.txt
AutoSave: True
Active:True
Execute a aplicao novamente e clique no boto para abrir o relatrio.
Depois que o relatrio foi gerado abra o arquivo log.txt que foi criado no mesmo diretrio do
projeto e perceba um contedo semelhante ao que temos a seguir onde fao alguns comentrios
em alguns pontos:
INTERBASE - isc_attach_database
INTERBASE - isc_dsql_allocate_statement
INTERBASE - isc_start_transaction
## Executando a Query mestre
SELECT
PED_NUMERO,
PED_DATA,
PED_VALOR
FROM
PEDIDO
INTERBASE
INTERBASE
INTERBASE
INTERBASE
INTERBASE
INTERBASE

isc_dsql_prepare
isc_dsql_describe_bind
SQLDialect = 3
isc_dsql_execute
isc_dsql_fetch
isc_dsql_allocate_statement

## Preparando a query detail


SELECT
PED_NUMERO,
PEDITEM_DESCRICAO,
PEDITEM_QTDE,
PEDITEM_VALTOTAL
FROM
PEDIDO_ITEM
WHERE
PED_NUMERO = ?
INTERBASE - isc_dsql_prepare
INTERBASE - isc_dsql_describe_bind
## Executando a query detail pela 1.a vez
INTERBASE - SQLDialect = 3
INTERBASE - isc_dsql_execute
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_commit_retaining
INTERBASE - isc_dsql_free_statement
## Executando a query detail pela 2.a vez
INTERBASE - SQLDialect = 3
INTERBASE - isc_dsql_execute
INTERBASE - isc_dsql_fetch
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 120 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


INTERBASE
INTERBASE
INTERBASE
INTERBASE

isc_dsql_fetch
isc_dsql_fetch
isc_commit_retaining
isc_dsql_free_statement

## Executando a query detail pela 3.a vez


INTERBASE - SQLDialect = 3
INTERBASE - isc_dsql_execute
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_commit_retaining
INTERBASE - isc_dsql_free_statement
## Executando a query detail pela 4.a vez
INTERBASE - SQLDialect = 3
INTERBASE - isc_dsql_execute
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_commit_retaining
INTERBASE - isc_dsql_free_statement

E assim vai indo, se tivssemos muitos registros o log estaria enorme, pois para cada registro
mestre so executados estes blocos que vimos acima, ou seja, uma query de itens sendo
executada para cada pedido.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 121 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Criando o Relatrio utilizando Joins


Com o projeto aberto, insira um novo Report conforme foi explicado no captulo anterior utilizando
o menu File->New->Other

Figura 1 Criando um novo report


Salve a unit como uqrModeloJoin.pas, em seguida nomeie o Report para qrModeloJoin.
Adicione na clusula uses a unit udmprincipal:
...
implementation
uses udmPrincipal;
...

Agora adicione os seguintes componentes:

TSQLQuery
Name: qryPedido
SQLConnection: dmPrincipal.SqlConnPrincipal
SQL:
SELECT
PED.PED_NUMERO,
PED.PED_VALOR,
PEDITEM.PEDITEM_QTDE,
PEDITEM.PEDITEM_VALUNIT,
PEDITEM.PEDITEM_DESCRICAO
FROM
PEDIDO_ITEM PEDITEM
INNER JOIN PEDIDO PED ON PED.PED_NUMERO = PEDITEM.PED_NUMERO
ORDER BY
PED.PED_NUMERO

TDataSetProvider
Name: dspPedido
DataSet: qryPedido
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 122 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

TClientDataSet
Name: cdsPedido
ProviderName: dspPedido
Em seguida de um duplo clique no cdsPedido para abrir o FieldsEditor e clique com o boto
direito acessando o item de menu Add fields.

Figura 2 Abrindo o FieldsEditor e adicionando os campos no cdsPedido

Figura 3 Campos a serem adicionadas ao cdsPedido


Perceba que teremos num nico ClientDataSet campos da tabela de Pedido e Itens, pode parecer
estranho, mas isto mesmo.
Agora selecione o Report e na propriedade Bands ative a opo HasDetail.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 123 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 4 Ativando a opo HasDetail na propriedade Bands do Report


Ajuste a propriedade DataSet do Report apontando para cdsPedido.

Figura 5 Ajustando o DataSet do Report


Neste momento j teramos pronto nosso relatrio para exibir uma listagem dos registros sem
quebras, mas no este nosso objetivo, precisamos da quebra para simular o mestre/detalhe,
portanto vamos l!
Insira um TQRGroup no Report conforme demonstra a figura a seguir:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 124 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 6 Adicionando um TQRGroup no Report


O Report ficar da seguinte forma:

Figura 7 Report com o TQRGroup adicionado

Adicionamos o TQRGroup, pois este o componente para realizarmos agrupamento no


QuickReport, neste caso estaremos utilizando esta tcnica para fazermos as quebras simulando o
mestre/detalhe.
Agora precisamos definir no QRGroup qual o campo que utilizaremos como sendo o agrupador,
portanto, na propriedade Expression desta banda informe o campo PED_NUMERO conforme
demonstra a figura a seguir:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 125 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 8 Ajustando a propriedade Expression do QRGroup


Agora precisamos ajustar a propriedade ForceNewPage do Grupo, portanto, defina com True:

Figura 9 Ajustando a propriedade do QRGroup


Pronto, neste momento j temos o Report preparado para trabalhar com Mestre/Detalhe,
precisamos apenas inserir os QRDBText's nas respectivas Bandas. Na banda QRGroup devemos
inserir os campo relativos a tabela mestre (tabela de Pedido), j na banda Detail colocamos os
campos relativos a tabela detalhe (tabela de Itens do Pedido).
O report dever ficar da seguinte forma:

Figura 10 Componentes QRDBText's inseridos no Report

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 126 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Vale lembrar que todos componentes QRDBTexts estaro apontando para o mesmo DataSet, no
caso o cdsPedido.
O ltimo passo para finalizarmos este relatrio codificarmos o evento BeforePrint para que o
ClientDataSet de Pedido seja aberto ao imprimir o relatrio, portanto, codifique o evento da
seguinte forma:
procedure TqrModeloJoin.QuickRepBeforePrint(Sender: TCustomQuickRep;
var PrintReport: Boolean);
begin
cdsPedido.Open;
end;

Agora basta ajustarmos nosso formulrio principal para fazer chamada a este report.
Abra a unit ufrmPrincipal e na clusula uses adicione a unit uqrModeloJoin
...
implementation
uses
uqrModeloNestedDataSet,
uqrModeloJoin;
...

Em seguida adicione um boto ajustando as respectivas propriedades:

TButton
Caption: Abrir QuickReport 1 Modelo Join
Name: btnQrJoin
Codifique o evento OnClick da seguinte forma:
procedure TfrmPrincipal.btnQrJoinClick(Sender: TObject);
begin
qrModeloJoin := TqrModeloJoin.Create(Self);
try
qrModeloJoin.PreviewModal;
finally
qrModeloJoin.Free;
end;
end;

Agora vamos verificar como est a ordem de criao dos formulrios e quais esto como AutoCreate, deixe-os da seguinte forma:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 127 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 11 Verificando a ordem e criao automtica dos formulrios


Esta verificao feita apenas para no deixarmos nossos Report's sendo criados
automaticamente ao entrar na aplicao, eles so criados dinamicamente somente quando
clicamos nos botes.
Para podermos fazer o teste, primeiro verifique no datamodule principal se o componente
SQLConnection est conectado no banco, se estiver desconecte-o. Em seguida exclua o arquivo
log.txt que est na pasta do projeto e foi gerado no captulo anterior.
Agora vamos rodar a aplicao e clicar no boto para gerar o relatrio, teremos o seguinte
resultado:

Figura 12 Relatrio gerado no modelo Join


Podemos analisar o arquivo log.txt e notaremos a diferena comparando com o log visto no
captulo anterior:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 128 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


INTERBASE - isc_attach_database
INTERBASE - isc_dsql_allocate_statement
INTERBASE - isc_start_transaction
# Aqui est a diferena, apenas um select executado
SELECT
PED.PED_NUMERO,
PED.PED_VALOR,
PEDITEM.PEDITEM_QTDE,
PEDITEM.PEDITEM_VALUNIT,
PEDITEM.PEDITEM_DESCRICAO
FROM
PEDIDO_ITEM PEDITEM
INNER JOIN PEDIDO PED ON PED.PED_NUMERO = PEDITEM.PED_NUMERO
INTERBASE
INTERBASE
INTERBASE
INTERBASE

isc_dsql_prepare
isc_dsql_describe_bind
SQLDialect = 3
isc_dsql_execute

# Daqui para baixo apenas fetchs executados para trazer os registros,


isso normal, no log anterior vimos estes fetchs tambm, porm aqui no
temos mais aquele bloco responsvel por executar a query
detalhe para cada pedido
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch
INTERBASE - isc_dsql_fetch

....

Concluso de ambos os modelos


Simulamos os dois exemplos com poucos registros, por este motivo no pudemos notar diferenas
em performance, alm disso, estamos rodando a aplicao com o banco local, em um ambiente de
rede perceberamos mais a diferena.
De qualquer forma pudemos notar a diferena no prprio log entre um modelo e outro, ento sugiro
que faa testes mais precisos em um ambiente de rede com mais registros para notar a diferena e
decidir qual modelo utilizar.
Caso sejam poucos registros, sugiro manter o modelo tradicional, j que com ele podemos facilitar
outros trabalhos, somente em casos onde haja muitos registros mestres, interessante pensar em
utilizar o modelo Join.
Outro aspecto importante que no foi citado que no necessariamente precisaramos ter utilizado
o ClientDataSet para gerar o relatrio, no caso do QuickReport ele permite que seja utilizado
DataSets unidirecionais, portanto, caso voc no necessite de algo especfico do ClientDataSet,
poder utilizar diretamente a TSQLQuery, mas fique atento com outros geradores de relatrio, pois
pode acontecer de algum deles no permitir a utilizao destes DataSets unidirecionais.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 129 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Instalando e utilizando driver DBExpress de terceiros


O driver DBExpress que estamos utilizando nativo da Borland especfico para Interbase, porm
estamos utilizando com Firebird pelo fato de ainda existir compatibilidade pelo menos at a verso
1.5 do banco de dados.
Infelizmente esta compatibilidade pode no durar muito, com a nova verso 2.0 poderemos ter
algumas incompatibilidades, por este motivo interessante comearmos a utilizar drivers da
DBExpress especficos para Firebird.
Existem dois drivers DBExpress disponveis na Internet at este momento. Um deles o
InterXPress da Upscene sendo pago e podendo ser baixado em http://www.upscene.com. O outro
driver o UIB (Unified Interbase), este j gratuito e pode ser baixado em:
http://www.progdigy.com/modules.php?name=UIB.
Estaremos utilizando este ltimo driver citado, justamente pelo fato de no haver custo!
A instalao um pouco trabalhosa, teremos que ajustar o arquivo INI que contm os drivers da
DBExpress e compilar o cdigo fonte do projeto que baixaremos do site para gerar a DLL do driver,
mas no se preocupe, no to complicado assim.

Partindo para prtica


Primeiramente devemos baixar o pacote do site:
http://www.progdigy.com/modules.php?name=UIB
Resolvi fazer o download do UIB 2.0, pois segundo o site, este possui compatibilidade com a
verso do Firebird 2.0.
Depois de feito o download do arquivo zip, descompacte-o em: C:\CursoClientDataSet2\Diversos.
Algumas sub-pastas sero criadas conforme demonstra a figura abaixo:

Figura 1 Estrutura de diretrio aps a descompactao


Entre na pasta DBExpress e note que existem diversos projetos Delphi (DPR):

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 130 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 2 Projetos disponveis na pasta DBExpress


Agora abra o projeto dbexpUIBfire15.dpr no Delphi.
Precisamos ajustar o SearchPath, portanto, clique no menu Project->Options em seguida clique
na
aba
Directories/Conditionals
e
ajuste
o
campo
SearchPath
informando:
C:\CursoClientDataSet2\Diversos\UIB2\source

Figura 3 Ajustando o Search path do projeto


Neste momento podemos confirmar e compilar o projeto clicando no menu Project->Build
dbexpUIBfire15.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 131 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 4 Compilando o projeto para gerar a DLL


Com
isso
j
temos
a
DLL
gerada,
C:\CursoClientDataSet2\Diversos\UIB2\DBExpress.

podemos

conferir

na

pasta

Figura 5 DLL gerada aps a compilao


Agora precisamos copiar a DLL para pasta bin do Delphi onde est tambm a atual dbexpint.dll e
outras dlls da DBExpress.

Figura 6 Copiando a DLL gerada para a pasta bin do Delphi


Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 132 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Feche o Delphi e agora faremos o ajuste no arquivo de drivers da DBExpress.
V at a pasta C:\Arquivos de programas\Arquivos comuns\Borland Shared\DBExpress e
abra o arquivo dbxdrivers.ini.
Neste arquivo que esto armazenados os drivers disponveis da DBExpress com seus
respectivos parmetros de conexo. O que precisamos fazer incluir o driver UIB com seus
parmetros, portanto, siga os passos:
- Na seo [Installed Drivers] inclua a linha UIB FireBird15 = 1 conforme demonstra o
bloco abaixo:
[Installed Drivers]
...
UIB FireBird15 = 1

Em seguida, adicione uma seo chamada [UIB FireBird15] com suas respectivas linhas
conforme demonstra o cdigo abaixo:
...
[UIB FireBird15]
GetDriverFunc=getSQLDriverINTERBASE
LibraryName=dbexpUIBfire15.dll
VendorLib=fbclient.dll
BlobSize=-1
CommitRetain=False
Database=database.fdb
ErrorResourceFile=
LocaleCode=0000
Password=masterkey
RoleName=RoleName
ServerCharSet=
SQLDialect=3
Interbase TransIsolation=ReadCommited
User_Name=SYSDBA
WaitOnLocks=True
...

O arquivo ficar da seguinte forma:

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 133 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 7 Arquivo dbxdrivers.ini modificado com a incluso do novo driver


Pronto, agora podemos salvar este arquivo e abrir o Delphi.
Carregue nosso projeto no Delphi em seguida abra o datamodule principal e selecione o
componente SQLConnection.
Clique na propriedade DriverName e note que foi adicionado o driver UIB Firebird 15 na lista de
drivers disponveis.

Figura 8 Driver UIB Firebird 15 adicionado na lista de Drivers da DBExpress


Agora basta selecion-lo e as propriedades GetDriverFunc e LibraryName do componente sero
modificadas de acordo com o novo driver.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 134 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 9 Propriedades GetDriverFunc e LibraryName sendo modificadas de acordo com o driver


Pelo fato de termos mudado de driver, precisamos ajustar novamente os parmetros de conexo,
portanto, clique na propriedade Params ajustando o parmetro DataBase para
C:\CursoClientDataSet2\Projeto\exemplo.fdb e ServerCharSet para WIN1252.

Figura 10 Redefinindo os parmetros de conexo aps a mudana do driver

Distribuindo aplicao
Com o uso deste novo driver a distribuio da aplicao no ser muito diferente do que j vimos
com o driver antigo, a diferena que agora ao invs de levarmos junto a nossa aplicao o
arquivo dbexpint.dll levaremos o arquivo dbexpUIBfire15.dll, lembrando que em seu cliente esse
arquivo dever estar no mesmo diretrio da aplicao ou no System do Windows.

Concluso
Neste captulo demonstramos como instalamos e utilizamos um driver de terceiro especfico para
Firebird com objetivo de evitar incompatibilidades futuras com o banco de dados. Para este caso
utilizamos o driver gratuito, porm, vale a pena comparar com os recursos existentes no driver
pago para sabermos em que momento seria interessante o investimento em um driver DBExpress.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 135 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Trocando a senha do usurio SYSDBA


Durante todo curso utilizamos a senha padro do Firebird, porm interessante modificarmos para
dificultarmos o acesso ao banco por pessoas no autorizadas.
O Firebird possui um utilitrio chamado gsec responsvel pela manipulao de usurios no banco,
portanto estaremos utilizando-o para modificarmos a senha do servidor.
importante sabermos que no adianta apenas modificarmos a senha no servidor, pois o Firebird
armazena as definies de usurios no prprio servidor (tabela security.fdb) e no em nosso
banco de dados especfico, isso significa que se algum copiar o banco de dados da aplicao e
colocar em um outro servidor Firebird, o mesmo poder ter acesso ao banco mesmo no sabendo
a nova senha, pois ele utilizar a senha do SYSDBA deste outro servidor.
Por esta razo a segurana deve iniciar no prprio ambiente de rede limitando o acesso ao
diretrio onde est o banco de dados da aplicao e o Firebird.

Partindo para prtica


Vamos ento executar o gsec para modificarmos a senha do usurio SYSDBA
Entre no prompt de comando e acesse o diretrio bin do Firebird.

Figura 1 Entrando na pasta bin do Firebird


Agora digite:
gsec -user SYSDBA -pass masterkey

Ao pressionar o ENTER estaremos no prompt do utilitrio gsec.

Figura 2 Entrando no gsec com o usurio SYSDBA


Se digitarmos HELP em seguida ENTER, veremos todos comandos que o gsec disponibiliza.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 136 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 3 Comandos do gsec


Estaremos utilizando o comando modify para modificar os dados de um determinado usurio.
Neste caso estaremos modificando a senha do usurio SYSDBA, portanto, devemos digitar o
seguinte comando:
modify SYSDBA pw 123456

Figura 4 Definindo a nova senha para o usurio SYSDBA


Ao pressionar o ENTER j teremos o usurio SYSDBA modificado com a nova senha 123456.
Um detalhe importante que o Firebird considera apenas os 8 primeiros caracteres, portanto, no
adiantaria definirmos uma senha como 123456789 a mesma seria considerada como 12345678.
Para sair do gsec basta digitar
quit

Figura 5 Saindo do gsec


Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 137 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados


Em seguida pressione ENTER.
Para termos a certeza de que a senha foi modificada, basta tentarmos acessar o gsec novamente
com a senha masterkey:

Figura 6 Tentando acessar o gsec com a senha masterkey


Perceba a mensagem de erro dizendo que este usurio e senha no est definido no servidor.
Se tentssemos executar nossa aplicao ou abrir a conexo do banco no IBExpert no
conseguiramos tambm, precisaramos modificar as senhas onde definimos como masterkey.
Aqui concluiramos o assunto, porm vamos voltar a senha anterior:

Figura 7 - Entrando no gsec com a senha nova


Note que agora entramos com a nova senha no gsec.
Modificaremos a senha para masterkey novamente, portanto devemos digitar o seguinte comando:
modify SYSDBA pw masterkey

Figura 8 Voltando a senha sysdba


Perceba que o gsec alertou de que somente os primeiros 8 bytes so considerados conforme
comentamos no incio. O interessante que podemos acessar o banco entrando apenas com a
senha masterke que at onde completam 8 caracteres.
Em seguida vamos sair do gsec digitando quit para finalizarmos.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 138 -

Active Delphi - http//www.activedelphi.com.br

ClientDataSet com DBExpress e Firebird Mdulo II Explorando o Banco de Dados

Figura 9 Saindo do gsec

Concluso
Neste captulo vimos como modificamos a senha do usurio SYSDBA atravs do utilitrio gsec,
mas importante no esquecermos da segurana no prprio ambiente de rede.
O gsec permite tambm a criao de usurios, definies de regras de acesso, entre outros
detalhes, deixaremos este assunto para uma prxima oportunidade pelo fato de que o Firebird 2.0
teve diversas modificaes conceituais e estruturais nesta parte de usurios para garantir maior
segurana, portanto, meu objetivo esperar a verso 2.0 ficar bastante estvel e logo estudar com
detalhes estas mudanas e disponibilizar um artigo passando todos procedimentos necessrios
para criarmos novos usurios e regras de acesso no servidor.
O importante que com este captulo j conseguimos uma segurana a mais por no utilizarmos a
senha padro do servidor.

Verifique se esta apostila possui uma licena registrada


www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br

- 139 -

Active Delphi - http//www.activedelphi.com.br