Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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
-2-
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:
-3-
-4-
-5-
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;
-6-
-7-
-8-
-9-
- 10 -
- 11 -
- 12 -
- 13 -
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:
- 14 -
- 15 -
- 16 -
- 17 -
- 18 -
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.
- 19 -
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
- 20 -
Utilizando o alias:
192.168.0.1:SisExemploAlias
Note que utilizando alias ocultamos o caminho do banco, esta a grande vantagem.
- 21 -
- 22 -
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.
- 23 -
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:
- 24 -
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.
- 25 -
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.
- 26 -
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
- 27 -
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.
- 28 -
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;
- 29 -
- 30 -
- 31 -
Executando a instruo acima comprovamos que os campos que utilizam o domnio tiveram sua
estrutura modificada, ou seja, a propriedade Size passou para 10:
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.
- 32 -
at
diretrio:
C:\Arquivos
de
- 33 -
Em seguida pressione ENTER para confirmar o ltimo comando, veja abaixo como ficou nossa
seqncia de comandos executados:
- 34 -
- 35 -
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.
- 36 -
- 37 -
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.
- 38 -
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';
- 39 -
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.
- 40 -
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;
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 -
- 42 -
- 43 -
Estas instrues SQL's podero ser executadas no IBExpert atravs do menu Tools->Script
Executive... conforme demonstra figura a seguir:
- 44 -
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.
- 45 -
Vantagens
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.
- 46 -
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.
- 47 -
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.
- 48 -
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.
Note que passamos os parmetros logo aps o nome da procedure separando-os com vrgula,
muito semelhante ao que fazemos no Delphi.
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 -
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.
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.
- 50 -
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
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).
- 51 -
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;
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
- 52 -
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.
- 53 -
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
- 54 -
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.
- 55 -
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.
- 56 -
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 -
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
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 -
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);
- 59 -
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';
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'
- 60 -
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.
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
- 61 -
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.
Utilizamos como exemplo o bloco WHEN ANY DO, mas poderamos utilizar qualquer um dos blocos
demonstrados anteriormente.
- 62 -
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.
- 63 -
Em seguida clique no boto Run para executar o script conforme demonstra a figura a seguir:
- 64 -
- 65 -
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:
- 66 -
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 -
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 -
- 69 -
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:
- 70 -
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.
- 71 -
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.
- 72 -
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:
TButton
Name: btnExeSP2
Caption: Exec. SP_RETORNA_MAIOR_VALOR
No evento OnClick do boto insira o seguinte cdigo:
- 73 -
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.
- 74 -
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.
- 75 -
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
- 76 -
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
- 77 -
Testando aplicao
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.
- 78 -
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
- 79 -
Testando aplicao
- 80 -
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:
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.
- 81 -
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.
- 82 -
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.
- 83 -
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.
- 84 -
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.
- 85 -
- 86 -
- 87 -
- 88 -
- 89 -
- 90 -
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')
- 91 -
- 92 -
Portanto, basta alterar o que for necessrio e executar o mesmo procedimento de compilao para
efetivar a alterao.
- 93 -
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.
- 94 -
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;
- 95 -
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 -
Neste momento j temos tudo preparado para fazermos manutenes na tabela de produtos, mas
agora vamos falar dos problemas!
- 97 -
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.
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 -
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.
- 99 -
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 -
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
- 101 -
- 102 -
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.
- 103 -
- 104 -
- 105 -
- 106 -
- 107 -
- 108 -
- 109 -
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.
- 110 -
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:
- 111 -
- 112 -
TSQLQuery
Name: qryPedido
SQLConnection: dmPrincipal.SqlConnPrincipal
SQL:
SELECT
PED_NUMERO,
PED_DATA,
PED_VALOR
FROM
PEDIDO
TDataSetProvider
Name: dspPedido
DataSet: qryPedido
- 113 -
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.
- 114 -
- 115 -
- 116 -
- 117 -
...
Verifique se esta apostila possui uma licena registrada
www.edudelphipage.com.br/licenca?key=SM36A-93DI1-OW59G
EduDelphiPage - http://www.edudelphipage.com.br
- 118 -
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;
- 119 -
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
- 120 -
isc_dsql_fetch
isc_dsql_fetch
isc_commit_retaining
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.
- 121 -
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 -
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.
- 123 -
- 124 -
- 125 -
- 126 -
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;
...
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:
- 127 -
- 128 -
isc_dsql_prepare
isc_dsql_describe_bind
SQLDialect = 3
isc_dsql_execute
....
- 129 -
- 130 -
- 131 -
podemos
conferir
na
pasta
- 132 -
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
...
- 133 -
- 134 -
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.
- 135 -
- 136 -
- 137 -
- 138 -
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.
- 139 -