Académique Documents
Professionnel Documents
Culture Documents
www.axcel.com.br
ORACLE 9i
PARA DESENVOLVEDORES
ORACLE DEVELOPER 6i
CURSO COMPLETO
Lúcia Fernandes
Pirataria é crime contra os direitos autorais, com penas para os infratores de
acordo com a Lei 9.610 de 19 de fevereiro de 1998.
Este e-book não pode ser vendido e/ou distribuído em CD-ROM, DVD-ROM ou por programas de
compartilhamento P2P. A forma correta de obter este arquivo é adquirindo-o através dos sites da Editora
Axcel (www.axcel.com.br) e de Júlio Battisti (www.juliobattisti.com.br).
Se você adquiriu este documento através dos meios legais descritos acima, não distribua ou venda este
produto. Você estará cometendo um crime contra o autor da obra.
Se você adquiriu este e-book por intermédio de terceiros, regularize sua situação entrando em contato pelo e-mail
editora@axcel.com.br, para que não seja alvo das penalizações previstas em Lei. Usar cópia ilegal também é
crime de violação dos direitos autorais.
CRÉDITOS
PRODUÇÃO
Alexandre Ramires
Carlos Alberto Sá Ferreira
REVISÃO
Sandro Gomes dos Santos
ARTE E DIAGRAMAÇÃO
Ingo Bertelli
SUPERVISOR DE PRODUÇÃO
Carlos Alberto Sá Ferreira
CAPA
Ingo Bertelli
EDITORA DE PRODUÇÃO
Gisella Narcisi
EDITOR RESPONSÁVEL
Ricardo Reinprecht
DEDICATÓRIA
À minha família, que me acompanha a cada dia, no desenvolvimento deste trabalho, e me encoraja a prosseguir,
principalmente nos momentos de desânimo. Dedico este livro, portanto, aos meus filhos Davi, Daniel e Gabriel,
ao meu esposo Dilson e aos meus pais Lourdes e Milton (em memória). E, também, a uma amiga muito especial,
que foi uma grande admiradora do meu trabalho, Lucianita (em memória).
AGRADECIMENTOS
A todos os que me apoiaram antes e durante o desenvolvimento deste trabalho.
A todo o pessoal da Axcel Books, especialmente a Alexandre Ramires, Romero Portela Rodrigues e Ricardo Reinprecht.
Ao amigo Max Guyer, por mais uma vez realizar a revisão do conteúdo técnico de todo o material.
SOBRE A AUTORA
Lúcia Fernandes é arquiteta formada pela Universidade Federal do Rio de Janeiro. Na área de informática, sua
atuação foi toda voltada para a área de suporte, especialmente banco de dados. Ministrou diversos treinamentos
associados a bancos de dados e linguagens de programação, principalmente relacionados com o ambiente Oracle.
Atualmente é Diretora de Suporte e Tecnologia da Relacional Consultoria e Sistemas Ltda.
IV ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
SUMÁRIO
PREFÁCIO
Este material foi construído para o desenvolvedor Oracle, ou seja, aquele profissional que deseja se tornar (ou já é)
desenvolvedor de sistemas no ambiente Oracle.
O livro foi dividido em três partes:
♦ Fundamentos – onde encontramos a parte básica, a interface com o banco de dados através das linguagens SQL
e PL/SQL.
♦ Developer – onde encontramos o estudo das ferramentas de desenvolvimento de sistemas Form Builder e Re-
port Builder.
♦ Referência – onde encontramos a sintaxe das linguagens estudadas na parte Fundamentos e lista de propriedades,
de menus, de triggers, de rotinas, de parâmetros, etc. das ferramentas estudadas na parte Developer.
Este livro segue a mesma linha do anterior em que, inicialmente, estudamos a linguagem SQL em seguida passando
ao desenvolvimento de lógicas de programação com o PL/SQL. Consideramos que o estudo sobre objetos no
banco de dados merecia uma atenção maior, e por este motivo dedicamos o Capítulo 4 ao estudo de objetos tanto
em SQL quanto em PL/SQL.
Assim, se você não conhece Oracle (é o seu primeiro contato), deve começar o estudo no Capítulo 2 com a linguagem
SQL, passando então para o Capítulo 3, que contém a linguagem PL/SQL (para construção de aplicações em batch).
De posse desse conhecimento, você poderá avaliar o que a versão 9i trouxe de novidades para o desenvolvedor.
Se, por outro lado, você já conhece Oracle 8i, não deixe de estudar os Capítulos 2 e 3, pois você perceberá que
muitas implementações foram feitas no SQL. A quantidade de funções cresceu tremendamente, a sintaxe dos
comandos de DML ganhou acréscimos para aceitar o padrão ANSI. A PL/SQL também ganhou novos pacotes e
implementou todas as alterações realizadas para o SQL.
A parte (tanto da SQL quanto da PL/SQL) relativa a uso de objetos no banco de dados também foi incrementada
com o conceito de herança e polimorfismo. No Capítulo 4 fazemos um estudo específico sobre objetos, tanto do
ponto de vista conceitual quanto do uso no ORACLE.
No Capítulo 5 o desenvolvedor encontrará alguns tópicos gerais relativos ao banco de dados, que podem ser úteis
no emprego mais eficiente no software; muitas vezes, porém, não diretamente ligados ao seu dia-a-dia, por exemplo,
particionamento de tabelas, views materializadas, performance do SQL, dentre outros.
A parte Fundamentos conta com um conjunto de aproximadamente 250 exercícios e mais de 600 exemplos.
Certamente você encontrará muita coisa interessante para estudar, independente do seu nível de conhecimento
atual. Na parte Referência, você encontrará a sintaxe de SQL9i, de PL/SQL9i além da sintaxe de SQL*Plus.
Para facilitar o estudo daqueles que já conhecem o Oracle8i criamos um índice exclusivo com as novidades. Neste
índice incluiremos, apenas, aqueles tópicos que sofreram modificações na versão 9i ou que ainda não havíamos
estudado no livro anterior.
Se você pretende se utilizar das ferramentas de desenvolvimento da Oracle, seu estudo ainda não acabou: devemos
passar à segunda parte (Developer), onde estão os capítulos referentes às ferramentas de desenvolvimento.
Iniciamos o estudo das ferramentas com a instalação, no Capítulo 6, e passamos então ao Form Builder 6i (Capítulo
7) e Report Builder 6i (Capítulo 8). O Capítulo 9 é dedicado ao estudo das ferramentas em ambiente Web.
Se você não conhece as ferramentas de desenvolvimento da Oracle, seu estudo começa no Capítulo 7, onde você
conhecerá a filosofia da ferramenta (Form Builder), sua utilização passo a passo e dicas diversas. Em seguida, você
deve passar ao Capítulo 8, para que possamos estudar juntos a confecção de relatórios com a ferramenta Report
Builder. Quando você estiver bem experiente nas duas ferramentas, passe ao Capítulo 9 e verifique como utilizar o
mesmo programa que você desenvolveu para ambiente cliente-servidor na Web (Internet ou Intranet).
CURSO COMPLETO00✦ V
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO
Se você já conhece as ferramentas em versões anteriores, o estudo dos Capítulos 7 e 8 terá o objetivo de verificar o
que houve de implementação na versão 6i. Não deixe, no entanto, de ler esses capítulos, pois, além das modificações,
você encontrará dicas úteis ao longo do texto. No Capítulo 9, você já sabe, encontrará um estudo passo-a-passo
para a implementação das aplicações em ambiente Web.
A parte Developer conta com um conjunto de aproximadamente 120 exercícios e 200 figuras e 90 listagens com
exemplos. Na parte Referência, você encontrará as propriedades dos objetos do Form e do Report, os menus, as
variáveis de sistema, os parâmetros de execução, os triggers e as rotinas dos pacotes internos. Enfim, muita informação
para o seu estudo.
Quanto ao desenvolvimento do material, utilizamos a seguinte regra geral: os assuntos são apresentados com uma
parte teórica seguida de exemplos que permitam o entendimento prático. Ao final do tópico propomos alguns
exercícios para fixação do assunto. Todos os exercícios estão resolvidos ao final de cada capítulo, para que você
possa comparar o seu resultado com uma solução.
O material segue uma ordem crescente de dificuldade, isto é, minha expectativa é de que você siga o estudo na
ordem proposta, pois o tópico seguinte pressupõe o conhecimento do anterior.
Em relação à convenção sintática apresentada neste livro, utilizamos, basicamente, a mesma encontrada nos manuais
da Oracle.
De acordo com essas convenções, as informações entre colchetes – [ ] – são opcionais e as informações entre os
símbolos < e > indicam valores a serem substituídos. Por exemplo, Round (<n> [ , <m>]) indica que a função Round
aceita um ou dois parâmetros e que n deve ser substituído pelo valor que desejamos arredondar. Nesse caso,
teríamos opcionalmente Round (1234.87) ou Round (1234.87, 1).
As sintaxes alternativas e/ou as repetitivas são representadas por linhas e pontes como na figura-exemplo a seguir.
Dentro de cada capítulo veremos trechos das sintaxes, pois estaremos analisando individualmente os assuntos;
porém, na parte de anexos, teremos a sintaxe completa com a explicação específica sobre cada opção.
Como recomendação ao leitor interessado em se tornar um desenvolvedor, sugiro que não se atenha apenas à leitura
do material. Praticar traz dúvidas que a leitura não traz; portanto refaça todos os testes apresentados, faça outros
testes complementares com opções não exemplificadas e tente realizar todos os exercícios de fixação. Duvide e teste!
Dessa forma, você terá condições de tirar suas próprias conclusões sobre as ferramentas apresentadas. Se, após este
estudo, você tiver dúvidas, escreva para o e-mail da Editora, a fim de entrar em contato comigo para novas explicações.
Não deixe, também, de obter todos os scripts e aplicativos presentes no livro para que seu estudo seja mais ágil.
Faça download em www.axcel.com.br.
Bom estudo!
Lúcia.
VI ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
SUMÁRIO
Sumário
PARTE I – FUNDAMENTOS ................................................................................................................................ 1
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000 .................................................................. 3
Fundamentos em: Instalação do Produto ............................................................................................ 4
Requerimentos Para Instalação ............................................................................................................................ 4
Acompanhando a Instalação ............................................................................................................................... 4
Localização dos Arquivos ..................................................................................................................................... 5
Produtos Disponíveis ........................................................................................................................................... 5
Tipos de Instalação ............................................................................................................................................... 6
Configuração do Banco de Dados ........................................................................................................................ 7
Identificação do Banco de Dados ......................................................................................................................... 7
Local do Arquivo do Banco de Dados .................................................................................................................. 8
Conjunto de Caracteres de Banco de Dados ........................................................................................................ 8
Resumo ................................................................................................................................................................. 9
Fundamentos em: Substituição da Linguagem .................................................................................. 10
Executando o Regedit ......................................................................................................................................... 10
O Nó Oracle ........................................................................................................................................................ 10
Fundamentos em: Criação de um Usuário-Padrão com o SQL*Plus ................................................. 12
Fundamentos em: Criação da Base Relacional ................................................................................... 13
Modelo de Dados ............................................................................................................................................... 13
Gerando a Base de Dados ................................................................................................................................... 14
Criando o Atalho Para o SQL*Plus ..................................................................................................................... 20
Sobre a Base de Dados Objeto-Relacional .......................................................................................................... 20
CAPÍTULO 2 – SQL E SQL*PLUS ................................................................................................................... 21
Fundamentos em: Linguagem SQL ...................................................................................................... 22
Dados Históricos ................................................................................................................................................ 22
O Oracle e o SQL ................................................................................................................................................ 22
Banco de Dados Relacional ................................................................................................................................ 22
A Abrangência da Linguagem ............................................................................................................................ 23
Linguagem de Manipulação dos Dados (Data Manipulation Language – DML) .......................................... 23
Linguagem de Definição dos Dados (Data Definition Language – DDL) ...................................................... 23
Linguagem de Controle dos Dados (Data Control Language – DCL) ........................................................... 23
Fundamentos em: Ferramenta SQL*Plus ............................................................................................ 24
Abrindo uma Sessão ........................................................................................................................................... 24
O SQL Buffer ....................................................................................................................................................... 24
Os Comandos do SQL*Plus ................................................................................................................................ 25
Digitando no SQL*Plus ...................................................................................................................................... 25
Comandos de Edição .......................................................................................................................................... 26
List .................................................................................................................................................................. 26
Append ........................................................................................................................................................... 27
Change ........................................................................................................................................................... 27
Del .................................................................................................................................................................. 28
Input .............................................................................................................................................................. 29
Edit ................................................................................................................................................................. 29
Comandos de Execução e de Encerramento ...................................................................................................... 31
Run ................................................................................................................................................................. 31
/ (Barra) .......................................................................................................................................................... 32
Exit / Quit ...................................................................................................................................................... 32
Describe .......................................................................................................................................................... 33
Comandos Para Tratamento de Arquivos .......................................................................................................... 34
Save ................................................................................................................................................................ 34
Get .................................................................................................................................................................. 34
Start ................................................................................................................................................................ 35
Fundamentos em: Consulta à Base de Dados ..................................................................................... 37
Introdução .......................................................................................................................................................... 37
Forma Básica do Comando SELECT ................................................................................................................... 37
Restringindo a Consulta ..................................................................................................................................... 38
O Uso de All Versus Distinct ou Unique ............................................................................................................ 38
Operadores de Comparação ............................................................................................................................... 39
Usando And e Or ................................................................................................................................................ 39
Mudando a Precedência das Operações ............................................................................................................. 39
Operadores Aritméticos e de Concatenação ...................................................................................................... 40
Selecionando um Intervalo de Valores – Between ............................................................................................. 40
Selecionando uma Lista de Valores – In ............................................................................................................. 41
Pesquisando o Conteúdo de um Texto – Like .................................................................................................... 41
Pesquisando um Valor Desconhecido – Is Null ................................................................................................. 42
Consultando Dados de uma Tabela Particionada .............................................................................................. 42
Exercícios ............................................................................................................................................................ 43
Fundamentos em: Atualização da Base de Dados .............................................................................. 43
Incluindo Novas Linhas – Insert Básico ............................................................................................................. 44
Retornando Informações dos Dados Incluídos .................................................................................................. 46
Alterando Linhas Existentes – Update Básico .................................................................................................... 46
Retornando Informações dos Dados Alterados .................................................................................................. 48
Excluindo Linhas da Base de Dados – Delete Básico ......................................................................................... 48
Retornando Informações dos Dados Excluídos ................................................................................................. 49
Exercícios ............................................................................................................................................................ 49
Fundamentos em: Ordenação e Subconsulta ..................................................................................... 50
Usando Apelidos ................................................................................................................................................ 50
Obtendo os Resultados em uma Ordem Específica ........................................................................................... 51
Usando Subquery Para Restringir o Resultado ................................................................................................... 52
Exercícios ............................................................................................................................................................ 53
Fundamentos em: Grupamentos ......................................................................................................... 53
Funções de Grupo ou de Agregação ................................................................................................................... 54
Avg ................................................................................................................................................................. 55
Corr ................................................................................................................................................................ 55
Count ............................................................................................................................................................. 56
Covar_Pop ...................................................................................................................................................... 56
Covar_Samp ................................................................................................................................................... 56
Cume_Dist ..................................................................................................................................................... 57
Dense_Rank ................................................................................................................................................... 57
First ................................................................................................................................................................ 57
Group_Id ........................................................................................................................................................ 58
Grouping ........................................................................................................................................................ 58
Grouping_id ................................................................................................................................................... 58
Last ................................................................................................................................................................. 58
Max ................................................................................................................................................................ 58
Min ................................................................................................................................................................. 58
Percent_Rank ................................................................................................................................................. 58
Percentile_Cont ............................................................................................................................................. 59
Percentile_Disc ............................................................................................................................................... 60
Rank ............................................................................................................................................................... 60
Regr_Avgx ...................................................................................................................................................... 61
Regr_Avgy ...................................................................................................................................................... 61
Regr_Count .................................................................................................................................................... 61
Regr_Intercept ................................................................................................................................................ 61
Regr_R2 .......................................................................................................................................................... 61
Regr_Slope ...................................................................................................................................................... 61
Regr_Sxx ......................................................................................................................................................... 61
Regr_Sxy ......................................................................................................................................................... 61
Regr_Syy ......................................................................................................................................................... 61
Stddev ............................................................................................................................................................ 62
Stddev_Pop .................................................................................................................................................... 62
Stddev_Samp .................................................................................................................................................. 62
Sum ................................................................................................................................................................ 62
Var_Pop .......................................................................................................................................................... 62
Var_Samp ....................................................................................................................................................... 62
Variance ......................................................................................................................................................... 63
Grupando as Linhas Selecionadas ...................................................................................................................... 63
Regra .............................................................................................................................................................. 64
A Cláusula Having .............................................................................................................................................. 64
As Expressões Rollup e Cube .............................................................................................................................. 65
Rollup ............................................................................................................................................................. 65
Cube ............................................................................................................................................................... 66
Identificando as Linhas com as Funções Group ............................................................................................ 67
Exercícios ............................................................................................................................................................ 68
Fundamentos em: Modificação do Resultado com Funções ............................................................. 69
Introdução .......................................................................................................................................................... 69
Numéricas Simples ............................................................................................................................................. 70
Abs ................................................................................................................................................................. 70
Bitand ............................................................................................................................................................. 70
Ceil ................................................................................................................................................................. 70
Exp ................................................................................................................................................................. 71
Floor ............................................................................................................................................................... 71
Ln ................................................................................................................................................................... 71
Log ................................................................................................................................................................. 71
Mod ................................................................................................................................................................ 71
Power ............................................................................................................................................................. 71
Round ............................................................................................................................................................. 72
Sign ................................................................................................................................................................ 72
Sqrt ................................................................................................................................................................. 72
Trunc .............................................................................................................................................................. 72
Width_Bucket ................................................................................................................................................ 72
Trigonométricas ................................................................................................................................................. 73
Acos ................................................................................................................................................................ 73
Asin ................................................................................................................................................................ 74
Atan ................................................................................................................................................................ 74
Atan2 .............................................................................................................................................................. 74
Cos ................................................................................................................................................................. 74
Cosh ............................................................................................................................................................... 74
Sin .................................................................................................................................................................. 75
Sinh ................................................................................................................................................................ 75
Tan ................................................................................................................................................................. 75
Tanh ............................................................................................................................................................... 75
Alfanuméricas ..................................................................................................................................................... 75
CURSO COMPLETO00✦ IX
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO
Chr ................................................................................................................................................................. 75
Concat ............................................................................................................................................................ 76
Initcap ............................................................................................................................................................ 76
Lower ............................................................................................................................................................. 77
Lpad ............................................................................................................................................................... 77
Ltrim .............................................................................................................................................................. 77
Nls_Initcap ..................................................................................................................................................... 77
Nls_Lower ...................................................................................................................................................... 77
Nls_Upper ...................................................................................................................................................... 78
Nlssort ............................................................................................................................................................ 78
Replace ........................................................................................................................................................... 78
Rpad ............................................................................................................................................................... 78
Rtrim .............................................................................................................................................................. 78
Soundex ......................................................................................................................................................... 79
Substr ............................................................................................................................................................. 79
Substrb, Substrc, Substr2, Substr4 .................................................................................................................. 79
Translate ......................................................................................................................................................... 79
Treat ............................................................................................................................................................... 79
Trim ................................................................................................................................................................ 79
Upper ............................................................................................................................................................. 80
Alfanuméricas que Retornam Valores Numéricos ............................................................................................. 80
Ascii ................................................................................................................................................................ 81
Instr ................................................................................................................................................................ 81
Instrb, Instrc, Instr2, Instr4 ........................................................................................................................... 81
Length ............................................................................................................................................................ 82
Lengthb, Lengthc, Length2, Length4 ............................................................................................................ 82
Datas ................................................................................................................................................................... 82
Sysdate ........................................................................................................................................................... 82
Add_Months .................................................................................................................................................. 82
Current_Date ................................................................................................................................................. 83
Sessiontimezone ............................................................................................................................................ 83
Current_Timestamp ....................................................................................................................................... 84
Dbtimezone ................................................................................................................................................... 84
Extract ............................................................................................................................................................ 84
From_Tz ......................................................................................................................................................... 84
LocalTimestamp ............................................................................................................................................. 84
Last_Day ......................................................................................................................................................... 85
Months_Between ........................................................................................................................................... 85
New_Time ...................................................................................................................................................... 85
Next_Day ....................................................................................................................................................... 86
Round ............................................................................................................................................................. 86
Sys_Extract_UTC ............................................................................................................................................ 86
SysTimestamp ................................................................................................................................................ 86
Trunc .............................................................................................................................................................. 87
Tz_Offset ........................................................................................................................................................ 87
Conversão ........................................................................................................................................................... 87
AsciiStr ........................................................................................................................................................... 89
Bin_To_Num .................................................................................................................................................. 89
Cast ................................................................................................................................................................ 89
CharToRowid ................................................................................................................................................. 89
Compose ........................................................................................................................................................ 89
Convert .......................................................................................................................................................... 89
Decompose .................................................................................................................................................... 90
HexToRaw ...................................................................................................................................................... 90
X ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
SUMÁRIO
Numtodsinterval ............................................................................................................................................ 90
Numtoyminterval .......................................................................................................................................... 90
RawToHex, RawToNhex ................................................................................................................................. 90
RowidToChar, RowidToNchar ....................................................................................................................... 91
To_Char .......................................................................................................................................................... 91
To_Char .......................................................................................................................................................... 91
To_Clob .......................................................................................................................................................... 92
To_Date .......................................................................................................................................................... 92
To_Dsinterval ................................................................................................................................................. 94
To_Lob ............................................................................................................................................................ 94
To_Multi_Byte ................................................................................................................................................ 95
To_Nchar ........................................................................................................................................................ 95
To_Nchar ........................................................................................................................................................ 95
To_Nchar ........................................................................................................................................................ 95
To_Nclob ........................................................................................................................................................ 95
To_Number .................................................................................................................................................... 95
To_Single_Byte ............................................................................................................................................... 96
To_Timestamp ................................................................................................................................................ 96
To_Timestamp_TZ .......................................................................................................................................... 96
To_Yminterval ................................................................................................................................................ 96
Translate Using .............................................................................................................................................. 96
Unistr ............................................................................................................................................................. 96
Outras ................................................................................................................................................................. 96
Bfilename ....................................................................................................................................................... 96
Coalesce ......................................................................................................................................................... 97
Decode ........................................................................................................................................................... 97
Dump ............................................................................................................................................................. 97
Empty_Blob ou Empty_Clob ......................................................................................................................... 98
ExistsNode ..................................................................................................................................................... 98
Extract ............................................................................................................................................................ 99
Greatest .......................................................................................................................................................... 99
Least ............................................................................................................................................................... 99
Nls_Charset _Decl_Len .................................................................................................................................. 99
Nls_Charset _Id ............................................................................................................................................ 100
Nls_Charset _Name ...................................................................................................................................... 100
NullIf ............................................................................................................................................................ 100
Nvl ................................................................................................................................................................ 100
Nvl2 .............................................................................................................................................................. 100
Sys_Connect_By_Path .................................................................................................................................. 100
Sys_Context ................................................................................................................................................. 101
Sys_DbUriGen .............................................................................................................................................. 102
Sys_Guid ...................................................................................................................................................... 102
Sys_Typeid .................................................................................................................................................... 102
Sys_XmlGen ................................................................................................................................................. 102
Sys_XmlAgg ................................................................................................................................................. 103
Uid ............................................................................................................................................................... 103
User .............................................................................................................................................................. 103
Userenv ........................................................................................................................................................ 103
Vsize ............................................................................................................................................................. 103
Exercícios .......................................................................................................................................................... 104
Fundamentos em: Funções Analíticas ............................................................................................... 104
Introdução ........................................................................................................................................................ 105
Funções Somente Analíticas ............................................................................................................................. 105
CURSO COMPLETO00✦ XI
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO
CURSO COMPLETO00✦ XV
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO
XX ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
SUMÁRIO
XL ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
SUMÁRIO
L ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
SUMÁRIO
Mostrar Botão Fast Forward (Show Fast Forward Button) ......................................................................... 1369
Mostrar Controle de Volume (Show Volume Control) ............................................................................. 1369
Mostrar Indicador de Tempo (Show Time Indicator) ................................................................................ 1369
Mostrar Slider (Show Slider) ...................................................................................................................... 1369
Atributos Visuais (Visual Attribute) ............................................................................................................... 1369
Grupo de Atributos Visuais (Visual Attribute Group) ............................................................................... 1369
Grupo de Atributos Visuais do Prompt (Prompt Visual Attribute Group) ................................................ 1369
Atributo Lógico do Modo Caractere (Character Mode Logical Attribute) ................................................ 1370
Branco Sobre Preto (White on Black) ........................................................................................................ 1370
Cor (Color) ..................................................................................................................................................... 1370
Cor de Fundo (Foreground Color) / Cor de Fundo (Background Color) .................................................. 1370
Padrão de Preenchimento (Fill Pattern) .................................................................................................... 1370
Fonte (Font) .................................................................................................................................................... 1370
Nome da Fonte (Font Name) ..................................................................................................................... 1370
Tamanho da Fonte (Font Size) ................................................................................................................... 1370
Peso da Fonte (Font Weight) ..................................................................................................................... 1370
Estilo da Fonte (Font Style) ........................................................................................................................ 1371
Espaçamento da Fonte (Font Spacing) ...................................................................................................... 1371
Prompt (Prompt) ............................................................................................................................................ 1371
Prompt (Prompt) ........................................................................................................................................ 1371
Estilo de Exibição do Prompt (Prompt Display Style) ............................................................................... 1371
Justificação do Prompt (Prompt Justification) .......................................................................................... 1371
Limite de Conexão do Prompt (Prompt Attachment Edge) ...................................................................... 1371
Alinhamento do Prompt (Prompt Alignment) .......................................................................................... 1371
Deslocamento de Conexão do Prompt (Prompt Attachment Offset) ....................................................... 1371
Deslocamento do Alinhamento do Prompt (Prompt Alignment Offset) .................................................. 1371
Ordem de Leitura do Prompt (Prompt Reading Order) ............................................................................. 1372
Cor do Prompt (Prompt Color) ...................................................................................................................... 1372
Cor de Fundo do Prompt (Prompt Foreground Color) ............................................................................. 1372
Fonte do Prompt (Prompt Font) .................................................................................................................... 1372
Nome da Fonte do Prompt (Prompt Font Name) ...................................................................................... 1372
Tamanho da Fonte do Prompt (Prompt Font Size) ................................................................................... 1372
Peso da Fonte do Prompt (Prompt Font Weight) ...................................................................................... 1372
Estilo da Fonte do Prompt (Prompt Font Style) ........................................................................................ 1372
Espaçamento da Fonte do Prompt (Prompt Font Spacing) ....................................................................... 1372
Ajuda (Help) ................................................................................................................................................... 1372
Dica (Hint) ................................................................................................................................................. 1372
Exibir Dica Automaticamente (Display Hint Automatically) ................................................................... 1373
Dica de Ferramenta (Tooltip) ..................................................................................................................... 1373
Grupo de Atributos Visuais de Dica de Ferramenta (Tooltip Visual Attribute Group) ............................. 1373
Internacional (International) ......................................................................................................................... 1373
Estado Inicial do Teclado (Initial Keyboard State) ..................................................................................... 1373
Ordem de Leitura (Reading Order) ............................................................................................................ 1373
Estado do Teclado (Keyboard State) ........................................................................................................... 1373
Direção (Direction) .................................................................................................................................... 1373
Item de Menu (Menu Item) .............................................................................................................. 1374
Geral (General) ............................................................................................................................................... 1374
Nome (Name) ............................................................................................................................................ 1374
Informações Sobre a Divisão em Subclasses (Subclass Information) ........................................................ 1374
Comentários (Comments) ......................................................................................................................... 1374
Funcional (Functional) ................................................................................................................................... 1374
Ativado (Enabled) ...................................................................................................................................... 1374
Etiqueta (Label) .......................................................................................................................................... 1375
CURSO COMPLETO00✦ LI
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO
Atributo Lógico do Modo Caractere (Character Mode Logical Attribute) ................................................ 1381
Branco Sobre Preto (White on Black) ........................................................................................................ 1381
Cor (Color) ..................................................................................................................................................... 1381
Cor de Fundo (Foreground Color) / Cor de Fundo (Background Color) .................................................. 1381
Padrão de Preenchimento (Fill Pattern) .................................................................................................... 1381
Fonte (Font) .................................................................................................................................................... 1382
Nome da Fonte (Font Name) ..................................................................................................................... 1382
Tamanho da Fonte (Font Size) ................................................................................................................... 1382
Peso da Fonte (Font Weight) ..................................................................................................................... 1382
Estilo da Fonte (Font Style) ........................................................................................................................ 1382
Espaçamento da Fonte (Font Spacing) ...................................................................................................... 1382
Internacional (International) ......................................................................................................................... 1382
Direção (Direction) .................................................................................................................................... 1382
Menu e Submenu (Menu) ................................................................................................................. 1383
Geral (General) ............................................................................................................................................... 1383
Nome (Name) ............................................................................................................................................ 1383
Informações Sobre a Divisão em Subclasses (Subclass Information) ........................................................ 1383
Comentários (Comments) ......................................................................................................................... 1383
Funcional (Functional) ................................................................................................................................... 1383
Menu Tirar (Tear-off Menu) ....................................................................................................................... 1383
Menu Pop-up (Popup Menu) ............................................................................................................ 1383
Geral (General) ............................................................................................................................................... 1383
Nome (Name) ............................................................................................................................................ 1383
Informações Sobre a Divisão em Subclasses (Subclass Information) ........................................................ 1383
Comentários (Comments) ......................................................................................................................... 1384
Funcional (Functional) ................................................................................................................................... 1384
Menu Tirar (Tear-off Menu) ....................................................................................................................... 1384
Módulo Form (Form Module) ........................................................................................................... 1384
Geral (General) ............................................................................................................................................... 1384
Nome (Name) ............................................................................................................................................ 1384
Informações Sobre a Divisão em Subclasses (Subclass Information) ........................................................ 1384
Comentários (Comments) ......................................................................................................................... 1384
Título do Livro de Ajuda (Help Book Topic) ............................................................................................. 1384
Funcional (Functional) ................................................................................................................................... 1384
Título (Title) ............................................................................................................................................... 1384
Janela Console (Console Window) ............................................................................................................ 1385
Origem de Menu (Menu Source) ............................................................................................................... 1385
Módulo de Menu (Menu Module) ............................................................................................................. 1385
Menu Inicial (Initial Menu) ....................................................................................................................... 1385
Diferir Imposição Obrigatória (Defer Required Enforcement) .................................................................. 1385
Segurança do Menu (Menu Security) ............................................................................................................. 1385
Atribuição de Menu (Menu Role) .............................................................................................................. 1385
Navegação (Navigation) ................................................................................................................................. 1385
Limite de Navegação do Mouse (Mouse Navigation Limit) ...................................................................... 1385
Primeiro Bloco de Dados de Navegação (First Navigation Data Block) .................................................... 1386
Registros (Records) ......................................................................................................................................... 1386
Grupo de Atributos Visuais do Registro Atual (Current Record Visual Attribute Group) ......................... 1386
Banco de Dados (Database) ............................................................................................................................ 1386
Unidade de Validação (Validation Unit) ................................................................................................... 1386
Modo de Interação (Interaction Mode) ..................................................................................................... 1386
Tempo Máximo Para Consulta (Maximum Query Time) .......................................................................... 1386
Máximo de Registros Extraídos (Maximum Records Fetched) .................................................................. 1386
Modo de Isolamento (Isolation Mode) ...................................................................................................... 1386
CURSO COMPLETO00✦ LV
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO
LX ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
SUMÁRIO
Usar Linha de Status do Previsualizador (Use Previewer Status Line) ....................................................... 1519
Incluir Objetos de Bitmap (Include Bitmapped Objects) .......................................................................... 1519
Incluir Bordas (Include Borders) ................................................................................................................ 1519
Desativar Item de Menu do Host (Disable Host Menu Item) .................................................................... 1519
Desativar Tecla de Tela Dividida (Disable Split Screen Key) ...................................................................... 1519
Desativar Tecla de Zoom (Disable Zoom Key) ........................................................................................... 1519
Iniciar no Zoom (Start in Zoom) ............................................................................................................... 1520
Suprimir Título do Previsualizador (Suppress Previewer Title) ................................................................. 1520
Objeto OLE2 (OLE2 Object) ............................................................................................................... 1520
Informações Gerais (General Information) ................................................................................................... 1520
Nome (Name) ............................................................................................................................................ 1520
Comentários (Comments) ......................................................................................................................... 1520
Configurações de Web (Web Configuration) ................................................................................................. 1520
Destino de Hiperligação (Hyperlink Destination) ..................................................................................... 1520
Marcador (Bookmark) ................................................................................................................................ 1520
Hiperligação (Hyperlink) ........................................................................................................................... 1520
Linha de Comandos da Aplicação (PDF) - (Application Command Line (PDF)) ..................................... 1521
Layout Geral (General Layout) ...................................................................................................................... 1521
Quebra de Página Anterior (Page Break Before) ........................................................................................ 1521
Quebra de Página Posterior (Page Break After) .......................................................................................... 1521
Proteção de Página (Page Protect) .............................................................................................................. 1521
Elasticidade Vertical (Vertical Elasticity) ................................................................................................... 1521
Elasticidade Horizontal (Horizontal Elasticity) ......................................................................................... 1521
Formatação Condicional (Conditional Formatting) ................................................................................. 1521
Layout Avançado (Advanced Layout) ............................................................................................................ 1522
Impressão de Objeto Ativada (Print Object On) ....................................................................................... 1522
Impressão de Base Ativada (Base Printing On) .......................................................................................... 1522
Manter com Objeto de Ancoragem (Keep With Anchoring Object) ......................................................... 1522
Gatilho de Formato (Format Trigger) ........................................................................................................ 1522
Código da Impressora Anterior (Printer Code Before) .............................................................................. 1522
Código da Impressora Posterior (Printer Code After) ................................................................................ 1522
Parâmetro (Parameter) .................................................................................................................... 1523
Informações Gerais (General Information) ................................................................................................... 1523
Nome (Name) ............................................................................................................................................ 1523
Comentários (Comments) ......................................................................................................................... 1523
Parâmetro (Parameter) ................................................................................................................................... 1523
Tipo de Dados (Datatype) .......................................................................................................................... 1523
Largura (Width) ......................................................................................................................................... 1523
Máscara de Entrada (Input Mask) .............................................................................................................. 1523
Valor Inicial (Initial Value) ........................................................................................................................ 1523
Gatilho de Validação (Validation Trigger) ................................................................................................. 1523
Lista de Valores (List of Values) ................................................................................................................. 1523
Quadro (Frame) ................................................................................................................................. 1523
Informações Gerais (General Information) ................................................................................................... 1523
Nome (Name) ............................................................................................................................................ 1523
Comentários (Comments) ......................................................................................................................... 1524
Configurações de Web (Web Configuration) ................................................................................................. 1524
Destino de Hiperligação (Hyperlink Destination) ..................................................................................... 1524
Marcador(Bookmark) ................................................................................................................................. 1524
Hiperligação (Hyperlink) ........................................................................................................................... 1524
Linha de Comandos da Aplicação (PDF) - (Application Command Line (PDF)) ...................................... 1524
Layout Geral (General Layout) ...................................................................................................................... 1524
Quebra de Página Anterior (Page Break Before) ........................................................................................ 1524
Painéis Verticais por Página (Vertical Panels per Page) ............................................................................. 1530
Orientação (Orientation) ........................................................................................................................... 1531
Distribuição (Distribution) ........................................................................................................................ 1531
Modo Caractere (Character Mode) ................................................................................................................ 1531
Largura do Relatório (Report Width) ......................................................................................................... 1531
Altura do Relatório (Report Height) .......................................................................................................... 1531
CAPÍTULO 19 – PARÂMETROS DE EXECUÇÃO ................................................................................................. 1533
Para Relatórios .................................................................................................................................. 1534
Access ............................................................................................................................................................. 1534
Arraysize ......................................................................................................................................................... 1534
Authid ............................................................................................................................................................ 1534
Autocommit ................................................................................................................................................... 1534
Background .................................................................................................................................................... 1534
Batch ............................................................................................................................................................... 1535
BlankPages ...................................................................................................................................................... 1535
Buffers ............................................................................................................................................................. 1535
CacheLob ........................................................................................................................................................ 1535
CellWrapper ................................................................................................................................................... 1535
Cmdfile ........................................................................................................................................................... 1535
Copies ............................................................................................................................................................. 1535
Currency ......................................................................................................................................................... 1536
Customize ....................................................................................................................................................... 1536
DateFormatMask ............................................................................................................................................ 1536
Decimal .......................................................................................................................................................... 1536
Delimiter ........................................................................................................................................................ 1536
Desformat ....................................................................................................................................................... 1536
Desname ......................................................................................................................................................... 1537
Destination ..................................................................................................................................................... 1537
Destype ........................................................................................................................................................... 1537
DisableFile ...................................................................................................................................................... 1538
DisableMail ..................................................................................................................................................... 1538
DisableNew ..................................................................................................................................................... 1538
DisablePrint .................................................................................................................................................... 1538
Distribute ........................................................................................................................................................ 1538
Errfile .............................................................................................................................................................. 1538
Express_Server ................................................................................................................................................ 1539
Jobname ......................................................................................................................................................... 1539
Keyin .............................................................................................................................................................. 1539
Keyout ............................................................................................................................................................ 1539
Logfile ............................................................................................................................................................. 1539
Longchunk ..................................................................................................................................................... 1539
Maximize ........................................................................................................................................................ 1539
Mode .............................................................................................................................................................. 1540
Module | Report .............................................................................................................................................. 1540
Nonblocksql ................................................................................................................................................... 1540
NumberFormatMask ...................................................................................................................................... 1540
PageStream ..................................................................................................................................................... 1540
Onfailure ........................................................................................................................................................ 1540
Onsuccess ....................................................................................................................................................... 1540
Orientation ..................................................................................................................................................... 1541
Pagesize ........................................................................................................................................................... 1541
Paramform ...................................................................................................................................................... 1541
Printjob ........................................................................................................................................................... 1541
Parte I
FUNDAMENTOS
CURSO COMPLETO00✦ 1
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
2 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000
Capítulo 1
INSTALANDO O PERSONAL
ORACLE9I NO WINDOWS2000
CURSO COMPLETO00✦ 3
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Neste capítulo serão apresentados os procedimentos para a instalação do produto Personal Oracle9i para Windows 2000.
O Oracle9i release 9.0.1.1.1 não é suportado para o Windows 95. Podemos, no entanto, instalar a versão client
(Oracle8i client ou Oracle8 client) para estabelecer conexão com um banco de dados Oracle9i Sever.
ACOMPANHANDO A INSTALAÇÃO
Ao colocarmos o CD-ROM na unidade apropriada, será apresentada a tela Autorun, na qual teremos três opções
para execução.
A primeira opção, com o título de Iniciar Instalação, efetua a instalação dos produtos. A segunda opção, intitulada
Explore CD, faz a leitura do diretório-raiz do CD-ROM e o apresenta para que possamos navegar (ou explorar) pelas
diversas pastas presentes. A terceira e última opção chamada de Informações de Paginação abre a documentação em
formato HTML (welcome.htm) presente no CD-ROM. Os dois botões no fim da página permitem o acesso à Home
Page da Oracle (www.oracle.com) e Suporte (www.oracle.com/support); para tal devemos estar online na Internet.
Para iniciarmos a instalação propriamente dita, devemos clicar na primeira opção, ou seja, Iniciar Instalação, a
qual dará início ao programa de instalação chamado Oracle Universal Installer, que fará alguns questionamentos
para efetuar a gravação dos arquivos.
Caso a tela de Autorun, por algum motivo, não apareça automaticamente, podemos executar (no menu Iniciar do Windows, opção Executar) o
programa E:\Autorun\Autorun.exe (para o Autorun) ou diretamente E:\Setup.exe (para o Oracle Universal Installer), onde a letra E corresponde
à unidade de CD-ROM do computador.
4 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000
A próxima tela apresentada dá as Boas-Vindas ao usuário e permite que façamos uma verificação dos produtos já instalados.
Uma vez que estamos iniciando o processo de instalação agora, passaremos simplesmente ao próximo diálogo.
A escolha é livre. No meu caso escolhi como Oracle Home o texto OraHome9i e como diretório de destino
c:\Oracle\Ora9i.
PRODUTOS DISPONÍVEIS
Nova tela de diálogo será apresentada para que façamos a escolha do que desejamos instalar. Neste momento,
optaremos por Oracle9i Database 9.0.1.1.1, pois esta é a opção que fará a instalação do banco de dados (que é o
nosso interesse).
A segunda opção Oracle9i Client 9.0.1.1.1 seria usada se tivéssemos instalado o banco de dados em uma máquina
(que faria o papel de servidora de banco de dados) e desejássemos fazer acesso a este banco de dados a partir de
outra máquina (que faria o papel de cliente para o banco de dados).
A terceira opção Oracle9i Management and Integration 9.0.1.0.1 seria usada também em uma máquina cliente,
porém por alguém (um DBA, por exemplo) que viesse a gerenciar ou controlar os serviços do banco de dados.
CURSO COMPLETO00✦ 5
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
TIPOS DE INSTALAÇÃO
Este diálogo é apresentado para nós porque optamos, anteriormente, por instalar o banco de dados Oracle9i.
Observamos na Figura 1.03 que podemos optar por três tipos diferentes de bancos de dados ou por uma instalação
customizada (opção Personalizar).
6 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000
As duas primeiras opções se referem a bancos de dados a serem instalados em máquinas servidoras; o que varia de
um para o outro (além do preço, é claro) é a quantidade de características disponíveis no software. A versão
Enterprise é completa contendo todas “features” disponíveis para o Oracle9i. Já a versão Standard não apresenta
determinadas “features”, como particionamento de tabelas, por exemplo, sendo, portanto, uma versão mais barata.
A terceira opção, que será exatamente a escolhida por nós, instalará um banco de dados similar à versão Enterprise
(a maioria da “features”), porém restrito à uma pessoa. É a versão ideal para testes e estudos.
A última opção não cria o banco de dados, apenas o software. A criação do banco de dados poderá ser feita
posteriormente de forma manual ou através do Database Configuration Assistant.
No nosso caso estaremos instalando um banco de dados que será usado por uma única instância. A identificação
da instância (SID) deve ser única no computador, mas não precisa ter o mesmo nome do banco de dados; portanto,
o nome fica a nosso critério.
Pela Figura 1.04, você observa que a escolha feita por mim foi um nome único para as duas informações.
CURSO COMPLETO00✦ 7
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Neste diálogo podemos informar um diretório onde desejamos que os arquivos do banco de dados sejam instalados
(se tivermos um outro disco, esta pode ser uma opção interessante). No meu caso escolhi C:\DATABASE\ORADATA.
As diversas línguas existentes no mundo utilizam caracteres diferentes para escrever seus idiomas. Por exemplo, na língua
portuguesa utilizamos caracteres como o ç (cedilha), acentos agudos, circunflexo, crase, til, que não existem no inglês.
Neste diálogo devemos escolher qual conjunto de caracteres (ou tabela de caracteres) é capaz de armazenar todas
as peculiaridades da língua ou línguas que desejamos armazenar.
A primeira opção já apresenta uma tabela ou conjunto de caracteres previamente escolhido baseado no idioma em
que o sistema operacional está instalado. No meu caso o valor que aparece na Figura 1.05 (WE8MSWIN1252) foi
escolhido porque o meu Windows 2000 Professional foi instalado em português.
A segunda opção Unicode (UTF8) corresponde a um conjunto de caracteres que engloba diversos outros e permite
a utilização simultânea de diversas línguas.
8 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000
RESUMO
Neste diálogo não fornecemos nenhuma outra indicação; simplemente o Oracle nos informa o que será instalado.
Se você usar a barra de rolagem verificará que o software é bem grande.
Para iniciarmos a instalação devemos pressionar o botão Instalar. O tempo de instalação dependerá do hardware e da
quantidade de memória que você tiver. Não haverá mais necessidade de intervenção do usuário de agora em diante.
Ao término da instalação poderemos verificar, no Windows, as pastas criadas pelo instalador. A Figura 1.06 nos
mostra as pastas subordinadas à pasta principal Oracle – OraHome9i (este nome foi dado durante a instalação).
CURSO COMPLETO00✦ 9
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Os utilitários estão subdivididos por grupos. Na pasta Application Development encontramos as ferramentas que,
possivelmente, utilizaremos no desenvolvimento de aplicações (Sql*Plus, Objects for OLE, Pro*C-C++, etc.). Du-
rante o estudo neste livro, utilizaremos o SQL*Plus, você poderá usar o SQL*Plus WorkSheet, que possui uma
interface mais amigável que o SQL*Plus.
Na pasta Configuration and Migration Tools encontramos ferramentas que nos auxiliarão na criação/configuração
de um novo banco de dados (Database Configuration Assistant), administração do banco de dados em uso (Ad-
ministration Assistant), configuração da parte de rede, ODBC, etc. A pasta Enterprise Manager Quick Tours possui
apenas um ícone que aciona uma apresentação sobre a ferramenta.
Na pasta Integrated Management Tools encontramos ferramentas relacionadas a segurança em diversos níveis e
formas. A última pasta trata do Oracle 9i HTTP Server (ativação e interrupção do serviço no Windows).
Além desta pasta você também encontrará uma outra pasta chamada Oracle Installation Products onde encontrare-
mos o instalador e documentação sobre ele, além de uma ferramenta (Home Selector) que permite a troca do
Oracle Home principal.
Uma das informações registradas nesta área é o idioma, território e conjunto de caracteres válidos para a estação do
usuário, que após o processo de instalação do banco corresponde ao valor escolhido para o banco de dados.
Se desejarmos, podemos modificar o valor destas variáveis de ambiente a fim de modificarmos algumas das
características de nosso sistema. Para tal, devemos executar o programa Regedit do Windows que apresenta todas
as variáveis cadastradas para todos os aplicativos.
EXECUTANDO O REGEDIT
No menu Iniciar, opção Executar, podemos digitar Regedit e pressionar o botão OK para que seja apresentada a tela
abaixo, contendo a estrutura principal onde estão armazenadas as informações de ambiente. Estas informações
estão organizadas em nós. Como nosso interesse se refere às variáveis do Oracle, deveremos expandir o nó (basta
clicar sobre o símbolo + à esquerda do nome do nó) HKEY_LOCAL_MACHINE e, subordinado a este nó, deveremos
expandir também o nó SOFTWARE.
O NÓ ORACLE
No editor de registro, poderemos visualizar uma pasta com o nome de ORACLE. Se a expandirmos encontraremos
uma pasta ALL_HOMES, uma pasta HOME0, uma pasta OLEDB, uma pasta ORACLE_HOMES, etc. Se esta foi a sua
primeira instalação, significa que você só tem um Oracle Home e, portanto, não estão criadas as pastas HOME1,
HOME2, HOME3, HOME4 e HOME5, como vemos na Figura 1.07. No meu caso este foi o quinto Oracle Home
10 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000
criado nesta máquina. Isto significa que cada produto Oracle instalado foi armazenado em um diretório físico
diferente (lembra que existe uma associação entre o Oracle Home e o diretório físico?).
Para verificarmos as variáveis de ambiente e seus valores, devemos clicar sobre a pasta Home0 (para vocês e Home5
para mim). As variáveis de ambiente relativas a esta instalação estão visíveis na janela à direita. Nesta janela
procure a variável Oracle_Home e verifique o diretório correspondente.
Dentre estas variáveis, devemos procurar pela variável NLS_LANG, a qual deve estar preenchida com o valor
“BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252” se tivermos escolhido o conjunto de caracteres
WE8MSWIN1252 e o idioma do seu sistema operacional for português.
Para modificarmos o valor desta variável, devemos efetuar um double-click no ícone (ab) à esquerda do nome da
variável para que seja apresentada uma janela de edição.
Os valores válidos para estas variáveis estão detalhados no item referente a Globalization Support. Para efeito de
exemplificação, modificamos seu valor para “AMERICAN_AMERICA.WE8MSWIN1252”.
Com esta alteração todas as mensagens que recebermos no SQL*Plus passarão a ser apresentadas em inglês e toda
informação monetária ou de data apresentará o padrão americano. Como, agora, você já sabe modificar esta variável,
você poderá escolher uma das duas opções apresentadas anteriormente para ela. Observe, com cuidado, porém, que
o texto deve estar escrito exatamente como visto para que o banco de dados e o aplicativo funcionem corretamente.
CURSO COMPLETO00✦ 11
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Neste momento, preencheremos o campo usuário com SYSTEM e o campo senha com o valor MANAGER. O
campo referente à string de conexão (Host String ou String do Host) não precisa ser preenchido, uma vez que
estamos fazendo conexão com um banco de dados local. Posteriormente, ao instalarmos os softwares aplicativos
(Oracle Developer 6i), necessitaremos preencher um nome para a conexão, e este assunto será visto no item
referente à instalação dos produtos de desenvolvimento. Dê OK.
Para a criação de um usuário, devemos digitar na linha apresentada o comando mostrado na Listagem 1.01. O
texto deve ser digitado exatamente como mostrado na listagem (começando com o texto CREATE USER). Após
cada linha, tecle Enter para que o SQL*Plus perceba que o comando tem continuação e numere as linhas seguintes.
A troca de linha é feita com Enter. Para execução do comando, deve ser anexado na última linha um ponto-e-
vírgula.
A criação do usuário não é suficiente para sua utilização. O próximo comando dará poderes de DBA (administrador
do banco de dados) para o usuário DESENV.
12 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000
Todos os exercícios do livro usarão este usuário. A seguir faremos a criação das tabelas que usaremos em nosso
estudo. Para tal começaremos com o modelo de dados e, na seqüência, passaremos para os arquivos (scripts) que
contêm os comandos para criação e preenchimento das referidas tabelas.
MODELO DE DADOS
Na Figura 1.10, apresentamos um esquema do modelo de entidades e relacionamentos, descrito logo a seguir.
A tabela Funcionário (Func) tem como primary key (PK) a coluna cd_mat e como foreign key (FK) a coluna cd_depto,
que estabelece relacionamento com a tabela Depto.
A tabela Departamento (Depto) tem como primary key (PK) a coluna cd_depto e como foreign key (FK) a coluna
cd_gerente, que estabelece relacionamento com a tabela Func, e a coluna cd_depto_ctb, que estabelece um auto-
relacionamento.
A tabela Projeto (Proj) tem como primary key (PK) a coluna cd_proj e como foreign key (FK) a coluna cd_resp, que
estabelece relacionamento com a tabela Func, e a coluna cd_depto, que estabelece relacionamento com a tabela Depto.
A tabela Atividades (Ativ) tem como primary key (PK) a coluna cd_ativ e não possui relacionamentos com outras tabelas.
Finalmente, a tabela Projetos-Atividades (PrjAtv) tem como primary key (PK) as colunas cd_proj e cd_ativ, que
simultaneamente agem como foreign key (FK) e estabelecem relacionamento com as tabelas Proj e Ativ,
respectivamente.
CURSO COMPLETO00✦ 13
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Observe que na última linha da listagem, o caractere delimitador é o plic ( ' ). No momento da digitação, certifique-se de usar esse caractere. Caso
seja utilizado algum outro, como aspas simples ( ‘ ), por exemplo, haverá erro na compilação. Use sempre o plic!
Nesse primeiro script, todas as tabelas são removidas, o que permite que reexecutemos as mesmas operações
diversas vezes e façamos a implementação do modelo novamente; portanto, não se espante se a primeira vez que
você executá-lo cada um dos comandos DROP apresente a mensagem de erro ERRO na linha 1: ORA-00942: a
tabela ou view não existe.
Nesse script, criamos a especificação física da tabela Depto. Observe que foram fornecidos parâmetros físicos no
comando Create Table para que a tabela criada tivesse um tamanho reduzido.
14 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000
STORAGE (INITIAL 4K
NEXT 4K
MINEXTENTS 1
MAXEXTENTS 5)
PCTFREE 10
PCTUSED 80;
Nesse script, criamos a tabela Func, que já estabelece o relacionamento com a tabela Depto e cria uma regra de
integridade para a coluna in_sexo.
A criação da tabela Proj apresentada na Listagem 1.07 já estabelece os relacionamentos com as tabelas Depto e Func.
A criação da tabela Ativ apresenta como particularidade a expressão Organization Index, indicando que não haverá
estruturas separadas para os dados e a PK. Será construída uma única estrutura B*Tree contendo o índice e na
mesma linha os dados correspondentes. Esta tabela não possui Rowid físico e sim lógico. Estudaremos este assunto
no próximo capítulo.
Na Listagem 1.09, criamos a tabela Projetos-Atividades com os relacionamentos estabelecidos para as tabelas Proj e Ativ.
CURSO COMPLETO00✦ 15
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
,VL_SAL NUMBER(9,2)
,CD_DEPTO CHAR(3)
,NR_CARGO NUMBER(3)
,TX_MOTIVO VARCHAR2(200)
,PRIMARY KEY (DT_PROMOCAO, CD_MAT)
)
STORAGE (INITIAL 4K
NEXT 4K
MINEXTENTS 1
MAXEXTENTS 15)
PCTFREE 10
PCTUSED 80
PARTITION BY RANGE (DT_PROMOCAO)
(PARTITION ANOS80 VALUES
LESS THAN (TO_DATE('01011990', 'DDMMYYYY')),
PARTITION ANOS90_94 VALUES
LESS THAN (TO_DATE('01011995', 'DDMMYYYY')),
PARTITION ANOS95_99 VALUES
LESS THAN (TO_DATE('01012000', 'DDMMYYYY')),
PARTITION ANOS2000 VALUES
LESS THAN (MAXVALUE)
);
Na Listagem 1.10, criamos uma tabela que não se acha presente no modelo. Ela tem as colunas cd_mat e cd_depto,
mas não estabelece relacionamento com as tabelas Func e Depto. Essa tabela tem a finalidade de armazenar
informações históricas da empresa que podem não mais estar cadastradas nas tabelas diárias. Usaremos suas
informações para teste de tabelas particionadas.
Observe que ela possui uma cláusula Partition By Range, indicando que, fisicamente, esta tabela está subdividida
em quatro partes e que, logicamente, se trata de uma única tabela. O Oracle é responsável por adicionar ou
pesquisar as informações na partição correta.
16 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000
(60,'IRACY','SOUZA','D11',6423,'14091993',55,16,'F','07071955'
,3225,'c:\windows\bolhas.bmp');
INSERT INTO FUNC VALUES
(70,'EVA','PEREIRA','D21',7831,'30091990',56,16,'F','26051963'
,3617,'c:\windows\ladrilhos.bmp');
INSERT INTO FUNC VALUES
(90,'ELIANE','HONOFRE','E11',5498,'15081995',55,16,'F','15051971'
,2975,'c:\windows\esteira.bmp');
INSERT INTO FUNC VALUES
(100,'TEODORO','SIQUEIRA','E21',972,'16061990',54,14,'M','18121966'
,2615,'c:\windows\bolhas.bmp');
INSERT INTO FUNC VALUES
(110,'VICENTE','LOURENCO','A00',3490,'16051994',58,19,'M','05111969'
,4650,'c:\windows\egito.bmp');
INSERT INTO FUNC VALUES
(120,'SILVIO','OLIVA','A00',2167,'05121993',58,14,'M','18101962'
,2925,'c:\windows\esteira.bmp');
INSERT INTO FUNC VALUES
(130,'DOLORES','QUEIROZ','C01',4578,'28071991',55,16,'F','15091955'
,2380,'c:\windows\ondas.bmp');
INSERT INTO FUNC VALUES
(140,'HELENA','NOVAES','C01',1793,'15121991',56,18,'F','19011956'
,2842,'c:\windows\bolhas.bmp');
INSERT INTO FUNC VALUES
(150,'BRUNO','AZEVEDO','D11',4510,'12021992',55,16,'M','17051967'
,2528,'c:\windows\pied-de-poule.bmp');
INSERT INTO FUNC VALUES
(160,'ELIZABET','PINTO','D11',3782,'11101993',54,17,'F','12041965'
,2225,'c:\windows\egito.bmp');
INSERT INTO FUNC VALUES
(170,'GABRIEL','YVES','D11',2890,'15091989',54,16,'M','05011971'
,2468,'c:\windows\bolhas.bmp');
INSERT INTO FUNC VALUES
(180,'MARIA','SANTOS','D11',1682,'07071990',53,17,'F','21021969'
,2134,'c:\windows\pied-de-poule.bmp');
INSERT INTO FUNC VALUES
(190,'JAIRO','WILARES','D11',2986,'26071994',53,16,'M','25061972'
,2045,'c:\windows\ladrilhos.bmp');
INSERT INTO FUNC VALUES
(200,'DAVI','BARBOSA','D11',4501,'03031996',55,16,'M','29051971'
,2774,'c:\windows\ondas.bmp');
INSERT INTO FUNC VALUES
(210,'WILIAM','JONES','D11',942,'11041994',52,17,'M','23021963'
,1827,'c:\windows\egito.bmp');
INSERT INTO FUNC VALUES
(220,'JOANA','LUZ','D11',672,'29081995',55,18,'F','19031968'
,2984,'c:\windows\pied-de-poule.bmp');
INSERT INTO FUNC VALUES
(230,'JOAQUIM','JANUARIO','D21',2094,'21111995',53,14,'M','30051965'
,2218,'c:\windows\bolhas.bmp');
INSERT INTO FUNC VALUES
(240,'SALVADOR','MEDEIROS','D21',3780,'05121993',55,17,'M','31031974'
,2876,'c:\windows\esteira.bmp');
INSERT INTO FUNC VALUES
(250,'DANIEL','SANTANA','D21',961,'30101999',52,15,'M','12111969'
,1918,'c:\windows\ladrilhos.bmp');
INSERT INTO FUNC VALUES
(260,'SILVIA','JUVENTO','D21',8953,'11091995',52,16,'F','05101966'
,1725,'c:\windows\pied-de-poule.bmp');
INSERT INTO FUNC VALUES
(270,'MARTA','PARENTE','D21',9001,'30091990',55,15,'F','26051973'
,2738,'c:\windows\esteira.bmp');
INSERT INTO FUNC VALUES
(280,'ELINE','SEVERO','E11',8997,'24031991',54,17,'F','28031966'
,2625,'c:\windows\bolhas.bmp');
INSERT INTO FUNC VALUES
(290,'JOAO','PONTES','E11',4502,'30051990',42,12,'M','09071966'
,1534,'c:\windows\egito.bmp');
INSERT INTO FUNC VALUES
(300,'FELIPE','SARAIVA','E11',2095,'19061992',48,14,'M','27101956'
,1775,'c:\windows\esteira.bmp');
INSERT INTO FUNC VALUES
(310,'MARINA','SALGADO','E11',3332,'12091991',43,12,'F','21041971'
,1590,'c:\windows\ondas.bmp');
INSERT INTO FUNC VALUES
(320,'ROBERTO','MARQUES','E21',9990,'07071990',52,16,'M','11081972'
CURSO COMPLETO00✦ 17
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
,1995,'c:\windows\ladrilhos.bmp');
INSERT INTO FUNC VALUES
(330,'WILSON','LOPES','E21',2103,'23021996',55,14,'M','18071971'
,2537,'c:\windows\egito.bmp');
INSERT INTO FUNC VALUES
(340,'DILSON','GONCALVES','E21',5698,'05051996',54,16,'M','17051966'
,2384,'c:\windows\bolhas.bmp');
18 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 1 – INSTALANDO O PERSONAL ORACLE9I NO WINDOWS2000
O último script executa todos os demais e estabelece o relacionamento da tabela Depto com a tabela Func, o auto-
relacionamento e dá Commit em todas as atualizações realizadas. Como último passo, fecha o SQL*Plus.
CURSO COMPLETO00✦ 19
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
20 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Capítulo 2
SQL E SQL*PLUS
CURSO COMPLETO00✦ 21
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
A ferramenta SQL*Plus nos permitirá estabelecer interface com o banco de dados Oracle utilizando a linguagem SQL.
A SQL é a linguagem que deveremos utilizar para criar objetos, manipular dados, definir autorizações, controlar o
acesso aos dados, etc., ou seja, toda a comunicação com o banco de dados. Nosso foco no estudo da SQL é a parte
da linguagem chamada de DML (Data Manipulation Language), capaz de realizar a manipulação dos dados do
usuário. Veremos, também, de forma superficial, comandos para controle de acesso e criação de objetos.
DADOS HISTÓRICOS
Em junho de 1970, o Dr. E.F. Codd publicou um artigo intitulado “A Relational Model of Data for Large Shared
Data Banks”. Este artigo determinou o início da mudança na filosofia de bancos de dados, até então hierárquicos
ou de rede. A IBM Corporation, Inc. desenvolveu uma linguagem para usar o modelo imaginado por Codd. Esta
linguagem foi batizada SEQUEL (Structured English Query Language) e posteriormente apenas SQL. Hoje, a
linguagem SQL é aceita como um padrão para bancos de dados relacionais.
A SQL (Structured Query Language) é uma linguagem para interface com bancos de dados relacionais, isto é, todos
os usuários e programas que desejarem realizar alguma tarefa no banco de dados devem fornecer comandos escritos
nesta linguagem.
Para que esta linguagem se mantivesse comum a todos os fabricantes de software, algumas instituições estabeleceram
padrões para a linguagem. A última versão publicada pela ANSI (American National Standard Institute) e pela ISO (Inter-
national Standards Organization) é datada de 1999 e chamada de SQL:99. O SQL do Oracle9i é um superset deste padrão.
O ORACLE E O SQL
No Oracle, todo e qualquer acesso ao banco de dados deve ser codificado na linguagem SQL. Apesar de muitos dos
produtos da Oracle apresentarem uma interface que, aparentemente, não utiliza SQL, o que fazem, na verdade, é
converter as solicitações dos usuários em comandos de SQL no relacionamento com o banco de dados.
Desta forma, poderíamos concluir dizendo que o banco de dados Oracle só entende SQL.
22 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Ao longo deste capítulo, veremos como usar o SQL do Oracle9i para: fazer acesso, incluir, excluir e alterar as
informações armazenadas no banco de dados. Aprenderemos sobre as operações relacionais e sobre os
relacionamentos (sua implementação e garantias).
No Capítulo 1 você encontrará o modelo de dados utilizado ao longo de todo o livro, além do conjunto de valores armazenados. Se necessário,
para estudarmos características específicas, novas tabelas ou colunas poderão ser adicionadas.
A ABRANGÊNCIA DA LINGUAGEM
Se o banco de dados só entende SQL, então devemos supor que a linguagem possui não apenas comandos de
manipulação, mas também comandos para criação dos diversos objetos, controle de acesso, autorização, etc.
Como isto é verdade e em função da grande quantidade de comandos, a linguagem SQL foi dividida em três
partes principais.
CURSO COMPLETO00✦ 23
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Para darmos início aos testes dos comandos, precisamos de uma ferramenta que nos possibilite esta conversa
(interação) com o banco de dados. A ferramenta que usaremos em todo este capítulo se chama SQL*Plus.
A terceira informação deste diálogo corresponde à string de conexão (String do Host), ou seja, o nome de um
parâmetro que indica a que máquina e a que banco de dados desejamos estabelecer conexão. Se você estiver
estabelecendo conexão com um banco de dados instalado na mesma máquina (local), este valor não precisa ser
preenchido; caso isto não aconteça, consulte seu DBA para obter o nome adequado para preenchimento. Em todo
este capítulo estaremos usando o Personal Oracle9i (versão 9.0.1.1.1) para realização dos testes. A instalação deste
produto se encontra descrita no Capítulo 1 (Instalando o Personal Oracle9i no Windows 2000).
Quando a conexão é estabelecida, obtemos permissão do banco de dados para enviar comandos e receber respostas.
O intervalo de tempo entre o momento em que uma conexão é estabelecida até o momento em que ela é encerrada
é chamado de Sessão.
O SQL BUFFER
No SQL*Plus, a tela apresentada mostra uma linha com o texto SQL> à esquerda do vídeo, indicando que poderemos
digitar o comando que desejamos executar.
24 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Ao digitarmos um comando na linha de prompt (SQL>), a ferramenta identifica este comando e verifica se se trata de
um comando de SQL. Em caso afirmativo, coloca-o numa área de memória chamada SQL Buffer (ver Figura 2.03).
Quando terminamos a digitação, esta área de memória, que só pode conter 1(um) comando de SQL, é transmitida para
o banco de dados. Quando o banco de dados retorna o resultado, o SQL*Plus recebe a informação, a formata e apresenta.
OS COMANDOS DO SQL*PLUS
No esquema da Figura 2.03, observamos que nem todos os comandos digitados são colocados na área de Buffer para
transmissão ao banco de dados. Isto ocorre porque o SQL*Plus também possui comandos próprios com a finalidade de:
♦ Editar o comando SQL armazenado no Buffer.
♦ Formatar os resultados retornados pelo banco de dados.
♦ Armazenar os comandos de SQL para disco e recuperá-los para execução.
♦ Modificar o modo de trabalhar do SQL*Plus.
♦ Enviar mensagens e receber respostas de outros usuários.
♦ Listar a definição de qualquer tabela.
♦ Fazer acesso e copiar dados entre banco de dados.
DIGITANDO NO SQL*PLUS
A digitação na linha de prompt pode ser contínua (uma única linha) ou pode ocupar mais de uma linha, bastando
que teclemos Enter para que seja mostrada uma numeração seqüencial no lado esquerdo do vídeo, indicando que
o SQL*Plus considerou continuação do estado de digitação.
CURSO COMPLETO00✦ 25
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Para encerrarmos a digitação de um comando temos quatro opções, cada uma delas indicando ações diferentes.
A primeira opção é digitar um ponto-e-vírgula (;) seguido de Enter, indicando fim de digitação e ao mesmo tempo
solicitação de execução.
Outra opção que causa o mesmo resultado é pressionarmos a tecla Enter e na nova linha digitarmos a barra (/),
como primeiro caracter da linha, seguida de Enter. Novamente, o SQL*Plus considerará fim de digitação e dará
início à execução do comando.
Se não desejarmos que o comando seja executado, podemos teclar Enter duas vezes seguidas (deixando uma linha
vazia) ou teclar Enter uma vez, colocar um ponto (.) como primeiro caracter da nova linha e pressionar Enter
novamente. Nestas duas situações, o SQL*Plus apenas registrará o comando no SQL Buffer, mas não o executará.
Havendo um comando de SQL armazenado no SQL Buffer, poderemos alterá-lo, listá-lo ou substituí-lo com alguns
comandos básicos, próprios do SQL*Plus.
COMANDOS DE EDIÇÃO
Os comandos de edição têm o objetivo de modificar a informação armazenada no SQL Buffer. Estes comandos
afetam apenas uma linha de cada vez, isto é, a edição é feita linha a linha.
Quando listamos o conteúdo do SQL Buffer, o SQL*Plus mostra do lado esquerdo do texto (ao lado da numeração)
um asterisco em uma das linhas, indicando que se trata da linha corrente, ou seja, da linha apta para modificação.
Desta forma, qualquer comando de edição que viermos a fazer afetará apenas a linha corrente.
LIST
Este comando tem a finalidade de listar uma ou mais linhas do SQL Buffer. A última linha listada pelo comando se
tornará a linha corrente.
Na Listagem 2.02, o comando List é usado em letra minúscula. Repita o exemplo utilizando letra maiúscula. Você
poderá observar agora que os comandos do SQL*Plus não são case sensitive, isto é, a informação pode ser fornecida
em letra minúscula ou maiúscula indiferentemente.
26 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
A Sintaxe 2.01 indica como podemos listar parte do SQL Buffer e transformar em linha corrente quaisquer das
linhas digitadas.
Repita o teste apresentado na Listagem 2.02 com outras opções sintáticas. Verifique se ocorre alguma diferença na
digitação dos comandos em letra maiúscula ou minúscula.
APPEND
Com este comando, podemos adicionar um trecho de texto ao fim da linha corrente. Sua sintaxe é apresentada na
Sintaxe 2.02 a seguir.
Observe, no exemplo da Listagem 2.03, que o texto é adicionado imediatamente após o texto existente na linha
corrente, mesmo havendo um branco entre o comando e o texto. Observe, ainda, que, após a execução do comando,
o SQL*Plus apresenta a linha modificada para verificação.
Se desejarmos incluir um branco (ou mais) entre o texto antigo e o novo, devemos digitar o comando Append,
dois brancos (ou mais) e o texto a ser adicionado. Como teste adicional, tente usar este comando para incluir um
ponto-e-vírgula ao final de alguma linha. Isto não é possível, uma vez que o ponto-e-vírgula não faz parte da
sintaxe do SQL e tem uma conotação especial para o SQL*Plus, pois indica término de digitação e solicitação de
execução. Se, porém, o trecho que estivermos digitando não for de SQL e sim de PL/SQL, teremos necessidade de
incluir o ponto-e-vírgula no texto. Para que isto seja possível, devemos repetir a ação realizada com o branco, ou
seja, para a inclusão de um ponto-e-vírgula ao fim do texto, devemos digitar dois ponto-e-vírgulas seguidos.
CHANGE
Este comando de edição tem o objetivo de substituir parte do texto (ou todo) por outro. O separador (<sepchar>)
pode ser qualquer caracter especial que não esteja presente no texto <old> nem no texto <new>.
Observe que os separadores apresentados são iguais. Podemos utilizar qualquer caracter especial não presente nos
textos, porém, dentro de um comando, só podemos usar um deles.
CURSO COMPLETO00✦ 27
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Este comando efetua apenas uma substituição por linha, isto é, a linha é analisada da esquerda para a direita
e, quando for encontrado um trecho de texto igual ao texto <old>, é feita a substituição pelo texto <new> e o
comando é encerrado. Se desejarmos repetir a substituição para outro trecho da linha, devemos digitar o
comando novamente.
Para que não precisemos digitar repetidamente o mesmo comando, podemos “pintá-lo” com o botão esquerdo do mouse (pressionar o mouse
sobre o primeiro caracter que desejamos copiar, mantê-lo pressionado e arrastá-lo até o último caracter desejado) e, sem soltar o botão esquerdo,
clicar o botão direito do mouse. Esta ação fará com que o trecho pintado seja copiado para a linha de prompt. Experimente.
DEL
Exclui uma determinada linha da área do SQL Buffer. Caso não sejam informados parâmetros que indiquem a
linha a ser removida, será excluída a linha corrente.
No exemplo da Listagem 2.05, foi excluída a linha 2, deixando a sintaxe do comando SQL inválida. O próximo
comando (Input) resolve este problema.
28 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
INPUT
Este comando adiciona uma ou mais linhas após a linha corrente (no SQL Buffer). Este comando difere do comando
Append uma vez que pode voltar ao estado de digitação, abrindo uma nova linha para digitação imediatamente
após a linha corrente.
Quando digitamos o comando juntamente com um texto, é criada uma nova linha imediatamente após a linha
corrente, sendo seu conteúdo o texto informado. Quando digitamos apenas o comando, o SQL*Plus volta ao
estado de digitação, apresentando uma linha vazia com a numeração à esquerda seqüencial à da linha corrente,
anexada da letra i (ver exemplo da Listagem 2.06).
Para concluirmos a digitação desta(s) linha(s), devemos seguir os procedimentos normais vistos anteriormente no
tópico Digitando no SQL*Plus.
Observe que, ao listarmos o conteúdo do SQL Buffer novamente, as linhas já foram renumeradas.
EDIT
Este comando aciona um editor registrado no Windows e passa como parâmetro o nome de um arquivo ou o texto
presente no SQL Buffer, de acordo com o comando executado.
Quando omitimos o nome do arquivo a ser editado, o SQL*Plus aciona o editor do sistema passando como parâmetro
o texto do SQL Buffer.
Quando desejamos editar um determinado arquivo, seu nome pode ser informado com ou sem a extensão. A
extensão default é SQL.
O editor em uso pode ser obtido através de uma variável chamada _EDITOR. Para sabermos seu valor, podemos
digitar na linha de prompt DEFINE _EDITOR ou apenas DEFINE. No primeiro caso, o SQL*Plus nos mostrará o
valor apenas da variável solicitada. No segundo caso, serão apresentadas todas as variáveis existentes até o momento.
CURSO COMPLETO00✦ 29
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Posteriormente, no item referente a outros comandos do SQL*Plus, veremos o que são as variáveis de substituição
(ou variáveis definidas pelo usuário) e como podemos criar novas variáveis ou removê-las.
O editor-padrão no Windows é o bloco de notas (Notepad). Antes de substituirmos o editor-padrão por outro de
nossa escolha, devemos nos lembrar de que o editor escolhido deve aceitar um parâmetro correspondente ao arquivo
a ser editado. A Figura 2.04 apresenta a execução do comando EDIT sem que informemos o nome do arquivo.
Observe a mensagem apresentada na linha imediatamente abaixo da linha de prompt. Nesta situação, o SQL*Plus
deveria passar como parâmetro para o editor o conteúdo do SQL Buffer. O que ele faz, na verdade, é gravar um
arquivo em disco (cujo nome default é Afiedt.Buf) e passar o nome deste arquivo como parâmetro para o editor.
Quando efetuamos as modificações desejadas, salvamos e fechamos o editor (Notepad), o SQL*Plus refaz a leitura
do arquivo Afiedt.Buf carregando o texto modificado para o SQL Buffer.
Observe na Figura 2.04 que o Notepad apresenta o texto seguido de uma barra. Essa barra indica ao SQL*Plus que
o comando está completo. Caso retiremos a barra do arquivo, ao retornarmos para o SQL*Plus, ele apresentará
uma linha vazia imediatamente após a última linha lida para que continuemos a digitação. Experimente.
O diretório do Windows onde serão gravados (ou lidos) os arquivos de trabalho pode ser controlado por nós
(default é C:\<Oracle Home>\BIN). Se criarmos um atalho para o SQL*Plus (o executável se encontra na pasta
C:\<Oracle Home>\BIN e se chama SqlPlusw.exe), basta que modifiquemos o diretório “Iniciar em” da pasta
Atalho (ver Figura 2.05), obtida ao pressionarmos o botão direito do mouse sobre o ícone do SQL*Plus e escolhermos
a opção Propriedades.
Podemos, também, modificar o diretório de trabalho default do atalho presente na pasta Application Development
da seguinte forma: clicar no botão Iniciar (do Windows), opção Configurações, opção Barra de Tarefas e menu Iniciar,
pasta Avançado, clicar no botão Avançado, expandir o nó Programas, pesquisar (subordinado à pasta Documents
and Settings) a pasta All Users e expandi-la, seguir expandindo seqüencialmente as pastas Menu Iniciar, Programas e
Oracle – OraHome9i. Finalmente clicar sobre a pasta Application Development para que tenhamos acesso ao ícone
de ferramentas. Neste ponto, pressionar o botão direito do mouse sobre o ícone do SQL*Plus e escolher a opção
30 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Propriedades. Novamente será mostrada a tela de propriedades e, na pasta Atalho, poderemos alterar o diretório
“Iniciar em” (ver Figura 2.05). Para que a modificação tenha efeito, o SQL*Plus deve ser reiniciado.
Com esta modificação, qualquer arquivo a ser lido ou gravado pelo SQL*Plus o será no novo diretório default.
Se desejarmos efetuar a leitura ou gravação de arquivos em outros diretórios, podemos incluir o caminho onde se
encontra o arquivo ao usarmos o comando EDIT.
RUN
Este comando envia o conteúdo do SQL Buffer para o banco de dados e, ao mesmo tempo, apresenta no vídeo as
linhas enviadas (lista o SQL Buffer).
Para efeito de teste, digite o comando de SQL apresentado na Listagem 2.08 e execute o comando RUN.
'TEST
-----
TESTE
SQL>
CURSO COMPLETO00✦ 31
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
/ (BARRA)
Quando digitamos uma barra na linha de prompt e em seguida teclamos Enter, o SQL*Plus envia o conteúdo do
SQL Buffer para o banco de dados, porém não apresenta o texto enviado, isto é, não lista o SQL Buffer. Esta é a
diferença entre o comando Run e a barra.
EXIT / QUIT
Os comandos Exit e Quit são equivalentes e têm a finalidade de encerrar a sessão do SQL*Plus. Isto significa que a
conexão com o banco de dados e, simultaneamente, o próprio programa serão encerrados.
De acordo com a Sintaxe 2.09, observamos que podemos determinar como deve ser considerado o término do
programa, isto é, com sucesso ou não e com efetivação ou não das modificações realizadas no banco de dados.
Quando digitamos apenas Quit (ou apenas Exit), ficam valendo as opções sublinhadas. O término do programa é
considerado normal e a conexão se encerra também normalmente com Commit.
As demais opções indicam a ocorrência de uma falha na execução do SQL*Plus. Isto pode ser útil quando executamos
o SQL*Plus dentro de um arquivo de comandos para o sistema operacional em que devemos determinar como foi
o término do programa anterior, para que o próximo comando do arquivo seja executado ou não.
Podemos informar um valor numérico fixo, o valor de uma variável de substituição ou o valor de uma variável
BIND (variável para troca de informações com um programa PL/SQL será vista posteriormente).
A utilização destes parâmetros de encerramento é comum em arquivo de comandos. Desta forma, poderemos
transferir o valor para o arquivo de comandos a fim de controlar a execução do comando seguinte.
A conexão com o banco pode ser encerrada independentemente do tipo de término do SQL*Plus (Commit ou Rollback).
A execução de um comando Commit indica ao banco de dados que todos os comandos que modificaram informações do banco de dados devem
ser considerados válidos e as alterações devem ser efetivadas. Já um comando Rollback indica que as modificações devem ser desconsideradas.
32 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
O objetivo de transferirmos informações para o ambiente é permitir que executemos o SQL*Plus em batch e
façamos o controle sobre o resultado, definindo alternativas de ação em caso de erro, warning, etc.
DESCRIBE
Este comando tem a finalidade de apresentar a definição de um objeto criado na base de dados Oracle. O objeto
pode ser uma table, view, synonym, function, procedure ou package.
A Sintaxe 2.10 indica que podemos obter informações de objetos pertencentes ao usuário que estabeleceu a conexão,
objetos de outros usuários (informando-se <schema>) ou objetos existentes em outros bancos de dados (informando-
se <database_link_name>). Posteriormente, veremos o conceito de schema e como criar um database_link.
No exemplo a seguir, estamos obtendo a descrição da tabela Dual e da rotina Proc.
Observe que a tabela Dual não pertence ao usuário DESENV e sim ao usuário SYS; por este motivo, estamos
informando o schema da tabela. Já a procedure Teste pertence ao usuário DESENV e desta forma não é necessário
que o schema seja fornecido.
CURSO COMPLETO00✦ 33
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Por default, o banco de dados procura o objeto no próprio schema do usuário conectado.
SAVE
Este comando salva o conteúdo do SQL Buffer em um arquivo do sistema operacional.
A sintaxe acima permite que o conteúdo do SQL Buffer seja salvo em um arquivo novo (default), substitua um
arquivo existente ou seja adicionado a um arquivo existente.
A extensão do arquivo é fornecida por .<ext> . Caso seja omitida, será usado SQL como extensão padrão. O padrão
pode ser mudado com o uso da variável de sistema Suffix.
COUNT(*)
--------
32
No exemplo (Listagem 2.10), recebemos um erro quando indicamos que a salva deve ser efetuada e que o arquivo
já existe em disco. Se desejarmos, realmente, efetuar a salva, complementamos o comando com a opção Replace,
indicando que desejamos a substituição do arquivo.
GET
A recuperação de um texto para o SQL Buffer é feita por meio do comando GET. Todo o conteúdo do arquivo é
copiado para o SQL Buffer, e portanto este arquivo deve conter apenas um comando.
34 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
A extensão só precisa ser mencionada se for diferente do padrão (SQL). O padrão pode ser mudado com o uso da
variável de sistema Suffix.
Observe no exemplo (Listagem 2.11) que todo o conteúdo do arquivo é carregado para o SQL Buffer; desta forma,
se o arquivo contiver mais de um comando, ocorre um erro na execução porque o SQL*Plus envia todo o buffer
para o banco de dados como se fosse um único comando e, portanto, não reconhecido pelo banco de dados.
Caso o nome do arquivo seja composto das palavras List ou File, seu nome deve ser mencionado entre aspas.
Por default, o conteúdo do arquivo é listado após ser carregado para o SQL Buffer. Se esta ação não for desejada,
devemos usar a opção Nolist.
START
Este comando executa o conteúdo de um arquivo de comandos existente no sistema operacional. Cada comando
de SQL ou de SQL*Plus é lido e tratado individualmente. Num arquivo executado por Start, podemos incluir
diversos comandos de SQL.
O comando @ é sinônimo de Start e o @@ é semelhante, com a diferença de que, se este comando for incluído em
um arquivo de comandos, ele pesquisará o arquivo associado no diretório do arquivo de comando e não no
diretório local, como seria o caso do @ e do Start.
A Sintaxe 2.13 do comando Start permite a passagem de parâmetros. Estes parâmetros são variáveis de substituição
que são utilizadas para a alteração de trechos do comando SQL. Observe no exemplo (Listagem 2.12) que o valor
passado como parâmetro é substituído antes de o SQL*Plus enviar o comando ao banco de dados (é apresentada
uma mensagem com o texto da linha antes e após a substituição).
Foram usados dois parâmetros, um para a coluna Nr_git (numérica) e outro para a coluna Cd_depto (alfanumérica).
O valor &1 indica que deve ser feita a substituição pelo primeiro parâmetro passado na linha de comando. Como
CURSO COMPLETO00✦ 35
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
este valor é numérico, não houve necessidade de ser informado entre aspas simples. O segundo parâmetro deveria
ser informado entre aspas simples, pois se tratava de uma string. No exemplo, utilizamos a comparação com ‘&2’
no próprio comando de SQL, de tal forma que o valor informado na linha de comando não precisasse de aspas.
Quando executamos o comando Start passando parâmetros na linha de comando, o SQL*Plus define uma variável
de substituição com o nome de cada um dos parâmetros passados, de tal forma que uma segunda execução do
mesmo comando não precisa da passagem dos parâmetros (ver Listagem 2.13).
As variáveis de substituição não precisam ter nomes numéricos, podemos dar qualquer nome a elas; porém, neste
caso, não podem ser utilizadas como parâmetro para o comando Start. Ao executarmos um comando de SQL ou de
SQL*Plus contendo uma referência a variáveis de substituição, o SQL*Plus solicita que o valor da variável seja
informado. Observe na Listagem 2.14 que, mesmo quando informamos os valores na linha de comando, estes são
ignorados e é feita a solicitação dos valores.
Quando o comando contém a variável de substituição com nome alfanumérico precedido por um &, o SQL*Plus
não define uma variável de substituição com este nome. Se for desejada esta ação, devemos preceder a variável de
substituição com && e teremos o mesmo efeito que no caso do Start com parâmetros numéricos.
SQL> @TESTE
antigo 3: WHERE NR_GIT > &&INST AND CD_DEPTO = '&&DEP'
novo 3: WHERE NR_GIT > 17 AND CD_DEPTO = 'D11'
Quando desejamos que o valor da variável de substituição seja concatenado com outro valor, devemos usar um
ponto (.) para separar seu nome do valor.
36 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Com este comando, encerramos nosso estudo preliminar do SQL*Plus, pois já estamos em condições de editar e
executar os comandos de SQL que trataremos de agora em diante.
Posteriormente voltaremos a estudar outro grupo de comandos do Plus, a fim de formatarmos o resultado de um
comando executado ou modificarmos características de execução da ferramenta.
INTRODUÇÃO
Retomaremos, agora, o estudo da linguagem SQL. Para os testes iniciados a partir deste ponto, utilizaremos as
tabelas apresentadas no tópico Criação da Base Relacional (no Capítulo 1).
Como já vimos anteriormente, a DML é a parte da SQL que permite que os usuários façam consultas, modifiquem
informações existentes, criem novos dados ou excluam dados das tabelas do banco de dados.
As consultas aos dados são feitas através do comando SELECT, que é um dos comandos mais ricos da linguagem,
possuindo uma sintaxe ampla que permite diversas opções de pesquisa.
Na Sintaxe 2.14, verificamos que num comando SELECT, obrigatoriamente, devemos especificar que dados devem
ser trazidos, em que tabelas se encontram e, opcionalmente, podemos especificar que condições devem ser satisfeitas
para a obtenção destes dados.
As informações a serem trazidas do banco de dados podem ser compostas de nomes de colunas, funções ou expressões.
No exemplo da Listagem 2.17 usamos uma função (to_char), uma expressão matemática (vl_sal * 1.2) e um nome
de coluna (cd_mat) na cláusula Select. Repita este exemplo e você verificará que todas as linhas da tabela Func são
apresentadas no resultado, uma vez que não existem restrições quanto às linhas lidas da tabela.
CURSO COMPLETO00✦ 37
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
RESTRINGINDO A CONSULTA
As restrições são estabelecidas com o uso da cláusula Where. É com esta cláusula que determinamos que linhas
devem ser selecionadas. Observe o exemplo da Listagem 2.18.
Neste exemplo, só os funcionários que trabalham no departamento A00 são apresentados no resultado. Se você
observar detalhadamente o exemplo, verificará que a forma como foi escrito o comando SELECT mistura letras
maiúsculas e minúsculas indiscriminadamente e sem problemas de execução, porém a string ‘A00’ deve ser escrita
em letras maiúsculas, uma vez que, na coluna cd_depto da tabela Func, esta informação foi armazenada em letras
maiúsculas. Repita o exemplo anterior comparando cd_depto com a string ‘a00’. Qual o resultado encontrado?
Imaginemos agora que desejamos obter informações de todas as colunas da tabela Func para o funcionário com
matrícula 100.
Ao utilizarmos o símbolo * (asterisco), estamos informando ao Oracle que desejamos obter todas as colunas da
tabela referenciada na cláusula From. Estas colunas são apresentadas na mesma ordem em que foram criadas na
tabela correspondente. Já no exemplo da Listagem 2.18, as informações foram trazidas na ordem de seleção, uma
vez que mencionamos explicitamente o que desejávamos obter.
Para a montagem do resultado, o SQL*Plus tem a necessidade de determinar o tamanho de cada coluna para que possa
definir o layout de apresentação; desta forma, existem alguns padrões de layout de acordo com o tipo de coluna.
Para as colunas de data, o tamanho é determinado pela máscara de edição default em uso na sessão (obtida pela
NLS do banco de dados ou da estação) ou pela máscara de edição específica modificada pelo uso da função To_Char.
Em ambos os casos, o alinhamento é pela esquerda.
Para as colunas alfanuméricas, o tamanho da coluna é determinado por sua definição na tabela do banco de dados
(Char, Nchar, Varchar2, Varchar ou Nvarchar2) e o alinhamento é pela esquerda.
Para as colunas Long, Clob ou Nclob, a largura é determinada pelas variáveis de sistema Longchunksize ou Long,
o que for menor.
Para as colunas numéricas, o tamanho é determinado pelo cabeçalho da coluna, sendo que seu tamanho mínimo
é dado pela variável de sistema NumWidth (do SQL*Plus). O alinhamento é pela direita.
Todos estes padrões podem ser modificados com o uso do comando Column do SQL*Plus.
38 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Isto ocorre porque a cláusula Select possui duas palavras-chave que podemos utilizar para indicar se desejamos que
todas as linhas sejam selecionadas (mesmo correndo o risco de obtermos duplicidades) ou se desejamos que apenas
as linhas distintas sejam selecionadas. Quando não mencionamos nenhuma das opções, por default, todas as
linhas são selecionadas. Estas palavras-chave devem ser codificadas imediatamente após a cláusula Select, e fazem
referência a toda a linha e não apenas à primeira coluna. As palavras-chave são ALL (todas as linhas devem ser
selecionadas) e DISTINCT ou UNIQUE (apenas as linhas distintas devem ser selecionadas). As palavras DISTINCT
e UNIQUE são sinônimas. Observe, agora, a diferença no resultado gerado na Listagem 2.21.
OPERADORES DE COMPARAÇÃO
Até este momento, as restrições estabelecidas na cláusula Where utilizaram apenas a igualdade como operador de
comparação, porém a sintaxe do comando permite a utilização dos seguintes operadores: = (igual), ^= (diferente),
> (maior), >= (maior ou igual), < (menor), <= (menor ou igual), <> (diferente) e != (diferente).
A palavra NOT também pode ser usada para estabelecer uma negação.
USANDO AND E OR
Se desejamos colocar mais de uma condição de restrição na cláusula Where, estas condições devem ser combinadas
através das palavras And ou Or.
Com a palavra And, indicamos restrições que devem acontecer simultaneamente, ambas obrigatórias. Com a
palavra Or, indicamos restrições que podem ou não acontecer simultaneamente. Veja os exemplos da Listagem
2.24 a seguir.
ou
SQL> SELECT CD_MAT, NM_FUNC, CD_DEPTO, NR_CARGO
2 FROM FUNC
3 WHERE CD_DEPTO = 'A00' OR NR_CARGO = 56;
CURSO COMPLETO00✦ 39
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Observe a diferença de resultado quando retiramos os parênteses. Neste caso, são selecionados os funcionários do
departamento D11 (todos) e ainda aqueles do departamento D21 que tenham cargo maior que 54.
Observe no exemplo da Listagem 2.26 que o valor do salário está sendo multiplicado por um número negativo (-
1.1). O Oracle considera este símbolo como o sinal do número (menos unário) e não uma operação de subtração.
Este predicado compara valores correspondentes à coluna mencionada. Podemos comparar valores numéricos,
alfanuméricos e até mesmo datas. Neste caso, desejamos selecionar todos os funcionários com data de nascimento
entre 01/01/70 e 31/12/71.
Como as datas armazenadas no banco de dados comportam hora, minuto e segundo, optamos por transformar
uma constante com data de 01/01/72 e subtrair da mesma 1 segundo (1/86400), de tal forma que todos os
funcionários nascidos até às 23:59:59 do dia 31/12/71 pudessem ser selecionados.
40 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Listagem 2.29 – In
SQL> SELECT CD_MAT, NM_FUNC, CD_DEPTO
2 FROM FUNC
3 WHERE CD_MAT IN (10, 100, 320);
Da mesma forma que o predicado Between, podemos comparar valores alfanuméricos, datas ou valores numéricos.
No exemplo (Listagem 2.31), foram selecionados todos os funcionários cujo nome começasse com a letra “E” e que
trabalhassem em um departamento cujo código tivesse três caracteres, o primeiro fosse “D” e o terceiro fosse “1”.
Se desejássemos saber quais os funcionários que tivessem a letra “A” em seu nome, qual a sintaxe necessária?
Os caracteres porcentagem e sublinhado, por possuírem um significado especial, não podem ser usados normalmente
na string de pesquisa; precisamos indicar ao Oracle que estamos pesquisando exatamente aquele caracter.
Suponhamos, então, que desejássemos pesquisar a existência do caracter % num texto de uma determinada coluna
de tabela. Teríamos a necessidade de indicar que, neste caso, o símbolo de porcentagem deveria ser considerado
um caracter normal apto para pesquisa. Veja exemplo na Listagem 2.32.
Na cláusula Like, aparece o caracter porcentagem três vezes. A primeira e a última indicam que pode haver qualquer
número de caracteres (de 0 a n) antes e depois do texto a ser pesquisado. A segunda, uma vez que é precedida pelo
caracter de escape (/), indica que este é o texto que desejamos pesquisar.
O caracter de escape é definido pela cláusula Escape e pode ser qualquer caracter exceto % e _ (underscore).
CURSO COMPLETO00✦ 41
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
CD_ NM_DEPTO
--- ---------------------
D01 DIRETORIA DE SISTEMAS
No exemplo, tentamos comparar o valor ausente com NULL através dos operadores >= (maior ou igual) e = (igual),
o que não produziu nenhuma linha como resultado. Faça outros testes utilizando comparações com esta coluna e
você comprovará que, apenas quando vier a utilizar a expressão Is Null, conseguirá obter a linha em que a coluna
cd_gerente não está preenchida, ou seja, seu valor está ausente.
Se a pesquisa, por outro lado, não fornecer possibilidade de o Oracle restringir a busca a determinadas partições,
todas serão selecionadas.
Utilizando uma sintaxe própria do comando SELECT, podemos contornar esta situação (se desejarmos) limitando
a busca a uma determinada partição, bastando que mencionemos a cláusula Partition após a cláusula From, como
mostrado na Listagem 2.35.
42 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
O uso de tabelas particionadas pode ser muito útil, justamente para dados históricos, que não precisam ser
consultados todo o tempo e que, estando armazenados em áreas (tablespaces) separadas das linhas mais
freqüentemente utilizadas da tabela, podem trazer significativo ganho na performance das aplicações diárias.
EXERCÍCIOS
A solução dos exercícios propostos aqui está no último tópico deste Capítulo, intitulado Resolução dos Exercícios
Propostos. Tente resolver toda a lista primeiro e só no final verifique as respostas. Salve todos os exercícios em
arquivos de trabalho. Se as respostas estiverem difíceis de conferir refaça a carga das tabelas com o sript L01_17.sql
2.01) Deseja-se uma lista que contenha número da matrícula, primeiro e último nome e cargo de todos os
funcionários do sexo feminino que tenham cargo superior a 55.
2.02) Deseja-se uma lista que contenha número de matrícula, nome e sobrenome do funcionário em cujo sobrenome
não seja encontrada a letra “E”.
2.03) Repita o exercício anterior de tal forma que a letra pesquisada seja fornecida por variável de substituição na
linha do comando.
2.04) Deseja-se uma lista contendo código e nome do projeto para todos os projetos que possuam o texto “AMA”
em algum lugar de seu nome. Como restrição adicional, temos que somente os projetos em cujo código existam os
números 21 como terceiro e quarto caracter devem ser pesquisados.
2.05) Obtenha a descrição da tabela Funcionário.
2.06) Deseja-se uma lista contendo os códigos de departamento para os departamentos que possuam funcionários.
Na listagem-resposta, não deve haver repetição de código de departamento.
2.07) Deseja-se uma lista contendo código do departamento e nome do departamento de todos os departamentos
em que o código do departamento contábil não está preenchido.
2.08) Deseja-se uma lista (matrícula, nome e departamento) de todos os funcionários que estejam alocados aos
departamentos A00, B01 ou C01.
2.09) Deseja-se saber quais os funcionários (matrícula, cargo e departamento) que foram cadastrados na partição
Anos95_99 da tabela de histórico de promoções.
CURSO COMPLETO00✦ 43
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Com esta sintaxe, podemos incluir linhas em tabelas locais, de outros schemas e ainda de outros bancos de dados
(@<dblink>). A inclusão pode ser feita linha a linha ou os valores podem ser obtidos de outra(s) tabela(s) do banco
de dados de tal forma que a inclusão de diversas linhas pode ser feita com um único comando Insert. Finalmente,
podemos definir que os valores sejam cadastrados em uma determinada partição de uma tabela específica. A
seguir, estudaremos separadamente cada uma das opções apresentadas.
Suponhamos que desejássemos incluir duas novas linhas na tabela de funcionários, porém não dispomos de
informações completas destes novos funcionários. Observe as diferenças sintáticas nos exemplos da Listagem 2.36.
No primeiro Insert, foram mencionadas as colunas que desejávamos preencher. Desta forma, informamos valores
apenas para estas colunas.
No segundo caso, as colunas da tabela não foram mencionadas; sendo assim, precisamos associar valores a cada
uma das colunas. Faça um Describe da tabela Func e verifique a ordem em que as colunas foram criadas na tabela.
Esta é a ordem em que devemos fornecer informações para a segunda forma sintática.
Quando não possuímos valor para uma determinada coluna, podemos utilizar a palavra-chave NULL, indicando
que a coluna específica não será gravada no banco de dados.
No próximo exemplo, faremos a inclusão de dados sem mencionar em que partição a inclusão deve ser realizada.
Uma vez que a coluna dt_promocao é de preenchimento obrigatório, será em função dela que o Oracle descobrirá
em que partição deve incluir cada uma das linhas.
SQL> SELECT *
2 FROM HST_PROMO PARTITION (ANOS95_99)
3 WHERE CD_MAT = 272;
44 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Neste exemplo (Listagem 2.37), apesar de não mencionarmos em qual partição desejávamos que fosse feita a
inclusão das linhas, em função da especificação feita no momento da criação da tabela para a coluna dt_promocao,
o Oracle pode determinar qual a partição mais adequada para a inclusão da nova linha.
O comando Select apresentado já menciona o nome da partição. Sendo assim, a consulta se restringe à partição mencionada.
Neste exemplo, tentamos incluir linhas na partição Anos2000, quando, na verdade, a data da promoção era de
1999. Observamos que o Oracle, apesar de informarmos o nome da partição, faz a verificação e impede que façamos
a inclusão na partição incorreta, garantindo a integridade lógica da informação armazenada.
No exemplo da Listagem 2.39, o comando Insert foi utilizado para efetuar a inclusão de diversas linhas
simultaneamente. As linhas foram obtidas da própria tabela Func para efeito de teste. Observe que o novo código
da matrícula foi derivado do valor antigo, porém foi obrigatória sua modificação, pois cd_mat é primary key da
tabela Func. Isto significa que o Oracle não admitirá duas linhas com o mesmo valor de matrícula.
Na Listagem 2.40, foram feitas duas tentativas de inclusão que resultaram em falha.
No primeiro comando, tentamos incluir uma matrícula já existente, o que causou a mensagem de erro ORA-
00001: restrição exclusiva (DESENV.SYS_C00642) violada, onde nos é mostrada qual a regra de integridade que foi
violada (SYS_C00642); este é o nome da restrição de primary key da tabela Func.
CURSO COMPLETO00✦ 45
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
No segundo comando, fizemos a tentativa de incluir uma linha com matrícula válida, porém contendo um código
de departamento que não existe na tabela Depto. Neste caso, a mensagem de erro ORA-02291: restrição de integridade
(DESENV.SYS_C00643) violada – chave-pai não localizada, nos informa novamente qual a regra de integridade
referencial violada (SYS_C00643).
Experimente, agora, incluir linha com um valor inválido para a coluna in_sexo (válidos são F e M escritos com
letras maiúsculas). Verifique qual a mensagem de erro obtida.
Todas estas regras são definidas pelo DBA quando da criação da tabela. Estas regras de integridade estabelecidas no
banco de dados garantem que, independente do modo como o usuário faça a inclusão ou alteração dos dados
(SQL*Plus, Forms Builder, Reports Builder, PL/SQL, etc.), sua validação será feita pelo banco de dados e nenhuma
tentativa de violação será aceita.
MAT
---
101
À primeira vista, pode não fazer sentido a utilização desta cláusula, porém, posteriormente, veremos que pode ser
interessante obter como retorno o endereço lógico de gravação da linha, chamado de ROWID, ou ainda a referência
a um objeto tabela (object table).
No exemplo, declaramos duas variáveis no SQL*Plus (será visto no item Conhecendo Mais Sobre o SQL*Plus) e as utilizamos
para receber o valor retornado. O comando Print também é um comando do SQL*Plus e será visto no mesmo item.
46 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Suponhamos que desejássemos alterar o salário de todos os funcionários em 10%. O comando Update poderia ser
utilizado de forma que o novo salário fosse igual ao anterior mais 10%. Para que todos os funcionários fossem
atualizados, bastaria que omitíssemos a cláusula Where. Faça este teste.
No próximo exemplo, tentaremos atualizar o salário e cargo dos funcionários com cargo 58 para que ganhem 90%
do salário da gerente Cristina Henderson (matrícula 10) e o mesmo cargo. Para realizarmos esta atualização,
precisaremos consultar os dados para obter o salário e cargo do gerente, calcular 90% do salário e, então, fazer a
atribuição aos funcionários com cargo 58.
No exemplo apresentado, todas as operações foram feitas em um único comando Update. Sua sintaxe permite que
na cláusula de atribuição façamos uma busca para obtenção do valor a ser atribuído. Observe que o Select interno
possui uma cláusula Where que determina os valores a serem obtidos e o comando Update também possui uma
cláusula Where para determinar quais linhas serão atualizadas.
Experimente repetir o exemplo, porém no lugar de matrícula 10 na restrição do Select utilize matrícula maior que
10. Substitua o cargo para 66 (caso contrário, nenhuma linha estará apta para atualização).
A mensagem de erro apresentada ORA-01427: a subconsulta de uma única linha retorna mais de uma linha, indica
que a subquery só pode retornar uma linha para ser usada como atribuição nas colunas a serem atualizadas.
Daremos um exemplo a seguir que fará a atualização dos dados em uma tabela particionada (Hst_Promo).
Primeiramente sem mencionar a partição e posteriormente indicando qual a partição a ser modificada.
Se não mencionarmos a partição, todas as partições serão consultadas para verificação da condição de seleção.
Quando mencionamos a partição, a restrição presente na cláusula Where somente será verificada para esta partição.
CURSO COMPLETO00✦ 47
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
END_LINHA
------------------
AAAAd/AACAAAAGkAAU
Neste exemplo apenas uma linha foi atualizada; para que fosse possível o retorno das informações de diversas
linhas, deveríamos declarar um host array (por exemplo, um nível 01 do Cobol) para receber a informação. Os
tipos das colunas retornadas e os elementos do array devem ser compatíveis, além do que o número de linhas
retornadas não pode exceder ao tamanho do array.
Na Listagem 2.45, declaramos uma variável BIND no SQL*Plus do tipo alfanumérica e utilizamos a função
ROWIDTOCHAR para converter o formato ROWID para o formato alfanumérico, já que não pudemos declarar no
SQL*Plus uma variável com o tipo de que necessitávamos. As funções de SQL serão tratadas ainda neste capítulo
no tópico Modificando o Resultado com Funções e a declaração de variáveis no SQL*Plus no tópico Conhecendo
Mais Sobre o SQL*Plus.
Nosso primeiro exemplo removerá aquela funcionária recém-contratada “Elizabeth Jorio” e, ainda, o gerente do
departamento D11.
No primeiro comando Delete executado, conseguimos remover a funcionária desejada. Na cláusula Where, utilizamos
a pesquisa pelo nome Elizabeth, que foi escrito exatamente igual à forma como estava armazenado. O que aconteceria
se tivéssemos feito a pesquisa com o nome escrito com todas as letras em maiúsculas? Faça este teste você mesmo.
A sintaxe dos comandos de SQL pode ser escrita em letras maiúsculas ou minúsculas, conforme nosso desejo, uma
vez que os comandos não são sensíveis à utilização de maiúsculas ou minúsculas. Já o conteúdo de uma coluna
depende da forma como a informação foi armazenada. Em uma pesquisa posterior, devemos igualar a coluna a um
valor constante escrito exatamente da mesma forma que foi armazenado. Caso contrário, não encontraremos a
linha na base de dados.
48 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
No segundo comando Delete executado, não conseguimos remover o gerente do departamento D11 porque existe um
relacionamento (veja o modelo de dados) entre a tabela de Departamentos e a tabela de Funcionários, onde o código do
gerente (que corresponde à matrícula do funcionário) se encontra presente na tabela de Departamentos. Neste caso, o
Oracle somente permitirá a remoção do funcionário se, primeiro, tirarmos sua referência da tabela de Departamentos.
A mensagem de erro ORA-02292: restrição de integridade (DESENV.SYS_C00650) violada – registro filho localizado,
indica que foi encontrado um registro subordinado ao registro de funcionário que desejávamos remover. A restrição
de integridade que garante esta regra se chama SYS_C00650.
Nosso próximo teste será a remoção de linhas de uma tabela particionada. Inicialmente sem mencionarmos a
partição e, posteriormente, mencionando o nome da partição desejada.
Quando mencionamos o nome da partição, estamos restringindo a pesquisa a esta partição, tornando a execução
do comando mais eficiente. Quando isto não ocorre, todas as partições são pesquisadas.
MAT
---
272
EXERCÍCIOS
A solução dos exercícios propostos aqui está no fim deste capítulo, em tópico intitulado Resolução dos Exercícios
Propostos. Tente resolver toda a lista primeiro e só no final verifique as respostas. Salve todos os exercícios em
arquivos de trabalho.
CURSO COMPLETO00✦ 49
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
2.10) Deseja-se incluir dois novos empregados na tabela de funcionários. Este cadastramento é preliminar e,
portanto, nem todos os dados são conhecidos. Utilize as duas sintaxes vistas no item Incluindo Novas Linhas
para realizar as inclusões.
2.11) Deseja-se, agora, completar as informações sobre os novos funcionários. Sabendo-se que a funcionária Joana
recebeu ramal 1512 e data de admissão 15/01/99 e que o funcionário Marcelo recebeu ramal 1418 e data de
admissão 15/02/99, é necessário que os dados na tabela Func sejam atualizados e que sejam incluídas as linhas
correspondentes ao valor inicial dos funcionários na tabela de histórico de promoções.
2.12) Inclua-se como funcionário. Preencha todas as colunas da tabela. O número da matrícula deve corresponder
ao dia do seu aniversário somado ao ano.
2.13) Tente trocar o código do departamento associado a você para um código de departamento inválido. O que
acontece? Por quê?
2.14) Inclua todos os funcionários do departamento D11 no departamento D01, acrescentando ao número da
matrícula o valor 340.
2.18) Exclua todos os funcionários que ganhem mais que o funcionário cuja matrícula é 200. O que ocorre? Por quê?
USANDO APELIDOS
A partir de agora, você verá aparecer nos comandos de SQL apelidos para as colunas (ou expressões) e posteriormente
para o nome da tabela. A utilização de apelidos é bastante simples, bastando que coloquemos o apelido desejado
ao lado da expressão (ou nome da coluna), sem vírgula entre eles. O Oracle enviará ao SQL*Plus o valor da coluna
indicando o apelido (ou alias) como sendo o nome daquela coluna. Esta é uma forma de modificarmos o cabeçalho
do resultado gerado.
50 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Este apelido pode ser informado entre aspas duplas se desejarmos um texto que não seja permitido sintaticamente
como nome de coluna Oracle (por exemplo, um nome composto).
Neste primeiro exemplo, ordenamos o resultado por código do departamento ascendentemente e por salário
(terceira coluna da lista de seleção) em ordem descendente. Observe que as três primeiras linhas são do departamento
A00 e que o primeiro funcionário apresentado possui salário superior aos demais.
Na Listagem 2.50, a ordenação primária é feita pela coluna cd_depto (segunda coluna na lista de seleção) sem que
tenhamos fornecido a indicação Asc ou Desc. Pelo resultado, concluímos que a ordenação default é Asc.
Neste comando Select foi calculada uma expressão (vl_sal * 1.1), a qual recebeu o apelido de Projeção. Este apelido
foi utilizado com sucesso na cláusula Order By.
No exemplo anterior, a ordenação foi feita pela coluna cd_depto, apesar de esta não estar presente na lista de
seleção. Na verdade, o Oracle faz a seleção da coluna, ordena o resultado e apenas não envia o valor correspondente
para o usuário solicitante.
Ainda neste exemplo, utilizamos para apelido um nome composto de duas palavras, sendo necessário o uso das
aspas para indicar que se tratava de um único nome. A palavra-chave “AS” foi usada para indicar ao Oracle que
incluiríamos um apelido para a coluna, isto não é obrigatório; podemos trabalhar com o formato visto no exemplo
2.50. Teste você agora outros tipos de apelidos usando os caracteres especiais do teclado. Experimente a utilização
sem aspas e verifique o erro recebido.
Façamos, agora, a ordenação proposta pela Listagem 2.52. O que acontece quando ordenamos por uma coluna
cujo conteúdo de alguma (ou algumas linhas) está ausente. Teste este exemplo.
CURSO COMPLETO00✦ 51
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Podemos observar que a linha em que o gerente não está definido aparece em último lugar, ou seja, para ordenação
ascendente NULL é considerado “maior valor”. Experimente usar ORDER BY 2 DESC e confirme que neste caso o
departamento D01 é o primeiro a ser apresentado.
Na Listagem 2.53 usamos a cláusula NULLS FIRST para que o posicionamento das linhas com valores ausentes seja
apresentado antes dos demais valores em ordenação. Podemos optar por NULLS LAST se desejarmos que estas
linhas sejam apresentadas após os demais valores.
A utilização é direta, através dos operadores de comparação, quando a subquery retorna apenas uma linha. Na
Listagem 2.54 a seguir, estamos obtendo todos os funcionários que recebam maior salário que o gerente do
departamento X (recebido como parâmetro de substituição).
Foram utilizados dois subselects. O mais interno retorna apenas uma linha, pois a restrição é feita pelo código do
departamento (que é primary key da tabela Depto). O segundo também retorna uma única linha, pois a restrição
é feita por cd_mat (que é primary key da tabela Func). A execução do comando é iniciada no subselect mais
interno até atingir o nível da consulta principal.
No exemplo da Listagem 2.55, estamos selecionando todos os funcionários do gerente cuja matrícula é fornecida
como parâmetro.
Nos dois exemplos, o subselect retornou apenas uma linha e pudemos comparar o valor retornado diretamente
com o valor correspondente na consulta principal.
Suponhamos, agora, que a subconsulta retorne mais de uma linha. Neste caso, a comparação não poderá ser feita
apenas com um dos operadores de comparação (>, <, =, >=, etc.).
Na Listagem 2.56, a subconsulta retornou diversas linhas (B01, C01, D01 e E01). Desta forma, a consulta principal
não poderia testar apenas a igualdade para uma lista de valores. Foi, então, utilizada a palavra-chave Some (ou
Any), que indica “algum”. As palavras-chave a serem usadas juntamente com os operadores de comparação são:
52 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
♦ ALL – A condição será satisfeita se a expressão for verdadeira para todos os valores do subconjunto obtido.
♦ ANY ou SOME – A condição será satisfeita se a expressão for verdadeira para algum dos valores do subconjunto obtido.
Na Listagem 2.57, foram selecionados todos os departamentos em que não existiam funcionários alocados, uma
vez que a restrição indicava diferente de todos os códigos de departamento selecionados na subquery.
Além desta combinação de palavras-chave e operadores de comparação para tratamento das subqueries, também
podemos utilizar o predicado IN (já visto anteriormente), que terá o mesmo significado de = ANY ou, no caso de
NOT IN, o mesmo significado de <> ALL.
Neste exemplo (Listagem 2.58) foram selecionadas, da tabela de funcionários, apenas informações dos gerentes.
O gerente do departamento é identificado na tabela Depto através da coluna cd_gerente, cujo conteúdo corresponde
ao código da matrícula do funcionário (gerente) na tabela de Funcionários.
EXERCÍCIOS
2.19) Deseja-se atualizar o salário de todos os funcionários que são gerentes de departamento em 5%.
2.20) Deseja-se excluir todos os departamentos que não possuam funcionários alocados.
2.21) Deseja-se uma lista (matrícula, nome e salário) de todos os funcionários que ganhem mais que todos os
funcionários do departamento parametrizado. Ordene o resultado por salário. Os funcionários sem salário devem
ser apresentados no início da relação.
2.22) Deseja-se uma lista (matrícula, nome e cargo) dos funcionários que possuam cargo igual ao cargo de algum
dos funcionários do departamento D11.
2.23) Deseja-se uma lista contendo matrícula, nome, departamento e salário de todos os funcionários que sejam
responsáveis por projeto (tabela Proj), mas não sejam gerentes (tabela Depto). Ordene o resultado por salário. Os
funcionários sem salário devem ser apresentados no fim da relação.
2.24) Deseja-se uma lista (código e nome) dos departamentos que iniciaram projetos em janeiro de 1996.
CURSO COMPLETO00✦ 53
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
54 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
São programas que têm a finalidade de efetuar cálculos sobre um conjunto de linhas e retornam um valor. Elas se
aplicam a um grupo de linhas e retornam um único valor relativo a todo o grupo selecionado. Neste conjunto o
Oracle disponibiliza 34 funções que conheceremos a seguir.
O argumento para estas funções pode ser o nome de uma coluna ou uma expressão (combinação de nomes de
colunas, constantes ou outras funções).
Neste primeiro exemplo, o grupo sobre o qual os cálculos foram feitos foi toda a tabela Funcionário, uma vez que
não limitamos as linhas selecionadas (Where). Obtivemos a soma de todos os salários cadastrados, a média salarial
(aritmética), o valor do maior e do menor salário e quantas linhas foram encontradas na tabela Funcionário.
Dentro do algoritmo de cálculo das funções de grupo, as linhas com NULL são excluídas da etapa de avaliação.
Caso esta ação não fosse efetuada, o resultado, freqüentemente, seria NULL, uma vez que ao operarmos um valor
desconhecido (NULL) com um valor conhecido o resultado será invariavelmente desconhecido.
Para verificação dos resultados gerados, prepare a massa de teste apresentada na Listagem 2.60 a seguir.
Nesta massa de teste, temos duas linhas em que a coluna Salário não está preenchida. Sobre esta massa vamos
efetuar alguns cálculos relativos às funções de grupo.
Na sintaxe verificamos que All é a opção default; todos os valores (exceto NULL) são passados como argumento das funções.
De acordo com a descrição das funções de agregação a seguir faremos exemplos com a massa de dados anterior
para que os resultados possam ser conferidos e entendidos.
AVG
Retorna a média dos valores de <expressão>. Ela pode ser usada como uma função de agregação ou analítica. Se a
função for aplicada a um grupamento vazio (sem linhas) o retorno é null.
CORR
Retorna o coeficiente da correlação de um conjunto de pares de números. Ela pode ser usada como uma função de
agregação ou analítica. Os parâmetros <expr1> e <expr2> devem ser numéricos. Os pares em que <expr1> ou
<expr2> estiverem sem valor são excluídos do resultado. A fórmula de cálculo para esta função é a seguinte:
CURSO COMPLETO00✦ 55
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
COUNT
Retorna o número de linhas que satisfaçam a query. Ela pode ser usada como uma função de agregação ou analítica.
COVAR_POP
Retorna a covariância populacional de um conjunto de pares numéricos. Ela pode ser usada como uma função de
agregação ou analítica. Os parâmetros <expr1> e <expr2> devem ser numéricos. Os pares em que <expr1> ou
<expr2> estiverem sem valor são excluídos do resultado. A fórmula de cálculo para esta função é a seguinte:
Se a função for aplicada a um grupamento vazio (sem linhas) o retorno é null. O divisor n indica a quantidade de
linhas onde <expr1> e <expr2> estão preenchidos.
A função AVG nos traz como resultado 166,667, indicando que a soma das linhas (1000) foi dividida por 6 (linhas
em que salário tem valor) e não por 8 (total de linhas que atendem à condição de busca). As linhas em que salário
não possui valor (NULL) são ignoradas para cálculo do resultado.
A função Count sobre a coluna vl_sal nos traz como resultado 6, indicando que das linhas selecionadas seis
possuem valor na coluna vl_sal. Quando a mesma função Count é aplicada sobre a coluna cd_mat (primary key),
que possui valor para todas as linhas, o resultado é 8, indicando que foram selecionadas oito linhas na consulta.
Observe que a função Count com o argumento * (asterisco) retorna o mesmo valor que para a coluna cd_mat. Esta
sintaxe fornece o número de linhas selecionadas no comando, independente de qualquer coluna. Pode ser usada
sempre que desejarmos saber a quantidade de linhas obtidas.
A função Sum soma todas as linhas não nulas do resultado. Caso as linhas com valor Null fossem incluídas, o valor
seria necessariamente Null (isto é, desconhecido).
A fórmula da função Covar_Pop utiliza apenas a função Sum sendo, neste caso, mais fácil de conferirmos o resultado. Se
aplicarmos a fórmula ( [35500 – [[215*1000 ] / 6 ]] / 6 ) diretamente aos valores obtidos separadamente no exemplo
verificaremos que o resultado obtido é negativo (-55.556). Devemos observar que a descrição da função diz que as linhas
em que uma das expressões é Null são excluídas do resultado, e neste caso a linha com cargo 12 não entra nos cálculos. A
fórmula modificada ( [35500 – [[203*1000 ] / 6 ]] / 6 ) em função desta regra obtém o valor esperado de 277,778.
Observe a seguir a descrição da função Covar_Samp. Repita o exemplo da Listagem 2.61 substituindo Covar_Pop
por Covar_Samp e confira o resultado.
COVAR_SAMP
Retorna a covariância simples de um conjunto de pares numéricos. Ela pode ser usada como uma função de
agregação ou analítica. Os parâmetros <expr1> e <expr2> devem ser numéricos. Os pares em que <expr1> ou
<expr2> estiverem sem valor são excluídos do resultado. A fórmula de cálculo para esta função é a seguinte:
(SUM(<expr1> * <expr2>) – (SUM(<expr2>) * SUM(<expr1>)) / n) / (n-1)
56 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Se a função for aplicada a um grupamento vazio (sem linhas) o retorno é null. O divisor n indica a quantidade de
linhas onde <expr1> e <expr2> estão preenchidos.
CUME_DIST
Esta função calcula a distribuição cumulativa de um valor em um grupo de valores. O valor retornado por esta função
estará dentro do intervalo > 0 e <= 1. Ela calcula, para uma linha hipotética R identificada pelos argumentos da
função e especificação de ordenação, a posição relativa de R no grupo de agregação. O cálculo considera como se R
estivesse inserida no grupo de linhas a serem agregadas. Os argumentos da função identificam um única linha dentro
de cada grupo; desta forma devem estar associados a expressões constantes dentro de cada grupo. Os números de
expressões no argumento e na cláusula Order By devem ser idênticos pois serão considerados 1 para 1 posicionalmente.
DENSE_RANK
Esta função calcula o posicionamento (rank) de uma linha em um grupo ordenado de linhas. O posicionamento é
consecutivo, inteiro, começando em 1. O maior valor do Rank corresponde ao número de valores distintos retornados
pela query. Ela calcula o posicionamento relativo de uma linha hipotética identificada pelos argumentos da função
de acordo com a ordenação especificada. Os argumentos da função identificam uma única linha dentro de cada
grupo; desta forma devem estar associados a expressões constantes dentro de cada grupo. Os números de expressões
no argumento e na cláusula Order By devem ser idênticos pois serão considerados 1 para 1 posicionalmente.
FIRST
Pode ser usada como função de agregação ou analítica. Opera em um conjunto de valores a partir de um conjunto
de linhas que “rank” (são identificadas) como FIRST com relação a uma determinada ordem. Se somente uma
linha for classificada (“rank”) como FIRST, a agregação é realizada em um conjunto de apenas uma linha. A função
de agregação utilizada em conjunto pode ser MIN, MAX, SUM, COUNT, AVG, VARIANCE ou STDDEV.
Na Listagem 2.62 observamos que as funções Cume_Dist e Dense_Rank receberam como parâmetro a constante
300. Poderíamos ter fornecido mais de um valor (separados por vírgulas), desde que constantes.
Como primeiro resultado da Cume_Dist para o valor 300 recebemos 1, isto significa que 100% das linhas selecionadas
possuíam valores de salário menores (ou igual) que 300 considerando-se um total de 9 linhas ordenadas
ascendentemente por salário (o valor 300 é incluído no resultado) e nos quais os valores Null são considerados os
menores. O segundo resultado (44,44%) indica que o cálculo 4/9 foi realizado. Este cálculo possui a seguinte
lógica: o valor 300 é incluído na lista de valores, e desta forma passamos de 8 linhas para 9. Como os valores com
Null foram colocados na frente, os dois valores 300 (o da linha com matrícula 104 e o da constante) ocuparam
respectivamente o terceiro e quarto lugares na seqüência de leitura. Como o cálculo se refere a todos os valores
maiores ou iguais a 300 (devido à ordenação estabelecida), escolhe-se a posição 4 como numerador do cálculo. Se
toda esta explicação está confusa para você, faça as contas com um valor que não tenha na sua lista, por exemplo
290 ou 310. Outro teste interessante é retirar as linhas com Null da query (where vl_sal is not null). Estas duas
modificações devem te ajudar a entender melhor o resultado.
CURSO COMPLETO00✦ 57
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
A primeira construção função Dense_Rank classifica o valor da expressão (no caso 300) dentro do conjunto de
valores selecionados e de acordo com a ordenação especificada na cláusula Within Group. O resultado é 4, o que
indica que a classificação 1 é atribuída às linhas com NULL (pois indicamos que NULLS FIRST), a classificação 2
para as linhas com salário 100, a classificação 3 para as linhas com salário 200 e a 4 para o valor 300. Observe que
a classificação é do valor e não da quantidade de linhas. A segunda construção, com ordenação descendente,
classifica o valor 300 em segundo lugar, já que o primeiro é ocupado pelas linhas com salário null (Nulls First).
A primeira construção da função FIRST obterá o maior cargo (max) das linhas classificadas como FIRST. Esta
classificação é dada através da ordenação de salário, no caso ASC e com nulls no fim. Sendo assim, o menor valor
de salário é 100 (as linhas com salário 100 são, portanto, classificadas como FIRST). Das 3 linhas com salário 100,
o maior cargo é 32. No segundo exemplo a ordenação de salário é descendente; desta forma a linha com salário
300 é classificada como FIRST e, portanto, o maior (e único) cargo é 21.
GROUP_ID
Esta função distingue linhas duplicadas resultantes de uma especificação GROUP BY. Ela somente é válida em
comandos SELECT que utilizem a cláusula GROUP BY. Se houver n duplicatas para um determinado grupamento
a função retornará valores de 0 a n-1.
GROUPING
Esta função distingue valores relativos a uma agregação que utilize GROUP BY juntamente com as extensões
ROLLUP ou CUBE. O objetivo é determinar quando o valor null de uma determinada expressão significa uma
agregação e quando significa o valor real (ou ausente) da expressão. A <expressão> que viermos a usar na função
GROUPING deve ser compatível com o valor usado na cláusula GROUP BY. O retorno da função é 1 se o valor de
<expressão> é null significando um conjunto de todos os valores e 0 se o null significar valor ausente.
GROUPING_ID
Retorna um número que corresponde ao Grouping bit vector associado com uma linha. É aplicável somente a
comandos SELECT que incluam a cláusula GROUP BY com a extensão ROLLUP ou CUBE e uma função GROUPING.
LAST
Pode ser usada como função de agregação ou analítica. Opera em um conjunto de valores a partir de um conjunto
de linhas que “rank” (são identificadas) como LAST com relação a uma determinada ordem. Se somente uma linha
for classificada (“rank”) como LAST, a agregação é realizada em um conjunto de apenas uma linha. A função de
agregação utilizada em conjunto pode ser MIN, MAX, SUM, COUNT, AVG, VARIANCE ou STDDEV.
MAX
Retorna o maior valor de <expressão>. Pode ser usada como uma função de agregação ou analítica.
MIN
Retorna o menor valor de <expressão>. Pode ser usada como uma função de agregação ou analítica.
PERCENT_RANK
Esta função é similar a CUME_DIST (distribuição cumulativa). O intervalo de valores retornados por PERCENT_RANK
é de 0 a 1 (inclusive). A primeira linha em qualquer conjunto tem um PERCENT_RANK de 0.
58 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
L_ASC L_DESC MX_SAL MX_CRG MN_SAL MN_CRG P310_ASC P290_ASC P310_DESC P290_DESC
----- ------ ------ ------ ------ ------ -------- -------- --------- ---------
12 8 300 65 100 8 ,75 ,625 0 ,125
A primeira construção da função LAST obterá o menor cargo (min) das linhas classificadas como LAST. Esta
classificação é dada através da ordenação de salário, no caso ASC e com nulls no fim. Sendo assim, o maior valor de
salário é NULL (as linhas sem salário são, portanto, classificadas como LAST). Das 2 linhas com salário 100, o
menor cargo é 12. No segundo exemplo a ordenação de salário é descendente e as linhas sem salário (NULL) são
ordenadas no início da fila; desta forma as linhas com salário 100 são classificadas como LAST e, portanto, o
menor deste grupo cargo é 8.
As funções max e min são facilmente compreendidas por nós. O maior salário, desconsiderando-se as linhas sem
salário, é 300 e o maior cargo é 65. O menor salário e o menor cargo são, respectivamente, 100 e 8.
Nos testes da função Percent_Rank utilizamos, desta vez, valores que não pertencem à lista de valores presentes na
tabela. Como esta função é similar à função Cume_Dist já sabemos que a fórmula corresponde à divisão da posição
da linha em questão em relação à posição da última linha do grupo. Como esta função inicia a classificação em
zero, temos como primeira fórmula a divisão de 6 por 8, ou seja, a posição da linha com valor de salário 310 é 6 (os
três valores 100 ocupam as posições 0, 1 e 2; os dois valores 200 ocupam as posições 3 e 4; o valor 300 ocupa a
quinta posição; o valor 310 a sexta e os dois valores null as posições 7 e 8) e da última linha é 8. O resultado 0.75
corresponde a esta divisão. No segundo exemplo temos 5 sobre 8 (os três valores 100 ocupam as posições 0, 1 e 2;
os dois valores 200 ocupam as posições 3 e 4; o valor 290 ocupa a quinta posição; o valor 300 a sexta posição e os
dois valores null as posições 7 e 8). No terceiro exemplo, pela classificação, o valor 310 é o primeiro da lista,
recebendo o valor 0, que, dividido por qualquer valor, dá zero. No último exemplo a divisão realizada é de 1 por 8.
PERCENTILE_CONT
Esta função realiza uma distribuição inversa considerando um modelo de distribuição contínua. Ela obtém um
valor percentual e uma especificação de ordenação e retorna um valor interpolado que deve cair dentro do percentual
em relação à especificação de ordenação. Os nulls são ignorados no cálculo. O parâmetro deve ser uma constante
com valor entre 0 e 1, pois indica um valor percentual. A cláusula ORDER BY deve ser composta de uma única
expressão numérica ou datetime. O resultado é calculado por uma interpolação linear entre os valores após a
ordenação. Usando-se o valor percentual (P) e o número de linhas (N) no grupo de agregação, determina-se o
número da linha de interesse. Este número de linha é calculado de acordo com a fórmula:
RN = (1 + (P * ( N –1)
O resultado final da função de agregação é calculado pela interpolação linear entre os valores das linhas relativas
ao número da linha, onde CRN = CEILING(RN) e FRN = FLOOR(RN). O resultado final será o valor da expressão da
linha em RN se CRN=FRN=RN (não houver mais de um valor resultante) ou (CRN – RN) * (valor da expressão da
linha em FRN) + (RN – FRN) * (valor da expressão da linha em CRN).
Também pode ser usada como função analítica.
CURSO COMPLETO00✦ 59
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
PERCENTILE_DISC
É uma distribuição inversa que assume um modelo de distribuição discreta. Ela recebe um valor percentual e uma
especificação de ordenação e retorna um elemento do conjunto. Os Nulls são ignorados no cálculo. O parâmetro deve
ser uma constante com valor numérico entre 0 e 1 pois corresponde a um percentual. A cláusula ORDER BY não possui
restrições de tipo. Para um determinado valor percentual P e de acordo com a ordenação, a função retornará o menor
valor CUME_DIST (com relação à mesma especificação de ordenação) que seja maior ou igual ao parâmetro P.
RANK
Calcula o posicionamento (rank) de um valor em um grupo de valores. As linhas com valores iguais recebem a
mesma classificação. Calcula a posição de uma linha hipotética identificada pelos argumentos da função com
relação a uma ordenação. Os argumentos da função devem ser constantes. O número de expressões no argumento
e na cláusula Order By devem ser idênticos pois serão considerados 1 para 1 posicionalmente.
Listagem 2.64 – PERCENTILE_CONT, PERCENTILE_DISC, RANK
SQL> SELECT PERCENTILE_CONT(.5) WITHIN GROUP (ORDER BY VL_SAL ASC) CONT_ASC,
2 PERCENTILE_CONT(.5) WITHIN GROUP (ORDER BY VL_SAL DESC) CONT_DESC,
3 PERCENTILE_DISC(.5) WITHIN GROUP (ORDER BY VL_SAL ASC) DISC_ASC,
4 PERCENTILE_DISC(.5) WITHIN GROUP (ORDER BY VL_SAL DESC) DISC_DESC,
5 RANK(290) WITHIN GROUP (ORDER BY VL_SAL ASC NULLS FIRST) RK_ASC,
6 RANK(290) WITHIN GROUP (ORDER BY VL_SAL DESC NULLS FIRST) RK_DESC
7 FROM FUNC
8 WHERE CD_DEPTO = 'A02';
Para as funções Percentile, passamos como parâmetro um percentual e recebemos como resultado um valor relativo
à expressão de ordenação (no nosso caso VL_SAL), ou seja, elas funcionam de forma inversa à da função CUME_DIST.
Nos quatro exemplos passamos como parâmetro 50%. Uma vez que nestas funções os valores NULLS são eliminados,
a quantidade de linhas úteis passa a ser 6 e 50%, ou seja, o centro da lista corresponde a duas linhas, uma linha
com valor 100 e uma linha com valor 200 (tanto ascendentemente quanto descendentemente).
Para Percentile_Cont, uma vez que não conseguimos obter uma única linha (veja a seguir o cálculo de RN), devemos
aplicar a fórmula (CRN – RN) * (valor da expressão da linha em FRN) + (RN – FRN) * (valor da expressão da linha em CRN).
Como primeiro passo devemos determinar a linha de interesse, ou seja, RN = (1 + P * (N – 1)); no nosso caso, temos
que RN = (1 + 0.5 * (6 – 1)), onde P é o percentual (0.5) e N a quantidade de linhas (6). O resultado é RN=3.5. O valor
de CRN (o menor inteiro maior que RN) é 4. O valor de FRN (o maior inteiro menor que RN) é 3.
Uma vez que RN representa a linha desejada e a linha 3.5 não existe, devemos aplicar a fórmula mostrada acima e
obter o valor de salário.
Valor = (4 – 3.5) * (salário na linha FRN = 100) + (3.5 – 3) * (salário na linha CRN = 200)
Valor = 0.5 * 100 + 0.5 * 200 = 50 + 100 = 150
Para Percentile_Disc não é feita a interpolação, o valor retornado será o primeiro em relação às linhas que atendem
ao percentual, ou seja, será o valor da linha FRN. Neste caso temos valores diferentes para ordenações diferentes.
Para ordenação ascendente, o valor correspondente à linha 3 (FRN) é 100 e para ordenação descendente, o valor
correspondente à linha 3 (FRN) é 200.
A função Rank dá a posição relativa do valor na lista ordenada considerando o valor inserido no grupo; desta
forma o primeiro resultado 8 considera a seguinte lista: null (1), null (2), 100 (3), 100 (4), 100 (5), 200 (6), 200 (7),
290 (8) e 300 (9). No segundo exemplo, temos a posição 4 para o valor de salário 290, o que significa: null (1), null
(2), 300 (3), 290 (4), 200 (5), 200 (6), 100 (7), 100 (8) e 100 (9).
As funções a seguir calculam a regressão linear de um conjunto de duplas de números. Podem ser usadas como
funções de agregação ou analíticas.
60 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
REGR_AVGX
Avalia a média da variável independente, representada por <expressão2> da regressão linear. Ela calcula
AVG(<expressão2>) após a eliminação das linhas em que <expressão1> ou <expressão2> não possuem valor (NULL).
REGR_AVGY
Avalia a média da variável dependente, representada por <expressão1> da regressão linear. Ela calcula
AVG(<expressão1>) após a eliminação das linhas em que <expressão1> ou <expressão2> não possuem valor (NULL).
REGR_COUNT
Retorna um inteiro que representa o número de pares não nulos usados para cálculo da regressão linear.
REGR_INTERCEPT
Retorna o y-intercept da regressão linear. Após a eliminação dos pares de nulos o seguinte cálculo é realizado:
AVG(<expr1>) – REGR_SLOPE(<expr1>, <expr2>) * AVG(<expr2>)
REGR_R2
Retorna o coeficiente de determinação para a regressão. Após a eliminação dos pares nulos o seguinte cálculo é realizado:
IF VAR_POP (<expr2>) = 0 THEN NULL;
ELSIF VAR_POP (<expr1>) = 0 AND VAR_POP(<exp2>) <> 0 THEN 1;
ELSIF VAR_POP(<expr1>) > 0 AND VAR_POP(<expr2>) != 0 THEN POWER(CORR(<expr1>,<expr2>),2);
ELSE NULL;
REGR_SLOPE
Retorna o “declive” da linha. Após a eliminação dos pares nulos, o seguinte cálculo é realizado:
COVAR_POP(<expr1>, <expr2>) / VAR_POP(<expr2>)
REGR_SXX
As funções Regr_Sxx, Regr_Sxy e Regr_Syy são funções auxiliares usadas para calcular várias estatísticas. Após a
eliminação dos pares nulos, o seguinte cálculo é realizado:
REGR_COUNT(<expr1>, <expr2>) * VAR_POP(<expr2>)
REGR_SXY
As funções Regr_Sxx, Regr_Sxy e Regr_Syy são funções auxiliares usadas para calcular várias estatísticas. Após a
eliminação dos pares nulos, o seguinte cálculo é realizado:
REGR_SYY
As funções Regr_Sxx, Regr_Sxy e Regr_Syy são funções auxiliares usadas para calcular várias estatísticas. Após a
eliminação dos pares nulos, o seguinte cálculo é realizado:
CURSO COMPLETO00✦ 61
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Neste exemplo analisaremos apenas os três primeiros, pois os demais podem ser conferidos diretamente pelas
fórmulas descritas.
Dentro da nossa massa de dados apenas seis linhas (veja REGR_COUNT) possuem valor em ambas as colunas
VL_SAL e NR_CARGO; portanto, este será a quantidade utilizada para cálculo em todas as funções deste grupo.
Para a média de NR_CARGO (calculada por REGR_AVGX) devemos levar em consideração os valores (8 + 32 + 32
+ 45 + 65 + 21) divididos por 6. Para a média de VL_SAL (calculada por REGR_AVGY devemos levar em consideração
os valores (100 + 100 + 100 + 200 + 200 + 300) divididos por 6.
STDDEV
Retorna o desvio padrão simples da <expressão>. Pode ser usada tanto como função de agregação como função analítica.
Retorna 0 quando houver apenas uma linha de entrada. O resultado corresponde à raiz quadrada da variância.
STDDEV_POP
Calcula o desvio padrão populacional e retorna a raiz quadrada da variância populacional. Pode ser usada como
uma função de agregação ou como função analítica. Retorna Null se o retorno da função VAR_POP for Null.
STDDEV_SAMP
Calcula o desvio padrão simples cumulativo e retorna a raiz quadrada da variância simples. Pode ser usada como
função de agregação ou analítica. Utiliza a função VAR_SAMP como entrada. Se o resultado de VAR_SAMP for null,
seu retorno também será null.
SUM
Retorna o somatório dos valores de <expressão>. Pode ser usada como função de agregação ou analítica.
VAR_POP
Retorna a variância populacional de um conjunto de linhas após descartar as linha nulas. Pode ser usada como função
de agregação ou analítica. Se o conjunto de entrada for vazio, o resultado será null. O seguinte cálculo é realizado:
(SUM(<expr> ** 2) - SUM(<expr>) ** 2 / COUNT(<expr>)) / COUNT(<expr>)
VAR_SAMP
Retorna a variância simples de um conjunto de linhas após descartar as linhas nulas. Pode ser usada como função
de agregação ou analítica. Se o conjunto de entrada for vazio, o resultado será null. O seguinte cálculo é realizado:
(SUM(<expr> ** 2) - SUM(<expr>) ** 2 / COUNT(<expr>)) / (COUNT(<expr>) – 1)
Esta função é similar à função VARIANCE, exceto que para um elemento a função VARIANCE retorna 0 e VAR_SAMP
retorna null.
62 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
VARIANCE
Retorna a variância dos valores de <expressão>. Pode ser usada como função de agregação ou analítica. O cálculo
da variância é feito da seguinte forma:
IF <quantidade de linhas> = 1 THEN 0
ELSE VAR_SAMP(<expr>)
SDEV SDEV_POP SDEV_SAMP SUM SUM_DIST SUM_2 SUM**2 VAR_POP VAR_SAMP VAR
------ -------- --------- ----- -------- ------ -------- ------- -------- ------
81,65 74,536 81,65 1000 600 200000 1000000 5555,6 6666,7 6666,7
Começando pelo fim, confirmamos que o resultado da função VARIANCE e VAR_SAMP são iguais pois a quantidade
de linhas informadas para a função foi maior que 1. A função SUM, presente no resultado, pode ser utilizada
juntamente com a cláusula DISTINCT indicando que somente valores diferentes de salário serão somados (100 +
200 + 300). Para conferirmos os valores das demais funções devemos apenas realizar os cálculos descritos acima,
considerando o resultado de SUM_2 como sendo sum(vl_sal 2) e SUM**2 como sendo sum(vl_sal)2. A quantidade
de linhas para salário é 6.
Neste primeiro exemplo, as linhas da tabela de funcionários foram divididas em grupos com relação à coluna
Código do Departamento. Desta forma, o grupo com cd_depto valendo ‘A00’ possui soma total dos salários igual
a 19.665,13 e é composto de quatro linhas. Já o grupo com cd_depto valendo ‘C01’ possui soma total dos salários
igual a 10.162,08 e é composto de três linhas. Das informações apresentadas, a única que não se apresenta como
argumento de uma função de grupo é a coluna em relação à qual foi feito o grupamento, uma vez que seu valor é
igual em todas as linhas do grupo.
CURSO COMPLETO00✦ 63
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
ERRO na linha 1:
ORA-00979: não é uma expressão GROUP BY
Na Listagem 2.68, foi feita uma tentativa de se obter uma informação unitária do conjunto de linhas de cada
grupo. A mensagem de erro indica que isto não é possível, uma vez que aquela coluna não se encontra presente na
cláusula Group By.
REGRA
Não é possível a utilização direta de colunas não referenciadas na cláusula Group By na lista de seleção. Estas
colunas só podem ser usadas como argumento das funções de grupo.
Na lista de seleção, podemos utilizar outras expressões que resultem no mesmo valor para todas as linhas de cada
grupo, tais como: valores constantes, as funções User, Userid, Sysdate, cálculos envolvendo as colunas sobre as
quais está sendo feito o grupamento (ver Listagem 2.65).
No exemplo da Listagem 2.69, foram selecionadas da tabela Funcionário as linhas em que a coluna in_sexo possuía
o valor ‘M’. Este conjunto de linhas foi separado de acordo com o valor de cargo. Para cada um dos grupos foram
aplicadas as funções Max, Min e Avg.
Observe que a restrição presente na cláusula Where faz referência a uma informação da tabela Func. Imagine que
desejássemos obter apenas as linhas em que a média salarial fosse superior a R$ 2.500,00.
A utilização desta restrição na cláusula Where causa um erro (ORA-00934: a função de grupo não é permitida aqui)
que indica que não podemos fazer referência ao resultado do grupamento antes de o grupamento ser realizado.
A CLÁUSULA HAVING
A cláusula Having vem resolver o problema apresentado no exemplo da Listagem 2.70. Ela se aplica após o
grupamento ter sido realizado. Assim, poderemos efetuar uma restrição sobre as colunas calculadas durante a
execução da cláusula Group By.
A cláusula Having não precisa ser usada em conjunto com a cláusula Group By. Se ela for usada sem a cláusula Group By, toda a tabela será
tratada como um (1) grupo.
64 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
3 FROM FUNC
4 WHERE IN_SEXO = 'M'
5 GROUP BY NR_CARGO
6 HAVING AVG(VL_SAL) > 2500;
Na Listagem 2.71, a restrição foi feita sobre a soma salarial que não foi mencionada na cláusula Select. Neste
exemplo, foram selecionados outros tipos de informação que podem aparecer na lista de seleção de um grupamento.
Observe que em todos os exemplos apresentados o resultado de um grupamento sempre trouxe as linhas ordenadas
pela coluna (ou colunas) sobre a qual foi feito o grupamento. Isto ocorre porque o Oracle pode executar uma operação
de ordenação para separar as linhas selecionadas de acordo com os grupos. O resultado desta operação pode trazer os
dados na ordem ascendente do grupo ou não. A cláusula Group By tem a finalidade de grupar as linhas e não ordenar.
A cláusula a ser usada para garantir que o resultado será apresentado na ordem desejada é a cláusula Order By.
ROLLUP
É uma extensão da cláusula Group By que, além de executar as funções de agregação para os grupos estabelecidos
na cláusula, executa as mesmas funções de agregação para subgrupos compostos das n-1, n-2, ..., até 0 expressões
incluídas na cláusula Rollup e retorna uma única linha sumariada para cada um destes subgrupos. Tem grande
utilidade na construção de subtotais.
Observe na Listagem 2.73 que o grupamento desenvolvido retorna 1 (uma) linha para cada grupo depto-cargo-sexo.
Adicionalmente a estas linhas, a cláusula Rollup acrescentou uma linha para cada grupo depto-cargo, outra linha
para cada depto, contendo um sumário ou subtotal referente às linhas grupadas, e, finalmente, um total geral.
CURSO COMPLETO00✦ 65
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
23 linhas selecionadas.
Poderíamos considerar que esta cláusula fez uma operação de grupamento para cada quebra do grupo. Esta operação
de agregação para cima (para estabelecer sumários menos detalhados) é chamada de Rollup.
A quantidade de grupos que a cláusula Rollup gerará será igual à quantidade de expressões incluídas na cláusula + 1. No caso do exemplo,
incluímos na cláusula Rollup três expressões; portanto, obtivemos quatro tipos de totais.
CUBE
Também é uma extensão da cláusula Group By que, além de executar as funções de agregação para os grupos
estabelecidos na cláusula Cube, executa as mesmas funções de agregação para subgrupos compostos dos valores de
todas as possíveis combinações das expressões (informadas para Cube) e retorna uma única linha sumariada para
cada subgrupo. Podemos nos utilizar desta característica para a montagem de produtos matriciais (cross-tab).
Observe na Listagem 2.74 que utilizamos o mesmo grupamento do exemplo anterior, porém obtivemos um número
maior de linhas no resultado.
66 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
E11 54 F 2625
E11 54 2625 ** acumulado de depto= E11 e cargo = 54 independente de sexo
E11 F 2625 **** acumulado de depto = E11 e sexo=F independente de cargo
E11 M 1775 **** acumulado de depto = E11 e sexo=M independente de cargo
E11 4400 ****** acumulado de depto = D21 independente de sexo e cargo
E21 52 M 1995
E21 52 1995 ** acumulado de depto= E21 e cargo = 52 independente de sexo
E21 54 M 4999
E21 54 4999 ** acumulado de depto= E21 e cargo = 54 independente de sexo
E21 M 6994 **** acumulado de depto = E21 e sexo=M independente de cargo
E21 6994 ****** acumulado de depto = D21 independente de sexo e cargo
48 M 1775 ## acumulado de cargo=48 e sexo = M independende de depto
48 1775 #### acumulado de cargo = 48 independente de sexo e depto
52 F 1725 ## acumulado de cargo=52 e sexo = F independende de depto
52 M 5740 ## acumulado de cargo=52 e sexo = M independende de depto
52 7465 #### acumulado de cargo = 52 independente de sexo e depto
54 F 4850 ## acumulado de cargo=54 e sexo = F independende de depto
54 M 7467 ## acumulado de cargo=54 e sexo = M independende de depto
54 12317 #### acumulado de cargo = 54 independente de sexo e depto
56 F 3617 ## acumulado de cargo=56 e sexo = M independende de depto
56 3617 #### acumulado de cargo = 56 independente de sexo e depto
F 10192 ###### acumulado de sexo = F independente de cargo e depto
M 14982 ###### acumulado de sexo = M independente de cargo e depto
25174 >>>>>>>> Total Geral
42 linhas selecionadas.
Isso ocorreu porque a cláusula Cube, além de calcular a função SUM(vl_sal) para o grupo depto-cargo-sexo, também
gerou somas para os subgrupos depto-cargo, depto-sexo, cargo-sexo, só cargo, só depto, só sexo e um total geral.
A quantidade de grupos que a cláusula Cube gerará será igual a 2 elevado à quantidade de expressões incluídas na cláusula. No caso do exemplo,
incluímos na cláusula Cube três expressões; portanto, obtivemos 8 tipos de totais.
CURSO COMPLETO00✦ 67
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
16 linhas selecionadas.
Nos exemplos da Listagem 2.75, simplificamos o grupamento para que o resultado fosse mais claro.
Observe que, os valores de Grouping_id correspondem à concatenação dos diversos resultados da função Group-
ing na ordem em que ocorrem. Considerando-se uma formação (Grouping só retorna zero ou 1), temos que o valor
de Grouping_id seria calculado (no exemplo) como GRP_DEPTO * 21 + GRP_SEXO * 20.
Desta forma as linhas em que GRP_DEPTO recebeu 0 e GRP_SEXO recebeu 1 calcularam GRP_ID com 1 (0 * 21 + 1 * 20).
As linhas em que GRP_DEPTO recebeu 1 e GRP_SEXO recebeu 0 calcularam GRP_ID com 2 (1 * 21 + 0 * 20). Finalmente
a linha em que tanto GRP_DEPTO quanto GRP_SEXO receberam valor 1 calcularam GRP_ID com 3 (1 * 21 + 1 * 20).
9 linhas selecionadas.
Neste último exemplo utilizamos a função GROUP_ID para identificar as linhas de D11 e D21 que aparecem duas
vezes (com os mesmos valores em toda a linha) em função de um grupamento duplo entre cd_depto e a extensão
Rollup de cd_depto com in_sexo.
EXERCÍCIOS
2.25) Deseja-se uma lista contendo matrícula, nome e salário de todos os funcionários que ganhem mais que a
média salarial da empresa.
2.26) Produza uma lista contendo a média salarial, total de salários e quantidade de linhas selecionadas por
departamento, de todos os funcionários que tenham em seu primeiro nome a letra “A”.
2.27) Produza uma lista contendo o cargo, a média salarial e o número de funcionários grupados por cargo para os
departamentos D01, D11, D21 e E11. Todos os cargos com menos de três funcionários devem ser excluídos do
resultado. A lista deve vir ordenada descendentemente por média salarial.
68 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
2.31) Deseja-se uma lista (cd_mat, vl_sal, nr_git) dos funcionários mais graduados (com maior grau de instrução)
da empresa.
2.32) Deseja-se saber qual departamento possui maior média salarial da empresa.
2.33) Deseja-se saber quais os funcionários (matrícula, nome, sobrenome e data de admissão) que possuem mais de
nove anos de empresa.
2.34) Deseja-se uma relação contendo matrícula, nome completo e idade do funcionário na data de admissão.
2.35) Deseja-se o total salarial e a média salarial por quantidade de anos trabalhados e por cargo dos funcionários
que tenham menos de 10 anos de casa e cargo superior a 50. Devem ser informados, simultaneamente, totais por
cargo e por quantidade de ano, além de um acumulado geral.
2.36) Deseja-se uma tabulação contendo a quantidade de funcionários por sexo e por quantidade de anos na
empresa. Além dos dados individuais, deseja-se totalizações por sexo, por quantidade de anos e por sexo e quantidade
de anos simultaneamente.
2.37) Repita os dois exercícios anteriores de tal forma que os totais provenientes da quebra sejam identificados
diferentemente dos valores gerados em função de valores NULL.
2.38) Um novo funcionário foi contratado na empresa, o cargo definido para ele foi 55 e seu salário deve ser 2700,
2800 ou 2900. Determine qual dos três salários se enquadra nos requisitos estabelecidos pela gerência de projetos:
a) Seu salário deve ser superior ao quarto maior salário dentre os funcionários com o mesmo cargo.
b) Pelo menos 60% do grupo de funcionários com o mesmo cargo deve ter salário menor que o dele.
2.39) Para determinar o percentual de promoção dos funcionários, o departamento Pessoal solicitou:
a) o menor, o maior e a média salárial do menor cargo
b) o menor, o maior e a média salárial do maior cargo
2.40) O novo diretor do Departamento pessoal deseja estabelecer faixas salariais para futuro enquadramento dos
funcionários. Com este objetivo deseja obter informações sobre a distribuição salarial atual. Considerando-se
intervalos de 20% (.20, .40, .60, .80 ou 1) deseja-se saber qual o salário correspondente.
INTRODUÇÃO
Funções são programas que realizam determinadas ações, podem receber parâmetros e retornam pelo menos um resultado.
As funções de que trataremos neste item são as escalares. Uma função é dita escalar quando se aplica a um valor (e
não a um conjunto, como as funções de grupo).
Dentre as funções predefinidas pelo SQL do Oracle9i, o maior conjunto se refere às funções escalares. Estas built-
ins se aplicam à(s) coluna(s) de uma única linha, desta forma produzindo um resultado por linha.
CURSO COMPLETO00✦ 69
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Podemos subdividir este grupo de funções de acordo com o tipo de parâmetro e resultado gerado, da seguinte forma:
♦ Numéricas – São aquelas que recebem parâmetros numéricos e geram resultados numéricos. Podem ser
subdivididas em Trigonométricas e Numéricas Simples.
♦ Alfanuméricas – Geram resultados alfanuméricos. Recebem parâmetros alfanuméricos e (algumas) numéricos.
♦ Alfanuméricas que Retornam Valores Numéricos – Recebem parâmetros alfanuméricos e geram resultados numéricos.
♦ Datas – Realizam a manipulação de datas.
♦ Conversão – Realizam conversão de tipo.
♦ Outras – Características diversas.
Para efeito de simplicidade usaremos, na exemplificação, sempre que possível, valores constantes e a tabela Dual (do dicionário de dados do
Oracle), pois possui apenas uma linha.
NUMÉRICAS SIMPLES
Recebem parâmetros numéricos e geram resultados numéricos. Foram, para efeito de sintaxe, grupadas de acordo
com a quantidade de parâmetros recebidos: um parâmetro, dois parâmetros obrigatórios e um parâmetro obrigatório
e um opcional. Serão apresentadas em ordem alfabética.
ABS
Retorna o valor absoluto do argumento.
BITAND
Calcula uma operação de AND entre os bits dos dois argumentos. Os valores do argumento devem ser não
negativos e inteiros.
Esta função não determina o tipo de seu resultado; portanto, pode ser necessário que a utilizemos dentro de outra
função (TO_NUMBER, por exemplo) para garantir que o retorno será numérico.
CEIL
Retorna o menor inteiro maior ou igual ao argumento.
70 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
EXP
Retorna e elevado à n-ésima potência (de acordo com o valor do argumento), onde e = 2.71828183....
Na Listagem 2.77, observamos que a função Ceil, quando recebe um argumento negativo, aparentemente produz
um resultado incorreto; porém, devemos nos lembrar que –2 é maior que –2.5 e, portanto, o resultado está correto.
Para entendermos o resultado da função Bitand devemos nos lembrar da formação binária dos números envolvidos:
1 = 0 * 2**2 + 0 * 2**1 + 1 * 2**0 2 = 0 * 2**2 + 1 * 2**1 + 0 * 2**0
5 = 1 * 2**2 + 0 * 2**1 + 1 * 2**0 6 = 1 * 2**2 + 1 * 2**1 + 0 * 2**0
Uma operação AND somente produzirá resultado diferente de zero se ambos os bits correspondentes forem 1.
Neste caso BITAND(1, 2) fará um AND entre (001) e (010). Como não ocorre empate (de 1 e 1 na mesma posição
correspondente), o resultado é zero. Observe o resultado entre 6 (110) e 2(010).
Esta função pode ser interessante quando utilizada junto com DECODE.
FLOOR
Retorna o maior inteiro menor que ou igual ao argumento.
LN
Retorna o logaritmo natural do argumento, que deve ser maior que zero.
LOG
Retorna o logaritmo de <expressão2> na base <expressão1>. A base (<expressão1>) deve ser qualquer número
positivo diferente de 0 e 1 e <expressão2> deve ser maior que zero.
MOD
Retorna o resto da divisão de <expressão1> por <expressão2>. Se o valor do divisor (<expressão2>) for zero, retornará
o próprio valor de <expressão1>.
POWER
Retorna <expressão1> elevada à <expressão2> potência. Os argumentos <expressão1> e <expressão2> podem assumir
qualquer valor, porém se <expressão1> for negativo, <expressão2> deve ser inteira.
CURSO COMPLETO00✦ 71
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
ROUND
Retorna <expressão1> arredondado para um determinado número (<expressão2>) de posições à direita do ponto decimal.
Se <expressão2> for omitida, o segundo argumento será considerado zero. Se <expressão2> for negativa, serão arredondados
os dígitos à esquerda do ponto decimal. Como restrição temos que <expressão2> deve ser um valor inteiro.
A função Round realiza a ação de arredondamento se o valor do número a ser omitido for maior ou igual a 5. Caso
contrário, a casa decimal será simplesmente omitida do resultado.
SIGN
Retorna o sinal da <expressão>. Desta forma, se a <expressão> for menor que zero, o valor retornado será –1. Se a
<expressão> for igual a zero, o valor retornado será zero e se a <expressão> for maior que zero, o valor retornado será 1.
SQRT
Retorna a raiz quadrada do argumento. A função retorna um resultado real. O argumento (<expressão>) deve ser positivo.
TRUNC
Retorna <expressão1> truncado para um determinado número (<expressão2>) de posições à direita do ponto deci-
mal. Não há arredondamento; as posições superiores ao valor de <expressão2> são apenas omitidas do resultado. Se
<expressão2> for omitida, o segundo argumento será considerado zero. Se <expressão2> for negativa, serão considerados
os dígitos à esquerda do ponto decimal. Como restrição temos que <expressão2> deve ser um valor inteiro.
WIDTH_BUCKET
Esta função permite a construção de um histograma de intervalos de mesmo tamanho. Os parâmetros <menor_valor>
e <maior_valor> determinam o menor valor do histograma e o maior valor do histograma, que será subdividido
em tantos intervalos quanto determinarmos em <num_buckets> (deve ser uma constante inteira e positiva). Os
intervalos são do tipo fechado-aberto, o que significa que o valor inferior de cada intervalo estará incluído naquele
grupo e o valor superior não. A <expressão> deve ser do tipo numérica ou datetime.
72 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Se forem encontrados valores abaixo do <menor_valor>, o Oracle criará um Bucket 0 onde acomodará todos estes
valores. Caso ocorra o oposto, ou seja, valores acima do <maior_valor> será criado um Bucket <num_buckets> + 1
que acomodará todos os valores superiores.
VL_SAL FAIXAS
------ ------
2045 6
2134 6
2218 6
2225 6
2380 6
2384 6
2468 7
2528 7
2537 7
2615 7
2625 7
2738 7
2774 7
2842 8
2876 8
2925 8
2975 8
2984 8
18 linhas selecionadas.
TRIGONOMÉTRICAS
Recebem parâmetros numéricos e geram resultados numéricos. Estão relacionadas com cálculos matemáticos de
trigonometria. Levam em consideração que o círculo trigonométrico tem o tamanho de 1. Os argumentos relativos
a ângulos são fornecidos em radianos.
Para transformarmos um ângulo (em graus) para radianos, devemos dividi-lo por 57.29578.
ACOS
Retorna o arco do cosseno (argumento) informado.
O argumento (<expressão>) deve estar no intervalo de -1 a 1. O resultado será fornecido em radianos e varia de 0 a p (pi).
CURSO COMPLETO00✦ 73
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
ASIN
Retorna o arco do seno (argumento) informado.
O argumento (<expressão>) deve estar no intervalo de –1 a 1. O resultado será fornecido em radianos e varia de
-p/2 a p/2 (pi / 2).
ATAN
Retorna o arco da tangente (<expressão>) informada.
O resultado será fornecido em radianos e varia de -p/2 a p/2 (pi / 2).
ATAN2
Retorna o arco da tangente (<expressão1>/<expressão2>) informada.
O resultado será fornecido em radianos e varia de -p a p (pi). Observe que ATAN2 (<expressão1>, <expressão2>)
produz o mesmo resultado que ATAN (<expressão1>/<expressão2>).
COS
Retorna o cosseno do ângulo (<expressão>) informado, o qual deve ser expresso em radianos.
COSH
Retorna o cosseno hiperbólico do ângulo (<expressão>) informado, o qual deve ser expresso em radianos.
74 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
SIN
Retorna o seno do ângulo (<expressão>) informado, o qual deve ser expresso em radianos.
SINH
Retorna o seno hiperbólico do ângulo (<expressão>) informado, o qual deve ser expresso em radianos.
TAN
Retorna a tangente do ângulo (<expressão>) informado, o qual deve ser expresso em radianos.
TANH
Retorna a tangente hiperbólica do ângulo (<expressão>) informado, o qual deve ser expresso em radianos.
ALFANUMÉRICAS
Recebem parâmetros alfanuméricos e/ou numéricos e geram resultados alfanuméricos.
A sintaxe foi organizada de acordo com a quantidade e tipo dos parâmetros recebidos, porém serão apresentadas
em ordem alfabética.
Os exemplos, preferencialmente, usarão constantes para melhor entendimento e a tabela Dual (do dicionário de
dados do Oracle) por conter apenas uma linha.
CHR
Retorna o caracter correspondente a <valor>. Esta transformação pode ser feita de acordo com o charset do banco
de dados ou de acordo com o national charset .
Se a opção Using Nchar_Cs não for utilizada, a transformação de <valor> no caracter equivalente será feita de
acordo com o charset do banco de dados.
CURSO COMPLETO00✦ 75
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Se a opção Using Nchar_Cs for utilizada, a transformação de <valor> no caracter equivalente será feita de acordo
com o national charset .
O charset e o national charset são especificados no momento da criação do banco de dados e não podem ser
modificados posteriormente. O charset determina o conjunto de valores válidos para armazenamento. O national
charset determina o conjunto de valores válidos para colunas do tipo Nchar, Nvarchar, etc.
CONCAT
Retorna um texto resultante da concatenação de <texto1> com <texto2>. O resultado é equivalente ao uso do
operador || (concatenação).
INITCAP
Retorna <texto> com a primeira letra de cada palavra em maiúscula e as demais em minúsculas. O espaço em
branco determina o término de uma palavra e o início de outra. Podemos utilizar também outros caracteres não
alfanuméricos com este fim.
76 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
LOWER
Retorna o <texto> com todas as letras em minúsculas.
LPAD
Retorna <texto1> completado à esquerda com os caracteres definidos em <texto2> para o comprimento definido
por <tamanho>. Caso <texto2> não seja informado, será completado com brancos.
Se <texto1> tiver comprimento maior que o valor de <tamanho>, a string resultante será truncada para o
comprimento definido por <tamanho>.
LTRIM
Retorna <texto> sem os caracteres presentes em <conjunto>, encontrados à esquerda. A busca, que se processa da
esquerda para a direita, é interrompida quando for encontrado o primeiro caracter não pertencente a <conjunto>.
Caso <conjunto> não seja fornecido, o caracter pesquisado será o branco.
NLS_INITCAP
Retorna <texto> com a primeira letra de cada palavra em letra maiúscula e as demais em minúsculas. A função
considera que as palavras estão separadas por brancos ou caracteres não alfanuméricos.
O segundo parâmetro (<nlsparam>) só pode conter a sintaxe NLS_SORT = <sort>, onde <sort> pode ser um nome
de idioma ou BINARY. A seqüência de ordenação para determinadas línguas também apresenta requerimentos
específicos para colocação de maiúsculas e minúsculas.
INITCAP NLS_INI
------- -------
Ijsland IJsland
NLS_LOWER
Retorna <texto> com todas as letras em minúsculas.
O segundo parâmetro (<nlsparam>) só pode conter a sintaxe NLS_SORT = <sort>, onde <sort> pode ser um nome
de idioma ou BINARY. A seqüência de ordenação para determinadas línguas também tem requerimentos específicos
para colocação de maiúsculas e minúsculas.
CURSO COMPLETO00✦ 77
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
NLS_UPPER
Retorna <texto> com todas as letras em maiúsculas.
O segundo parâmetro (<nlsparam>) só pode conter a sintaxe NLS_SORT = <sort>, onde <sort> pode ser um nome
de idioma ou BINARY. A seqüência de ordenação para determinadas línguas também tem requerimentos específicos
para colocação de maiúsculas e minúsculas.
NLSSORT
Retorna a string de bytes usada para ordenar <texto>.
O segundo parâmetro (<nlsparam>) só pode conter a sintaxe NLS_SORT = <sort>, onde <sort> pode ser um nome
de idioma ou BINARY. Se omitirmos o segundo parâmetro, esta função usa a ordenação default em uso na sessão.
Se especificarmos BINARY, ela retorna <texto>.
DEFAULT BINARY
---------------------------- --------
1E37140001010100 43484100
REPLACE
Retorna <texto> substituindo cada aparecimento de <string1> no <texto> por <string2>. Se <string2> não for
informada, cada aparecimento de <string1> em <texto> será removido.
RPAD
Retorna <texto1> completado à direita com os caracteres definidos em <texto2> para o comprimento definido por
<tamanho>. Caso <texto2> não seja informado, será completado com brancos.
Se <texto1> tiver comprimento maior que o valor de <tamanho>, a string resultante será truncada para o
comprimento definido por <tamanho>.
RTRIM
Retorna <texto> sem os caracteres presentes em <conjunto>, encontrados à direita. A busca, que se processa da
direita para a esquerda, é interrompida quando for encontrado o primeiro caracter não pertencente a <conjunto>.
Caso <conjunto> não seja fornecido, o caracter pesquisado será o branco.
78 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
SOUNDEX
Retorna uma string que represente o som de <texto>. A função retorna fonemas iguais para palavras que tenham
o mesmo som em inglês.
SUBSTR
Retorna uma parte de <texto>, começando no caracter definido por <posição> e com comprimento de <tamanho>.
A função realiza ações diferentes de acordo com o valor de <posição>. Se <posição> for maior que zero, o Oracle
iniciará a contagem a partir do caracter mais à esquerda. Se <posição> for zero, o comprimento será considerado 1
(o caracter mais à esquerda). Finalmente, se <posição> for menor que zero, o Oracle iniciará a contagem a partir do
caracter mais à direita.
O parâmetro <tamanho>, quando omitido, indica que será considerado o comprimento determinado por <posição>
até o final da string. Por outro lado, se <tamanho> for menor que 1, será retornado Null.
Se para os parâmetros numéricos forem fornecidos valores em ponto flutuante haverá transformação com truncamento.
TRANSLATE
Retorna <texto> substituindo cada uma das ocorrências de <conjunto1> pela ocorrência correspondente em <conjunto2>.
O relacionamento entre os caracteres de <conjunto1> e <conjunto2> é posicional. Se o comprimento de <conjunto2>
for inferior ao comprimento de <conjunto1>, os caracteres sem correspondência serão omitidos do resultado.
TREAT
Esta função altera o tipo declarado para a expressão. Uma vez que ela está ligada à definição de tipo, somente será
estudada no Capítulo 4.
TRIM
A função TRIM retira caracteres iniciais (leading), finais (trailing) ou ambos de uma string de caracteres. Se o
conjunto de caracteres a serem pesquisados (Trim_Character) ou o conjunto de caracteres onde a pesquisa será
feita (Trim_Source) forem literais, deverão ser apresentados entre aspas simples.
CURSO COMPLETO00✦ 79
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Nos exemplos da Listagem 2.94, usamos um conjunto de caracteres numéricos do qual retiramos os zeros iniciais
e finais, e um conjunto de caracteres alfanuméricos (literais) do qual retiramos os brancos iniciais e finais. Se não
especificarmos o Trim_Character, o default é branco.
Se especificarmos LEADING, o Oracle remove qualquer caracter inicial (lado esquerdo) igual ao Trim_Character.
Se, por outro lado, especificarmos TRAILING, o Oracle remove qualquer caracter final (lado direito) igual ao
Trim_Character.
Se especificarmos BOTH ou omitirmos as três indicações, o Oracle remove tanto os caracteres do lado esquerdo
quanto os do lado direito que sejam iguais ao Trim_Character.
TRIM(TRA
--------
@@@TESTE
TRIM(LEA
--------
TESTE@@@
UPPER
Retorna <texto> com todas as letras maiúsculas.
TRANS UPPER
----- --------------------
1M230 TEXTO EM MAIÚSCULAS
A sintaxe foi organizada de acordo com a quantidade e tipo dos parâmetros recebidos, porém serão apresentadas
em ordem alfabética.
Os exemplos, preferencialmente, usarão constantes para melhor entendimento e a tabela Dual (do dicionário de
dados do Oracle) por conter apenas uma linha.
80 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
ASCII
Retorna a representação decimal, no charset do banco de dados, para o primeiro byte de <texto>. Se o charset do
banco de dados for ASCII, esta função retornará um valor ASCII. Se o banco de dados possuir um charset EBCDIC,
esta função retornará o valor EBCDIC correspondente.
INSTR
Retorna a posição da n-ésima ocorrência de <texto2> dentro de <texto1>. A ocorrência desejada é fornecida pelo
parâmetro <ocorrência>. A posição inicial de pesquisa é dada por <posição>. Se <posição> for negativa, a pesquisa
se dará da direita para a esquerda.
Observe na Listagem 2.98 que, quando <posição> é negativa, o posicionamento é feito da direita para a esquerda, a
ocorrência é contabilizada da direita para a esquerda, mas a posição resultante é fornecida da esquerda para a direita.
CURSO COMPLETO00✦ 81
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
LENGTH
Retorna o comprimento de <texto> em caracteres.
DATAS
Realizam manipulação de datas.
A sintaxe foi organizada de acordo com a quantidade e tipo dos parâmetros recebidos, porém serão apresentadas
em ordem alfabética (exceto Sysdate e SessionTimezone).
Os exemplos, preferencialmente usarão constantes para melhor entendimento e a tabela Dual (do dicionário de
dados do Oracle) por conter apenas uma linha.
Em algumas das funções de data, podemos passar um texto no lugar do parâmetro <data>. O Oracle fará a conversão
usando a função To_Date com o formato de acordo com o padrão em uso na estação do usuário. Nas funções Trunc
e Round, esta ação não é possível.
SYSDATE
Retorna a data e hora correntes do banco de dados. O formato de apresentação depende do idioma e do território
em uso na estação do usuário. Não é afetado pelas modificações de zona de tempo da sessão do usuário.
ADD_MONTHS
Retorna a data <data1> adicionada de <meses>. O parâmetro <meses> deve ser inteiro, porém pode ser negativo. Se
o mês resultante da soma tiver menos dias que o dia calculado ou se o dia fornecido no parâmetro <data>
corresponder ao último dia do mês, o dia resultante será o último dia do mês calculado. Caso contrário, será
exatamente o dia fornecido no parâmetro <data1>.
82 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
CURRENT_DATE
Retorna a data corrente na zona de tempo (meridiano) da sessão do usuário. Caso não venhamos a modificar
características de meridiano, esta função e a Sysdate serão similares.
SESSIONTIMEZONE
Apresenta o posicionamento em relação ao fuso horário da sessão do usuário. Os fusos horários são calculados em
relação ao meridiano de Greenwich. Se caminharmos para o lado esquerdo do Planisfério (para este teste é convenien-
te que você tenha um à mão) estaremos subtraindo horas em relação à hora oficial de Greenwich. Se caminharmos
para a direita estaremos somando.
CURSO COMPLETO00✦ 83
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
Observe na Listagem 2.101 que Sysdate não foi afetada pela modificação na zona de tempo da sessão do usuário.
CURRENT_TIMESTAMP
Retorna a data corrente e hora na zona de tempo da sessão do usuário. Apresenta, adicionalmente, a time zone da
sessão do usuário. A precisão determina fração de segundos (o default é 6, o limite é 9). A diferença entre esta função
e LocalTimestamp é que é apresentado o valor da zona de tempo enquanto que Localtimestamp não apresenta.
DBTIMEZONE
Retorna o valor da zona de tempo do banco de dados. O formato do retorno pode ser um offset (‘[ + | - ] TZH:TZM’)
ou um nome de região, de acordo com a especificação da data na criação do banco de dados. A tabela
V$Timezone_Names contém uma lista das zonas de tempo por nome.
EXTRACT
Extrai uma determinada informação de tempo (por exemplo ano, mês, dia, segundo, etc.) de um campo do tipo
datetime ou interval. A tabela V$Timezone_Names contém uma lista das zonas de tempo por nome.
FROM_TZ
Converte um valor de timestamp sem zona de tempo para um valor de timestamp com zona de tempo solicitada.
O formato do parâmetro <time_zone_value> deve ser um offset (‘[ + | - ] TZH:TZM’). Não é feita conversão de hora,
apenas anexada a especificação de zona de tempo ao timestamp fornecido como parâmetro.
LOCALTIMESTAMP
Retorna a data e hora corrente na zona de tempo da sessão.
84 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
Neste exemplo observamos que a função Extract pode ser usada em variáveis (no caso usamos as funções SYSDATE
e CURRENT_TIMESTAMP) no formato DATE ou TIMESTAMP. Para que possamos extrair valores como
TIMEZONE_HOUR, o parâmetro deve possuir especificação de zona de tempo; caso contrário receberemos erro
(teste com CURRENT_DATE em vez de CURRENT_TIMESTAMP).
Observe que o resultado da função FROM_TZ não fez nenhuma modificação na informação passada como parâmetro,
e o que muda realmente é o tipo de dado retornado, que passa a ser TIMESTAMP WITH TIME ZONE. O primeiro
parâmetro passado para a função tem de ser, necessariamente, um timestamp. No exemplo usamos o formato
TIMESTAMP <string>. A string deve estar no formato: ‘yyyy-mm-dd hh24:mi:ss’. Poderíamos ter usado,
alternativamente, um valor que já fosse um timestamp, por exemplo Localtimestamp. Receberemos erro se tentarmos
outro tipo de valor, por exemplo uma data ou timestamp with time zone.
A diferença entre a função Current_Timestamp e a função Localtimestamp pode ser visualizada no exemplo. A
função Current_Timestamp é do tipo timestamp with time zone, enquanto que Localtimestamp é do tipo timestamp.
LAST_DAY
Retorna a data do último dia do mês obtido do parâmetro <data>.
MONTHS_BETWEEN
Retorna o número de meses entre <data1> e <data2>. Se <data1> e <data2> fizerem referência ao mesmo dia do
mês ou ao último dia do mês, o resultado é sempre inteiro. Caso contrário, o Oracle calcula a fração do resultado
baseado em meses de 31 dias e considera a diferença de horas entre as datas.
NEW_TIME
O parâmetro <data1> é fornecido na zona horária <zona1> e será convertido para a data e hora correspondente em <zona2>.
Abreviatura Descrição
CURSO COMPLETO00✦ 85
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
LASTDAY ULTIMO DIA MESMO DIA OUTRO DIA BST EST NST
------------------- ---------- --------- --------- ----- ----- -----
28/02/1999 00:00:00 2 5 5,03226 23:00 05:00 06:30
NEXT_DAY
Retorna a data correspondente a <dia da semana> que seja posterior a <data1>. A língua em que o parâmetro <dia
da semana> deve ser fornecido depende do idioma em uso na sessão.
NEXT_DAY NEXT_DAY
-------- --------
02/01/99 24/02/99
ROUND
Retorna o parâmetro <data> arredondado para o formato especificado. Caso <formato> não seja informado, haverá
o arredondamento para o dia mais próximo.
Observe que a opção WW transformou a data 17/02/1999 em 19/02/1999. Se pegarmos um calendário de 1999
veremos que o dia primeiro de janeiro caiu em uma sexta-feira. Desta forma a sexta-feira mais próxima do dia 17/
02 (que é quarta-feira) corresponde ao dia 19/02 (sexta-feira).
SYS_EXTRACT_UTC
Extrai o UTC (Coordinated Universal Time, ou seja, Greenwich Mean Time) de um parâmetro do tipo datetime
with time zone, isto é, determina a data e hora no meridiano de Greenwich.
SYSTIMESTAMP
Retorna a data do sistema, incluindo frações de segundo e a time zone do banco de dados.
86 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
TRUNC
Retorna o parâmetro <data> truncado para o formato especificado. Caso <formato> não seja informado, haverá o
truncamento para o dia mais próximo.
Formato Descrição
TZ_OFFSET
Retorna a time zone offset correspondente ao valor passado no parâmetro baseado na data que o comando é executado.
No exemplo da Listagem 2.107 podemos observar que a função Sys_Extract_Utc recalcula o parâmetro recebido,
fornecendo o resultado no timestamp de Greenwich. O parâmetro deve ser um timestamp com zona de tempo.
CONVERSÃO
Realizam conversão de tipo.
A sintaxe foi organizada de acordo com a quantidade e tipo dos parâmetros recebidos, porém serão apresentadas
em ordem alfabética.
Os exemplos, preferencialmente usarão constantes para melhor entendimento e a tabela Dual (do dicionário de
dados do Oracle) por conter apenas uma linha.
CURSO COMPLETO00✦ 87
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
88 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
ASCIISTR
Recebe um argumento string em qualquer charset e retorna uma string ASCII no charset do banco de dados. O valor
retornado contém somente caracteres que são válidos em SQL e a contrabarra ( \ ).
BIN_TO_NUM
Converte um vetor de bits no seu número equivalente. Cada argumento desta função deve representar um bit
(somente valores 0 e 1 e são permitidos) no vetor.
CAST
Uma conversão de tipo coleção para outro tipo coleção. Podemos converter uma coleção anônima (o resultado de
uma subquery) ou uma coleção identificada (um Varray ou uma Nested Table) em uma outra coleção que seja
compatível. Para que seja aceita a conversão, os elementos de ambas as coleções devem ser de mesmo tipo. Se o
resultado da subquery retornar diversas linhas, devemos indicar isso usando a palavra Multiset. Como esta função
trata de coleções, ela somente será estudada no Capítulo 4.
CHARTOROWID
Converte o valor de <texto> para o formato interno de Rowid.
Cada linha no banco de dados possui um endereço. Este endereço é chamado de Rowid. Ele é composto de quatro
informações: data object number (número associado a cada segmento do banco de dados), block (bloco de dados
do arquivo que contém a linha), row (número da linha dentro do bloco) e file (indica o arquivo – database file –
onde se acha a linha). Este assunto será mais explorado no tópico Administrando o Banco de Dados.
Cada tabela (exceto Index Table) possui uma pseudocoluna chamada Rowid. Ela não é criada pelo DBA, não é
apresentada quando usamos o comando Describe (do SQL*Plus), mas pode ser listada através de um comando Select.
No exemplo acima o cedilha maiúsculo corresponde ao valor C7 (ou 199) e A com til corresponde ao valor C3(195). A
contrabarra indica a presença de um valor em hexadecimal na seqüência. A string de bits informada na função
BIN_TO_NUM resultou no valor 25 (2**4 + 2**3 + 2**0). A conversão do texto Rowid para formato interno pode ser útil
na programação, principalmente em linguagens que não possuam variáveis com o tipo ROWID (como por exemplo C).
COMPOSE
Recebe um argumento string em qualquer tipo de dados e retorna uma string Unicode em sua forma normalizada
no mesmo charset da entrada. O parâmetro de entrada poderá estar no formato CHAR, VARCHAR2, NCHAR,
NVARCHAR2, CLOB ou NCLOB.
CONVERT
Converte <texto> para o <charset _destino>. O <charset _db> corresponde ao charset em que <texto> está armazenado.
O valor default é o charset do banco de dados.
CURSO COMPLETO00✦ 89
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
DECOMPOSE
Recebe um argumento string em qualquer tipo de dados e retorna uma string Unicode após decomposição canônica
no mesmo charset da entrada. O parâmetro de entrada poderá estar no formato CHAR, VARCHAR2, NCHAR,
NVARCHAR2, CLOB ou NCLOB.
HEXTORAW
Converte <texto>, que deve ser um valor hexadecimal, para o formato interno Raw.
NUMTODSINTERVAL
Converte um numérico para o formato de armazenamento INTERVAL DAY TO SECOND. O primeiro parâmetro
deve ser numérico. O segundo parâmetro pode ser uma string do tipo CHAR, VARCHAR2, NCHAR ou NVARCHAR2
e deve corresponder a um dos seguintes valores: ‘DAY’, ‘HOUR’, ‘MINUTE’, ‘SECOND’ (case sensitive).
NUMTOYMINTERVAL
Converte um numérico para o formato de armazenamento INTERVAL YEAR TO MONTH. O primeiro parâmetro
deve ser numérico. O segundo parâmetro pode ser uma string do tipo CHAR, VARCHAR2, NCHAR ou NVARCHAR2
e deve corresponder a um dos seguintes valores: ‘YEAR’, ‘MONTH’ (case sensitive).
No exemplo da Listagem 2.109 podemos observar o uso das funções NUMTODSINTERVAL e NUMTOYMINTERVAL.
No primeiro parâmetro passamos um valor numérico (inteiro ou decimal) e no segundo informamos a unidade do
primeiro parâmetro. Observe que 125 meses corresponde a 10 anos e 5 meses (NUMTOYMINTERVAL).
RAWTOHEX, RAWTONHEX
Rawtohex converte <raw> para seu texto correspondente em hexadecimal e Rawtonhex converte para hexadeci-
mal em NVARCHAR2.
RAWTOHEX(IMAGEM)
----------------
7D9A8B
90 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
ROWIDTOCHAR, ROWIDTONCHAR
A função RowidToChar converte valores de Rowid para caracteres (ver CharToRowid). O tamanho da string resultante
é sempre de 18 caracteres. A função RowidToNchar converte um valor de Rowid para NVARCHAR2 com comprimento
de 18 caracteres.
ROWIDTOCHAR
------------------
AAAACsAABAAAATmAAA
TO_CHAR
Esta primeira forma sintática da função TO_CHAR só possui um parâmetro. Seu objetivo é converter valores
NCHAR, NVARCHAR2, CLOB ou NCLOB para o charset do banco de dados.
TO_CHAR
A função To_Char possui duas sintaxes, uma para efetuar a conversão de datas para o formato caracter e outra para
converter o formato numérico para caracter.
As especificações de formato variam de acordo com a conversão desejada. Se o formato não for especificado, será
usado o formato padrão da sessão do usuário. Esse formato é determinado pelos parâmetros da National Language
Support em uso.
Formato Descrição
CURSO COMPLETO00✦ 91
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
continuação
Formato Descrição
TM “Text minimum”. Retorna (em formato decimal) o menor número de caracteres possível. O default é TM9 que retorna o número em formato
fixo (a menos que exceda 84 caracteres, neste caso retornado em notação científica).
U Mostra o símbolo Euro (ou outro dual), associado ao parâmetro NLS_DUAL_CURRENCY.
V Multiplica o valor por 10n, onde n corresponde ao número de 9’s após v.
X Retorna o valor hexadecimal do número.
Os formatos numéricos podem ser usados na To_Char com parâmetro numérico, ou na To_Number.
Os formatos de data podem ser usados na To_Char com parâmetro data, ou na To_Date.
TO_CLOB
Converte o valor passado como parâmetro (que pode ser uma coluna NCLOB ou outro tipo de caracter) para
CLOB. O parâmetro pode ser do tipo CHAR, NCHAR, VARCHAR2, NVARCHAR2, CLOB ou NCLOB.
TO_DATE
Converte <texto> para o formato interno de data. O parâmetro <formato> indica em que formato está o texto. Se
o formato for omitido, o Oracle assumirá que o texto está no formato de data padrão da sessão do usuário.
Tabela 2.04 – Formatos de data válidos para To_Char, To_Date, To_Timestamp e To_Timestmap_Tz
Formato Descrição
92 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
continuação
Formato Descrição
CURSO COMPLETO00✦ 93
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
♦ São admitidos três sufixos: TH (acrescenta ao número as letras TH), SP (apresenta o número por extenso) e SPTH
ou THSP (apresenta o ordinal do número por extenso). Todos os três sufixos retornam o valor em inglês.
♦ O parâmetro <nlsparam> pode conter o texto Nls_Date_Language = <idioma> para os formatos de data e pode
conter os textos Nls_Numeric_Characters = ‘’<d><g>’’ Nls_Currency = ‘’<texto>’’ Nls_Isso_Currency = <territorio>
para os formatos numéricos, onde <d> indica o separador decimal e <g> o separador de grupo.
DATA TIMESTAMP
------------------------- ---------------
18 FEVEREIRO, 2049, 23:00 13:37:07,000000
TO_DSINTERVAL
Converte uma string (no formato CHAR, VARCHAR2, NCHAR ou NVARCHAR2) para INTERVAL DAY TO SEC-
OND. O único parâmetro NLS que pode ser utilizado é NLS_NUMERIC_CHARACTERS.
TO_LOB
Essa função converte valores Long ou Long Raw armazenados em colunas do tipo Long para valores Lob. Podemos
aplicar essa função somente a uma coluna Long ou Long Raw e somente na lista de seleção de uma subquery de um
comando INSERT.
SQL> commit;
Validação completa.
Como primeiro passo de nosso teste, criamos uma tabela contendo uma coluna do tipo Long e a preenchemos
com dados (Listagem 2.114).
Como segundo passo, criamos uma tabela similar à primeira, porém utilizando o tipo de dados Clob.
Fizemos, em seguida, uma tentativa de realizar uma conversão implícita da coluna Long para a coluna Lob e
recebemos o erro reportado na Listagem 2.115.
94 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
SQL> COMMIT;
Validação completa.
TO_MULTI_BYTE
Retorna <texto> com todos os seus caracteres single-byte convertidos para o seu correspondente multi-byte. Qualquer
caracter single-byte que não tenha correspondência é incluído na string de saída no formato single-byte.
TO_NCHAR
Converte uma string do tipo CLOB ou NCLOB a partir do charset do banco de dados para o national charset . Esta
função é equivalente a TRANSLATE…USING NCHAR_CS.
TO_NCHAR
Converte uma string no formato DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL
TIME ZONE, INTERVAL MONTH TO YEAR ou INTERVAL DAY TO SECOND a partir do charset do banco de dados
para o national charset .
TO_NCHAR
Converte um número para uma string NVARCHAR2. O formato e correspondente nlsparam pode ser relativo a
DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE, INTERVAL MONTH
TO YEAR ou INTERVAL DAY TO SECOND.
TO_NCLOB
Converte valores CLOB em uma coluna LOB ou outro tipo de string para valores NCLOB. O Oracle converte a
coluna LOB a partir do charset do banco de dados para o national charset .
TO_NUMBER
Converte <texto> para o valor numérico correspondente. O parâmetro <formato> tem a finalidade de indicar
como o texto está formatado.
CURSO COMPLETO00✦ 95
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
TO_SINGLE_BYTE
Retorna <texto> com todos os seus caracteres multi-byte convertidos para single-byte. Se houver caracteres multi-
byte na string sem correspondente single-byte, ele permanecerá multi-byte no resultado.
TO_TIMESTAMP
Converte um texto de tipo CHAR, VARCHAR2, NCHAR ou NVARCHAR2 no formato timestamp para um valor
interno de timestamp. O parâmetro nls especifica o formato do texto.
TO_TIMESTAMP_TZ
Converte um texto de tipo CHAR, VARCHAR2, NCHAR ou NVARCHAR2 para um valor interno de TIMESTAMP
WITH TIME ZONE. O parâmetro nls especifica o formato do texto.
TO_YMINTERVAL
Converte um texto de tipo CHAR, VARCHAR2, NCHAR ou NVARCHAR2 para um valor interno de INTERVAL
YEAR TO MONTH.
TRANSLATE USING
Converte o texto no charset especificado, que pode ser charset do banco de dados ou national charset . Ambos são
especificados quando o banco de dados é criado e não podem ser mudados posteriormente. O national charset está
relacionado aos tipos de dados Nchar, Nvarchar2, etc.
UNISTR
Converte uma string em qualquer charset e a retorna em Unicode. Para incluirmos UCS2 codepoints devemos
preceder o caracter por uma contrabarra ( \ ). Para incluirmos a própria contrabarra ( \ ) devemos precedê-la com
outra contrabarra.
TMST TMSTZ YM
--------------------------- ---------------------------------- -------------
12/05/32 10:32:45,067000000 12/05/32 10:32:00,000000000 -03:00 +000000022-10
OUTRAS
Neste grupo de funções, veremos algumas funções que não se enquadram na classificação anterior. Tanto a sintaxe
quanto a apresentação das funções serão feitas em ordem alfabética.
Sempre que possível, nos exemplos, usaremos a tabela Dual (do dicionário de dados do Oracle).
BFILENAME
Retorna um locator associado a um arquivo binário presente no ambiente servidor. O objetivo é estabelecer uma
ligação entre um arquivo fora do banco de dados e uma coluna no banco de dados. Esta coluna é do tipo Bfile.
96 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
COALESCE
Esta função retorna a primeira expressão não nula da lista. Se todas as expressões forem Null, o resultado será Null.
DECODE
Compara <expressão> a cada valor do parâmetro <compara> e retorna <resultado> se a expressão fornecida for
igual ao parâmetro <compara>. Se toda a lista for pesquisada e <expressão> não for igual a nenhum dos parâmetros
<compara> fornecidos, o resultado da função é o conteúdo do parâmetro <default>, que se não for informado
causará um resultado Null.
DUMP
Retorna um valor VARCHAR2 contendo o tipo de dado, comprimento (em bytes) e a representação interna da expressão.
CURSO COMPLETO00✦ 97
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
O parâmetro <formato> indica o formato no qual o valor da expressão deve ser apresentado. Os formatos válidos
estão presentes na Tabela 2.05 a seguir.
Formato Descrição
Os argumentos <inicio> e <comprimento> podem ser combinados para determinar que parte da representação
interna deve ser apresentada. O default é retornar a representação interna inteira na notação decimal.
EMPTY_BLOB OU EMPTY_CLOB
Retorna um locator vazio. Pode ser usado para dar valor inicial a uma variável ou coluna. Empty significa que o
Lob está inicializado mas não preenchido com dados.
EXISTSNODE
Esta função determina se existe uma estrutura hierárquica (passada como parâmetro) no documento especificado.
O retorno da função será zero se a estrutura não existir e > 0 se for encontrada.
98 ✦00CURSO COMPLETO
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
CAPÍTULO 2 – SQL E SQL*PLUS
5 <Numero>60</Numero>
6 <Andar>7</Andar>
7 <Bairro>Centro</Bairro>
8 <Cidade>Rio de Janeiro</Cidade>
9 <Estado>RJ</Estado>
10 </Endereço>
11 '));
1 linha criada.
ROWNUM NÓ
------- -------
1 1
No exemplo da Listagem 2.121 criamos uma tabela com uma coluna do tipo SYS.XMLTYPE (verifique este Datatype
no Capítulo 10). Como este tipo de coluna não é um tipo de dado escalar, é um objeto, para incluirmos a informação
precisamos da ajuda do método CREATEXML.
Um documento XML pode ter uma estrutura como podemos observar no exemplo. Diretamente subordinado a
<Endereco> encontramos diversos elementos (<Bairro>, <Cidade>, <Estado>, etc.).
A função Existsnode verifica a existência de uma estrutura. No nosso caso poderíamos ter procurado por qualquer
elemento subordinado a endereço. O único cuidado é que a informação é case sensitive, e desta forma o parâmetro
‘/endereco/numero’ não é encontrado.
O estudo sobre objetos (necessário para que você consiga entender o teste) será realizado no Capítulo 4.
EXTRACT
A função Extract retorna um objeto do tipo XML que contenha a hierarquia pesquisada. Podemos, então, aplicar
um método deste tipo de objeto e visualizar o conteúdo, por exemplo.
TEXTO
-------------------
<Numero>60</Numero>
GREATEST
Retorna a maior <expressão> da lista de valores. Todas as expressões após a primeira são convertidas para o tipo de
dado da primeira antes de a comparação ser feita. O Oracle não completa as expressões para que fiquem do mesmo
tamanho. Expressões do tipo caracter levarão em consideração o charset do banco de dados.
LEAST
Retorna a menor <expresão> da lista de valores. Todas as expressões após a primeira são convertidas para o tipo de
dado da primeira antes de a comparação ser feita. O Oracle não completa as expressões para que fiquem do mesmo
tamanho. Expressões do tipo caracter levarão em consideração o charset do banco de dados.
NLS_CHARSET _DECL_LEN
Retorna o comprimento da coluna em caracteres no charset fornecido. O parâmetro <tamanho> é fornecido em
bytes. O parâmetro <charset _id> corresponde ao número identificador do charset .
CURSO COMPLETO00✦ 99
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE I: FUNDAMENTOS
NLS_CHARSET _ID
Retorna o número identificador do charset fornecido pelo parâmetro <texto>. A palavra-chave Char_cs retorna o
identificador do charset do banco de dados. A palavra chave Nchar_cs retorna o identificador do national charset .
Nomes de charset inválidos causam o retorno de Null.
NLS_CHARSET _NAME
Retorna o nome do charset correspondente ao número identificador fornecido por <charset _id>. Se o identificador
fornecido não tiver correspondência com um charset válido, a função retorna Null.
NULLIF
Esta função compara <expressão1> e <expressão2>. Se forem iguais será retornado Null, e caso contrário será
retornada <expressão1>.
NVL
Se <expressão1> for Null, a função retornará <expressão2>, e caso contrário será retornado o próprio valor de <expressão1>.
Preferencialmente as duas expressões devem ser de mesmo tipo. Caso não sejam, o Oracle converterá <expressão2>
para o tipo de <expressão1>. O tipo de dado retornado será o tipo de <expressão1> (exceto se <expressão1> for de
um dos tipos de dado caracter, pois neste caso o tipo de dado do retorno será Varchar2).
NVL2
Se <expressão1> não for null retornará <expressão2>. Se <expressão1> for null, retornará <expressão3>. O
argumento <expressão1> pode ser de qualquer tipo. Os argumentos <expressão2> e <expressão3> podem ser de
qualquer tipo exceto Long.
SYS_CONNECT_BY_PATH
Válido apenas para queries hierárquicas. Retorna o caminho do valor da coluna a partir do nó raiz. Tanto o parâmetro
<coluna> quanto o parâmetro <texto> podem ser dos tipos CHAR, VARCHAR2, NCHAR e NVARCHAR2.
9 linhas selecionadas.
O resultado deste exemplo será melhor compreendido depois que estudarmos hierarquias, neste capítulo.
SYS_CONTEXT
Retorna o valor do atributo informado como parâmetro e associado com o “context namespace”.
A tabela a seguir apresenta os atributos válidos para a função considerando-se o namespace default USERENV.
Podemos criar nossos próprios namespaces usando o package DBMS_SESSION.
O objetivo de um namespace é criarmos uma área associada à sessão do usuário para armazenamento de informações,
que podem vir a ser usadas em aplicações.
Formato Descrição
SYS_CONTEXT('USERENV','NLS_TERRITORY')
--------------------------------------
BRAZIL
SYS_DBURIGEN
Esta função recebe como parâmetro uma ou mais colunas (ou atributos) e, opcionalmente, um ROWID e gera uma
URL do tipo DBUriType para uma coluna ou row. Podemos usar o URL para recuperar um documento XML no
banco de dados.
Todas as colunas (ou atributos) devem residir na mesma tabela. Devem fazer referência a valores que identifiquem
uma linha (PK ou UK). Por default a URL aponta para um documento XML formatado. Se desejarmos que a URL
aponte somente o texto do documento, devemos especificar o parâmetro ‘text( )’.
SYS_GUID
Gera e retorna um identificador único global (RAW) composto de 16 bytes.
URI(URL, SPARE)
-----------------------------
GUID
-----------------------------
DBURITYPE('/PUBLIC/DEPTO/ROW[CD_DEPTO=''D11'']/CD_DEPTO', NULL)
8E164AF4A9A54218AA21144834232696
DBURITYPE('/PUBLIC/DEPTO/ROW[CD_DEPTO=''A00'']/CD_DEPTO', NULL)
DF067895682041B9842A20C3DFFC0FF2
SYS_TYPEID
Esta função retorna o typeid do mais específico tipo do parâmetro. Uma vez que esta função está totalmente ligada
à concepção de objetos, somente será estudada no Capítulo 4.
SYS_XMLGEN
Esta função retorna uma instância do tipo SYS.XMLType contendo um documento XML. A <expressão> pode ser
um valor escalar, um tipo definido pelo usuário ou uma instância de um XMLType.
Se <expressão> for escalar o resultado será um elemento XML contendo o valor escalar. Se a expressão for um tipo
do usuário, a função mapeará os atributos do tipo do usuário para elementos XML. Se <expressão> for uma instância
XMLType, a função incluirá o documento em um elemento XML cuja tag default é ROW.
SYS_XMLGEN('TESTE')()
---------------------
XMLTYPE()
Observe que o resultado desta função é um objeto do tipo XMLType e não podemos visualizar diretamente seu
conteúdo. Para isto devemos usar um método que liste seu conteúdo. Veja o próximo exemplo.
Esta função será melhor compreendida depois do estudo sobre objetos no Capítulo 4.
SYS_XMLAGG
Agrega todos os documentos XML (ou fragmentos) representados por <expressão> e produz um único documento
XML. Ele adiciona um novo elemento com o nome default de ROWSET.
SYS_XMLAGG(SYS_XMLGEN('TESTE')).GETCLOBVAL()
--------------------------------------------
<?xml version=”1.0"?>
<ROWSET>
<ROW>teste</ROW>
</ROWSET>
UID
Retorna um número inteiro que corresponde e identifica o usuário corrente.
USER
Retorna o usuário corrente com o tipo de dado Varchar2.
USERENV
Retorna informações sobre a sessão corrente.
Os valores válidos para o parâmetro <opção> são os seguintes:
♦ Isdba – Retorna True se a sessão corrente foi habilitada como DBA. Caso contrário, retorna False.
♦ Language – Retorna a linguagem, território e charset atualmente em uso na sessão.
♦ Terminal – Retorna um identificador do sistema operacional para o terminal em uso na sessão corrente.
♦ Sessionid – Retorna o identificador de auditoria da sessão. Para que este valor seja significativo, o parâmetro de
inicialização do banco de dados Audit_Trail deve estar com o valor True.
♦ Lang – Retorna a abreviação ISO para o nome da linguagem.
♦ Instance – Retorna o número identificador da instância corrente.
♦ Entryid – Retorna o identificador da entrada na trilha de auditoria. Para que este valor seja significativo, o
parâmetro de inicialização do banco de dados Audit_Trail deve estar com o valor True.
♦ Client_Info – Retorna até 64 bytes de informação obtidos da sessão do usuário e gravados pelo pacote
DBMS_APPLICATION_INFO.
VSIZE
Retorna o número de bytes usados para armazenar a representação interna de <expressão>.
NLS_LANGUAGE TAMANHO
---------------------------------------- -------------------
BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252 8
EXERCÍCIOS
2.41) Deseja-se uma relação contendo matrícula, nome, idade atual e tempo de serviço para aqueles funcionários
que tenham sido admitidos com menos de 21 anos.
2.42) Deseja-se uma relação contendo nome, sobrenome, data e hora do nascimento, mês e ano de admissão em
algarismos romanos e o salário editado (contendo moeda) para todos os funcionários que possuam mais de quatro
vogais em seu sobrenome.
2.43) Deseja-se uma relação contendo nome completo do funcionário (centralizado sob o título Nome), data de
nascimento formatada com hora, minuto e segundo (alinhado à direita sob o título Nascimento), o código do
departamento (alinhado à esquerda e de tal forma que o título Depto seja apresentado).
2.44) Deseja-se uma relação contendo o nome e sobrenome de todos os funcionários, sendo que todas as vogais
devem ser apresentadas em minúsculas e as consoantes em maiúsculas. As informações sobre salário devem ser
criptografadas da seguinte forma: 22 será transformado na letra Z; 0,1 serão transformados na letra A; 2,3 serão
transformados na letra B; 4,5,6 serão transformados na letra C, e os demais números na letra D.
2.45) Deseja-se uma relação contendo nome completo do funcionário usando letras maiúsculas e minúsculas, sexo
por extenso, número de dias entre a data de admissão e o último dia do mês da data corrente e o valor do salário
(se houver definido; caso contrário, 0) formatado. Esta relação deve ser ordenada do menor salário para o maior.
2.46) Deseja-se uma relação com as seguintes informações: linguagem em uso no banco de dados, o conjunto de
caracteres nacionais e o do banco de dados, o endereço da linha do funcionário com matrícula 100, a data de hoje
(com dia, mês e ano por extenso), a data da próxima quinta-feira, o seno, cosseno e tangente do ângulo de 30 graus.
2.47) Deseja-se realizar o enquadramento dos funcionários da empresa em uma faixa salarial. O grupo será dividido
em 10 faixas iguais, sendo o intervalo salarial apreciável entre 1500 e 5000. Determine a faixa de cada funcionário.
2.48) Deseja-se obter o valor numérico e nome da zona de tempo da sessão e do banco de dados.
2.49) Receba um timestamp como parâmetro e sua zona de tempo e retorne este timestamp convertido para o
horário de Greenwich.
INTRODUÇÃO
São programas que têm a finalidade de efetuar cálculos sobre um conjunto de linhas. Elas diferem das funções de
agregação no sentido de retornarem múltiplas linhas para cada grupo.
O grupo de linhas é chamado de “window” e é definido pela cláusula “analytic”. A janela determina o intervalo de
linhas para que os cálculos sejam realizados para a “current row”. Esta janela pode ser definida em função de
quantidade de linhas ou em função de um intervalor lógico (por exemplo tempo).
As funções analíticas correspondem à penúltima etapa de execução de uma query (a última corresponde à cláusula
ORDER BY). Desta forma as funções analíticas somente podem ser usadas na cláusula SELECT ou na ORDER BY.
O argumento para estas funções pode ser o nome de uma coluna ou uma expressão (combinação de nomes de
colunas, constantes ou outras funções).
A Tabela 2.07 a seguir relaciona todas as funções analíticas. Você vai observar que diversas funções desta lista já
apareceram, no grupo de funções de agregação. O que as torna analíticas é o uso da palavra chave OVER seguida
das cláusulas que aparecem no início da Sintaxe 2.26.
Avg (*) Corr (*) Covar_pop (*) Covar_samp (*) Count (*)
Cume_dist Dense_rank First First_value (*) Lag
Last Last_value (*) Lead Max (*) Min (*)
Ntile Percent_rank Percentile_cont Percentile_disc Rank
Ratio_to_report Regr_ (*) Row_number Stddev (*) Stddev_pop (*)
Stddev_samp (*) Sum (*) Var_pop (*) Var_samp (*) Variance (*)
Na lista acima as funções com (*) permitem a sintaxe completa da cláusula analítica.
♦ Current Row – se esta expressão for usada como ponto inicial indica que a “window” começa na linha ou valor
corrente (dependendo da especificação ROW ou RANGE, respectivamente). Neste caso o ponto final não pode
ser <value_expr> PRECEDING. Se especificado como ponto final, indica que a janela termina na linha corrente
ou valor (dependendo da especificação ROW ou RANGE, respectivamente). Neste caso o ponto inicial não pode
ser <value_expr> FOLLOWING.
♦ <value_expr> Preceding – se esta expressão for usada como ponto final, então o ponto inicial também deverá
ser <value_expr> Preceding. Se especificarmos ROWS, <value_expr> é um offset físico, numérico, positivo. Se
<value_expr> for usada como ponto de início deve identificar uma linha antes do ponto final. Se especificarmos
RANGE, <value_expr> corresponde a um offset lógico, numérico e positivo ou um intervalo literal. Somente
poderemos especificar uma expressão na cláusula ORDER BY e se <value_expr> for numérica, a <expressão> da
cláusula ORDER BY deve ser um NUMBER ou DATE. Se <value_expr> for um intervalo, a <expressão> da cláusula
ORDER BY deve ser do tipo DATE.
♦ Unbounded Following – indica que a janela termina na última linha da partição. Esta é uma especificação de
ponto final e não pode ser usada como ponto de início.
♦ <value_expr> Following – se esta expressão for usada como ponto inicial, então o ponto final também deverá
ser <value_expr> Following. Se especificarmos ROWS, <value_expr> é um offset físico, numérico, positivo. Se
<value_expr> for usada como ponto de início deve identificar uma linha antes do ponto final. Se especificarmos
RANGE, <value_expr> corresponde a um offset lógico, numérico e positivo ou um intervalo literal. Somente
poderemos especificar uma expressão na cláusula ORDER BY e se <value_expr> for numérica, a <expressão> da
cláusula ORDER BY deve ser um NUMBER ou DATE. Se <value_expr> for um intervalo, a <expressão> da cláusula
ORDER BY deve ser do tipo DATE.
♦ Partition By – com esta cláusula podemos particionar o resultado da query em grupos baseados em um ou mais
valores de <value_expr>. Se a cláusula for omitida, haverá somente um grupo. Podemos especificar mais de uma
função analítica na mesma query, cada uma delas contendo cláusulas Partition By próprias.
Se omitirmos o uso da cláusula “windowing”, o default é RANGE BETWEEN UNBOUNDED PRECEDING AND
CURRENT ROW.
Se você removeu as linhas criadas no banco de dados para teste das funções de grupo refaça o exemplo da Listagem
2.60 para que estas linhas sejam restauradas e possamos testar este novo grupo de funções.
FIRST_VALUE
É uma função analítica que retorna o primeiro valor em um conjunto ordenado de valores.
Esta função não pode ser usada por qualquer das outras funções analíticas como parâmetro (na <expressão>), isto
é, não pode ser aninhada.
Para entendermos o resultado temos dois passos a verificar: primeiramente devemos identificar qual a janela de
linhas para cada linha selecionada e como segundo passo devemos aplicar a função First_Value a cada linha.
Neste primeiro exemplo em função da restrição especificada UNBOUNDED PRECEDING e UNBOUNDED FOL-
LOWING, indicamos que todas as linhas selecionadas fazem parte da janela. Como a ordenação ocorre em função
de salário DESC, o primeiro cargo de cada grupo é o cargo 21, que por este motivo aparece em todos os resultados.
LAG
É uma função analítica que fornece o acesso a mais de uma linha de uma tabela simultaneamente sem um auto-join.
Supondo-se um conjunto de linhas retornadas da querie e uma posição de cursor, esta função fornece o acesso a uma
linha específica anterior a esta posição. Caso não seja especificado offset, o default é 1. O valor <default> é retornado
se o offset apontar para fora do escopo da “window”. Se este parâmetro não for informado, o default é Null.
Esta função não pode ser usada por qualquer das outras funções analíticas como parâmetro (na <expressão>), isto
é, não pode ser aninhada.
A função LAG não permite a sintaxe completa da cláusula “analytic”, e desta forma, não determinamos a janela.
No exemplo a função traz o salário anterior em relação à ordenação de NR_CARGO, ou seja, para o funcionário
com cargo 45 e salário 200, a função apresentou o salário 100 que corresponde ao salário do funcionário com cargo
32 (imediatamente anterior ao funcionário com cargo 45).
LAST_VALUE
É uma função analítica que retorna o último valor em um conjunto ordenado de valores.
Esta função não pode ser usada por qualquer das outras funções analíticas como parâmetro (na <expressão>), isto
é, não pode ser aninhada.
A “window” deste exemplo será formada (a cada linha) a partir da linha corrente mais uma linha para frente. Assim sendo
para a linha com cargo 8 a “window” é composta das linhas 8 e 45. Para 45 das linhas 45 e 65, para 65 das linhas 65 e 21,
etc. Uma vez que a função retorna o último valor da seqüência, será retornado o segundo valor de cada seqüência.
LEAD
É uma função analítica que fornece o acesso a mais de uma linha de uma tabela simultaneamente sem um auto-join.
Supondo-se um conjunto de linhas retornadas da query e uma posição de cursor, esta função fornece o acesso a uma
linha específica posterior a esta posição. Caso não seja especificado offset, o default é 1. O valor <default> é retornado
se o offset apontar para fora do escopo da “window”. Se este parâmetro não for informado, o default é Null.
Esta função não pode ser usada por qualquer das outras funções analíticas como parâmetro (na <expressão>), isto
é, não pode ser aninhada.
NTILE
É uma função analítica que divide um conjunto ordenado de dados em faixas, de acordo com <expressão> e
associa o número da faixa correspondente a cada linha. As faixas (buckets) são numeradas de 1 até <expressão>,
que deve ser uma constante positiva (para cada partição).
Se <expressão> for maior que o número de linhas as faixas serão preenchidas de uma em uma até a quantidade de
linhas, ficando as demais vazias.
Esta função não pode ser usada por qualquer das outras funções analíticas como parâmetro (na <expressão>), isto
é, não pode ser aninhada.
No exemplo a lista de cargos foi classificada de acordo com a quantidade de faixas recebida como parâmetro e da
ordenação estabelecida. Indicamos a determinação de 3 faixas. Os cargos foram distribuídos da seguinte forma: de
8 a 21 para faixa 1, de 32 a 45 para faixa 2 e de 65 em diante para faixa 3.
RATIO_TO_REPORT
É uma função analítica que calcula a razão entre um valor e a soma de um conjunto de valores. Se o parâmetro
<expressão> for null o resultado da função também será null.
O conjunto de valores é determinado por <query_partition_clause>. Caso seja omitido será considerada uma única
partição composta de todas as linhas retornadas pela query.
Esta função não pode ser usada por qualquer das outras funções analíticas como parâmetro (na <expressão>), isto
é, não pode ser aninhada.
Neste exemplo incluímos 3 departamentos para que pudéssemos realizar o particionamento dos dados em relação
a estes departamentos. Isto significa que o valor de salário para os funcionários do departamento A00 foi dividido
por 12850 (5272+4650+2925) para cálculo da razão (Ratio). Observe que, no caso dos funcionários do departamento
A02, os salários foram divididos por 1000 (que corresponde à soma dos salários não nulos), e isto significa que os
Nulls foram ignorados para efeito de cálculo.
ROW_NUMBER
É uma função analítica que associa um número único para cada linha à qual esta é aplicada (cada linha da partição
ou retornada pela query), na ordem especificada pela cláusula Order By, começando com 1.
Esta função não pode ser usada por qualquer das outras funções analíticas como parâmetro (na <expressão>), isto
é, não pode ser aninhada.
Neste exemplo o particionamento foi, novamente, realizado em relação a departamento, ou seja, temos três grupos,
um para cada departamento. Em cada grupo as linhas foram ordenadas por cargo e receberam um número crescente,
começando em 1 e incremento de 1.
CD_ NR_CARGO VL_SAL CUME_DIST DENSE_RANK FIRST LAST P_RANK P_CONT P_DISC RANK
--- -------- ------ --------- ---------- ----- ----- ------ ------ ------ -----
A02 8 100 ,3333 2 8 32 1 32 32 3
A02 32 100 1 1 8 32 0 32 32 1
A02 32 100 1 1 8 32 0 32 32 1
A02 45 200 ,5 2 45 65 1 55 45 2
A02 65 200 1 1 45 65 0 55 45 1
A02 21 300 1 1 21 21 0 21 21 1
A02 12 ,5 1 12 0 12 12 1
A02 1 2 12 1 12 12 2
Neste exemplo também utilizamos diversas funções de grupo. O resultado de cada uma delas deve ser analisado
considerando-se a cláusula analítica empregada.
♦ Cume_Dist – quando esta função é usada analiticamente ela não possui parâmetro, o valor comparado se refere ao
valor da expressão usada na cláusula ORDER BY aplicada à linha corrente. A cláusula Partition determina o universo
analisado. Desta forma, para a primeira partição temos 3 linhas (com salário 100). O valor 0.333 (1/3) indica que
1 linha (no caso a corrente) possui cargo <= 8. Para as linhas com cargo 32, 100% delas possuem cargo <= 32,
considerando-se como universo as linhas com salário 100. No exemplo existem 4 “universos”: o universo das
linhas com salário 100, o das linhas com salário 200, o das linhas com salário 300 e o das linhas com salário Null.
♦ Dense_Rank – quando esta função é usada analiticamente ela não possui parâmetro. O valor comparado ou classificado
é aquele informado na cláusula ORDER BY aplicado à linha corrente. Considerando-se o universo das linhas com
salário 100 temos que o cargo 8 é o segundo na classificação e 32 é o primeiro, pois utilizamos a expressão DESC.
♦ First – o uso desta função analiticamente levará em consideração um universo de valores específico para cada
linha analisada. Com relação ao grupamento das linhas com salário 100, usamos ordenação por cargo; desta
forma a linha classificada como FIRST para este primeiro grupo foi aquela com cargo 8. Sobre esta linha aplicamos
a função max(nr_cargo). Para que o resultado fique mais “lógico” preencha mais uma coluna da tabela FUNC,
para as linhas com cd_depto = ‘A02’ e utilize esta coluna na função max para que os resultados fiquem diferenciados.
♦ Last – o uso desta função analiticamente levará em consideração um universo de valores específico para cada linha
analisada. Com relação ao grupamento das linhas com salário 100, usamos ordenação por cargo; desta forma as
linhas classificadas como LAST para este primeiro grupo foram aquelas com cargo 32. Sobre esta linha aplicamos
a função min(nr_cargo). Para que o resultado fique mais “lógico” preencha mais uma coluna da tabela FUNC, para
as linhas com cd_depto = ‘A02’ e utilize esta coluna na função min para que os resultados fiquem diferenciados.
♦ Percent_Rank – quando esta função é usada analiticamente ela não possui parâmetro, o valor comparado se
refere ao valor da expressão usada na cláusula ORDER BY aplicada à linha corrente. A cláusula Partition determina
o universo analisado. Desta forma para a primeira partição temos 3 linhas (com salário 100). Uma vez que
ordenamos por cargo descendentemente temos a classificação da seguinte forma: os dois cargos 32 ocupam as
posições 0 e 1, o cargo 8 ocupa a posição 2. Como resultado encontramos o denominador de todas as frações
deste grupo como sendo 2. Para o cargo 8 a razão é 2/2 que produz como resultado 1. Para as linhas com cargo
32 obteremos a primeira classificação, ou seja, 0/2, que produz como resultado zero.
♦ Percentile_Cont – a diferença desta função quando analítica é o particionamento, que produzirá 4 (no nosso
caso) grupos de interresse. Como primeiro passo devemos determinar a linha de interesse, usaremos, para efeito
de análise, um grupo com quantidade par de linhas (o grupo com salário 200). Como RN = (1 + P * (N – 1)), no
exemplo da Listagem 2.139, temos que RN = (1 + 0.5 * (2 – 1)), onde P é o percentual (0.5) e N a quantidade de
linhas (2). O resultado é RN=1.5. O valor de CRN (o menor inteiro maior que RN) é 2. O valor de FRN (o maior
inteiro menor que RN) é 1. Uma vez que RN representa a linha desejada e a linha 1.5 não existe, devemos aplicar
a fórmula e obter o valor de cargo.
Valor = (2 – 1.5) * (cargo na linha FRN = 45) + (1.5 – 1) * (cargo na linha CRN = 65) = (0.5)*45 + (0.5)* 65 = 22.5
+ 32.5 = 55
♦ Percentile_Disc – não é feita a interpolação, o valor retornado será o primeiro em relação às linhas que atendem
ao percentual, ou seja, será o valor da linha FRN. Para o primeiro grupo (salário igual a 100), a linha RN é
possível de ser encontrada pois RN = (1 + 0.5 * (3 –1)), cujo resultado é 2. Desta forma a linha de interesse é
aquela com cargo 32. Para o segundo grupo já sabemos que RN = 1.5 e portanto temos duas linhas candidatas a
linha de interesse. Como a função não realiza interpolação, o resultado corresponde, sempre, à primeira linha,
e no caso deste grupo o cargo retornado para as duas é 45.
♦ Rank – a função Rank dá a posição relativa do valor na lista ordenada. A diferença em relação ao seu uso como
função de agregação é que podemos determinar o universo de valores. Para o primeiro grupo, o valor 8 ficou
classificado com 3 e os dois valores 32 como 1. No segundo grupo o valor 45 foi classificado como 2 e o valor 65
como 1. Esta classificação foi dada em função da ordenação descendente.
EXERCÍCIOS
2.50) Deseja-se saber (somente para os cargos 55) o salário do funcionário com grau de instrução imediatamente
inferior e superior ao seu; o resultado deve vir ordenado pelo nome do funcionário.
2.51) Ainda estudando uma forma de enquadramento salarial o departamento Pessoal deseja dividir o grupo em
três faixas, considerando ordenação decrescente de cargo. Apresente o enquadramento para os funcionários dos
departamentos A00 e D11 e ordene o resultado pelo nome do funcionário.
2.52) Deseja-se saber quanto o salário de cada funcionário representa (percentualmente) em relação ao seu próprio
departamento e em relação à empresa.
2.53) Deseja-se saber para cada funcionário:
a) o salário imediatamente anterior e posterior ao seu.
b) o cargo imediatamente anterior e posterior ao seu.
c) a classificação do salário do funcionário em relação à empresa e a seu departamento.
O resultado deve vir ordenado pelo nome do funcionário.
INTRODUÇÃO
A Álgebra Relacional possui oito operações (restrição, projeção, união, interseção, diferença, produto cartesiano,
junção e divisão) para operar conjuntos. Neste tópico, trataremos destas operações e como executá-las usando o
SQL do Oracle.
SELEÇÃO OU RESTRIÇÃO
A seleção é uma operação que restringe linhas. Supondo-se a existência de uma tabela F, as tuplas resultantes
seriam representadas por T Æ F [cargo=53]. Isto significa que o resultado T é uma relação que contém apenas as
rows de F que satisfazem à comparação indicada.
Para exemplificação, utilizaremos duas tabelas F e G criadas a partir da tabela Func, como apresentado na Listagem
2.140 a seguir.
No Oracle, a operação “Seleção ou Restrição” é resolvida pela presença de uma cláusula Where que obtenha apenas
as linhas desejadas.
Observe que utilizamos o * (asterisco) para obter todas as colunas, uma vez que estamos restringindo apenas as linhas.
PROJEÇÃO
A projeção é uma operação que restringe colunas. Considerando-se a existência de uma tabela F, as tuplas resultantes
seriam representadas por T → F [cargo, depto]. Isto significa que o resultado T é uma relação que contém apenas as
colunas indicadas (cargo e depto). As rows duplicadas que seriam criadas são eliminadas.
No Oracle, esta operação pode ser resolvida utilizando-se a cláusula Distinct aplicada às colunas desejadas.
Neste caso, a operação não estabelece restrição sobre as linhas selecionadas (não é definida nenhuma cláusula Where).
No SQL do Oracle, podemos realizar a combinação destas duas operações ao adicionarmos ao comando SELECT a
cláusula Where, juntamente com a definição das colunas na cláusula Select.
UNIÃO
A operação de união efetua uma soma de conjuntos eliminando as duplicidades. Considerando-se a existência das
duas tabelas F e G, as tuplas resultantes da união seriam representadas por T → F ∪ G. A união só pode ser efetuada
entre relações união-compatíveis.
No SQL do Oracle, os dois conjuntos participantes do processo de união são definidos dinamicamente através de
dois (ou mais) comandos Selects unidos por Union ou Union All.
Para que seja possível a realização do processo, algumas regras devem ser respeitadas:
♦ Todos os Selects envolvidos devem possuir o mesmo número de colunas.
♦ As colunas correspondentes em cada um dos comandos devem ser de mesmo tipo.
♦ A cláusula Order By só se aplica ao resultado geral da união e deve utilizar indicação posicional em vez de expressões.
♦ As demais cláusulas que compõem um comando Select são tratadas individualmente nos comandos a que se aplicam.
♦ A cláusula Union elimina do resultado todas as linhas duplicadas. Esta operação pode realizar sort para garantir
a retirada das duplicatas.
♦ A cláusula Union All apresenta no resultado todas as linhas produzidas no processo de união, independente de
serem duplicatas ou não.
♦ Todos os operadores (Union, Intersect, etc.) possuem igual precedência.
♦ Em um comando Select composto de diversos operadores (Union, Intersect, etc.), o comando é executado da
esquerda para a direita. Podemos, neste caso, utilizar parênteses para alterar a ordem de execução.
Neste primeiro exemplo, fizemos a união de todas as linhas da tabela F (total de 12 linhas) com todas as linhas da
tabela G (total de oito linhas). O resultado apresenta apenas 15 linhas, pois existem rows em F que também
existem em G.
No exemplo da Listagem 2.144, utilizamos cláusulas Where individuais por comando Select e o operador Union All,
que fez com que as linhas selecionadas individualmente fossem apresentadas mesmo havendo duplicatas no resultado.
Neste último exemplo de união, foram somados três conjuntos. No primeiro conjunto, somente as linhas com
cargo igual a 52. No segundo conjunto, apenas as linhas com cargo igual a 53. Com estas restrições não houve
necessidade de utilizarmos Union, uma vez que não haveria linhas duplicadas, tornando a operação mais eficiente,
não havendo necessidade de sort.
Este resultado foi unido ao terceiro conjunto, que tinha como restrição depto = ‘D11’, podendo trazer linhas já
presentes no conjunto resultante anterior. Desta forma escolhemos utilizar o operador Union. Execute o comando
da Listagem 2.145 e observe que as linhas dos funcionários Jairo e Maria estão duplicadas (mesmo nome e mesmo
salário). Isto ocorre porque a avaliação de duplicidade não se dá em relação a uma coluna em particular e sim em
relação a toda a linha. Utilizamos constantes para modificar o resultado das linhas a serem unidas: a constante
‘Departamento 11’ substituiu a coluna Depto (isto foi possível pois ambas são alfanuméricas, apesar de diferirem
em tamanho) e a constante ‘Analista Pleno’ independente do cargo apresentado, fazendo com que as linhas
provenientes do terceiro Select fossem apresentadas integralmente.
INTERSEÇÃO
A operação de interseção restringe o conjunto resultante às tuplas presentes em todos os conjuntos participantes
da operação. Considerando-se a existência de duas tabelas F e G, as tuplas resultantes da interseção seriam
representadas por T → F ∩ G. A interseção só pode ser efetuada entre relações união-compatíveis.
No SQL do Oracle, os dois conjuntos participantes do processo de interseção são definidos dinamicamente através
de dois (ou mais) comandos Selects unidos por Intersect.
As mesmas regras aplicáveis à união são válidas na interseção:
♦ Todos os Selects envolvidos devem possuir o mesmo número de colunas.
♦ As colunas correspondentes em cada um dos comandos devem ser de mesmo tipo.
♦ A cláusula Order By só se aplica ao resultado geral da interseção e deve utilizar indicação posicional em vez de expressões.
♦ As demais cláusulas que compõem um comando Select são tratadas individualmente nos comandos a que se aplicam.
♦ A cláusula Intersect elimina do resultado todas as linhas duplicadas. Esta operação pode realizar sort para garantir
a retirada das duplicadas.
♦ Todos os operadores (Union, Intersect, etc.) têm igual precedência.
♦ Em um comando Select composto de diversos operadores (Union, Intersect, etc.), o comando é executado da
esquerda para a direita. Podemos, neste caso, utilizar parênteses para alterar a ordem de execução.
No exemplo da Listagem 2.146, incluímos uma nova linha na tabela F (com matrícula 999), exatamente igual, em
relação às colunas Nome, Depto e Salario, à linha existente de matrícula 160. Na interseção, só é apresentada uma
linha para a funcionária Elizabet.
DIFERENÇA
A operação de diferença efetua uma subtração de conjuntos eliminando as duplicidades. Considerando-se a existência
das duas tabelas F e G, o resultado T é uma relação que contém as rows de F que não estão presentes em G. As tuplas
da diferença seriam representadas por T → F - G. A diferença só pode ser efetuada entre relações união-compatíveis.
Neste caso, a ordem em que a operação é realizada produz modificações no resultado.
No SQL do Oracle, os dois conjuntos participantes do processo de diferença são definidos dinamicamente através
de dois (ou mais) comandos Selects unidos pelo operador Minus.
As regras já apresentadas na união e na interseção devem ser obedecidas também na diferença.
Neste primeiro exemplo, foi feita a diferença F - G e observamos que a linha nova adicionada na tabela F apareceu
no resultado. Na Listagem 2.148, invertemos o processo e realizamos a diferença G - F para verificarmos que o
resultado depende da ordem da operação.
PRODUTO CARTESIANO
Um produto de conjuntos contém todos os elementos do primeiro conjunto concatenados com todos os elementos
do segundo conjunto. Considerando-se a existência das duas tabelas F e P, o resultado T é uma relação que contém
as rows em F concatenadas às rows de P. As tuplas do produto seriam representadas por T → F x P. Neste caso, a
ordem dos fatores não altera o produto.
DEP GERENTE
--- -------
D21 EVA
D11 IRACY
A00 CRISTINA
No SQL do Oracle, os dois conjuntos participantes do processo de produto são definidos dinamicamente através
da cláusula Select (definindo as colunas a serem apresentadas no resultado) e da cláusula From, indicando as
tabelas a serem operadas.
Observe no resultado da Listagem 2.150 que a tabela P possui três linhas relativas aos departamentos A00, D11 e
D21. Cada uma destas linhas foi concatenada a cada uma das linhas da tabela F que atendesse à restrição de
matrícula entre 150 e 200.
Executando-se o comando da Listagem 2.150 veremos o resultado desta concatenação. Como a tabela P possuía
três linhas e a restrição sobre a tabela F resultou em seis linhas, o produto das duas tabelas gerou 18 linhas (3 x 6).
Observe, porém, que a coluna Depto (da tabela F) indica a que departamento aquele funcionário pertence. Na
mesma linha, estão presentes informações do departamento deptno e do funcionário depto. Quando estas informações
são iguais, significa que houve a concatenação da linha do funcionário com o seu departamento. Quando estas
informações são diferentes, significa que houve a concatenação da linha com um outro departamento qualquer.
Quando estabelecemos uma restrição que determine que linhas da tabela P devem ser concatenadas com que
linhas da tabela F, estamos determinando uma operação de Junção (ou Join).
JUNÇÃO OU JOIN
Uma operação de Join contém todos os elementos do primeiro conjunto concatenados a todos os elementos do
segundo conjunto que satisfaçam à regra de comparação indicada. Considerando-se a existência das duas tabelas
F e P, o resultado T é uma relação que contém as rows em F concatenadas às rows de P que satisfazem a comparação
entre os domínios indicados.
As tuplas da junção seriam representadas por T → F [depto=deptno] P. A ordem dos fatores não altera o resultado
da junção.
No SQL do Oracle, os dois conjuntos participantes do processo de Join são definidos dinamicamente através da
cláusula Select (definindo as colunas a serem apresentadas no resultado), da cláusula From, indicando as tabelas a
serem operadas, e da cláusula Where, contendo a relação entre as tabelas.
Neste primeiro exemplo da Listagem 2.151, as linhas de F foram concatenadas às linhas de P, porém atendendo à
restrição de que depto = deptno, garantindo que cada departamento seja concatenado exatamente a seus funcionários.
No exemplo da Listagem 2.152 a seguir, desejávamos obter informações sobre os gerentes dos departamentos. Na
tabela P temos o nome do gerente, e na tabela F temos o nome do funcionário. Nada mais natural, portanto, que
realizar um Join entre as tabelas de tal forma que a restrição fosse gerente = nome.
Observe que não é necessário que façamos a seleção de colunas da tabela P. O que estabelece o produto é a presença
das duas tabelas na cláusula From e o que estabelece a restrição é a presença da cláusula Where determinando a
regra de junção.
Neste exemplo da Listagem 2.153, desejávamos obter informações relativas ao funcionário que tivesse vencimentos
superiores aos do gerente de seu departamento. Desta forma, numa mesma linha precisávamos de informações
referentes ao gerente e ao funcionário. Como ambos estão presentes na mesma tabela, precisamos utilizar alguns
“artifícios” para que não haja erros de sintaxe ao selecionarmos uma mesma coluna duas vezes. Façamos a análise
passo a passo do comando Select desenvolvido.
Iniciaremos a análise pela cláusula From. Nela são referenciadas três tabelas: a tabela P (que contém informações
sobre o departamento), a tabela F (que contém informações sobre o funcionário) e novamente a tabela F, agora
apelidada de G (que contém informações sobre o funcionário gerente). A partir do momento que apelidamos a
tabela F de G, para nós e para o Oracle consideraremos a existência de uma tabela G.
Na cláusula Select, definimos as informações que desejamos visualizar de cada uma das tabelas. Como as colunas
da tabela F e da tabela G são iguais, há necessidade de qualificarmos as informações. Desta forma, desejávamos
obter a matrícula, nome e salário do gerente (g.mat, g.nome e g.salario) e matrícula, nome, salário e departamento
do funcionário (f.mat, f.nome, f.salario e f.depto).
A cláusula Where é o que vai determinar as regras do relacionamento. Precisávamos garantir que o funcionário e
o gerente trabalhassem no mesmo departamento, pois a proposta era obter os funcionários que tivessem salário
superior ao de seu gerente. Assim, restringimos que os departamentos de ambas as tabelas fossem o mesmo (f.depto
= g.depto). Como segunda restrição desejávamos que o salário do funcionário fosse superior ao salário do gerente
(f.salario > g.salario). Como restrição final, precisávamos garantir que o funcionário gerente (obtido da tabela G)
fosse realmente gerente de um departamento. Esta informação só se acha presente na tabela P (por este motivo ela
foi acrescentada ao Join) e, portanto, igualamos g.nome à coluna Gerente.
Este exemplo é semelhante ao da Listagem 2.151, o que mudamos foi a sintaxe. Substituímos a vírgula da listagem
anterior pelas palavras Natural Join; outra forma aceita que também produziria os mesmos resultados seria Natural
Inner Join. Em ambos os exemplos utilizamos a condição de igualdade para que tivéssemos mais facilidade de
entendimento. Este tipo de Join é dito eqüijoin, isto é, usando a igualdade. A forma mais comum de junção entre
as duas tabelas é o uso do Inner Join com a condição de igualdade, ou seja, Inner Eqüijoin. Um Inner Join é aquele
em que somente serão selecionadas para o resultado aquelas linhas que existam em ambos os lados da operação.
Para o exemplo em estudo significa que somente aparecerão no resultado aquelas linhas de F em que depto esteja
preenchido com um valor existente em P. Observe que o departamento A00 não apareceu no resultado (não existe
nenhum elemento em F cuja coluna DEPTO esteja preenchida com A00). Da mesma forma se incluirmos linhas na
tabela F cujo valor preenchido na coluna DEPTNO não exista em P ou esteja vazio (NULL), não encontraremos
estas linhas no resultado do Join. Faça um teste desta situação. Esta é a regra do Inner Join.
Nesta sintaxe alternativa para o comando da Listagem 2.154 podemos separar as cláusulas relativas à ligação entre as
tabelas no ON <condition> e as demais cláusulas de filtragem na cláusula WHERE. Isto pode ser muito útil, principalmente
quando realizamos um Join envolvendo diversas tabelas e/ou quando a chave para relacionamento é constituída de
mais de uma coluna. Esta sintaxe torna visível as restrições relativas à junção e aquelas relativas a filtragem.
Este exemplo da Listagem 2.156 produz exatamente o mesmo resultado daquele estudado na Listagem 2.150.
Substituímos a vírgula pelo texto CROSS JOIN. O resultado é um produto cartesiano, isto é, cada uma das linhas de
P é concatenada com cada uma das linhas de F, produzindo 18 linhas no resultado após a filltragem de matrícula
(entre 150 e 200). Esta sintaxe torna mais clara a intenção do programador no sentido de obter um produto cartesiano.
Isto, certamente, facilita a manutenção posterior de um programa pois indica claramente a intenção do resultado.
DIVISÃO
As tuplas da divisão seriam representadas por T → F [depto : deptno] P. A ordem dos operandos afeta o resultado da operação.
No SQL do Oracle não existe um operando específico para a realização desta operação, e portanto não a trataremos
neste livro (a operação pode ser realizada através de cláusulas como Group By, Subselect, etc.).
EXERCÍCIOS
2.54) Deseja-se uma lista contendo o nome do projeto, o nome das atividades e tempo de duração de cada atividade
(fornecido em número de horas). Ordene o resultado por projeto e atividade.
2.55) Deseja-se uma lista contendo o código e nome de cada departamento, nome e sobrenome do gerente, ordenado
por código de departamento.
2.56) Deseja-se uma lista contendo nome, sobrenome, salário e departamento de todos os funcionários que sejam
responsáveis por projeto, porém não sejam gerentes.
2.57) Deseja-se uma lista contendo o nome e departamento do gerente e nome e salário de todos os funcionários
subordinados a ele. Apresente o resultado ordenado por departamento e salário (descendente).
2.58) Deseja-se uma lista contendo o nome do projeto, o nome do departamento responsável e o nome do
funcionário responsável, desde que ele trabalhe no departamento responsável pelo projeto.
2.59) Deseja-se saber quais os departamentos que não possuem funcionários (usar Minus).
2.60) Deseja-se saber quais os departamentos (código e nome) responsáveis por mais de dois projetos e que,
simultaneamente, possuam mais de três funcionários (usar Intersect).
2.61) Deseja-se saber o código e nome do projeto, código e nome da atividade e o tempo de duração da atividade
durante o ano de 1996. Ordene o resultado por nome do projeto e nome da atividade. Se uma atividade se iniciou
antes de 1996 e terminou durante o ano de 1996, desejamos saber apenas quanto tempo ela durou de 01/01/96 até
a data de término. Se uma atividade começou durante o ano de 1996 e terminou em outro ano, desejamos saber
apenas o tempo da data de início da atividade até dia 31/12/1996. Se uma atividade começou antes de 1996 e
terminou depois de 1996, sua duração será de 01/01 a 31/12, e, finalmente, se uma atividade começou e terminou
em 1996, sua duração será desde a data de início até a data de término.
COMANDOS DE FORMATAÇÃO
Os comandos de formatação vão permitir a modificação do layout de apresentação dos comandos executados.
Poderemos estabelecer tamanho para as colunas, título para o relatório, colunas de quebra, cálculos quanto ao
relatório e à quebra.
COLUMN
O comando Column tem a finalidade de formatar uma determinada coluna ou expressão.
Podemos executar este comando sem coluna identificada para que ele apresente a formatação existente em vigor
no SQL*Plus. Se o executarmos informando um nome de coluna ou expressão, ele apresentará a formatação em
vigor para o elemento específico.
Cada uma das opções do comando afetará uma característica da coluna ou expressão, de acordo com a lista a seguir:
♦ Alias – Associa um alias para a coluna (ou expressão), que pode ser utilizado em um comando Break, Compute
ou até mesmo em outro comando Column.
♦ Clear – Desfaz os formatos especificados para a coluna.
♦ Entmap – Quando utilizamos HTML no relatório gerado pelo SQL*Plus, os símbolos <, >, “ e & podem ser substituídos
pelos valores <, >, " e &. A conversão ou não do conteúdo das colunas (ou expressões) que
incluímos em nosso comando Select é determinado pelo valor do parâmetro Entmap dentro do comando Markup
Html. Pode acontecer, porém, de desejarmos que para uma determinada coluna o padrão seja diferente. Neste caso
especificamos o parâmetro Entmap diretamente no comando Column para a coluna cujo padrão desejamos alterar.
♦ Fold (After ou Before) – Associa um carriage return antes (before) ou depois (after) do cabeçalho e coluna em
cada linha. Isto força uma quebra na linha na posição em que o carriage return é colocado. O SQL*Plus não
adiciona um carriage return extra ao final da linha listada.
♦ Format – Determina um formato de edição para as colunas numéricas e um tamanho de coluna para as demais
colunas. O <formato> não pode ser substituído por uma variável; deve ser um valor constante e pode ser composto
pelos caracteres { 9 0 , . $ L G D C B MI S PR V EEEE RN rn DATE }, com a mesma funcionalidade dos formatos
numéricos da função To_Char. Para os formatos alfanuméricos ou de data, podemos especificar An, onde n
indica a largura da coluna.
♦ Heading – Determina o cabeçalho da coluna.
♦ Justify – Determina o alinhamento para o cabeçalho da coluna. Se não especificado, o alinhamento padrão para
colunas numéricas é à direita e para as alfanuméricas à esquerda.
♦ Like – Copia os atributos de outra coluna definida anteriormente. A opção Like não recobre as características já
definidas para a coluna, só acrescenta aqueles não definidos.
♦ NewLine – Quebra a linha antes de o valor ser apresentado. Tem o mesmo efeito de Fold_Before.
♦ New_Value – Atribui ao parâmetro <variável> o novo valor desta coluna toda vez que houver mudança de valor.
♦ Print / NoPrint – Apresenta (Print) ou não (NoPrint) a coluna na listagem resultado (cabeçalho e todos os valores).
♦ Null – Indica o <texto> a ser apresentado quando o conteúdo da coluna for indeterminado (Null).
♦ Old_Value – Atribui ao parâmetro <variável> o valor anterior desta coluna toda vez que houver mudança de valor.
♦ On / Off – Habilita ou desabilita os atributos de apresentação para a coluna.
♦ Wrapped – Determina como será feito o controle de quebra quando o conteúdo da coluna for maior que a
largura especificada para ela. A opção Wrapped indica que o texto será cortado na largura especificada e continuará
na próxima linha. Word_wrapped indica que o texto será cortado em final de palavra. Truncated indica que o
texto apresentado será apenas aquele que couber na primeira linha.
DEPTO NOME DO
FUNCIONARIO SALÁRIO
----- --------------------- -----------
A00 CRISTINA Cr$5.275,00
B01 MIGUEL Cr$4.125,00
C01 SANDRA Cr$3.825,00
E01 JOAO Cr$4.017,50
No exemplo da Listagem 2.157, executamos o comando Select sem realizar a formatação das colunas, e
posteriormente reexecutamos o mesmo comando para analisarmos as diferenças.
A opção For garante o tamanho da coluna cd_depto, de tal forma que o cabeçalho aparece por completo. O
cabeçalho da coluna nm_func foi quebrado em duas linhas com o uso do | (pipe) no meio do texto. A coluna vl_sal
recebeu a formatação padrão correspondente ao NLS_Lang em vigor para a sessão. Por fim, a coluna dt_nasc não
foi impressa pois recebeu a opção NoPrint.
Após a execução do comando COL para as colunas cd_depto, nm_func, vl_sal e dt_nasc, qualquer comando Select
executado que retorne colunas com estes nomes (nome da coluna ou apelido) será formatado com as definições
anteriores até que venhamos a executar um comando COL com a opção Clear para cada uma das colunas, um
comando CLEAR com a opção Columns ou encerremos o SQL*Plus.
O comando COL é muito utilizado dentro de arquivos de comandos. Veja o exemplo da Listagem 2.158. Após a
execução do comando desejado, desfazemos a formatação de cada coluna, retornando aos valores padrões.
REPHEADER / REPFOOTER
Os comandos RepHeader e RepFooter têm a finalidade de formatar um título geral para o início ou fim do relatório.
Somente serão apresentados na primeira página (RepHeader) ou na última página do relatório (RepFooter).
A utilização de um dos comandos sem parâmetros faz com que o SQL*Plus liste o header ou footer em vigor.
Figura 2.07 – O resultado apresentado foi gerado pelo script da Listagem 2.159 a seguir.
O comando RepHeader ocupa diversas linhas e é considerado pelo SQL*Plus um único comando, pois o símbolo –
(hífen) foi utilizado ao fim de cada linha para indicar continuação de comando (para o SQL*Plus). A primeira coisa
formatada no header do relatório foi o número da página (Sql.Pno) à esquerda, depois no centro da mesma linha
foi formatado o texto “Relatório de Teste”. A opção Skip 2 posiciona no início da nova linha duas vezes, deixando,
portanto, uma linha em branco. A opção Format se aplica às variáveis numéricas seguintes; portanto formatamos
o número da página e a release do Oracle.
O retângulo preto à esquerda da linha de cabeçalho indica que existe um caracter para quebra de página. No
comando RepFooter, o primeiro texto não apresentou posicionamento; o SQL*Plus assume esquerda. Ao término
do arquivo, os três títulos foram desabilitados.
TTITLE / BTITLE
Os comandos Ttitle e Btitle formatam títulos a serem apresentados no topo (Ttitle) ou rodapé (Btitle) de cada
página do relatório.
A sintaxe destes dois comandos é semelhante à dos comandos RepHeader e RepFooter, excetuando-se a opção
Page, que não existe para Ttitle e Btitle.
O resultado da Figura 2.08 foi gerado pelo script da Listagem 2.160 a seguir. Observe que o texto adicionado ao
comando Ttitle aparece em todas as páginas, inclusive nas páginas de header e footer.
BREAK
O comando Break define quais são os elementos de quebra e que ação deve ser tomada quando ocorrer a mudança
de valor (quebra) em cada um deles. Este comando não ordena os dados recebidos do banco de dados. Para que o
resultado seja adequado, no comando Select devemos incluir a cláusula Order By com as mesmas colunas para as
quais desejamos que o SQL*Plus avalie a quebra.
Só podemos executar o comando Break uma vez em cada sessão. Um segundo comando desabilita o primeiro;
desta forma, o último comando Break que executarmos passa a determinar as quebras válidas. Não é cumulativo.
C01 55 DOLORES
60 SANDRA
D11 55 IRACY
55 BRUNO
E01 58 JOAO
E11 55 ELIANE
O resultado da Listagem 2.161 foi gerado com o script da Listagem 2.162. No script, foram estabelecidas duas
colunas de quebra cd_depto e nr_cargo. Para cd_depto, foi determinado que a cada quebra fossem puladas duas
linhas antes da impressão de uma linha com novo valor. A opção NoDuplicates é default e indica que não deve
haver repetição de valor para linhas com a coluna de quebra igual. No exemplo, a linha com nome do funcionário
Silvio não apresenta valor para a coluna cd_depto, pois seu valor é semelhante ao da linha anterior (A00). Para a
coluna nr_cargo, determinamos que a cada quebra fosse duplicado o valor do cargo. No exemplo, a linha do
funcionário Bruno tem o mesmo cargo da funcionária Iracy; no entanto, o cargo é repetido.
No comando Select apresentado na Listagem 2.162 aparece a pseudocoluna RowNum, que corresponde a uma
numeração seqüencial dada para as linhas selecionadas pela restrição presente na cláusula Where. No caso do
exemplo, utilizamos esta pseudocoluna como restrição para que apenas as oito primeiras linhas que atendessem à
restrição de cargo (58, 60 ou 55) fossem selecionadas. A restrição é feita antes da ordenação.
COMPUTE
O comando Compute efetua um cálculo em relação a um elemento de quebra. Se desejarmos efetuar um cálculo
quando houver quebra da coluna cd_depto, esta coluna deve estar referenciada no comando Break. Se desejarmos
um determinado cálculo ao término do relatório, a palavra Report deve estar mencionada no comando Break e
assim por diante. O cálculo só é efetuado em relação a um elemento presente no comando de quebra.
Podemos especificar um ou mais cálculos por elemento e, ainda, especificar um label que identifique o tipo de
cálculo efetuado.
Os parâmetros para determinação de cálculos são:
♦ Avg – Calcula a média de valores não incluindo Nulls.
♦ Count – Calcula a quantidade de valores não incluindo Nulls.
♦ Max – Calcula o maior valor não incluindo Nulls.
♦ Min – Calcula o menor valor não incluindo Nulls.
♦ Num – Calcula a quantidade de valores (total).
♦ Std – Calcula o desvio padrão não incluindo Nulls.
♦ Sum – Calcula o somatório de valores não incluindo Nulls.
♦ Var – Calcula a variância não incluindo Nulls.
♦ OF – Indica a coluna em relação à qual será feito o cálculo.
♦ Label – Indica o label referente ao cálculo.
♦ On – Indica em que momento o cálculo deve ser realizado (quebra).
O resultado apresentado na Listagem 2.163 foi gerado pelo script da Listagem 2.164.
No script, foi incluído apenas um comando Compute para efetuar o cálculo de somatório e média das colunas
Salário e Projeção, quando da ocorrência de quebra por departamento e ao final do relatório. Poderíamos ter
definido dois comandos Computes para realizar a operação anterior com o mesmo efeito, um para a quebra de
departamento e outro para o término do relatório.
Se criarmos mais de um comando Compute para a mesma indicação de quebra, somente a última é considerada.
As demais são ignoradas. Teste o exemplo da Listagem 2.165.
CLEAR
O comando Clear tem por finalidade limpar o valor atual da opção especificada.
SPOOL
Este comando armazena o resultado de uma consulta em um arquivo do sistema operacional e, opcionalmente,
envia o arquivo para a impressora default do sistema.
COUNT(*)
--------
32
Neste arquivo são gerados não só o resultado do(s) comando(s) executado(s), como também as mensagens enviadas,
o texto do comando, enfim, uma reprodução de tudo o que é mostrado no vídeo. Podemos alterar este resultado
através de variáveis de sistema.
--------
32
SHOW
Apresenta informações sobre o elemento especificado.
Dentre os parâmetros do comando Show apresentados na sintaxe, temos alguns ainda não utilizados nos comandos
anteriores. São eles:
♦ <variável> – Apresenta informações sobre a variável de sistema nomeada no comando.
♦ All – Apresenta informações sobre todas as variáveis de sistema.
♦ Parameters – Apresenta informações sobre os parâmetros de inicialização do banco de dados. É uma opção para
uso por DBAs.
♦ SGA – Apresenta a alocação de memória feita para o banco de dados. É uma opção para uso por DBAs.
♦ Errors – Apresenta informações sobre o último comando de PL/SQL compilado ou sobre uma rotina específica
nomeada no comando.
spool OFF
wrap: linhas serão passado para a linha seguinte
linesize 60
repfooter OFF e é NULL
SQL>
DEFINE
Este comando especifica uma variável de substituição e associa um valor alfanumérico a ela. Quando este comando
é executado sem parâmetros, o nome e valor de todas as variáveis de substituição são apresentados. Quando
informamos o nome de uma variável, apenas seu valor é apresentado.
O valor desta variável permanece no sistema até que modifiquemos seu valor através de outro comando Define,
um comando Accept ou Col com New_Value / Old_Value, ou ainda façamos a destruição da variável com o comando
Undefine ou encerremos o SQL*Plus.
NM_DEPTO
------------------------------------
GERENCIA DE SISTEMAS ADMINISTRATIVOS
UNDEFINE
Destrói a definição de uma determinada variável de substituição.
No exemplo da Listagem 2.171, após a destruição da variável “dep”, a execução do comando Select que faz referência
a esta variável solicita ao usuário que forneça um valor para “dep”, pois esta variável não existe.
NM_DEPTO
-------------------------------
GERENCIA DE SISTEMAS COMERCIAIS
VARIABLE
Este comando cria uma variável Bind, que pode ser usada em programas de PL/SQL.
NM_FUNC VL_SAL
--------------- ------
CRISTINA 5275
MIGUEL 4125
SANDRA 3825
Quando executamos o comando Print, são apresentados os valores da variável “mat” e da área apontada pela
variável cursor “wcursor”.
PRINT
Este comando apresenta o valor de uma variável Bind ou de todas as variáveis deste tipo declaradas (se for executado
sem argumentos).
ACCEPT
Este comando cria uma variável de substituição e, opcionalmente, formata uma mensagem para o usuário.
Quando criamos a variável de substituição com este comando, ela pode ser de tipo Number, Char ou Date, havendo
crítica se o valor informado não for compatível com o tipo definido. Os formatos válidos para uso são os mesmos
do comando Col, e ainda são suportados os formatos SQL de data quando o tipo da variável for Date. Podemos
informar um valor default (para o caso de o usuário não fornecer nenhum), apresentar uma mensagem ou não e
esconder o valor digitado pelo usuário (hide).
PROMPT
Envia uma mensagem ou uma linha em branco para a tela do usuário. Pode ser útil para scripts longos, a fim de
informar o passo executado.
PAUSE
Este comando envia uma linha em branco ou uma linha com texto para a tela do usuário e aguarda que este tecle
Enter para que o script tenha prosseguimento.
O exemplo da Listagem 2.174 mostra um script contendo os dois comandos e sua execução.
NM_FUNC
--------
CRISTINA
SET
Este comando, que pode ser incluído em um script, modifica o valor de uma das variáveis de sistema.
A Tabela 2.08 a seguir apresenta a lista e significados das variáveis de sistema do SQL*Plus.
Variável Descrição
APPI[NFO]{ON|OFF|text} Indica que os comandos executados com @, @@ e Start devem ser registrados pelo pacote DBMS_APPLI-
CATION_INFO a fim de terem sua execução monitorada pelo DBA. O valor default para texto é “SQL*Plus”.
ARRAY[SIZE] {15|n} Determina o número de linhas que o SQL*Plus deve obter do banco de dados a cada leitura (Fetch).
AUTO[COMMIT] {OFF | ON | IMM[EDIATE] | n} Indica se o ORACLE efetiva as modificações pendentes para o database. A opção ON faz com que seja
executado um COMMIT após cada comando SQL ou bloco PL/SQL. A opção IMM funciona de forma
semelhante a ON. A opção n indica que o comando COMMIT deve ser executado após n comandos de
atualização bem-sucedidos.
AUTOP[RINT] {OFF|ON} Apresenta, automaticamente, o valor das variáveis BIND após a execução de um PL/SQL.
AUTORECOVERY [ON | OFF] Esta opção pode ser utilizada pelo DBA durante um processo de recuperação do banco de dados.
AUTOT[RACE] {OFF|ON|TRACE[ONLY]} Apresenta um relatório sobre a execução dos comandos de SQL DML (Select, Insert, Update ou Delete) bem-
[EXP[LAIN]] [STAT[ISTICS]] sucedidos. O relatório pode incluir a apresentação de estatísticas e o caminho de execução (Explain). A opção
TraceOnly apresenta o relatório sem apresentar os dados da Query. Se Statistics for solicitado a execução do
comando é realizada, porém sem a apresentação dos resultados. Para que a opção Explain possa ser
executada deve ser criada a tabela Plan_Table para a geração do caminho de acesso.
BLO[CKTERMINATOR] { . |c} Determina um caracter não-alfanumérico a ser usado para indicar fim de blocos PL/SQL.
CMDS[EP] {;|c|OFF|ON} Determina um caracter não alfanumérico usado para separar múltiplos comandos de SQL*Plus digitados na
mesma linha. Se usarmos a opção ON, o caracter default será ponto-e-vírgula ( ; ).
COLSEP {_|text} Determina o texto a ser impresso entre colunas selecionadas (Select). Se o valor tiver brancos ou caracteres
de pontuação, deve ser informado entre aspas simples. O valor default é um único espaço em branco.
COM[PATIBILITY] {V7|V8|NATIVE} Especifica a versão do banco de dados com a qual estamos nos conectando.
CON[CAT] { . |c|OFF|ON} Determina o caracter para terminar uma variável de substituição se desejarmos seguir imediatamente a
variável com um caracter que o SQL*Plus deva interpretar como valor, e não como parte do nome da
variável de substituição.
COPYC[OMMIT] {0|n} Controla o número de linhas após as quais o comando COPY deve efetivar (Commit) as linhas para o banco
de dados. Se optarmos por 0 (zero), o commit só será executado ao final da cópia.
COPYTYPECHECK {OFF|ON} Determina que a verificação de compatibilidade de tipos de dados deve ser suprimida durante uma inclusão
ou adicionamento de linhas para tabelas usando-se o comando COPY. Esta é uma facilidade para DB2, que
necessita que um CHAR seja copiado para um DB2 DATE.
DEF[INE] {‘&’|c|OFF|ON} Determina o caracter a ser usado para prefixar variáveis de substituição. ON ou OFF controla se o SQL*Plus
irá ou não pesquisar no texto a procura de variáveis de substituição para substituí-las por valores. Ao
usarmos ON, o valor atribuído é &. Esta opção tem precedência sobre SCAN.
DESCRIBE [DEPTH{1|n|ALL}] Determina o nível de profundidade para o qual desejamos recursivamente descrever um objeto. Os valores
[LINENUM {ON|OFF}] [INDENT{ON|OFF}] válidos variam de 1 a 50. Aplicável a partir do SQL*Plus 8.1.5.
ECHO {OFF|ON} Controle quando o comando Start lista cada comando presente no arquivo de comandos quando realiza a
sua execução.
EDITF[ILE] file_name[.ext] Determina o nome default para o comando Edit (no Windows, o nome default é Afiedt.buf). Podemos incluir
caminho e/ou extensão para o arquivo.
EMB[EDDED] {OFF|ON} Controla onde cada nova página do relatório começa. OFF força cada relatório a começar no topo de uma
nova página. ON permite que um relatório inicie em qualquer parte da página.
ESC[APE] { \ |c|OFF|ON} Define qual o caracter a ser usado como escape. ON altera o valor <c> para o default “\”. Este caracter é
utilizado antes do caracter indicado para variáveis de substituição para indicar que o texto a seguir deve ser
considerado normal e não uma substituição.
FEED[BACK] { 6 | n } Mostra o número de registros retornados por uma query se forem selecionados mais de n registros (default 6).
continua
continuação
Variável Descrição
continuação
Variável Descrição
SHIFT[INOUT] {VIS[IBLE]|INV[ISIBLE]} Permite o alinhamento correto para terminais que mostrem caracteres shift junto com os dados (por
exemplo IBM 3270).
SHOW[MODE] {OFF|ON} Indica se o SQL*Plus mostra o valor antigo e o novo de uma variável de sistema quando esta é modificada
com o comando SET.
SPACE {1 | n} Indica o número de espaços entre as colunas do relatório. O valor máximo é 10 (default 1).
SQLBL[ANKLINES] {ON|OFF} Indica se desejamos preservar ou não os brancos dentro de um comando de SQL.
SQLC[ASE] {MIX[ED] | LO[WER] | UP[PER]} Converte os textos dos comandos SQL e PL/SQL de acordo com a opção escolhida, inclusive os textos
constantes (entre plics). (default MIXED)
SQLCO[NTINUE] { > |text} Determina o caracter que o SQL*Plus mostra como prompt se quebrarmos uma linha de comando do
SQL*Plus usando o hífen ( - ).
SQLN[UMBER] {OFF|ON} Determina o prompt para a segunda (e subseqüentes) linha quando estamos efetuando a digitação de
comandos SQL ou PL/SQL. ON indica que o prompt deve ser uma numeração seqüencial. OFF indica que o
valor deve ser SQLPROMPT.
SQLPLUSCOMPAT[IBILITY] {x.y[.z]} Determina a compatibilidade do SQL*Plus com relação ao comando VARIABLE (por enquanto somente este
comando é afetado). O parâmetro x representa version, o parâmetro y representa release e o parâmetro z
representa update. Se colocarmos um valor inferior a 9.0.0 (no arquivo Glogin.sql o valor default é 8.1.7), o
tamanho das variáveis de tipo Nchar e Nvarchar2 estarão associadas ao National Character Set em uso (que
determinará se o valor é expresso em bytes ou caracteres).
SQLP[ROMPT] {SQL> | text } Indica o texto de prompt para o SQL*PLUS.
SQLPRE[FIX] { # |c} Indica um prefixo. Durante a digitação de um comando de SQL podemos, em uma linha separada prefixada
pelo caracter escolhido, digitar um comando de SQL*Plus, que será executado imediatamente após o
<enter> da linha. Deve ser um caracter não alfanumérico.
SQLT[ERMINATOR] { ; | c | OFF | ON} Indica qual caracter o SQL*PLUS reconhecerá como fim de linha e execução. OFF indica que não existe caracter
associado, o fim do comando é reconhecido por uma linha inteira em branco. A opção ON retorna ao valor default de;
SUF[FIX] {SQL | text} Indica a extensão default para arquivos de comandos do SQL*PLUS.
TAB {OFF|ON} Determina como o SQL*Plus formata espaços no resultado. OFF usa brancos para formatar espaços no resultado.
ON usa o caracter TAB. Esta opção é aplicável apenas a terminais. TABs não são colocados em arquivos.
TERM[OUT] {OFF|ON} Controla a apresentação dos resultados gerados por comandos executados a partir de um arquivo de
comandos. OFF suprime a apresentação do resultado no vídeo, mas o spool do resultado é gerado. TERMOUT
OFF não afeta a apresentação de comandos interativos.
TI[ME] {OFF|ON} Controla a apresentação da hora atual. ON mostra a hora corrente antes do prompt.
TIMI[NG] {OFF|ON} Controla a apresentação de estatísticas de tempo. ON mostra as estatísticas em cada comando SQL ou bloco
de PL/SQL.
TRIM[OUT] {OFF|ON} Determina se o SQL*Plus deixa os brancos finais de cada linha ou remove-os. ON remove os brancos ao fim
de cada linha aumentando a performance, especialmente útil quando executamos o SQL*Plus de um
equipamento lento. Não afeta Spool.
TRIMS[POOL] {ON|OFF} Determina se o SQL*Plus retira os brancos ao final de cada linha enviada para spool. ON remove os brancos
finais. Não afeta o resultado para o terminal.
UND[ERLINE] { - | c | ON | OFF} Determina o caracter usado para sublinhar cabeçalhos de colunas. ON altera o valor para o padrão “-“. <c>
não pode ser um caracter alfanumérico.
VER[ IFY ] {ON | OFF} Determina se o texto do comando SQL será apresentado antes e após o SQL*PLUS ter efetuado a
substituição do parâmetro pelo valor real (default ON).
WRA[P] {OFF|ON} Controla se o SQL*PLUS trunca a apresentação de linhas selecionadas se o comprimento a ser apresentado é
muito longo para a largura atual da linha. OFF trunca a linha. ON permite a quebra de linha.
Na Listagem 2.175 a seguir, testamos a variável de sistema Autotrace. Para que ela possa realizar o relatório previsto,
precisamos criar uma tabela em nosso schema chamada Plan_Table. O script para criação desta tabela se acha no
diretório orawin95\rdbms80\admin\utlxplan.sql. A opção Traceonly do comando indica que o comando de SQL
não deve ser executado, apenas a apresentação do plano de acesso e as estatísticas. Os dois relatórios produzidos
auxiliam o DBA a detectar problemas na performance de comandos de SQL DML.
Plano de Execução
---------------------------------------------------------
0 SELECT STATEMENT OPTIMIZER=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'FUNC'
2 1 INDEX (RANGE SCAN) OF 'SYS_C00689' (UNIQUE)
Estatísticas
-------------------------------------------
0 recursive calls
0 db block gets
13 consistent gets
2 physical reads
Na Listagem 2.176, testamos as variáveis Escape, SqlTerminator, SqlPrompt e Time. A variável Escape pode ser
muito útil quando desejamos incluir o & dentro de um texto sem que ele tenha a função de variável de substituição.
Na Listagem 2.177, foram testadas as variáveis Serveroutput e Linesize. Para a variável Serveroutput, os formatos
disponíveis são Wrapped, Word_wrapped ou Truncated. Indicando que, quando o texto do pacote Dbms_Ouput é
maior que a largura de uma linha, o SQL*Plus deve formatar a linha de acordo com uma das opções fornecidas.
Se Wrapped é informado, a quebra de linha ocorre a cada Linesize caracteres. Se Word_Wrapped é informado, a
quebra de linha também ocorre, aproximadamente, a cada Linesize caracteres, porém em final de palavra. Se for
utilizado Truncated, cada linha é truncada em Linesize caracteres.
STORE
O comando Store gera um arquivo contendo todas as variáveis de sistema e seus valores defaults para que possamos
gerar um script com aquelas que desejamos alterar.
Quando o SQL*Plus começa a executar, ele procura por um arquivo de nome Login.Sql e, caso encontre, executa os
comandos existentes neste arquivo.
Desta forma, podemos criar um arquivo com este nome no diretório default do SQL*Plus contendo atribuições a
variáveis de sistema, títulos, formatação de colunas; enfim, todos os padrões que quisermos estabelecer para nossa
sessão. Toda vez que iniciarmos o SQL*Plus, este arquivo será executado automaticamente.
COMANDOS DIVERSOS
Neste item, veremos o restante dos comandos de SQL*Plus.
CONNECT / DISCONNECT
Permite a troca de sessão do SQL*Plus com o banco de dados ou encerra uma sessão com o banco de dados.
SQL> password
Alterando senha para DESENV
Senha antiga: ******
Nova senha: ******
Redigite a nova senha: ******
Senha alterada
COPY
Copia os dados de uma query para uma tabela em um banco de dados local ou remoto.
TIMING
Registra dados de tempo para um determinado intervalo. O parâmetro <texto> corresponde ao nome do timer
criado. Se executado sem parâmetros, lista a quantidade de timers ativos. A opção Show mostra o valor acumulado
para o timer corrente e a opção Stop interrompe a contagem para o timer ativo.
o sistema operacional. Este tipo de procedimento é interessante quando colocamos a execução do SQL*Plus em
um arquivo de comandos do sistema operacional. O encerramento com um valor permite que o script tome uma
ação associada a cada valor retornado.
ATTRIBUTE
Este comando especifica atributos de apresentação (display) para um determinado atributo de uma coluna Object Type.
HELP
Este comando aciona o mecanismo de Help do SQL*Plus mostrando o manual com a sintaxe desejada. Para que a
sintaxe seja apresentada o DBA deverá instalar os textos de Help executando o arquivo helpbld.sql presente no
diretório <Oracle_Home>\sqlplus\admin\help.
Na Listagem 2.180 encontramos inicialmente a linha de comando do SQL*Plus para execução de um arquivo de
nome arqhtm.sql e saída para arquivo em formato HTML.
O segundo grupo de comandos presente na listagem corresponde ao conteúdo do arquivo arqhtm.sql. Na Listagem
2.181 a seguir apresentamos o resultado gerado.
<th>
NM_FUNC
</th>
</tr>
<tr>
<td>
A00
</td>
<td>
CRISTINA
</td>
</tr>
<tr>
<td>
A00
</td>
<td>
VICENTE
</td>
</tr>
<tr>
<td>
A00
</td>
<td>
SILVIO
</td>
</tr>
</table>
<p>
</body>
</html>
O MENU DO SQL*PLUS
O menu do SQL*Plus apresenta cinco submenus: Arquivo, Editar, Procurar, Opções e Ajuda.
ARQUIVO
Temos as opções de salvar o Sql Buffer para um arquivo em disco, ler um arquivo e carregar para o buffer, iniciar ou
encerrar o envio de dados para Spool, executar o comando presente no Buffer ou interromper sua execução.
EDITAR
Realiza as operações básicas de copiar e colar, aciona o editor ou define um novo editor.
PROCURAR
Faz pesquisa de um texto na tela do SQL*Plus.
OPÇÕES
Apresenta o diálogo Ambiente com a lista de variáveis de sistema e seus valores defaults para modificação.
AJUDA
Apresenta informações sobre a versão do SQL*Plus.
EXERCÍCIOS
2.62) Sabendo-se que os códigos de departamento são subdivididos em depto (letra) e centro de custo (número),
deseja-se uma lista organizada por centro de custo contendo nome e sobrenome do funcionário, código do
departamento, salário e cargo. Deve ser apresentada uma única coluna para nome e sobrenome, salário deve ser
editado, deve ser feita uma separação de página para cada centro de custo. Deseja-se uma totalização dos salários,
numeração de página e o mês vigente no cabeçalho.
2.63) Gere um arquivo a ser utilizado para carga de dados em outro ambiente contendo as seguintes informações:
matrícula, nome e sobrenome (única coluna), salário, cargo, grau de instrução e data de nascimento. As informações
devem ser apresentadas alinhadas por coluna e separadas por vírgula. Faça um script para criação deste arquivo
(usar Spool). O arquivo gerado deve ter o nome de carga.sql.
2.64) Montar uma lista dos aniversariantes por mês, contendo para cada mês (apresentado por extenso em português) o
nome, idade e departamento do funcionário, ordenada por número de mês. Não deve haver repetição do nome do mês.
A página deve ser mudada quando ocorrer a mudança do mês.
2.65) Crie um relatório que forneça a média salarial, o maior salário e o menor salário do departamento informado
como parâmetro. O usuário poderá informar o departamento em letras maiúsculas ou minúsculas e sem aspas. A
solicitação do parâmetro deve ser formatada e deve ser enviada mensagem antes do início da execução.
2.66) Crie um relatório com as seguintes características:
♦ Capa: “Capa do Relatório – dd/mm/yyyy”
♦ Número de página em todas as folhas (direita).
♦ Título do relatório: Primeiro Relatório Exercício (centralizado).
♦ Apresentar a versão do Oracle em todas as páginas (esquerda).
♦ Datar todas as páginas (esquerda).
♦ Quebrar por Departamento e colocar o nome do departamento no título de cada página.
♦ No rodapé de cada página, devem constar também o nome do departamento, além do título “Confiden-
cial”(centralizado).
♦ Apresentar matrícula, data de admissão (dd/mm/yyyy), salário (formatado).
♦ Deve ser apresentado um total salarial e uma média por departamento no final do relatório. Deseja-se, também,
a quantidade de funcionários por departamento no final do relatório.
♦ Ordenar o relatório por departamento e salário descendente.
2.67) Criar um arquivo a ser usado toda vez que abrirmos o SQL*Plus com as seguintes características:
♦ O tamanho de cada linha deve estar limitado a 70 caracteres.
♦ Deve ser apresentada mensagem indicativa da quantidade de linhas selecionadas para qualquer número de
linhas selecionadas.
♦ A indicação de ausência de valor deve ser feita com o texto “<null>“.
♦ A largura-padrão para colunas numéricas deve ser 10 caracteres.
♦ O tamanho de uma página padrão deve ser de 20 linhas.
♦ O prompt apresentado à esquerda do vídeo deve ser “Plus> “, incluindo a hora.
♦ O sufixo dos arquivos de trabalho deve ser “.Txt”.
♦ As mensagens recebidas de programas PL/SQL devem ser habilitadas com área de armazenamento de 10.000 bytes.
2.68) Crie um relatório com as seguintes características:
♦ Capa: “Capa do Relatório”
♦ Número de página em todas as folhas (direita).
♦ Título do relatório: Relação de Funcionários e Projetos (centralizado).
OUTER JOIN
Quando estudamos Join, observamos que o resultado gerado conta apenas com as linhas da tabela A que têm
correspondência com alguma linha na tabela B.
Execute o comando da Listagem 2.182 e observe que, quando estabelecemos um Join da tabela F com a tabela P
que contém linhas referentes aos departamentos A00, D11 e D21, a linha referente ao departamento A00 não
aparece no resultado.
Esta situação ocorre porque na cláusula Where estabelecemos a restrição de que apenas quando ocorresse a igualdade
entre Depto e Deptno seria gerada uma linha resultante.
Este tipo de Join, que só gera linha resultante quando a informação que estabelece a ligação existe em ambas as tabelas, é
chamado de Inner Join e já foi estudado por nós anteriormente. Trata-se da forma mais usual de ligação entre duas tabelas.
No Oracle, temos outro tipo de Join chamado Outer Join, no qual podemos determinar que os dados de uma
tabela sejam mostrados mesmo que não seja encontrada a ligação com a outra tabela.
Quando executamos o comando da Listagem 2.183, vemos aparecer a linha contendo os dados da tabela de
departamento (P), mesmo não havendo correspondência com nenhuma linha da tabela de funcionários (F).
A indicação de Outer Join é feita com o símbolo (+) ao lado das colunas que estabelecem a relação na cláusula
Where. Caso o relacionamento fosse estabelecido com duas colunas, ambas receberiam a indicação.
A indicação de Outer Join é colocada à direita das colunas que representam a linha que pode estar ausente no resultado.
No exemplo da Listagem 2.183, colocamos o símbolo (+) ao lado de Depto, coluna da tabela F, indicando que
poderiam haver linhas da outra tabela (no caso P) que não tivessem correspondência com F, ou seja, os dados
relativos a F ficariam ausentes no resultado.
No exemplo da Listagem 2.184, listamos cada departamento (tabela Depto) e o nome do gerente correspondente
(tabela Func), porém sabíamos que havia departamentos sem indicação do gerente. Para conseguirmos realizar o
Join, precisamos informar ao Oracle que poderiam haver valores de cd_gerente que não teriam correspondência
na coluna cd_mat da tabela Func.
Como restrição, temos que o indicador só pode ser colocado em um dos lados do sinal de igualdade.
Este exemplo da Listagem 2.185 é equivalente àquele apresentado na Listagem 2.184, ou seja, todas as linhas de
departamento (presente do lado direito da cláusula OUTER JOIN) serão trazidas mesmo que não haja correspondência
com linhas em Func (lado esquerdo da cláusula OUTER JOIN). A utilização explícita da sintaxe RIGHT OUTER
JOIN torna o comando SELECT mais claro para quem o estiver lendo. A recomendação da Oracle é de que passemos
a usar esta sintaxe no lugar da outra (+).
NM_DEPTO NM_GERENTE
---------------------------------------- ----------
DIRETORIA DA EMPRESA CRISTINA
ASSESSORIA MIGUEL
CENTRO DE INFORMACAO SANDRA
GERENCIA DE SISTEMAS COMERCIAIS IRACY
GERENCIA DE SISTEMAS ADMINISTRATIVOS EVA
DIRETORIA DE SUPORTE/PRODUCAO JOAO
OPERACAO ELIANE
SUPORTE DE SOFTWARE TEODORO
JOANA
GABRIEL
. . .
DIRETORIA DE SISTEMAS
NOVO DEPTO
No exemplo da Listagem 2.186, removemos algumas linhas do resultado para efeito estético (observe . . .).
A sintaxe Full Outer Join permite que sejam trazidas linhas da tabela Func que não possuem correspondência em
Depto e linhas de Depto que não possuem correspondência em Func, além, é claro, daquelas que se relacionam. Esta
é uma vantagem sobre a sintaxe anterior (+), que não permite o uso do sinal (+) em ambos os lados da operação.
EXISTS
Exists é um predicado, e portanto deve ser usado sob condição. Não pode ser usado em nível de Select e nem
independentemente das cláusulas Where, Start With, Connect By ou Having.
Este predicado tem a finalidade de verificar se a condição estabelecida em um subselect existe ou não. Não é feita
comparação de valor, o retorno é True ou False. Tão logo a condição seja verificada, a busca é interrompida.
0 linhas deletadas.
No exemplo da Listagem 2.187, desejava-se remover um determinado departamento, desde que não houvesse
funcionários associados. Observe que no subselect associado à cláusula Exists não houve necessidade de se obter
nenhuma coluna em especial (Select 0). O objetivo era apenas determinar se existiam ou não linhas na tabela Func
relativas ao departamento fornecido.
4 linhas criadas.
SQL> /
0 linhas criadas.
No exemplo da Listagem 2.188, o objetivo era incluir linhas na tabela G, desde que os departamentos referenciados
(A00 e B01) não existissem em sua massa de dados. Isto garantiria que duas execuções não duplicariam os dados da
tabela. Observe que numa segunda execução do mesmo comando nenhuma linha foi incluída.
HIERARQUIA
As cláusulas Start With e Connect By utilizadas em um comando Select permitem que façamos a leitura organizada
de uma hierarquia. Como restrição, temos que a relação deve ocorrer entre colunas de uma mesma tabela.
Uma hierarquia é definida por um auto-relacionamento em diversos níveis. Suponhamos que tivéssemos uma
tabela contendo peças fabricadas por uma determinada empresa. Cada uma das peças é composta de outras peças,
que também podem ser compostas por outras peças, e assim por diante.
4 CD_PEÇA NUMBER(5),
5 CD_PEÇA_PAI NUMBER(5),
6 IN_PEÇA_ELEMENTAR NUMBER(1),
7 PRIMARY KEY (CD_PEÇA)
8 );
Tabela criada.
Na Listagem 2.189, criamos uma tabela capaz de armazenar as peças fabricadas pela empresa. Além da restrição da
primary key, criamos um relacionamento que garantirá que uma determinada peça esteja associada à peça-pai da
qual é componente.
Suponhamos, agora, que desejamos cadastrar as seguintes peças apresentadas no esquema da Figura 2.10.
No esquema, a peça 10000 é composta de três peças (11000, 12000 e 13000); a peça 11000 é, por sua vez, composta
de duas outras peças (11100 e 11200). A peça 11200 é composta das peças 11210 e 11220. Desta forma, geramos
um conjunto hierárquico em que cada peça-filha identifica qual a peça-pai da qual é componente.
Para refletirmos estas informações na tabela Peças do banco de dados, foram cadastradas as linhas de dados do
esquema, algumas das quais apresentadas na Listagem 2.190.
Com a tabela preparada, poderemos utilizar o comando Select para obter as linhas organizadas segundo a hierarquia.
NM_PEÇA
----------
PEÇA 10000
PEÇA 11000
PEÇA 11100
PEÇA 11200
PEÇA 11210
PEÇA 11220
PEÇA 12000
PEÇA 13000
PEÇA 13100
PEÇA 13200
Observe a ordem em que as linhas são apresentadas: a peça 10000 aparece em primeiro lugar, seguida da primeira
peça-filha 11000, que possui filhas 11100 e 11200, esta última, por sua vez, possuindo filhas 11210 e 11220,
encerrando este ramo da hierarquia. Retornamos ao segundo nível (filhos diretos de 10000) com a peça 12000 que,
como não tem filhos, faz com que a lista prossiga no mesmo nível com a peça 13000, que possui as peças-filhas
13100 e 13200. Esta é a ordem em que o Oracle pesquisa cada ocorrência na tabela. Poderíamos entender como um
processo recursivo que só se encerra quando chega ao último nível da hierarquia.
As cláusulas Start With e Connect By têm a finalidade de:
♦ Start With – Indicar ao Oracle em que ramo da hierarquia deve-se restringir a pesquisa. Note-se que o Oracle, a
priori, não sabe quantas árvores diferentes e independentes existem na tabela. Esta cláusula limita a lista aos ramos
que desejamos listar. Se não informarmos esta cláusula, o Oracle lerá cada linha da tabela Peças e a considerará
início (topo) de hierarquia, tentando gerar uma árvore hierárquica independente para cada uma das linhas.
♦ Connect By – Indicar ao Oracle como ocorre o auto-relacionamento. Que colunas devem ser comparadas e qual
delas corresponde à coluna-pai do relacionamento. Pode parecer confuso, a princípio, uma vez que cd_peça_pai
contém o valor da peça-pai da relação; na verdade, este valor funciona como um “ponteiro” para a coluna que
realmente representa a coluna-pai da relação (a coluna filha aponta para a coluna-pai – o inverso não seria
possível, pois existem diversos filhos).
Quando trabalhamos com estas cláusulas, ainda temos como recurso adicional a possibilidade de identificar o
nível hierárquico da linha listada utilizando a pseudocoluna Level (esta pseudocoluna nos Selects que não usam a
cláusula Connect By retorna zero).
LEVEL NM_PEÇA
----- ----------
1 PEÇA 10000
2 PEÇA 11000
3 PEÇA 11100
3 PEÇA 11200
4 PEÇA 11210
4 PEÇA 11220
Já que contamos com esta informação adicional, podemos utilizá-la para estabelecer uma endentação no resultado,
como mostra a Listagem 2.194.
PEÇA
----------------------
PEÇA 10000
PEÇA 11000
PEÇA 11100
PEÇA 11200
PEÇA 11210
PEÇA 11220
PEÇA 12000
PEÇA 13000
PEÇA 13100
PEÇA 13200
PEÇA
----------------------
PEÇA 10000
PEÇA 13000
PEÇA 13200
PEÇA 13100
PEÇA 12000
PEÇA 11000
PEÇA 11200
PEÇA 11220
PEÇA 11210
PEÇA 11100
Compare este resultado com o anterior. Observe que a hierarquia não foi quebrada, porém a ordem dos elementos
subordinados foi invertida. A cláusula SIBLINGS associada à cláusula ORDER BY permite que controlemos a ordem
com que os ramos serão apresentados.
SUBSELECTS CORRELACIONADOS
Nos subselects estudados até agora, não havia relação entre a query principal e a query do subselect. A execução do
subselect acontecia independente da query principal, gerando um resultado que seria utilizado para estabelecer a
restrição nos dados da query principal.
Suponhamos, porém, que desejássemos obter uma informação relativa à linha lida na query principal. Por exemplo, se
desejássemos saber quais os funcionários que ganham mais que a média salarial de todos os funcionários do mesmo
departamento. Observe que para atender a esta consulta precisaríamos ler o funcionário, obter o código do departamento,
calcular a média salarial e retornar ao funcionário original para verificar se ele se enquadra na condição estabelecida.
Um subselect correlacionado indica ao Oracle a necessidade de realizar estas operações.
A correlação é estabelecida quando no subselect restringimos a pesquisa a uma informação vinda da query externa.
No exemplo da Listagem 2.196, limitamos o cálculo da média ao departamento (F.cd_depto) obtido da query
externa, que possui uma tabela Func apelidada de F.
Aparentemente, neste exemplo, a correlação necessita de um apelido na query externa. Veja, porém, o exemplo da
Listagem 2.197.
Na Listagem 2.197, desejávamos obter quais os funcionários que ganhavam mais que seu respectivo gerente.
O Join da query externa garante que na linha lida haverá dados de um funcionário qualquer e o código do gerente
do departamento em que este funcionário trabalha. Na subquery foi feita uma consulta à tabela Func para obtenção
do salário do funcionário cuja matrícula correspondesse ao código do gerente obtido na linha da query externa.
Não houve necessidade de qualificação.
A qualificação só é necessária quando temos um caso particular em que a subquery necessita comparar dados de
colunas que internamente e externamente tenham o mesmo nome.
Como último exemplo, suponhamos que desejássemos obter departamentos que não possuam funcionários. Ob-
serve que a cláusula Exists foi utilizada juntamente com a correlação na Listagem 2.198.
CD_ NM_DEPTO
--- ---------------------
D01 DIRETORIA DE SISTEMAS
VIEWS RELACIONAIS
Uma view relacional corresponde a um comando Select armazenado no banco de dados associado a um nome. Na
Listagem 2.199, criamos uma view que obtenha informações dos funcionários e dos departamentos respectivos.
O comando Create View pertence à parte da linguagem que define objetos no banco de dados, chamada de DDL,
porém inciaremos sua utilização neste item a fim de introduzirmos o próximo tópico. A criação de views associadas
a objetos será vista no Capítulo 4.
View criada.
DEPTO VARCHAR2(40)
SALARIO NUMBER(9,2)
CARGO NUMBER(3)
NASC VARCHAR2(16)
INST NUMBER(2)
Observe que a view contém a possibilidade de alterarmos o nome das colunas para nomes mais amigáveis e são
visualizadas, pelo usuário, como tabelas. Na verdade, não são tabelas capazes de armazenar dados. Fazem referência
a uma ou mais tabelas, outras views ou uma combinação de tabelas e views. Correspondem a um comando Select
armazenado na base de dados, que é obtido quando realizamos uma operação de DML fazendo referência à view.
Na Listagem 2.200 criamos a view FuncD11, semelhante à view Funcionário, incluindo a restrição de que só
devem ser selecionados os funcionários do departamento D11.
As views possuem uma grande utilização em um banco de dados: podemos armazenar queries complexas que
sejam muito utilizadas, podemos armazenar queries que contenham restrições permitindo o acesso apenas às
views no lugar das tabelas básicas (restrições de linhas e/ou colunas), podemos armazenar queries que contenham
cálculos, colunas constantes que decodifiquem a forma real como a informação está armazenada.
Quando realizamos uma consulta utilizando na cláusula From o nome da view, o Oracle junta as restrições existentes
nos dois Selects e realiza a consulta à tabela básica (pois é nela que estão armazenados os dados).
NOME DEPTO
------------------------- -------------------------------
IRACY SOUZA GERENCIA DE SISTEMAS COMERCIAIS
BRUNO AZEVEDO GERENCIA DE SISTEMAS COMERCIAIS
DAVI BARBOSA GERENCIA DE SISTEMAS COMERCIAIS
JOANA LUZ GERENCIA DE SISTEMAS COMERCIAIS
Na consulta da Listagem 2.201 utilizamos a view FuncD11, estabelecendo a restrição de que apenas o cargo 55 fosse
selecionado. Na base de dados existem nove linhas com cargo 55, porém apenas quatro foram listadas. Isto acontece
porque duas restrições foram estabelecidas na busca: cargo igual a 55 e código do departamento igual a D11.
Observe que o comando Select empregado com a view utiliza para nomes de colunas aqueles definidos para a view
tanto com referência à cláusula Select quanto à cláusula Where.
Uma view pode ser usada para Select e para Insert, Update ou Delete. Veja a Listagem 2.202. As linhas atualizadas,
na verdade, foram as linhas com nr_git = 17 e cd_depto = ‘D11’ da tabela Func.
3 linhas atualizadas.
No exemplo da Listagem 2.203, estaremos criando uma view que obtenha apenas os gerentes cadastrados na
tabela Func.
Utilizamos a cláusula With Check Option para garantir que a restrição estabelecida para leituras (nr_cargo >= 60 )
também seja verificada nas inclusões, alterações e exclusões. Caso esta opção não tivesse sido estabelecida,
poderíamos ter efetuado a inclusão na view (na tabela Func, na verdade), porém não obteríamos a linha criada
quando efetuássemos uma consulta usando a view.
Se desejarmos impedir que sejam feitas atualizações utilizando a view, podemos dispor da cláusula With Read Only
em substituição a With Check Option.
Neste caso, qualquer tentativa de atualização (Insert, Update ou Delete) através da view resulta em erro.
EM SELECTS
Veremos aqui a utilização subquery na cláusula From de um comando Select.
Neste exemplo, utilizamos um Join de duas subqueries. A primeira obtém o total salarial por departamento, a
segunda, o total salarial de toda a empresa. Na query principal estabelecemos um Join com o resultado das duas
subqueries, de tal forma que a soma salarial por departamento foi dividida pelo total da empresa, obtendo-se então
um percentual da participação de cada departamento na empresa.
As subqueries na cláusula From são bastante utilizadas, principalmente quando a subquery realiza uma agregação.
SQL> WITH QMIN AS (SELECT MIN(VL_SAL) MINIMO, AVG(VL_SAL) MEDIA FROM FUNC)
2 SELECT MEDIA FROM QMIN;
MEDIA
----------
2730,35938
O comando de SQL apresenta uma outra forma de utilizarmos subquery na cláusula FROM, porém de uma maneira
mais clara. Com a cláusula WITH utilizada precedendo a query, damos um nome à subquery, e a partir daí ela pode
ser usada como se fosse uma “view” para todas as queries internas a esta, desde a principal até a mais interna. O
nome dado tem visibilidade a partir da query principal.
EM UPDATES
Para efeito de exemplificação, repetiremos as condições da view Gerentes, porém relacionada diretamente no
lugar do nome da tabela básica.
Até mesmo a cláusula With Check Option pode ser utilizada para garantir que a verificação seja realizada. Observe
que, com a seleção de apenas algumas colunas da tabela Func, somente estas podem ser atualizadas.
EM INSERTS
Na Listagem 2.209, utilizamos a mesma query do exemplo anterior, porém violamos a restrição de cargo >= 60. Observe
que a mensagem de erro é exatamente a mesma de quando fizemos uma tentativa de inclusão incorreta com a view.
EM DELETES
Na Listagem 2.210, tentamos fazer referência a uma coluna da tabela Func que não estava presente no Select usado
na cláusula From.
A mensagem de erro indica que somente podemos mencionar na cláusula Where do comando Delete colunas
presentes no Select da subquery.
O COMANDO MERGE
O comando tem a função de obter linhas de uma determinada tabela para atualizar ou incluir linhas em outra tabela.
Como restrição temos que não podemos atualizar múltiplas vezes a mesma linha da tabela destino em um mesmo
comando Merge.
As cláusulas presentes nesse comando são:
♦ Into – determina a tabela destino onde faremos a inclusão ou atualização.
♦ Using – determina o dado (origem) que será incluído ou atualizado.
♦ When Matched / Not Matched – determina a condição a ser avaliada para inclusão ou atualização. Quando a
condição for verdadeira ocorrerá a atualização; caso contrário será realizada a inclusão.
Analisemos o exemplo da Listagem 2.211; a operação de Merge será realizada sobre a tabela Func. A cláusula Using
determina a origem dos dados, que pode ser uma outra tabela (neste caso não há necessidade do parêntese), um
view ou, como usamos, uma subquery. A tabela Func foi apelidada de F para que pudesse ser qualificada no
comando Insert. Isto foi necessário pois usamos a mesma coluna VL_SAL tanto no trecho relativo ao Update
quanto relativo ao Insert, o que causou um erro de ambigüidade. No exemplo da Listagem 2.212, usamos o mesmo
exemplo, mas como não fizemos a inclusão na coluna VL_SAL, não tivemos necessidade de qualificação.
No nosso caso as colunas das tabelas envolvidas não possuem qualquer semelhança; porém havendo necessidade
podemos apelidar a subquery e usar este apelido como qualificador das colunas similares, como fizemos no exemplo
da Listagem 2.212.
Neste exemplo observamos que, apesar de as duas inclusões serem realizadas pelo mesmo comando, elas são
tratadas separadamente no banco de dados. No exemplo tentamos incluir um funcionário com um departamento
ainda inexistente, incluído no mesmo comando, porém na linha seguinte. Isto não foi possível. Porém, quando
invertemos a operação obtivemos sucesso (veja o exemplo da Listagem 2.214).
A sintaxe do comando exige que se viermos a determinar mais de uma tabela, utilizemos a cláusula Values para
todas as tabelas, exceto para a última, que deverá, obrigatoriamente, vir acompanhada de um comando Select.
Como somente desejávamos que uma linha fosse incluída em Func, usamos, como artifício, o uso de constantes de
leitura da tabela Dual (que possui somente uma linha).
Neste exemplo da Listagem 2.215 utilizamos a cláusula When em conjunto com a cláusula All. Esta combinação
faz com que todas as condições sejam analisadas e se mais de uma for verdadeira mais de um Insert será realizado.
Verifique a sintaxe completa no Capítulo 10.
CD_MAT NM_FUNC
---------- ----------
11 TESTE ALL
13 TESTE WHEN
16 TESTE WHEN
Quando usamos First com When as condições são analisadas em ordem e a primeira atendida é executada, sendo
as demais descartadas. O uso da subquery é obrigatória, veja sintaxe no Capítulo 10.
No exemplo da Listagem 2.217 obtivemos o maior valor de matrícula da própria tabela Func para que a inclusão
não corresse o risco de receber erro de duplicidade. Nesta sintaxe temos de garantir que o comando Select retorne
apenas uma linha.
MAIOR SAL
---------- ----------
7845 1827
Neste exemplo usamos um comando Select como expressão dentro da própria cláusula Select. Esta montagem é
similar ao uso do Select na cláusula From, com a desvantagem de que o retorno de cada comando Select embutido
deverá conter apenas uma linha.
Neste exemplo tentamos obter mais de uma linha de um dos comandos Selects embutidos e recebemos erro.
CASE NM_FUNC||''||NM_SOBRENOME
---- -------------------------
Sra. CRISTINA HENDERSON
Sr. VICENTE LOURENCO
Sr. SILVIO OLIVA
Neste exemplo analisamos o valor retornado pela coluna IN_SEXO e de acordo com o conteúdo retornamos
informações diferentes linha a linha. Esta sintaxe é similar ao uso do DECODE; no entanto, podemos usar uma
segunda forma sintática que elimina a necessidade da comparação e na qual podemos definir diversas condições
diferentes. Veja a sintaxe completa no Capítulo 10, pois você precisará dela para fazer os exercícios.
EXERCÍCIOS
2.70) Deseja-se uma lista com todos os gerentes e seus respectivos funcionários, contendo nome e sobrenome do
gerente, código e nome do departamento, nome e sobrenome do funcionário. Todos os departamentos devem ser
apresentados (mesmo que não haja gerentes ou funcionários) e todos os funcionários devem ser apresentados
(mesmo que estejam sem departamento).
2.71) Deseja-se remover todas as atividades que não estejam em uso.
2.72) Deseja-se uma lista contendo nome, matrícula, cargo e salário dos funcionários que possuam o maior salário
da empresa e daqueles que possuam o menor salário da empresa.
2.73) Deseja-se uma relação hierárquica de todos os departamentos da empresa (código e nome), considerando-se que
os departamentos estão subordinados aos seus respectivos departamentos contábeis. A relação deve apresentar endentação
de três espaços para identificar subordinação. O departamento no mais alto nível da hierarquia não possui indicação de
departamento contábil (Null). Apresente o caminho da hierarquia. Ordene o resultado pelo nome do departamento.
2.74) Deseja-se uma lista contendo nome, sobrenome, matrícula, ramal, código e nome do departamento, código
e nome do projeto de todos os funcionários que sejam responsáveis por projeto e, simultaneamente, gerentes.
2.75) Deseja-se uma lista contendo nome, sobrenome, matrícula, ramal, código e nome do departamento, código
e nome do projeto de todos os gerentes que sejam responsáveis por projeto não pertencentes ao seu departamento.
2.76) Produza uma lista contendo nome, sobrenome, cargo e salário de todos os funcionários do sexo feminino
que ganhem mais que todos os funcionários do sexo masculino.
2.77) Produza uma lista contendo nome, sobrenome e salário de todos os funcionários que possuam mais de cinco
anos de casa e que recebam menos que a média dos funcionários com o mesmo cargo.
2.78) Deseja-se obter a média de idade, maior e menor salário e média salarial dos funcionários do sexo feminino,
grupando por grau de instrução e cargo (somente dos cargos com mais de duas funcionárias).
2.79) Determine a quantidade de funcionários por departamento separados por sexo.
2.80) Deseja-se uma lista das atividades que estejam associadas a mais de dois departamentos.
2.81) Atualize o salário dos funcionários com mais de cinco anos de casa (exceto os gerentes) para que ganhem salário
semelhante ao do funcionário com maior cargo do seu próprio departamento (usar um único comando UPDATE).
2.82) Criar uma view sobre a tabela de funcionários que selecione apenas os funcionários com salário superior a R$
2.000,00. Garanta que a atualização através desta view somente possa incluir ou alterar funcionários cujo salário
seja superior a R$ 2.000,00.
2.83) Incluir dados na tabela Depto provenientes da tabela Dept do usuário Scott, prefixando os departamentos
com “D”. Caso exista um departamento com o mesmo código, apenas atualize o nome; caso contrário, inclua o
novo departamento. O valor do departamento contábil para todos os novos departamentos é D01.
2.84) Em mais um estudo salarial, o departamento Pessoal solicitou a relação de funcionários com a indicação de
sexo (por extenso) e uma classificação dos funcionários por idade, da seguinte forma: funcionários com menos de
30 anos (jovem), entre 30 e 45 (maduro), entre 46 e 60 (meia idade) e maior que 60 anos (idoso). Ordene o
resultado pelo nome do funcionário.
2.85) Deseja-se saber o total salarial por cargo, sexo e departamento. Apresente uma amostragem contendo 30%
do total de funcionários da empresa.
INTRODUÇÃO
O banco de dados Oracle possui um conjunto de tabelas especiais para registrar informações de todos os objetos
criados no banco. A este conjunto de tabelas chamamos Dicionário de Dados.
As tabelas do dicionário estão criadas no usuário SYS e possuem nomes utilizados internamente pelos softwares da
Oracle. Porém, foram criadas views para que pudéssemos consultar as informações cadastradas.
Estas views estão divididas em três grandes grupos: User_, All_ e DBA_.
As views prefixadas com User estão associadas a objetos do usuário; desta forma, ficam disponibilizadas as
informações dos objetos criados no schema do usuário.
As views prefixadas com All estão associadas a objetos a que o usuário tenha autorização, sejam do seu schema ou
de outros schemas.
As views prefixadas com DBA possuem informações sobre todos os objetos do banco de dados.
Neste tópico veremos algumas views User que permitirão a obtenção de diversas informações sobre os objetos do
usuário. Existem muitas outras views User com informações sobre privilégios, auditoria, clusters, dependências,
filas de jobs, roles, comentários, histogramas, etc.
Aquelas associadas a rotinas de PL/SQL serão vistas no próximo capítulo; as demais podem ser consultadas
diretamente no SQL*Plus e no manual Oracle9i Server Reference.
USER_OBJECTS
Esta view contém informações de todos os objetos do usuário, sejam tabelas, views, índices, sinônimos, etc.
Através da coluna Object_Type podemos identificar qual o tipo de objeto listado. Obtemos também informações
sobre a data e hora de criação, indicação de subobjeto (tabelas particionadas, por exemplo).
No seu banco de dados você encontrará mais objetos além destes apresentados na listagem. Retiramos algumas
linhas do resultado para que não ficasse muito longo.
Observe no exemplo que a tabela Ativ não tem indicação do Data_Object_Id. Isto ocorre porque ela é uma Index
Table; desta forma, os dados não estão armazenados “exatamente” na tabela e sim no índice correspondente
chamado Sys_Iot_Top_32223, uma vez que a tabela Ativ tem identificação do objeto de 32223.
A tabela Hst_Promo também não tem indicação do Data_Object_Id. Neste caso, isso se deve ao fato de o tipo da
tabela ser Partition: os dados estão armazenados nas partições (Anos80, Anos2000, etc.) que são consideradas
subobjetos da tabela.
Se você executou todos os exemplos, certamente, neste momento, verá listada uma tabela com o nome de Teste_Lob
(no meu caso, com Object_Id de 32242). Esta tabela possui duas colunas (uma com tipo Clob e outra com tipo
Blob). Estes tipos de dados são armazenados externamente à linha da tabela, como poderemos ver pelos objetos
SYS_LOB0000032242C00001$$ e SYS_LOB0000032242C00002$$ presentes na lista de objetos e com tipo LOB.
Finalmente, observamos também a presença de diversos índices, gerados em função das PKs das tabelas Func,
Depto, etc. Estes índices recebem nomes padrões de SYS_C99999 quando não especificamos seu nome a tempo de
criação do objeto.
USER_TABLES
Esta view contém a descrição das tabelas criadas no schema do usuário que realiza a consulta.
Esta view apresenta informações estáticas sobre a tabela, tais como o tablespace onde ela está alocada, o tamanho
de uma extensão, quantidade máxima de extensões, percentual de crescimento da extensão, etc., e, ainda, uma
série de informações dinâmicas, tais como o número de linhas, o número de blocos alocados, o tamanho médio de
cada linha e diversas outras. Estas informações são alimentadas pelo comando Analyze, que armazena informações
estatísticas sobre os objetos do banco de dados a fim de dar ao Otimizador maiores condições de definir qual o
melhor caminho para estabelecer acesso aos dados quando executamos os comandos de DML (ver o tópico
Administrando o Banco de Dados).
USER_TAB_COLUMNS
Esta view contém a descrição das colunas de todas as tabelas, views e clusters do schema do usuário.
Com esta view, podemos obter informações sobre as colunas de uma determinada tabela, view ou cluster. Da
mesma forma que na User_Tables, encontramos informações estáticas tais como o tipo da coluna, tamanho, indicação
de null e valor default, dentre outras, e, ainda, informações dinâmicas como o número de valores distintos, o
número de nulls encontrados, o maior valor e o menor, etc.
Estas informações também são alimentadas pelo comando Analyze com finalidade de otimização.
USER_TAB_PARTITIONS
Encontraremos, aqui, informações sobre as diversas partições de uma tabela particionada. Estas partições podem
ser armazenadas em localizações diferentes e possuir características físicas diferentes daquelas das tabelas.
USER_INDEXES
Esta view contém informações sobre os índices das tabelas. São informações estáticas (nome, tipo, tabela, tipo da
tabela, unicidade, localização, tamanho, etc.) e dinâmicas (número de níveis, chaves distintas, número de linhas)
preenchidas quando executamos o comando Analyze.
A listagem a seguir apresenta uma consulta sobre a view User_Indexes em que podemos observar os tipos de
índices criados para garantir a unicidade da linha (SYS_C99999), o índice referente à Index Table, que na verdade
conterá todos os dados da tabela (SYS_IOT_TOP_9999), e os índices para acesso aos grandes objetos Lobs
(SYS_IL0000009999C09999$$, identificando o objeto e a coluna a que se refere).
Observe na Listagem 2.228 a presença de um índice do tipo IOT_TOP. Este índice, na verdade, corresponde à tabela
Ativ. Esta tabela é do tipo Index Organized Table (IOT), ou seja, os dados da tabela estão armazenados na linha do
índice. Não existe para esta tabela nenhum outro índice além do índice da PK, pois os dados são armazenados
juntamente com a chave do índice, obedecendo à organização estabelecida para este índice (asc, desc). Esta tabela
não possui um Rowid (faça um teste e comprove).
USER_IND_COLUMNS
Esta view contém informações sobre as colunas que são chaves dos índices: nome, tabela, tamanho e posicionamento
no índice.
USER_IND_PARTITIONS
Nesta view, encontramos informações sobre as partições de índices.
HIGH_VALUE_LENGTH NUMBER
PARTITION_POSITION NUMBER
STATUS VARCHAR2(8)
TABLESPACE_NAME VARCHAR2(30)
PCT_FREE NUMBER
INI_TRANS NUMBER
MAX_TRANS NUMBER
INITIAL_EXTENT NUMBER
USER_CONSTRAINTS
Esta view contém informações sobre as regras de integridade de uma determinada tabela. Sejam elas restrições
sobre colunas ou relacionamentos.
USER_CONS_COLUMNS
Contém informações sobre as colunas existentes nas definições das constraints.
USER_SEQUENCES
Descrição das seqüências criadas no schema do usuário.
USER_SYNONYMS
Lista de todos os sinônimos criados no schema do usuário dos objetos presentes em seu schema ou em outros.
USER_USERS
Contém informações sobre os usuários do banco de dados.
USER_VIEWS
Lista dos textos das views do banco de dados.
USER_UPDATABLE_COLUMNS
Nesta view, são apresentadas as colunas das tabelas e views indicando se as mesmas podem ser incluídas, modificadas
ou removidas.
Para avaliarmos a utilização destas informações, criamos uma view de nome Atualiza, contendo um Join entre a
tabela Funcionário e a tabela Departamento.
3 D.NM_DEPTO
4 FROM FUNC F, DEPTO D
5 WHERE F.CD_DEPTO = D.CD_DEPTO
6 AND F.CD_DEPTO IN ('A00', 'B01')
7 WITH CHECK OPTION;
View criada.
Ao selecionarmos informações da view User_Updatable_Columns, observaremos que Atualiza aparece sob a coluna
Table_Name e possui indicações de quais colunas podemos atualizar.
USER_TYPES
Apresenta a lista de tipos criados no banco de dados sob o schema do usuário.
USER_TYPE_ATTRS
Apresenta os atributos referentes a cada tipo criado no banco de dados sob o schema do usuário.
USER_TYPE_METHODS
Descreve os métodos associados aos tipos criados no schema do usuário.
USER_NESTED_TABLES
Descreve a relação entre a tabela nested e a tabela na qual ela está contida.
USER_OBJECT_TABLES
Descreve as características de uma tabela Objeto. Contém informações de armazenamento estáticas e informações
geradas pelo Analyze relativas à utilização.
USER_LOBS
Contém informações sobre os Large Objects (Lobs), como, por exemplo, a tabela em que se encontra, se é um dado
armazenado dentro ou fora da linha da tabela, nome do índice, nome do segmento.
Na consulta realizada a esta tabela, encontramos as duas colunas criadas na tabela Teste, uma do tipo Clob e outra
do tipo Blob.
USER_METHOD_PARAMS
Esta view descreve os parâmetros associados a cada método dos tipos definidos.
USER_METHOD_RESULTS
Aqui vemos a descrição dos resultados dos tipos definidos.
EXERCÍCIOS
2.86) Deseja-se uma lista de todas as tabelas do usuário contendo a quantidade de colunas, a quantidade de
relacionamentos e a quantidade de índices desta tabela.
2.87) Deseja-se obter, para cada restrição de integridade, a tabela associada, a tabela correspondente (no caso de
relacionamento), o nome da restrição, o texto da restrição ordenado por tabela associada e nome da restrição.
2.88) Determinar, para cada tabela particionada, seu nome, o nome de cada partição e as regras do particionamento.
2.89) Deseja-se informações sobre as views criadas no schema do usuário, contendo nome, texto associado, colunas
que podem ser atualizadas.
METODOLOGIA
♦ Apresentação e descrição dos métodos para controle das alterações efetuadas com os comandos da Data Manipulation Language e, ainda, apresentação da
sintaxe necessária para modificação das características da sessão a fim de que se adaptem aos formatos nacionais.
TÉCNICA
♦ Apresentação conceitual e prática com exemplos específicos de cada um dos comandos.
TRANSACTION
Transação é um conceito que determina um intervalo de tempo durante o qual várias modificações podem ser
realizadas para o banco de dados, e ao término do qual estas modificações são efetivadas ou desmanchadas em
conjunto. Não é possível efetivar parte dos comandos da transação. A transação é tratada como uma unidade,
como se fosse um único comando.
Suponhamos uma transação de transferência de uma conta corrente para outra. Esta transação envolve pelo menos
duas operações de atualização. A primeira verifica e retira o dinheiro da conta corrente do cliente-origem e atualiza
seu saldo. A segunda credita o dinheiro na conta corrente do cliente-destino e atualiza seu saldo.
Esse conjunto de operações pode ser considerado uma transação porque ele não pode ser desmembrado em operações
separadas. O dinheiro não pode ser subtraído da conta do cliente-origem sem que o cliente-destino tenha os
créditos adicionados e nem vice-versa. A operação toda é uma única unidade, uma transação.
COMMIT
O Oracle possui dois comandos para que indiquemos ao banco de dados o momento em que concluímos a transação
da aplicação. A indicação de que a transação deve ser efetivada é feita com o comando Commit e a de que a
transação deve ser desmanchada é feita com o comando Rollback.
Até que uma transação seja encerrada e efetivada com o uso do comando Commit, nenhuma das alterações feitas
por ela sobre a base de dados fica visível por qualquer outra sessão que estabeleça conexão com o banco de dados,
qualquer que seja o usuário conectado.
Isto significa que as linhas modificadas por uma transação ficam bloqueadas, impedidas de uso por qualquer
usuário do banco de dados, até que a transação seja concluída. Esse mecanismo de bloqueio chama-se Lock. Ele
torna as transações independentes, uma vez que, estando o acesso para atualização impedido, não corremos o
risco de tomar decisões em relação a modificações ainda pendentes, não efetivadas.
Após a execução do Commit e conseqüente efetivação da transação, podemos estar seguros de que as modificações
foram refletidas no banco de dados e não mais poderão ser desfeitas.
Uma transação inicia quando o primeiro comando de SQL DML é encontrado no programa ou após um Commit
ou Rollback.
do comando. Isto encerra a transação que estava em andamento anteriormente e inicia uma outra contendo o
comando de DDL.
♦ Um comando de DDL é concluído. Após a execução do comando de DDL, o Oracle implicitamente executa um
Commit. Isto encerra a transação que continha o comando. Observe que não podemos desfazer um comando
de DDL com Rollback. Após solicitarmos sua execução, a transação em uso é fechada, abre-se uma outra, faz-se
a execução do comando, a transação é encerrada e é aberta outra. Quando novamente temos acesso à informação,
a transação do comando já foi concluída.
♦ O usuário se desconecta do Oracle. Se o término da transação foi normal, isto é, não ocorreram erros, o Oracle
efetiva os comandos da última transação (Commit). Se o término foi anormal, com erros, o Oracle desmancha
todos os comandos relativos à última transação (Rollback).
Para transações terminadas normalmente em um programa Oracle Precompiler (Pro*C, Pro*Cobol, etc.), não há efetivação da transação; o
compilador não monta um comando de Commit. Neste caso o Oracle fará um Rollback. Quando trabalhamos com aplicativos ou utilitários da
Oracle, este padrão de término é estabelecido, ou seja, para término normal Commit.
É recomendação da Oracle que o usuário explicitamente informe ao banco de dados qual a ação desejada também para a última transação da
aplicação, antes de encerrar a conexão com o banco de dados.
Como recomendação adicional, temos que um programa que altere o conteúdo de uma ou mais linhas em uma ou mais tabelas deve periodicamente
fixar estas modificações (Commit). Isto deve ocorrer pois cada uma das linhas modificadas fica bloqueada, impedida de ser atualizada por outra
aplicação (Locked). Desta forma, quanto mais linhas Locked uma aplicação mantiver, menor a possibilidade de concorrência e maior a necessidade
de controle por parte do Oracle e, portanto, maior gasto de CPU.
Inicialmente, a modificação foi realizada apenas para a transação que solicitou o comando. Após a execução do
Commit, todos os usuários têm acesso à informação modificada. A palavra Work é mantida para compatibilidade
com o SQL padrão. Os comandos Commit e Commit Work são equivalentes.
Para avaliarmos o impacto do comando abriremos duas sessões do SQL*Plus simultaneamente, lado a lado, utilizando
o mesmo usuário (Desenv).
VL_SAL
------
2842
Na sessão da esquerda, consultamos o valor do salário antes e após a modificação e visualizamos o novo valor
mesmo sem executarmos o comando Commit. Na sessão da direita, visualizamos apenas o salário sem modificação.
A leitura é permitida, porém o valor apresentado é sempre aquele de antes da modificação.
Neste ponto, executamos o comando Commit para a sessão da esquerda. Na sessão da direita, a leitura já trouxe a
nova informação.
Na sessão da esquerda, repetimos a operação de atualização sem executar um comando Commit. Na sessão da
direita, tentamos realizar uma atualização na mesma linha de matrícula 160. A sessão ficou bloqueada, na fila para
atualização. Não é liberada até que o usuário que possui o controle da linha realize um Commit ou Rollback,
desbloqueando a linha.
O comando Commit possui sintaxe específica para forçar ou comentar a execução de transações distribuídas, que não serão vistas neste material.
SAVEPOINT
Savepoints são utilizados junto com o comando Rollback. Têm a finalidade de marcar um ponto intermediário na transação.
Savepoints podem ser úteis quando temos uma transação que executa diversos programas. Antes de cada programa
podemos marcar um Savepoint e, caso ocorra um erro no programa, podemos realizar um Rollback somente até o
ponto marcado, desfazendo todas as modificações realizadas pelo programa e, então, executá-lo novamente com
as correções necessárias.
Quando ocorre um Rollback para Savepoint, todas as modificações ocorridas após o Savepoint são desmanchadas e
todos os locks adquiridos após este ponto também são liberados. A transação, porém, não é efetivada. Todas as modificações
ocorridas antes do Savepoint continuam Lockeds sem efetivação, aguardando que o usuário realize um Commit.
VL_SAL
------
2774
1918
Na Listagem 2.253 foram feitas modificações em dois funcionários, Davi e Daniel. Marcamos dois pontos de
controle: um após atualizarmos o salário de Daniel e outro após atualizarmos o salário de Davi.
VL_SAL
------
3500
4000
VL_SAL
------
2774
4000
Na Listagem 2.254, comprovamos que o salário de ambos os funcionários foi modificado. Realizamos, então, um
comando Rollback para um dos pontos intermediários. O salário de Davi foi desmanchado, mas o de Daniel não,
pois o Savepoint foi marcado após a ocorrência da modificação no salário de Daniel. Desta forma, todas as
modificações ocorridas após o Savepoint Daniel_Sal foram desmanchadas.
VL_SAL
------
4000
4000
SQL> ROLLBACK;
Rollback completo.
VL_SAL
------
2774
1918
Continuando o exemplo, listamos os valores do salário dos dois funcionários e comprovamos estarem iguais.
Resolvemos, então, desfazer toda a transação e executamos um comando Rollback. Observe pelo Select apresentado
posteriormente que a transação ainda estava pendente. Caso o comando Rollback To Savepoint houvesse efetivado
o salário de Daniel, não conseguiríamos desmanchar a modificação neste momento.
Somente o comando Commit efetiva uma transação.
ROLLBACK
O comando Rollback tem a finalidade de concluir uma transação desmanchando todas as modificações efetuadas
desde o último Savepoint ou Commit.
SQL> ROLLBACK;
Rollback completo.
COUNT(*)
--------
0
No exemplo da Listagem 2.256, as 32 linhas modificadas pelo comando Update foram desconsideradas com o uso
do comando Rollback. O comando Select realizado posteriormente comprova que não existem linhas com grau de
instrução 1 na base de dados.
READ CONSISTENCY
Nos comandos acima, testamos o funcionamento do modelo de consistência do Oracle. Veremos, a seguir, suas
regras de funcionamento.
Read Consistency é o modelo de consistência suportado pelo Oracle. Possui as seguintes características:
♦ As leituras de dados não esperam por gravações destes mesmos dados.
Esta característica foi comprovada nos exemplos acima. Quando alteramos uma informação no banco de dados, as
linhas afetadas ficam bloqueadas e não podem ser modificadas por outra transação. A leitura, porém, não é impedida
de agir. Podemos continuar a leitura, mesmo que a linha a ser lida esteja bloqueada. A informação obtida não
mostra a modificação e sim a imagem que o dado tinha antes da modificação.
♦ Todos os dados lidos por uma operação de consulta não são alterados durante sua execução.
Esta frase pode parecer confusa a princípio. As listagens abaixo mostrarão uma seqüência de comandos para que o
texto seja esclarecido. A fim de que você acompanhe os exemplos, abra duas sessões do SQL*Plus lado a lado, A e B.
ATUAL
------------------------
16/11/01 10:05:33,000000
A Listagem 2.257 apresenta uma transação A em que criamos a tabela teste_rc, incluimos uma linha correspondente
ao timestamp atual e demos commit. Em seguida atualizamos esta tabela para o timestamp corrente sem dar
commit.
ATUAL
------------------------
16/11/01 10:05:33,000000
Na Listagem 2.258, iniciamos a leitura dos dados na transação B. A leitura foi iniciada às 10:25:03, ou seja, após a
transação A atualizar os dados (sem Commit). O que constatamos é que a visualização da informação corresponde
ao que realmente está valendo no banco de dados. O que o usuário B consegue ler é o que está, com certeza,
valendo. Se o usuário A desistir de atualizar (fazendo um Rollback), as decisões tomadas pelo usuário B em relação
à informação lida não são afetadas. Caso o usuário A venha a efetivar a transação, a leitura realizada pelo usuário
B já não corresponderá mais à informação presente no banco de dados; no entanto, esta atualização feita pelo
usuário A foi realizada após a leitura feita pelo usuário B independentemente de a diferença de tempo ser um
segundo, uma hora ou um dia. O que importa é que a atualização foi feita após a leitura. Iniciamos uma leitura
mais demorada (pois é um produto cartesiano de 32* 32) às 10:25:05.
10:25:08 SQL>
Retornamos à transação A e efetuamos um Commit. Esta operação foi disparada às 10:25:06 (após o início da
leitura na transação A) e concluiu retornando uma resposta às 10:25:08. Enquanto isso, a transação B estava
processando a leitura.
Nesta listagem, verificamos que o processo de leitura apresentou a última linha às 10:25:32, porém a informação
referente ao dado atualizado na tabela teste_rc não foi atualizada; vemos o timestamp de inclusão, correspondente
ao valor que estava na base quando o processo de leitura foi disparado.
O que o Oracle garante é que, quando iniciamos uma leitura, todas as informações obtidas do banco de dados são
referentes ao exato momento em que a leitura foi iniciada e não do momento em que a linha específica foi obtida.
Desta forma, a informação é consistente; vemos todos os dados relativos ao mesmo momento de tempo, como se
fosse uma foto instantânea dos dados selecionados, mesmo que a informação lida requeira tempo de acesso maior
e não seja obtida instantaneamente.
O exemplo não pretende comprovar a execução deste processo, pois que o tempo decorrido pode ter sido derivado de outros fatores e não apenas
da leitura dos dados. A intenção é simplesmente favorecer o entendimento.
O SEGMENTO DE ROLLBACK
Cada base de dados contém um ou mais segmentos de rollback. Esta área tem a finalidade de registrar as modificações
feitas por cada transação, e que podem ser desmanchadas.
Essa área é utilizada para rollback das transações, Read Consistency e Recovery.
O segmento de rollback registra diversas informações, dentre as quais:
♦ Identificador da transação.
♦ Descrição da informação como ela existia antes da modificação.
Cada modificação que realizamos sobre um dado é registrada no segmento de rollback, porém não é registrada a
modificação e sim a imagem anterior do dado. A modificação desejada é realizada diretamente na área de memória
que contém a informação (o buffer de dados do database).
Sendo assim, quando efetuamos uma leitura e a informação ainda não foi efetivada no database (Commit), o Oracle
obtém todas as linhas não modificadas dos blocos de dados em memória e todas as informações modificadas diretamente
do segmento de rollback em memória. O segmento de rollback registra o dado antes da alteração. Por este motivo, ele
é utilizado para rollback e pelo mecanismo de consistência de leitura, pois contém a imagem original do dado.
Uma instância do banco de dados não pode ser ativada, isto é, o banco de dados não inicia se não tiver acesso a
pelo menos um segmento de rollback.
Todo o controle das modificações é feito com a ajuda do segmento de rollback.
10:46:32 SQL>
10:48:02 SQL>
Na transação B, executamos uma modificação no banco de dados sem efetuar um Commit (10:47:59).
--------
0
10:49:31 SQL>
Na transação A, executamos uma leitura-consulta sobre os dados de funcionário e, como era de se esperar, não
vimos a modificação, pois a transação não foi efetivada (10:49:29).
10:50:32 SQL>
Retornamos à transação B e efetuamos um Commit para que os dados da transação fossem efetivados e todos os
Locks liberados (10:50:32).
COUNT(*)
--------
0
10:51:51 SQL>
Retornamos à transação A e refizemos a leitura. Iniciada, agora, após a efetivação da transação. Não obtivemos
informação sobre as modificações, continuamos não percebendo que a coluna Nr_Git de todas as linhas foi
modificada (10:51:51).
COUNT(*)
--------
32
10:53:34 SQL>
Na própria transação A, executamos um Commit para encerrar o efeito do Set Transaction e imediatamente depois
executamos uma leitura. Finalmente tivemos informação dos dados modificados (10:53:33).
Com estes exemplos, comprovamos o comportamento do Set Transaction em relação à visibilidade das informações
atualizadas no banco de dados.
Devemos, no entanto, avaliar com cuidado a necessidade de utilizar este comando, pois transações Read Only
muito longas podem receber erro (Snapshot Is Too Old), indicando que a base de dados já sofreu muitas modificações
desde que o comando foi executado. Quando isto ocorre, podemos encerrar a transação e reexecutar o comando
Set Transaction, se necessário.
A cláusula For Update, quando adicionada ao comando Select, altera o mecanismo de Lock padrão do Oracle (não
temos bloqueio na leitura), fazendo com que o comando Select bloqueie as linhas lidas antes do momento da atualização.
Às vezes, pode ser necessário que façamos a leitura de uma informação para efetuar algum cálculo ou verificação e
posteriormente decidir pela atualização ou não.
Quando separamos o comando Select do comando Update, não temos a certeza de que as linhas atualizadas a
tempo de Update ainda tenham a mesma informação que aquelas lidas pelo comando Select. A cláusula For
update adicionada ao comando Select dá esta garantia.
Quando executamos um comando Commit ou Rollback na transação que efetuou o comando Select For Update,
todas as modificações são efetuadas e todos os locks adquiridos são liberados, mesmo que não tenha havido
modificação em todas as linhas.
Recomenda-se a utilização deste comando para um pequeno número de linhas, pois estaremos desfavorecendo
a concorrência.
NR_GIT
------
1
1
1
1
32 linhas selecionadas.
11:12:00 SQL>
Na Listagem 2.267, transação A, efetuamos o bloqueio de todas as linhas da tabela Funcionário (11:12:00).
Na transação B (Listagem 2.268), tentamos efetuar uma atualização em apenas uma linha e ficamos bloqueados (11:13:46).
11:14:26 SQL>
A transação A (Listagem 2.269) detém o conjunto de linhas e pode indiscriminadamente efetuar atualizações
(11:14:26).
11:16:15 SQL>
11:16:15 SQL>
Se neste momento executarmos novamente o comando Select For Update na transação A, ela ficará bloqueada até
que liberemos a linha atualizada na transação B.
Isto ocorre porque, antes de recebermos, na transação A, qualquer linha do banco de dados, todas as linhas
selecionadas são bloqueadas.
DEADLOCKS
Um DeadLock é uma situação de bloqueio múltiplo em que as transações envolvidas ficam aguardando umas pelas
outras sem que seja possível a alguma delas prosseguir. Isto causa um bloqueio recíproco que só pode ser percebido
e resolvido pelo banco de dados.
Observe que ambos os locks são adquiridos, pois as transações não são conflitantes. Cada uma delas adquire
bloqueio sobre uma linha independente.
O Oracle percebe a ocorrência do conflito e cancela o último comando de uma das transações. Permitindo que o
usuário cancele a transação e a execute novamente mais tarde.
SET CONSTRAINT
Este comando tem por finalidade modificar o momento de verificação das restrições de integridade.
Normalmente, tão logo enviemos um comando de atualização para a base de dados, as regras de integridade são
verificadas (esta é a situação mais comum e o que era disponível até a release 7.3).
A partir da release 8 do Oracle, podemos determinar que uma restrição de integridade seja verificada apenas no
momento em que a transação for encerrada com Commit.
Estabelecemos o modo como a restrição irá trabalhar no momento da criação da regra de integridade. Esta condição
poderá ser fixa ou variável. Caso especifiquemos que uma constraint é Deferrable, ela poderá ter sua condição de
verificação alterada a tempo de transação.
No exemplo, a coluna B possui uma restrição que será verificada tão logo um comando de DML seja executado. Já
a coluna A possui a especificação INITIALLY DEFERRED o que indica que a validação de integridade será adiada
(deferred) para o momento em que for executado o comando COMMIT. A opção Deferrable permite a modificação
do momento da verificação dinamicamente pelo usuário através do comando SET CONSTRAINT.
SQL> COMMIT;
COMMIT
*
ERRO na linha 1:
ORA-02091: transação repetida
ORA-02290: restrição de checagem (DESENV.SYS_C002846) violada
No primeiro comando Insert, a restrição relativa à coluna A é violada, mas não ocorre erro porque esta restrição só
será verificada a tempo de Commit. No segundo comando Insert, a restrição relativa à coluna B é violada e o erro
ocorre imediatamente.
Quando executamos o comando Commit, a verificação da constraint relativa à coluna A ocorre e não é feita a
inclusão na tabela TA.
SQL> COMMIT;
COMMIT
*
ERRO na linha 1:
ORA-02091: transação repetida
ORA-02290: restrição de checagem (DESENV.SYS_C002846) violada
O comando permite que façamos a alteração de uma constraint específica ou de todas as constraints que possuem
a opção de Deferrable.
Para modificarmos o momento de validação de uma restrição específica, devemos sabxer seu nome. No exemplo
da Listagem 2.277, o comando específico seria SET CONSTRAINT SYS_C002846 DEFERRED pois este é o nome da
constraint que desejamos modificar. Para sabermos as restrições associadas a uma determinada tabela devemos
consultar a view USER_CONSTRAINTS. Veja o tópico referente ao dicionário de dados anteriormente neste capítulo.
Na Listagem 2.277, alteramos a condição de validação para o momento do término da transação. Ambas as condições
foram violadas, porém o erro somente foi verificado a tempo de Commit.
ALTER SESSION
Este comando possui um amplo espectro de modificações que pode realizar. Veremos algumas destas modificações
e suas conseqüências.
♦ Commit in Procedure – Habilita ou desabilita (Enable ou Disable) a execução do comando Commit (e Rollback)
em stored procedures ou functions.
*
ERRO na linha 1:
ORA-00034: COMMIT não é possível na sessão PL/SQL atual
ORA-06512: em “DESENV.TESTE”, line 3
ORA-06512: em line 1
Quando um comando Commit ou Rollback é executado em uma sessão, isto afeta todos os comandos executados
na sessão. Quando desejamos garantir que as rotinas que executamos na sessão não efetivem a transação, podemos
utilizar este comando.
♦ Set Sql_Trace – Habilita ou desabilita (True ou False) a facilidade de trace para a sessão.
Esta opção aparentemente não muda o comportamento da sessão, porém passa a ser gerado em disco (no ambiente
servidor) um arquivo contendo informações sobre a execução de cada um dos comandos de DML ocorridos du-
rante a sessão (ou até que esta opção seja desabilitada). Isto ajuda o DBA a verificar a existência de comandos com
problemas de performance.
♦ Set NLS – Modifica diversas características relativas à National Language Support e serão tratadas no próximo tópico.
♦ Set Flagger – Indica que os comandos de SQL executados na sessão deverão passar pelo crivo de validação
sintática de acordo com o padrão Ansi (Entry, Intermediate, Full ou OFF).
O erro apresentado indica que a sintaxe informada se acha incompatível com o padrão SQL92 Entry.
♦ Set Current_Schema – Possibilidade de alteração do schema corrente sem alteração do usuário corrente.
Listagem 2.282 – Current_Schema
SQL> ALTER SESSION SET current_schema = scott;
Sessão alterada.
COUNT(*)
--------
14
A alteração de schema faz com que as referências feitas sem qualificação sejam direcionadas para o schema
especificado no comando. Isso é uma forma prática de acesso a dados que estão em outro usuário. Observe, no
exemplo 2.282, que fizemos acesso à tabela Emp do usuário Scott sem necessidade de qualificação (Scott.emp).
Essa característica, no entanto, não dá privilégios especiais ao usuário. Para que o acesso seja possível, ele deve ter
os privilégios necessários sobre o objeto desejado.
♦ Set Constraints – Este comando tem a finalidade de modificar o momento de verificação das restrições de integridade.
Listagem 2.283 – Constraints
SQL> ALTER SESSION SET constraints = default;
Sessão alterada.
SQL> COMMIT;
COMMIT
*
ERRO na linha 1:
ORA-02091: transação repetida
ORA-02290: restrição de checagem (DESENV.SYS_C002846) violada
Com a opção Immediate, indicamos que as condições especificadas por uma Constraint Deferrable serão verificadas
imediatamente após cada comando de DML (similar ao Set Constraints All Immediate marcado no início de cada transação).
A opção Deferred indica que as condições especificadas por uma Constraint Deferrable serão verificadas quando a
transação for Committed (similar ao Set Constraints All Deferred marcado no início de cada transação).
Finalmente, a opção Default restaura todas as Constraints, no início de cada transação, ao seu estado inicial
(Deferred ou Immediate).
♦ Set Time_Zone – Determina a forma de apresentação e a zona (meridiano) para a sessão corrente. Este parâmetro
está associado à sessão (não é um parâmetro de inicialização).
Ao usarmos o formato ‘+/- hh:mm’, indicamos que o valor deverá ser fornecido em relação ao meridiano de
Greenwich. Os valores válidos variam de –12:00 a + 14:00.
Se especificarmos LOCAL, será usado o valor estabelecido quando a sessão teve início. Se especificarmos
DBTIMEZONE, desejamos que o valor seja igualado à especificação do banco de dados.
Na última opção informamos um nome de região. Para sabermos os nomes de regiões existentes devemos consultar a
coluna TZNAME da view V$TIMEZONE_NAMES. Neste caso a função SESSIONTIMEZONE retornará um nome de região.
SET ROLE
O comando Set Role adquire para a sessão, dinamicamente, os privilégios das roles informadas.
A criação de roles e sua utilidade serão vistos no tópico Administrando o Banco de Dados.
Na primeira parte deste exemplo (Listagem 2.285), criamos a role Ler e autorizamos a leitura da tabela Func para
ela. A role foi autorizada para o usuário Scott.
COUNT(*)
--------
32
COUNT(*)
--------
32
Se tivéssemos uma sessão com o usuário Scott já conectado ao banco de dados, para que ele tivesse acesso aos
privilégios liberados pela role Ler, haveria necessidade de executar o comando Set Role a fim de adquirir estes privilégios.
Se estabelecermos uma nova conexão usando o usuário Scott, podemos ou não ter necessidade de usar o comando
Set Role. Isto dependerá da forma como o DBA da instalação criou o usuário Scott. No nosso caso, quando o
usuário Scott estabeleceu conexão, todas as roles a que ele tinha direito foram adquiridas automaticamente.
GLOBALIZATION SUPPORT
A Globalization Support permite o armazenamento, processamento e recuperação de dados em linguagem nativa.
Temos a garantia da Oracle de que os utilitários do banco de dados, as mensagens de erro, a ordem para sort, data,
informações monetárias e convenções de calendário se adaptem automaticamente à linguagem e local nativos.
Até a versão 8i este conjunto de características era chamado de National Language Support. A NLS habilita o
Oracle a apresentar mensagens na linguagem especificada e datas no formato determinado. Permite que as aplicações
utilizem um conjunto de caracteres para armazenamento de dados no banco de dados compatível com o país
(acentuação, cedilha, etc.).
As aplicações desenhadas com National Language Support podem trabalhar com diferentes conjuntos de caracteres
armazenados no banco de dados, com linguagens diferentes, com formatos de data, com formatos para números,
com regras de ordenação e de conversão.
Na versão 9i as capacidades anteriores foram ampliadas e a National Language Support passou a ser um subconjunto
da Globalization Support. Nesta versão poderemos desenvolver aplicações com capacidade multilingüística e
produtos de software podem ser acessados e executados de qualquer parte do mundo sem modificação.
utilitário (Lxegen) capaz de ler os dados de um arquivo de texto e convertê-lo para formato binário adequado a
que as rotinas do banco de dados façam acesso.
♦ Disponibilização do utilitário Oracle Locale Builder Utility (Lbuilder) para que possamos customizar os dados
locais tais como linguagem, charset, território ou ordenação lingüística.
ESQUEMA DE CODIFICAÇÃO
Quando pressionamos uma tecla em um terminal qualquer, a aparência do caracter apresentado depende do
esquema de codificação em uso naquela estação. A tecla pressionada é traduzida de acordo com o esquema de
codificação (ou character set) em uso na estação. O mesmo ocorre quando o terminal recebe um código e o
converte para uma figura (letra, número e pontuação) no vídeo.
UNICODE
Unicode é um esquema de codificação de caracteres universal que permite que armazenemos informações de
qualquer linguagem usando um único charset. Unicode gera um código único para cada caracter, independentemente
da plataforma, programa ou linguagem. A utilização de Unicode em aplicações multi-plataforma ou cliente-servidor
ou em sites da web pode trazer grandes benefícios uma vez que ele permite que um software possa ser utilizado em
diferentes plataformas e países sem necessidade de reengenharia e, talvez o mais importante, ele permite que o
dado seja transportado através de diferentes ambientes sem corrupção.
A definição destes conjuntos de caracteres é feita a tempo de criação do banco de dados e não pode ser alterada
posteriormente, a não ser para esquemas de codificação mais amplos que os originais.
♦ Variáveis da sessão (definidas com o comando Alter Session). As variáveis declaradas na sessão só valem para
aquela sessão do usuário. São elas: Nls_Calendar, Nls_Comp, Nls_Currency, Nls_Date_Format, Nls_Date_Language,
Nls_Dual_Currency, Nls_Iso_Currency, Nls_Language, Nls_Length_Semantics, Nls_Numeric_Characters, Nls_Sort,
Nls_Territory, Nls_Timestamp_Format, Nls_Timestamp_Tz_Format. Estas variáveis se sobrepõem àquelas
definições feitas para a estação.
O último grupo é a utilização dos parâmetros em funções de SQL, que aceitam parâmetros específicos.
Neste estudo, trabalharemos com a sessão do usuário, modificaremos variáveis no ambiente e testaremos algumas
funções de SQL. O arquivo init.ora é de utilização exclusiva do DBA e não será abordado.
ALTER SESSION
Nosso estudo começará pelo comando Alter Session, que, como já comentamos anteriormente, tem a finalidade
de alterar características relativas à sessão do usuário.
♦ A linguagem usada para as mensagens do Oracle. No caso do leitor que seguiu os passos para instalação do
Personal Oracle, as mensagens podem ser apresentadas, por default, em português (Brazilian Portuguese) ou
inglês (American), dependendo da língua em que o Windows está instalado.
♦ A linguagem usada para nomes de dias, nomes de meses e suas respectivas abreviações.
♦ Símbolos equivalentes usados na linguagem para A.M., P.M., A.D. e B.C.
♦ Seqüência de ordenação dos caracteres.
Listagem 2.287 – Alter Session Set Nls_Language
SQL> ALTER SESSION SET NLS_LANGUAGE = AMERICAN;
Session altered.
DATA 1 DATA 2
------------------------- ---------------------------
FRIDAY -16/NOVEMBER /01 FRIDAY -NOV-2001 03:56 PM
A tabela a seguir apresenta a lista de linguagens válidas para o Oracle9i. As linguagens listadas com (*) indicam
aquelas para as quais as mensagens de erro do Oracle foram traduzidas.
O parâmetro Nls_Date_Language determina a linguagem a ser usada para os nomes de dias e meses e suas respectivas
abreviaturas. Não há necessidade de arquivo específico, e portanto podemos efetuar a alteração para qualquer linguagem
válida (para linguagens que usem caracteres multi-byte há necessidade de o terminal suportar este tipo de código).
DATA 1 DATA 2
------------------------ --------------------------
VENDREDI-16/NOVEMBRE /01 VENDREDI-NOV-2001 04:10 PM
O parâmetro Nls_Numeric_Characters explicitamente especifica o caracter a ser usado como separador decimal e o caracter
a ser usado como separador de milhar. Estes caracteres devem ser informados na ordem <d> (decimal) e <g> (grupo,
milhar). Os valores devem ser diferentes, não podem ser numéricos nem um dos seguintes caracteres: “+”, “-“, “<“, “>“.
SAL 1 SAL 2
--------------------- ------------------
$5.275,00 USD5.275,00
O parâmetro Nls_Currency permite que façamos a modificação do símbolo financeiro local e o parâmetro
Nls_Iso_Currency permite que determinemos o território cujo símbolo ISO deve ser usado.
Session modifiée.
SAL 1 SAL 2
--------------------- ------------------
R$5.275,00 BRC5.275,00
Observe que só podemos modificar diretamente o símbolo local. O símbolo ISO é determinado indiretamente,
pelo território.
O parâmetro Nls_Sort altera a seqüência na qual o Oracle ordena os caracteres.
T
-
a
A
á
Á
T
-
A
a
Á
á
TO_CHAR(SY
----------
16/11/2544
TO_CHAR(SY
----------
16/11/0090
T
-
á
T
-
A
á
Á
O parâmetro NLS_COMP permite a utilização de características da língua para efeito de comparação. Normalmente,
a comparação na cláusula Where é binária. Para que a comparação obedecesse às características específicas da
linguagem era necessário o uso da função NLSSORT.
No exemplo da Listagem 2.295 pudemos observar que a modificação exclusiva do parâmetro NLS_SORT não fez
com que a comparação na cláusula Where levasse em consideração as características lingüísticas. Somente quando
indicamos o valor ANSI para NLS_COMP conseguimos que as comparações também levassem em consideração o
parâmetro NLS_SORT.
LOCAL DUAL
--------------------- ---------------------
R$123.456,78 US$123.456,78
O parâmetro NLS_Dual_Currency permite a definição de um outro símbolo financeiro a ser utilizado nas
apresentações monetárias.
LOCALTIMESTAMP CURRENT_TIMESTAMP
----------------------------------- -------------------------------
16/11/01 17:00:39,000000 16/11/01 17:00:39,000000 -02:00
LOCALTIMESTAMP CURRENT_TIMESTAMP
----------------------------------- ------------------------
16/11/2001 17:00:45 16/11/2001 17:00:45 BRST
ocorre quando modificamos o atributo do parâmetro TIME_ZONE. Quando usamos SET TIME_ZONE, a apresentação
passou a ser nomeada e o formato funcionou. Experimente você alterar o formato de TIME_ZONE para um valor
numérico (tipo ‘-02:00’) e executar o comando Select novamente ou alterar o formato de timestamp para numérico
e manter o valor atual de Time Zone. Verifique o que acontece em cada situação.
VARIÁVEIS DE AMBIENTE
Após verificarmos a utilização diretamente na sessão, veremos quais as diferenças para a declaração usando as
variáveis de ambiente. Como exemplificação, trabalharemos o RegEdit do Windows.
Se você não tem intimidade na alteração de valores no RegEdit, tome muito cuidado no seu manuseio. Todos os programas instalados no Windows
gravam variáveis de ambiente nestes registradores a fim de consultarem a tempo de inicialização. Uma alteração incorreta pode causar sérios
problemas na execução de programas e até do próprio Windows.
Vários dos parâmetros vistos junto com o comando Alter Session podem ser utilizados como variáveis de ambiente:
Nls_Calendar, Nls_Comp, Nls_Currency, Nls_Date_Format, Nls_Date_Language, Nls_Dual_Currency,
Nls_Iso_Currency, Nls_Numeric_Characters, Nls_Sort, Nls_Timestamp_Format, Nls_Timestamp_Tz_Format. Estes
valores não serão repetidos neste momento.
Estudaremos apenas aqueles parâmetros ainda não mencionados.
Para visualizarmos uma informação nos registradores do Windows, devemos:
♦ Clicar no botão Iniciar (Windows), opção Executar, escrever RegEdit e clicar OK.
♦ Na janela apresentada do lado esquerdo expandir o nó Hkey_Local_Machine (clicar sobre o sinal +). Novamente
expandir o nó Software subordinado ao nó anterior (clicar sobre o sinal + lateral ao nome do nó). Subordinada
a este nó, veremos a pasta Oracle.
♦ Clicar sobre a pasta Oracle e encontrar a pasta Home (no meu caso Home5) que corresponde à instalação do
banco de dados. Na janela à direita veremos surgir o conjunto de variáveis de ambiente do Oracle.
♦ Navegar com a barra de rolagem na janela da direita e localizar o parâmetro NLS_LANG.
O parâmetro Nls_Lang é composto de três informações: linguagem, território e character set, com o formato:
<linguagem>_<território>.<charset>.Todos os componentes são opcionais. Se desejarmos informar o território sem
a linguagem, por exemplo, devemos usar o formato: _<território>.<charset >.
Este parâmetro permite que associemos um charset para as aplicações executadas no ambiente cliente. Observe que
a definição de um charset só pode ser feita com referência ao banco de dados (e torna-se imutável) e na variável de
ambiente Nls_Lang, determinando o ambiente Cliente.
Cada sessão estabelecida neste ambiente usará as informações estabelecida na variável Nls_Lang. Isto significa que
podemos ter diferentes características de sessão conectadas ao banco de dados simultaneamente. A conversão de
um charset (banco para cliente) ao outro (cliente para banco) é feita de forma transparente.
Se não especificarmos um valor para Nls_Lang, serão usadas as especificações do banco de dados de Nls_Language
e Nls_Territory. Além disso, as demais especificações que fizermos relativas a outras variáveis de ambiente serão
ignoradas. Por outro lado, ao especificarmos Nls_Lang, as especificações feitas em nível de init.ora são ignoradas
para a sessão do usuário.
Para a criação dos demais parâmetros no registrador do Windows, devemos:
♦ Ainda usando a mesma janela do RegEdit, selecionar no menu de opções Editar, Novo e Valor da Seqüência.
♦ Será criado um novo parâmetro na janela à direita, que poderemos preencher com o nome da variável de
ambiente desejada.
♦ Depois de preenchermos o nome, devemos efetuar um clique duplo sobre o ícone para que seja apresentado um
diálogo que permitirá o preenchimento do valor desejado.
O parâmetro Nls_Credit determina a criação de um símbolo para indicação de crédito em relatórios. Este símbolo
pode conter quaisquer caracteres até o comprimento de nove posições. O valor default é obtido de Nls_Territory.
O parâmetro Nls_Debit determina a criação de um símbolo para indicação de débitos em relatórios. Este símbolo
pode conter quaisquer caracteres até o comprimento de nove posições. O valor default é obtido de Nls_Territory.
O parâmetro Nls_List_Separator especifica o caracter a ser usado para separar valores em uma lista de valores. Deve
ser um caracter single-byte e não pode ser numérico, nem similar aos símbolos monetários
(Nls_Monetary_Characters) e nem um dos seguintes símbolos: (+), (-), (<), (>), (.). O valor é derivado de Nls_Territory.
O parâmetro Nls_Monetary_Characters determina o símbolo para unidade monetária e centavos, por exemplo, ($)
para o dólar americano e (¢) para centavos de dólar. Os caracteres especificados devem ser diferentes entre si e não
podem ser numéricos, nem um dos seguintes símbolos: (+), (-), (<), (>), (.). O valor é derivado de Nls_Territory.
O parâmetro Nls_Nchar_Conv_Excp indica se a perda de dados durante uma conversão explícita ou implícita de
tipo de dado deve ou não reportar um erro.
EXERCÍCIOS
Neste grupo de exercícios, trabalharemos com duas cópias ativas do SQL*Plus. À primeira chamaremos sessão 1 e
à segunda, sessão 2.
2.90) Coloque outra cópia do SQL*PLUS ativa no usuário DESENV (sessão 2).
2.91) Atualize sua tabela Depto (sessão 1), mas não dê Commit. O que o outro usuário (sessão 2) vê? Por quê?
2.92) Dê Commit sobre suas atualizações (sessão 1). A visibilidade na sessão 2 é possível agora? Por quê?
2.93) Atualize sua tabela Depto (sessão 1), mas não dê Commit. Através da sessão 2, tente atualizar a mesma linha
alterada anteriormente. O que acontece? Por quê? Dê Rollback nas duas sessões.
2.94) Atualize sua tabela Depto (sessão 1), mas não dê Commit. Na sessão 2, execute um SELECT ….. FOR UPDATE.
Qual a diferença?
2.95) Explique, com suas palavras, o que acontece nos trechos de programa abaixo:
Listagem-resposta 2.95A
SQL> UPDATE FUNC
3 SET VL_SAL = VL_SAL * 1.10;
33 linhas atualizadas;
SQL> COMMIT;
Validação completa.
Listagem-resposta 2.95B
SQL> DELETE FROM FUNC WHERE NR_GIT = 21;
1 linhas deletada.
SQL> ROLLBACK;
Rollback completo.
Listagem-resposta 2.95C
SQL> UPDATE DEPTO
2 SET CD_GERENTE = 200
3 WHERE CD_DEPTO = 'A00';
1 linha atualizada.
2.100) Deseja-se uma relação dos aniversariantes da empresa, contendo o nome e sobrenome de cada funcionário,
o dia do aniversário e o mês do aniversário (por extenso, em português). Ordene a relação por número de mês e
estabeleça quebra de página a cada troca de mês.
2.101) Deseja-se uma relação para a folha de pagamento, contendo a matrícula, nome, sobrenome, salário bruto,
INSS (8% do salário), FGTS (10% do salário), Ticket (8,00 por dia do mês), Vale Transporte (2,00 por dia do mês). O
mês será fornecido como parâmetro. Os valores financeiros deverão ser formatados, devendo ser apresentado o
símbolo financeiro (R$).
2.102) Formatar Timestamp e Timestamp Tz para que o ano apresente 4 posições.
2.103) Iguale a zona de tempo da sessão à zona de tempo do banco de dados. Verifique o resultado em seguida.
INDEX TABLES
Index Organized Tables são tipos especiais de tabelas que armazenam os dados ordenados pela primary-key.
Nesta forma de organização, o Oracle mantém as linhas da tabela em um índice B-Tree construído com base na
primary key. As linhas do índice contêm o valor da chave e os valores dos demais dados.
Devemos especificar, obrigatoriamente, uma primary key para este tipo de tabela.
Cada tabela no banco de dados possui uma pseudocoluna chamada Rowid. As tabelas Index-Organized não possuíam
esta característica até a versão 8i. No nosso modelo de dados, a tabela Ativ foi construída com este tipo de organização.
Durante os exerícios apresentados neste capítulo, utilizamos algumas vezes a tabela Ativ e não notamos diferença
na sintaxe dos comandos de DML. Realmente, não existe diferença sintática. A diferença é na forma de
armazenamento da informação.
ROWID LÓGICO
A obtenção do endereço da linha (Rowid) de uma tabela Index-Organized é resolvida pelo Oracle ao fornecer um
endereço lógico chamado de Logical Rowid, que é baseado na chave primária da tabela.
É desta forma (através destes Rowids lógicos) que o Oracle consegue realizar a construção de índices secundários
para uma tabela do tipo Index-Organized.
Cada Logical Rowid usado em um índice secundário pode incluir um physical guess (como se fosse uma dica), que
identifica a localização do bloco da linha no momento em que o índice secundário foi criado ou reconstruído.
Com esta característica, o Oracle poderá usar este guess para fazer acesso diretamente ao bloco-folha (da tabela
Index-Organized) em vez de fazer uma pesquisa pela chave. Isto garante que acessos através dos Logical Rowids
para tabelas que não sejam voláteis (como é o caso do ambiente Data Warehouse) tenham performance similar aos
Rowids físicos das tabelas normais.
Para tabelas voláteis, no entanto, se o guess se tornar ultrapassado (envelhecido, incorreto), a pesquisa pela pri-
mary key deve ser realizada.
A pseudocoluna Rowid identifica uma linha. Uma primary A primary key identifica a linha. Deve ser especificada
key pode ser especificada, se desejarmos. É opcional. obrigatoriamente.
A existência de uma coluna Rowid permite a construção de índices secundários. O Rowid lógico permite a construção de índices secundários.
O acesso aos dados é baseado no Rowid. O acesso é baseado na primary key.
Uma pesquisa seqüencial retorna todas as linhas Um full-index scan retorna todas as linhas na ordem da primary key.
na ordem de leitura (aleatória).
Podemos declarar restrições do tipo Unique, assim Ambas as formas de restrição são permitidas.
como triggers associados à tabela.
A tabela pode ser armazenada em um Cluster Não pode ser armazenada em um cluster.
juntamente com outras tabelas.
Particionamento por Hash, por intervalo ou ambos. Particionamento por Hash.
As features de distribuição, replicação são suportadas. Nenhuma destas features é suportada.
CD_ATIV ROWID
---------- -------------
10 *BAIAAHICwQv+
20 *BAIAAHICwRX+
50 *BAIAAHICwTP+
100 *BAIAAHICwgL+
Podemos fazer acesso a uma linha usando o formato “Where Rowid = <valor>”, onde o valor corresponde à
estrutura incompleta (opaca) retornada pelo comando “Select Rowid”.
O acesso através do Rowid lógico é a maneira mais rápida de obter o acesso a uma linha específica, apesar de
eventualmente requerer o acesso a mais de um bloco.
Um Rowid lógico não é alterado se o valor da primary key não mudar. Isso é menos estável que um Rowid físico,
que permanece imutável independente das alterações feitas para a linha.
CD_ATIV ROWID
---------- -------------
11 *BAIAAHICwQz+
CD_ATIV ROWID
---------- -------------
51 *BAIAAHICwTT+
LARGE OBJECTS
Large Objects ou Lobs são tipos de dados que podem armazenar informações de até 4 GB de dados binários
(imagens, sons, vídeos, etc.) ou caracteres.
♦ Externos – São armazenados fora do banco de dados (Bfiles). Na coluna com este tipo, existe uma referência ao
arquivo existente no sistema operacional (Bfile).
TIPOS DE LOBS
Os tipos de Lobs são os seguintes:
♦ Blob – Contém dados binários.
♦ Clob – Contém dados caracteres compatíveis com o charset do banco de dados (single-byte).
♦ Nclob – Contém dados caracteres compatíveis com o national charset definido para o banco de dados.
♦ Bfile – Contém dados binários armazenados fora do banco de dados em arquivos do sistema operacional.
Listagem 2. 301 – Criação de Tlob
SQL> CREATE TABLE TLOB
2 (C_NUMBER NUMBER,
3 C_CLOB1 CLOB,
4 C_CLOB2 CLOB,
5 C_BLOB1 BLOB,
6 C_BLOB2 BLOB,
7 C_BFILE1 BFILE,
8 C_BFILE2 BFILE,
9 C_NCLOB1 NCLOB,
10 C_NCLOB2 NCLOB)
11 LOB (C_BLOB1, C_BLOB2) STORE AS (TABLESPACE USERS DISABLE STORAGE IN ROW),
12 LOB (C_CLOB1, C_CLOB2) STORE AS (ENABLE STORAGE IN ROW),
13 LOB (C_NCLOB1) STORE AS SEG_NCLOB1 (TABLESPACE USERS
14 DISABLE STORAGE IN ROW INDEX IX_NCLOB1 (TABLESPACE USERS));
Tabela criada.
No exemplo da Listagem 2.301, podemos ressaltar algumas características básicas dos Lobs:
♦ Podemos definir mais de um lob por tabela (isto não é possível com colunas Long ou Long Raw).
♦ Podemos especificar uma cláusula Lob que determine características físicas para a coluna, tais como o tablespace
onde a informação será armazenada, se o armazenamento poderá ser efetuado na linha (enable storage in row)
quando o tamanho da coluna é menor que 4000 bytes ou sempre será efetuado em outra área (disable storage in
row), o nome da área externa de armazenamento, o nome do índice de controle do lob e alguns outros parâmetros
de armazenamento (não serão vistos neste material).
A especificação de nome para o segmento onde serão armazenados os dados pode ser útil para avaliação física e
possível modificação.
LOCATOR
Um Lob é composto de duas partes:
♦ Dado – O que realmente é armazenado.
♦ Locator – Um indicador da localização do lob armazenado no banco de dados.
Quando inicializamos uma coluna Lob, seu conteúdo pode ser: Null (indicando que não existe valor nem locator
associado), Empty (indicando que existe um locator porém o dado está vazio) ou com valor (quando ambas as
informações estão preenchidas).
LOB INDEX
O Lob Index é criado implicitamente. É usado para encontrar o dado do lob em seu segmento. O lob index contém
o rowid (endereço) da tabela, que contém a coluna Lob, o offset e o endereço da parte de dados.
No exemplo da Listagem 2.301, observamos que podemos determinar um nome para este índice. Isto pode ser
interessante para obtermos informações físicas a respeito do índice gerado e, se necessário, alterá-las.
INCLUSÃO
Podemos inicializar uma coluna Lob usando o próprio comando Insert.
1 linha criada.
1 linha criada.
No exemplo da Listagem 2. 304, o directory Local indica o diretório do sistema operacional onde se encontra o arquivo.
ALTERAÇÃO
A alteração se dará em termos de locators, que serão substituídos por outros no caso do primeiro exemplo ou
diretamente sobre o texto com o uso da função TO_CLOB.
SQL> COMMIT;
Validação completa.
No exemplo da Listagem 2. 306 a seguir, alteraremos os valores das colunas Clob, sem uso de TO_CLOB.
SQL> COMMIT;
Validação completa.
SQL> COMMIT;
Validação completa.
CONSULTAS
Na primeira consulta, obteremos os dados das colunas CLOB.
Na Listagem 2. 307, vemos que o SQL*Plus apresenta o valor da coluna. Traz o conteúdo endereçado pelo locator.
Na Listagem 2.308, vemos que as demais colunas não podem ser apresentadas pelo SQL*Plus, pois se trata de
colunas binárias (C_BLOB1 e C_BFILE1).
Os exercícios referentes a Lobs serão feitos em PL/SQL, uma vez que a manipulação em SQL é bastante básica.
EXERCÍCIOS
2.104) Incluir dados na tabela TLOB com o formato especificado abaixo, a partir da tabela Func:
a) c_number deve receber cd_mat.
b) c_clob1 deve receber nm_func concatenado com nm_sobrenome.
c) c_clob2 deve receber o nome do departamento em que o funcionário trabalha.
d) c_nclob1 deve receber o projeto que o funcionário coordena (se for o caso).
e) c_nclob2 deve receber a concatenação de data de nascimento, data de admissão, cargo, grau de instrução e salário.
2.105) Associar a coluna C_BFILE1 ao arquivo correspondente indicado pela coluna nm_foto.
INTRODUÇÃO
Neste tópico, analisaremos alguns comandos da Data Definition Language a fim de conhecermos a amplitude da
linguagem SQL. De um modo geral, os comandos tratados na SQL DDL são executados por um Administrador de
Banco de Dados (DBA) que possui um conhecimento mais profundo do funcionamento interno do Oracle e,
portanto, mais condição de indicar as melhores formas de armazenamento.
Nosso estudo dará ao desenvolvedor uma visão geral da SQL DDL e dos mecanismos de armazenamento do
banco de dados.
SCHEMA
Os objetos do banco de dados estão divididos em dois grandes grupos: schema objects e non schema objects.
Um schema é uma coleção de estruturas de dados subordinadas a um user e possui o mesmo nome do user. Cada
usuário é “dono” de um único schema.
Os objetos subordinados a um usuário, ou seja, os schema objects, são os seguintes tipos de estruturas:
♦ clusters
♦ database links (+)
♦ index-only tables e tables
♦ indexes
♦ object tables, object types, object views (#)
♦ sequences
♦ materialized views e materialized view logs
♦ stored functions, stored procedures, database triggers, packages e external procedure libraries (*)
♦ synonyms
♦ views
(+) Só disponíveis se a opção de distribuição estiver instalada. Não serão vistos neste material.
(*) Só disponíveis se PL/SQL estiver instalado. Serão vistos no próximo capítulo (PL/SQL).
(#) Só disponíveis se a opção objects estiver instalada.
Existem, no banco de dados, objetos que são compartilhados por diversos usuários e não estão subordinados ao
schema de nenhum deles, são os non schema objects. Correspondem aos seguintes objetos:
♦ directories
♦ profiles
♦ roles
♦ rollback segments
♦ tablespaces
♦ users
♦ Alter – Com este grupo de comandos, podemos alterar a estrutura de um objeto previamente definido. De
acordo com o objeto são estabelecidos limites específicos para as modificações permitidas: Alter Table, Alter
Profile, Alter Rollback Segment, etc.
♦ Drop – Com este grupo de comandos, podemos remover o objeto e sua estrutura do banco de dados. As sintaxes
variam por tipo de objeto: Drop Sequence, Drop Synonym, Drop Cluster, etc.
♦ Grant / Revoke – Neste grupo de comandos, estabelecemos (ou revogamos) autorização de uso sobre objetos
criados ou sobre ações permitidas relativas ao banco de dados.
♦ Audit / NoAudit – Este grupo de comandos coordena a gravação de informações de auditoria para
acompanhamento e investigação das ações realizadas pelos usuários no banco de dados.
♦ Diversos – Neste grupo final se acham os comandos Analyze (responsável por coletar estatísticas, validar estruturas
ou identificar cadeias), Comment (que permitirá que adicionemos comentários ao dicionário de dados), Re-
name (para alterarmos o nome de um objeto) e Truncate (para removermos todas as linhas de uma tabela ou
cluster e liberarmos espaço livre).
A sintaxe e definição específica de cada um dos comandos serão objeto de estudo em outro material específico para DBAs.
ARMAZENAMENTO
Quando falamos em banco de dados Oracle, estamos tratando de duas partes bem distintas: a parte física de armazenamento
(estática), chamada de Database, e a parte dos mecanismos de software e memória (ativa), chamada de Instância.
Conceitualmente, diremos que um Database é composto de:
♦ Arquivos de Banco de Dados (Database Files) – Onde estão armazenados os dados do dicionário de dados e os
dados do usuário.
♦ Arquivos de Log (Redo Log Files) – Onde estão armazenadas todas as ações executadas sobre os dados e que
podem ser utilizadas para recuperação dos mesmos.
♦ Arquivos de Controle (Control Files) – Onde estão armazenadas informações sobre os arquivos de dados a fim
de garantir a integridade do banco como um todo.
♦ Arquivo de Parâmetros (Parameter File – Init.ora) – Onde estão armazenados os parâmetros de inicialização do
banco de dados.
No esquema da Figura 2.13, vemos a presença das estruturas de armazenamento e a Instância (representando os
mecanismos de software).
Uma instância Oracle é composta basicamente de:
♦ Uma área de memória compartilhada pelos componentes do software (processos), chamada de SGA (System
Global Area).
♦ Diversos componentes do software, chamados de processos background (programas que trabalham para todos
os usuários do banco de dados), dos quais quatro são indispensáveis: Pmon (Process Monitor – controle dos
processos Server que agem para os usuários), Smon (System Monitor – controle do sistema como um todo),
Dbwr (Database Writer – encarregado de efetuar a gravação nos arquivos do banco de dados) e Lgwr (Log Writer
– responsável por efetuar a gravação nos arquivos de Redo Log).
Esta é a noção básica de funcionamento do banco de dados onde os processos background, a área de memória
compartilhada e o database são os componentes mais importantes. Os processos Server também presentes no
diagrama fazem o acesso e atualização (em memória) nos dados dos usuários. Dependendo da arquitetura escolhida
pelo DBA, podemos ter um processo Server para cada processo do usuário (nesta arquitetura, cada sessão estabelecida
no ambiente cliente ativa um processo Server no ambiente servidor, que tem como tarefa executar todos os comandos
solicitados pela sessão do cliente) ou podemos ter um processo Server compartilhado por diversos usuários (nesta
arquitetura, cada sessão estabelecida no ambiente cliente envia solicitações de execução de comandos que são
enfileirados e executados por um dos processos Server disponíveis).
TABLESPACE
No esquema apresentado na Figura 2.13, vemos um conjunto de arquivos chamados de Database Files. Estes
arquivos são visíveis externamente pelo sistema operacional; internamente, o Oracle relaciona estes arquivos a
objetos internos chamados de Tablespaces.
No esquema da Figura 2.14, vemos que um tablespace pode estar associado a um ou mais database files, enquanto
um database file só pode estar associado a um tablespace.
O tablespace corresponde à unidade lógica de armazenamento. É dentro dele que armazenaremos as tabelas,
índices, dicionário de dados, etc.
BLOCO ORACLE
Pelo esquema, observamos que um tablespace é composto por diversas partes do mesmo tamanho. Estas partes são
chamadas de blocos. O tamanho de um bloco é definido pelo DBA na criação do banco de dados, no arquivo
init.ora. O bloco será a unidade mínima de leitura ou gravação para disco, ou seja, toda vez que desejarmos obter
informações de uma determinada linha de uma tabela, no mínimo estaremos solicitando a leitura de um bloco. Da
mesma forma, quando estivermos alterando apenas uma determinada coluna de uma linha específica, estaremos
solicitando a gravação de um bloco. Observemos que o tamanho deste bloco afeta tanto o espaço de disco quanto
o de memória alocada, uma vez que esta passará a ser a unidade de alocação de espaço.
Como o próprio sistema operacional possui uma unidade mínima de leitura e gravação, quando o DBA determinar
o tamanho do bloco Oracle, deverá verificar o tamanho desta unidade mínima do sistema operacional em que fará
a instalação do banco de dados e calcular um múltiplo inteiro deste valor.
SEGMENTOS
No esquema da Figura 2.15, vemos o espaço reservado para um determinado tablespace ser utilizado por quatro
segmentos: um segmento Func, um segmento Proj, um segmento de índice e um segmento de rollback.
Assim, formalizaremos dizendo que um database contém tipos de segmentos dos quais estamos conhecendo três:
segmentos para armazenamento de dados (Data Segment), segmentos para armazenamento de índices (Index
Segment) e segmentos para armazenamento de informações de rollback (Rollback Segment).
Na Figura 2.15, os segmentos Func e Proj são segmentos de dados, o segmento S1 é de índice e o segmento R é de rollback.
Fica claro, no esquema, que um segmento pode ser composto de diversas partes de informação, isto é, não necessariamente
é contínuo. Observe que o segmento Func possui duas “partes” (extensões), assim como o segmento R e o Proj.
EXTENSÃO
Uma extensão é uma área contínua para armazenamento de informações, um conjunto de blocos contíguos. Desta
forma, um segmento pode ser composto de uma ou mais extensões.
A primeira extensão alocada tem o nome especial de Initial. As demais são chamadas de Next. Por questões de
performance, serial ideal que todos os dados de uma determinada tabela estivessem armazenados na extensão
Initial. Como isto nem sempre é possível, devemos, na especificação de um segmento qualquer, estimar o tamanho
das extensões Initial e Next e a quantidade de vezes que um segmento pode se esticar, anexando novas extensões
à sua área útil.
Estas informações são fundamentais para que o DBA faça um cálculo preciso da área necessária para cada segmento,
da área necessária ao tablespace e, conseqüentemente, do espaço requerido para o banco de dados.
CREATE TABLE
A forma básica de um comando Create Table é apresentada na criação da tabela Empregado da Listagem 2. 309 a seguir.
Neste exemplo, vemos a especificação de uma tabela relacional. Cada coluna definida possui um tipo, que pode ser
escalar ou um tipo definido pelo usuário. Além do tipo, cada coluna pode ter uma ou mais restrições associadas. Na
especificação da tabela, determinamos o tamanho da área a ser reservada para aquela tabela com a cláusula Storage
e o tablespace em que esta área deve ser reservada.
As restrições de integridade também podem ser especificadas ao tempo de criação da tabela, inclusive com
especificação do momento da validação (DEFERRED). Quando não determinamos este momento, o default é que
a validação seja feita no momento em que o comando é executado.
CD_CHAVE ROWID
---------- -------------
1 *BAIABAICwQL+
Na Listagem 2.310, criamos uma tabela relacional com organização do tipo Index. Com este tipo de organização é
obrigatória a especificação de primary key. Os dados desta tabela estão organizados em relação a esta primary key
especificada, como se fosse um índice. Este tipo de organização pode ser muito útil pois não há necessidade da
criação de um índice para a primary key em separado, uma vez que a própria tabela já está organizada desta forma.
TIPOS DE DADOS
Quando especificamos uma coluna em uma tabela relacional ou um atributo em um objeto, devemos especificar o
tipo de dado que será armazenado naquele elemento. Os tipos de dados predefinidos pelo Oracle são apresentados
a seguir. Os tipos de dados padrão Ansi também são aceitos.
♦ Char – é uma string de caracteres de tamanho fixo (máximo de 2000 bytes). Tamanho default e mínimo é de 1
byte. A palavra Byte indica que o tamanho será considerado em bytes enquando Char indica caracteres. Para
ambientes multi-bytes o uso desta informação faz diferença.
♦ Varchar2 – é uma string de tamanho variável (máximo de 4000 bytes). O tamanho é obrigatório. A palavra Byte
indica que o tamanho será considerado em bytes enquando Char indica caracteres. Para ambientes multi-bytes
o uso desta informação faz diferença.
♦ Nchar – é uma string de caracteres de tamanho fixo (máximo de 2000 bytes). Tamanho default e mínimo é de
1 byte. O conteúdo armazenado deve ser compatível com o national charset definido para o banco de dados.
♦ Nvarchar2 – é uma string de tamanho variável (máximo de 4000 bytes). O tamanho é obrigatório. O conteúdo
armazenado deve ser compatível com o national charset definido para o banco de dados.
♦ Number(p,s) – dados numéricos, onde P varia de 1 a 38 dígitos. A escala S pode variar de –84 a 127.
♦ Long – é uma string de caracteres de tamanho variável com até 2Gb de comprimento. Só é possível a definição
de uma coluna do tipo long por tabela.
♦ Long Raw – é uma string de dados binários com comprimento variável até o limite de 2Gb de tamanho.
♦ Raw – armazena dados binários. O tamanho é obrigatório. Semelhante ao VARCHAR2 para dados binários.
Comprimento máximo de 2000 bytes.
♦ Date – armazena data e hora. Consideradas válidas no intervalo de 01/01/4712 AC. até 31/12/9999 DC. O
formato default é dd-mes-aa.
♦ Blob – armazena um locator para uma área que contenha dados binários (tam. máximo de 4Gb).
♦ Clob – armazena um locator para uma área que contenha dados alfanuméricos de comprimento máximo de
4Gb. Usa o database character set.
♦ Nclob – armazena um locator para uma área que contenha dados alfanuméricos de comprimento máximo de
4Gb. O conteúdo armazenado deve ser compatível com o national charset definido para o banco de dados.
♦ Bfile – armazena um locator para um arquivo do sistema operacional (tam. máximo de 4Gb).
♦ Rowid – string hexadecimal representando um endereço único de uma linha na tabela. O tipo é usado para
valores retornados pela pseudocoluna ROWID.
♦ Urowid (n) – string hexadecimal representando o endereço lógico de uma linha em uma IOT. O tamanho é opcional
e corresponde ao tamanho de uma coluna do tipo UROWID. O comprimento máximo e default é de 4000 bytes.
♦ Timestamp – Ano, mês e dia assim como hora, minuto, segundo e fração de segundo. O parâmetro <prc> indica
o número de dígitos da parte fracionária do segundo. Os valores podem variar de 0 a 9. O default é 6.
♦ A cláusula With Time Zone inclui a apresentação da zona de tempo. Onde a zona de tempo corresponde à
diferença (em horas e minutos) entre a hora local e UTC (hora de Greenwich).
♦ Se usarmos With Local Time Zone, são válidos todos os valores. A diferença entre esta opção e a anterior é
que a zona de tempo não é armazenada no banco de dados. O dado, quando armazenado, é normalizado
para a Dbtimezone e, quando recuperado, é visualizado pelo usuário com a Time Zone da sessão (ocorre uma
Segunda conversão).
♦ Interval Year – armazena um período de tempo em anos e meses, onde <prc> corresponde ao número de dígitos
do campo Year. São aceitos valores de 0 a 9. O default é 2.
♦ Interval Day – armazena um período de tempo em dias, horas, minutos e segundos. O primeiro <prc> determina o
número máximo de dígitos no campo Day. São aceitos valores de 0 a 9, sendo o default 2. O segundo <prc> determina
o número máximo de dígitos na parte fracionária do campo Second. Os valores válidos variam de 0 a 9. O default é 2.
♦ Sys.AnyData – contém uma instância de um determinado tipo com um conjunto de instâncias de dados daquele
tipo. Pode ser usado como parâmetro de rotina onde esta flexibilidade é necessária. Os valores podem ser built-
in datatypes ou user-defined types.
♦ Sys.AnyType – este tipo pode conter uma descrição de qualquer tipo SQL nomeado ou transiente.
♦ Sys.AnyDataSet – contém uma instância de um determinado tipo com dado e descrição. Pode ser usado como
coluna para uma tabela onde armazenamos valores heterogêneos em uma única coluna. Os valores podem ser
built-in datatypes ou user-defined types.
♦ Sys.XMLType – pode ser usado para armazenamento de dados XML no banco de dados. Possui funções membro
que podemos usar para acesso, extração e consulta. Internamente, a informação é armazenada em Clobs.
♦ Sys.UriType – corresponde a um supertipo que pode ser especializado em HttpUriType ou DbUriType. O subtipo
HttpUriType armazena URLs para páginas Web externas ou para arquivos usando o protocolo Http. O subtipo
DbUriType faz referências a dados (Uri) dentro do DB.
♦ Sys.UriFactoryType – é um tipo para fatoração. Pode criar e retornar outros tipos de objetos. Quando uma string
URL é atribuída a um tipo UriFactoryType podemos obter instâncias dos vários subtipos dos UriTypes. Ele
analisa a string URL e identifica o tipo da URL e cria uma instância do subtipo adequado (Htto, Dburi, etc.).
♦ Mdsys.SDO_Geometry – é uma coluna objeto para armazenamento da descrição geométrica de um objeto do
tipo spatial. Não pode ser a única coluna da tabela.
♦ Ordsys.OrdAudio – é um tipo objeto para armazenamento de áudio.
♦ Ordsys.OrdImage – é um tipo objeto para armazenamento de imagem.
♦ Ordsys.OrdVideo – é um tipo objeto para armazenamento de vídeo.
CONSTRAINTS
As constraints são restrições estabelecidas para as colunas de uma tabela. Podem ser dos seguintes tipos:
♦ Primary Key – Determina uma coluna ou conjunto de colunas como a chave primária da tabela. Esta restrição,
implicitamente, cria um índice único que garanta a regra.
♦ Unique – Determina uma coluna ou conjunto de colunas como chave única. Não serão admitidas duas linhas
com o mesmo valor para estas colunas.
♦ Foreign Key – Determina uma coluna ou conjunto de colunas como possuindo um conjunto válido de valores presentes
em outra tabela. Corresponde a uma referência ou integridade referencial. A palavra-chave References identifica a
primary key ou unique key que é referenciada por uma foreign key em uma restrição de integridade referencial.
♦ Check – Especifica a condição que cada linha da tabela deve satisfazer.
♦ Not Null – Especifica que a coluna é de preenchimento obrigatório.
As restrições podem ser validadas tão logo o comando de SQL DML seja submetido, ou podemos adiar sua validação
para o momento em que a transação for concluída.
Tabela criada.
No exemplo da Listagem 2.311, a restrição associada à coluna Dep e a restrição associada à coluna Sexo só serão
verificadas quando a transação vier a ser concluída. Já a restrição referente à coluna Empno (primary key) será
verificada imediatamente; podemos, se desejarmos, adiá-la até o término da transação. Isto é possível graças à
presença da cláusula Deferrable, que indica que o adiamento pode ser utilizado (através da cláusula Set Con-
straints, vista anteriormente).
CREATE TYPE
O comando Create Type permite a criação de um tipo de dado definido pelo usuário. Utilizamos a criação de tipos
no tópico referente a objetos.
CREATE INDEX
Já comentamos anteriormente que a criação de uma Constraint do tipo primary key para uma tabela estabelece a
criação implícita de um índice. Isto também ocorre quando a Constraint é do tipo Unique.
Desta forma, os índices criados explicitamente pelo comando Create Index não possuem o objetivo de garantir a
integridade lógica dos dados e sim produzir melhores resultados para as consultas efetuadas sobre a tabela que
mencionem as colunas do índice como restrição na cláusula Where.
Como a criação de índices adicionais para uma tabela pode trazer tanto benefícios quanto prejuízos, devemos
efetuar uma análise criteriosa, juntamente com o DBA, para verificarmos a necessidade de tal criação.
Na Listagem 2.302, vemos a criação de um índice para a coluna Nome do tipo único.
No exemplo da Listagem 2.313, criamos um database link de nome Centro para estabelecer conexão com um
banco de dados identificado pela string de conexão (Host String) DBCentro. Quando este link for usado, no banco
de dados remoto, estabelecerá conexão com o usuário Scott e password Tiger.
A Host String será analisada na instalação dos aplicativos de desenvolvimento.
CREATE SYNONYM
A criação de um sinônimo objetiva a definição de um nome alternativo para uma tabela ou view, presente no
schema do próprio usuário ou de outro (desde que tenha autorização para acesso).
No exemplo da Listagem 2.314, estamos criando um sinônimo para a tabela Scott.Emp no usuário Desenv. Desta
forma, qualquer referência que fizermos à tabela Emp será associada pelo Oracle à tabela Emp do schema Scott.
A associação só é estabelecida se tivermos privilégios para acesso à tabela desejada. A criação do sinônimo não é
suficiente para acesso.
No exemplo da Listagem 2.315, estamos criando um sinônimo Dept para uma tabela Dept armazenada no schema
do usuário Scott de um banco de dados remoto. A utilização do sinônimo, neste caso, teve a finalidade de tornar
transparente a localização de uma tabela.
CREATE SEQUENCE
Seqüências são objetos atualizados pelo Oracle Server com o objetivo de fornecer um número sequencial. Este
número pode ser usado para a geração de primary keys em tabelas.
SQL> SELECT CD_MAT, NM_FUNC FROM FUNC WHERE CD_MAT > 400;
CD_MAT NM_FUNC
---------- --------
401 SEQUENCE
Na Listagem 2.317, usamos o valor gerado seqüencialmente para preenchimento do número da matrícula da
tabela Func.
Observe que não existe nenhum vínculo entre o sequence e a matrícula da tabela Func. A seqüência pode ser usada
simultaneamente para o preenchimento da primary key de outra tabela ou outro uso qualquer.
Na Listagem 2.318, vemos a utilização da mesma seqüência para o preenchimento do número da atividade.
Na Listagem 2.319, consultamos a view User_Sequences para obter informações sobre a seqüência criada. Observamos
que a coluna Last_Number já possui valor 410, enquanto o valor atual da seqüência ainda é 402. Essa discrepância
ocorre em função do valor especificado no atributo Cache. Quando acionamos a numeração pela primeira vez, o
Oracle pré-aloca dez números (no nosso caso) de seqüência, atualiza o dicionário de dados que possui esta informação
e reserva estes números em memória. À medida que vamos utilizando a numeração, estes valores em memória vão
sendo fornecidos.
Existe um risco potencial de perda de numeração seqüencial em caso de falha no sistema (em que a memória é
perdida) e quando ocorre uma falha de programa e desmanchamos a transação sem, efetivamente, utilizar os
números seqüenciais solicitados. O sequence não volta a disponibilizar os números perdidos, pois não tem controle
sobre o uso dado à seqüência.
CREATE ROLE
Role é um conjunto de privilégios que pode ser adquirido por usuários ou outras roles. O objetivo das roles é
auxiliar a administração de privilégios no banco de dados.
Podemos adicionar diversos privilégios a uma determinada role e, posteriormente, autorizar o uso desta role por
diversos usuários.
No esquema da Figura 2.16, a role Funcionário recebe diversos privilégios: permissão para acesso à tabela Func
(schema Desenv), permissão para criar tabelas, permissão para criar seqüências, acesso irrestrito à tabela Depto
(schema Desenv). Estes privilégios são, agora, repassados para os usuários Scott, Aluno, Davi, Dilson e Gabriel.
Em vez de o DBA passar cada um dos privilégios individualmente para cada usuário, a role estabelece uma forma
de organizarmos perfis de usuário, de tal forma que podemos passar autorização coletivamente de acordo com o
perfil do usuário desejado.
A diferença entre a atribuição direta dos privilégios e a utilização da role é que os privilégios adquiridos diretamente
estão associados ao usuário até que o privilégio seja revogado. Quando atribuímos o privilégio para a role e
autorizamos o uso da role pelo usuário, os privilégios são adquiridos dinamicamente quando ocorre a conexão
daquele usuário. Se modificarmos os privilégios contidos na role e outro usuário utilizar a mesma role, já receberá
privilégios diferentes do primeiro usuário.
COUNT(*)
--------
33
Na Listagem 2.321, a role Funcionário é autorizada para o usuário Scott. Após a conexão, como Scott, podemos
adquirir o uso da role e utilizar os privilégios liberados para ela.
Os privilégios contidos em uma role são adquiridos por um determinado usuário a tempo de login. Esta ação pode
ser automática ou o usuário pode ser obrigado a executar o comando Set Role explicitamente. Na criação do
usuário, esta diferença é determinada (Create User).
CREATE DIRECTORY
Esse comando cria um objeto diretório no banco de dados e o associa a um diretório existente no sistema operacional.
Esse objeto será usado para indicação do diretório de armazenamento de arquivos associados às colunas do tipo Bfile.
No exemplo da Listagem 2.322, foi criado o objeto Disco_D, cujo diretório físico corresponde a “D:\teste”.
CREATE VIEW
O comando Create View já foi visto anteriormente no item Views Relacionais do tópico Consultas Complexas.
CREATE USER
Este comando cria um usuário para acesso ao banco de dados. Adicionalmente, indica o tablespace onde o usuário
poderá criar seus objetos, limita quota de espaço por tablespace, determina um profile contendo limites sobre os
recursos do sistema.
Na Listagem 2.323, criamos o usuário Gabriel e autorizamos sua conexão com o Oracle usando a role Connect
(será vista no item Grant).
A criação do usuário Gabriel utilizou os seguintes parâmetros:
♦ Identified By – Indica que o usuário deve especificar sua password a tempo de login.
♦ Default Tablespace – Indica que, quando o usuário executar um comando Create e não informar o tablespace
onde o objeto deve ser criado, este (indicado no parâmetro) será o tablespace utilizado.
♦ Temporary Tablespace – Indica o tablespace a ser utilizado pelo Oracle para alocação de área temporária para a
execução de determinados comandos do usuário.
♦ Quota – Limita a área disponível no tablespace especificado para a criação de objetos do usuário.
♦ Password Expire – Indica que a password criada é temporária e deve ser substituída quando o usuário fizer o
primeiro login.
Senha alterada
Conectado.
SQL>
No exemplo da Listagem 2.314 não vemos o momento em que a password é alterada. O motivo é que o Oracle
apresenta um diálogo contendo três campos para preenchimento: a senha antiga, a nova e uma redigitação da
nova. Com o sucesso da operação retornamos à linha de comando do SQL*Plus.
ALTER <OBJETO>
O comando Alter, de um modo geral, permite que façamos modificações nas especificações que tivermos feito a
tempo de Create.
Nem todos os objetos permitem modificações. Por exemplo, não temos comando Alter para Database Link, Syn-
onym e Directory.
Cada objeto também possui limitações sobre o que pode ser alterado. Por exemplo, o comando Alter View permite
que refaçamos a compilação da View.
No exemplo da Listagem 2.325, o usuário Gabriel recebeu autorização de uso da role Funcionário e esta passou a
ser sua role default. Isto significa que, quando este usuário estabelecer conexão com o banco de dados, todas as
autorizações presentes na role Funcionário serão adquiridas por ele, automaticamente.
Na Listagem 2.326, fazemos modificações nas especificações da seqüência (todos os parâmetros podem ser alterados)
e renomeamos o índice de primary key da tabela Func.
DROP <OBJETO>
O comando Drop remove tanto o objeto quanto sua definição do dicionário de dados. Esta ação é irreversível, pois
se trata de um comando de SQL DDL.
A sintaxe do comando Drop é simples e necessita apenas do tipo do objeto e de seu nome.
Na Listagem 2.327, diversos objetos do banco de dados foram eliminados. Observe que, quando eliminamos a
tabela F, usamos a expressão “cascade constraints”. Esta expressão força a eliminação da tabela mesmo havendo
relacionamentos associados a ela (o relacionamento é eliminado também).
TRUNCATE TABLE
O comando Truncate Table elimina todas as linhas da tabela (como se fosse um comando Delete sem cláusula Where)
e pode liberar espaço não utilizado de volta para o tablespace. A diferença básica para um comando Delete é que não
é gerada nenhuma informação de rollback; desta forma o comando não pode ser desfeito, como é o caso do Delete.
Na Listagem 2.328, a tabela G foi truncada (todas as linhas eliminadas) e o espaço reservado para ela foi retornado
ao tablespace, podendo ser utilizado por outros objetos. Já a tabela Peças foi truncada (todas as linhas eliminadas),
porém o espaço já alocado para ela foi preservado, permanecendo associado à tabela, porém vazio.
RENAME
Altera o nome de uma tabela, view, sequence ou sinônimo privativo. O objeto deve estar contido no schema do usuário.
GRANT
O propósito do comando Grant é ceder privilégios. Temos dois tipos de privilégios: sobre os objetos (que deve ser
cedido pelos usuários “donos” dos objetos) e de sistema (cedido pelo DBA), que autorizam determinadas ações dos
usuários no banco de dados.
Na Listagem 2.330, autorizamos diversas operações sobre a tabela Func para os usuários Gabriel e Scott. Permitimos
o uso do diretório Disco_D pelo usuário Gabriel e autorizamos que este mesmo usuário tivesse livre acesso à tabela
Depto. A cláusula With Grant Option indica que o usuário Gabriel pode passar os privilégios recebidos sobre a
tabela Depto para outros usuários à sua escolha.
A lista a seguir apresenta os privilégios disponíveis e a quais objetos se aplica:
♦ Alter – Permite que sejam feitas modificações na tabela (ou sequence). Aplicável a tabelas e seqüências.
♦ Delete – Permite que sejam removidas linhas da tabela. Aplicável a tabelas, views e views materializadas (que
sejam atualizáveis).
♦ Execute – Permite a execução da rotina especificada ou o acesso a qualquer programa especificado no package
nomeado. Aplicável a procedures, funções, pacotes, libraries, tipo definido pelo usuário, operator e Index Type.
♦ Index – Permite a criação de índices para a tabela. Aplicável a tabelas.
♦ Insert – Permite a inclusão de linhas na tabela. Aplicável a tabelas, views e views materializadas (que sejam atualizáveis).
♦ On Commit Refresh – Permite a atualização das views materializadas associadas à tabela quando ocorre um
Commit. Aplicável a tabelas usadas por views materializadas.
♦ Query Rewrite – Permite que um comando de pesquisa executado sobre uma tabela seja reescrito pelo otimizador
se ele encontrar uma View Materializada que responda à pergunta de forma mais eficaz. Aplicável a tabelas
usadas por views materializadas.
♦ Read – Permite a leitura de arquivos no diretório. Aplicável a Directories.
♦ References – Permite a criação de restrições de integridade que façam referência à tabela ou view. Aplicável a tabelas.
♦ Select – Permite que a tabela seja consultada. Aplicável a tabelas, seqüências, views e views materializadas.
♦ Under – Permite a criação de uma subview para a view ou um subtipo subordinado ao tipo. Aplicável a views e
tipos definidos pelo usuário.
♦ Update – Permite que sejam feitas alterações nos dados da tabela. Aplicável a tabelas, views e views materializadas
(que sejam atualizáveis).
♦ Write – Permite a gravação no diretório. Aplicável a Directories. Não permite que o usuário (ou role) que receber
os privilégios grave Bfiles.
Muitos dos privilégios listados ainda não fazem sentido uma vez que ainda não estudamos objetos (Cap. 4) ou,
especificamente, views materializadas (Cap. 5). O objetivo destes privilégios ficará bem mais claro após completarmos
estes estudos.
Os privilégios podem ser concedidos para o usuário diretamente ou para uma role.
Na Listagem 2.331, diversos privilégios foram autorizados para a role Funcionário. Desta forma, todos os usuários
que tiverem autorização de uso desta role receberão estes privilégios quando fizerem conexão com o banco de
dados novamente.
No exemplo da Listagem 2.332, a role Connect foi autorizada para o usuário Gabriel. Já o usuário Scott recebeu
dois privilégios de sistema (Alter Session e Drop User) com a possibilidade de repassar estes privilégios a outros
usuários (With Admin Option). No último exemplo o comando autorizou a role Connect para o usuário Novo ao
mesmo tempo que criou este usuário.
Ao instalarmos o Oracle, algumas roles são instaladas também:
♦ Connect – Alter Session, Create Cluster, Create Database Link, Create Sequence, Create Session, Create Syn-
onym, Create Table, Create View.
♦ DBA – Alter Any Cluster, Alter Any Index, Alter Any Library, Alter Any Procedure, Alter Any Role, Alter Any
Sequence, Alter Any Snapshot, Alter Any Table, Alter Any Trigger, Alter Any Type, Alter Database, Alter Profile,
Alter Resource Cost, Alter Rollback Segment, Alter Session, Alter System, Alter Tablespace, Alter User, Analyze Any,
Audit Any, Audit System, Backup Any Table, Become User, Comment Any Table, Create Any Cluster, Create Any
Directory, Create Any Index, Create Any Library, Create Any Procedure, Create Any Sequence, Create Any Snap-
shot, Create Any Synonym, Create Any Table, Create Any Trigger, Create Any Type, Create Any View, Create
Cluster, Create Database Link, Create Library, Create Procedure, Create Profile, Create Public Database Link, Cre-
ate Public Synonym, Create Role, Create Rollback Segment, Create Sequence, Create Session, Create Snapshot,
Create Synonym, Create Table, Create Tablespace, Create Trigger, Create Type, Create User, Create View, Delete
Any Table, Drop Any Cluster, Drop Any Directory, Drop Any Index, Drop Any Library,Drop Any Procedure, Drop
Any Role, Drop Any Sequence, Drop Any Snapshot, Drop Any Synonym, Drop Any Table, Drop Any Trigger, Drop
Any Type, Drop Any View, Drop Profile, Drop Public Database Link, Drop Public Synonym, Drop Rollback Seg-
ment, Drop Tablespace, Drop User, Execute Any Library, Execute Any Procedure, Execute Any Type, Force Any
Transaction, Force Transaction, Grant Any Privilege, Grant Any Role, Insert Any Table, Lock Any Table, Manage
Tablespace, Restricted Session, Select Any Sequence, Select Any Table, Update Any Table.
♦ Exp_Full_Database – Backup Any Table, Execute Any Procedure, Select Any Table.
♦ Imp_Full_Database – Alter Any Table, Alter Any Type, Audit Any, Become User, Comment Any Table, Create
Any Cluster, Create Any Directory, Create Any Index, Create Any Library, Create Any Procedure, Create Any
Sequence, Create Any Snapshot, Create Any Synonym, Create Any Table, Create Any Trigger, Create Any Type,
Create Any View, Create Database Link, Create Profile, Create Public Database Link, Create Public Synonym,
Create Role, Create Rollback Segment, Create Tablespace, Create User, Drop Any Cluster, Drop Any Directory,
Drop Any Index, Drop Any Library, Drop Any Procedure, Drop Any Role, Drop Any Sequence, Drop Any Snap-
shot, Drop Any Synonym, Drop Any Table, Drop Any Trigger, Drop Any Type, Drop Any View, Drop Profile,
Drop Public Database Link, Drop Public Synonym, Drop Rollback Segment, Drop Tablespace, Drop User, Ex-
ecute Any Procedure, Insert Any Table, Select Any Table.
As roles DBA, Connect e Resource estão mantidas nesta versão apenas para compatibilidade. A Oracle recomenda
que criemos nossas próprias roles para determinarmos privilégios e segurança do banco de dados. Estas roles
predefinidas podem não ser mais criadas em futuras versões do Oracle.
REVOKE
O comando Revoke retira um privilégio previamente fornecido.
Da mesma forma que o Grant, o comando Revoke se refere a privilégios de sistema e privilégios para os objetos.
Na listagem anterior, decidimos retirar todos os privilégios para atualização na tabela Func tanto do usuário Scott
quanto da role Funcionário.
Na Listagem 2.334, o usuário Scott perdeu a autorização de uso da role Connect e, conseqüentemente, de todos os
privilégios associados à role. Posteriormente, perdeu a possibilidade de alterar sua sessão.
EXERCÍCIOS
2.106) O que é e para que serve o ROLLBACK SEGMENT?
2.107) Crie um usuário de nome PROD com as seguintes características:
♦ tablespace default User_data
♦ tablespace temporario Temporary_Data
♦ password Prod
♦ espaço total no tablespace user_data
2.108) Transforme este usuário em um usuário comum (acesso à role Connect apenas).
2.109) Autorize o acesso para leitura sobre sua tabela Funcionário para o user PROD.
2.110) Estabeleça conexão com PROD. Crie um sinônimo para a tabela Func do user DESENV.
2.111) Ainda com a conexão PROD. Faca um select (join) entre sua tabela FUNC e a tabela FUNC do user DESENV
listando todos os funcionários (seus) que tenham ou não correspondência na tabela do outro user. Inverta o teste.
O resultado é o mesmo?
2.112) Agora com a conexão DESENV, autorize a atualização da tabela Depto pelo user PROD.
2.113) De que forma podemos autorizar e desautorizar o acesso a objetos no Oracle?
2.114) Qual a diferença entre o comando Truncate e o comando Delete?
2.115) Qual a utilidade de uma Role?
2.116) Descreva com suas palavras o relacionamento entre Physical Files, Tablespaces e Tables.
Listagem-resposta 2.01A
SQL> SELECT CD_MAT, NM_FUNC, NM_SOBRENOME, NR_CARGO
2 FROM FUNC
3 WHERE IN_SEXO = 'F'
4 AND NR_CARGO > 55;
2.02) Deseja-se uma lista que contenha número de matrícula, nome e sobrenome do funcionário em cujo sobrenome
não seja encontrada a letra “E”.
Listagem-resposta 2.02A
SQL> SELECT CD_MAT, NM_FUNC, NM_SOBRENOME
2 FROM FUNC
3 WHERE NM_SOBRENOME NOT LIKE '%E%';
2.03) Repita o exercício anterior de tal forma que a letra pesquisada seja fornecida por variável de substituição na
linha do comando.
Listagem-resposta 2.03A
SQL> L 3
3* WHERE NM_SOBRENOME NOT LIKE '%E%'
SQL> C/%E%/%&1%
3* WHERE NM_SOBRENOME NOT LIKE '%&1%'
SQL> SAVE LIKE
Criado file LIKE
SQL> @LIKE O
antigo 3:WHERE NM_SOBRENOME NOT LIKE '%&1%'
NOVO 3:WHERE NM_SOBRENOME NOT LIKE '%O%'
2.04) Deseja-se uma lista contendo código e nome do projeto para todos os projetos que possuam o texto “AMA”
em algum lugar de seu nome. Como restrição adicional, temos que somente os projetos em cujo código existam os
números 21 como terceiro e quarto caracter devem ser pesquisados.
Listagem-resposta 2.04A
SQL> SELECT CD_PROJ, NM_PROJ
2 FROM PROJ
3 WHERE NM_PROJ LIKE '%AMA%'
4 AND CD_PROJ LIKE '__21%';
Observe que o código do projeto foi comparado com dois sublinhados, os números 21 e %, indicando que as duas
primeiras posições seriam desconhecidas, o terceiro e quarto caracter, 2 e 1 respectivamente, e o % indicando
qualquer número de caracteres após estes valores.
2.05) Obtenha a descrição da tabela Funcionário.
Listagem-resposta 2.05A
SQL> DESCRIBE FUNC
A descrição apresenta o nome da coluna no banco de dados (Name), seu tipo e tamanho (Type) e a indicação de
obrigatoriedade de preenchimento (Null?). Sabemos, agora, que quando uma coluna não é preenchida, não ocupa
espaço na linha que é gravada no banco de dados; por isso, diz-se que seu conteúdo é NULL (desconhecido,
ausente). Na tabela Func, apenas a coluna Matrícula deve ser preenchida obrigatoriamente; as demais colunas
podem ser informadas ou não a tempo de cadastramento.
2.06) Deseja-se uma lista contendo os códigos de departamento para os departamentos que possuam funcionários.
Na listagem-resposta, não deve haver repetição de código de departamento.
Listagem-resposta 2.06A
SQL> SELECT DISTINCT CD_DEPTO
2 FROM FUNC
3 WHERE CD_DEPTO IS NOT NULL
4 /
No exercício, são selecionados apenas os funcionários que estão alocados a algum departamento, ou seja, cujo
código do departamento está preenchido.
2.07) Deseja-se uma lista contendo código do departamento e nome do departamento de todos os departamentos
em que o código do departamento contábil não está preenchido.
Listagem-resposta 2.07A
SQL> SELECT CD_DEPTO, NM_DEPTO
2 FROM DEPTO
3 WHERE CD_DEPTO_CTB IS NULL;
2.08) Deseja-se uma lista (matrícula, nome e departamento) de todos os funcionários que estejam alocados aos
departamentos A00, B01 ou C01.
Listagem-resposta 2.08A
SQL> SELECT CD_MAT, NM_FUNC, CD_DEPTO
2 FROM FUNC
3 WHERE CD_DEPTO IN ('A00', 'B01', 'C01');
Antes de prosseguir, faça outros testes usando BETWEEN, substituindo IN por OR e tentando realizar os exercícios
acima com variáveis de substituição.
2.09) Deseja-se saber quais os funcionários (matrícula, cargo e departamento) que foram cadastrados na partição
Anos95_99 da tabela de histórico de promoções.
Listagem-resposta 2.09A
SQL> SELECT CD_MAT, NR_CARGO, CD_DEPTO
2 FROM HST_PROMO PARTITION (ANOS95_99);
2.10) Deseja-se incluir dois novos empregados na tabela de funcionários. Este cadastramento é preliminar e,
portanto, nem todos os dados são conhecidos. Utilize as duas sintaxes vistas no item Incluindo Novas Linhas
para realizar as inclusões.
Listagem-resposta 2.10A
SQL> INSERT INTO FUNC
2 (NM_FUNC, NM_SOBRENOME, VL_SAL, CD_DEPTO,
3 IN_SEXO, NR_GIT, NR_CARGO, CD_MAT)
4 VALUES
5 ('JOANA', 'RODRIGUES', 1435, 'E21',
6 'F', 17, 52, 1);
1 linha criada.
1 linha criada.
2.11) Deseja-se, agora, completar as informações sobre os novos funcionários. Sabendo-se que a funcionária Joana
recebeu ramal 1512 e data de admissão 15/01/99 e que o funcionário Marcelo recebeu ramal 1418 e data de
admissão 15/02/99, é necessário que os dados na tabela Func sejam atualizados e que sejam incluídas as linhas
correspondentes ao valor inicial dos funcionários na tabela de histórico de promoções.
Listagem-resposta 2.11A
SQL> UPDATE FUNC
2 SET NR_RAMAL = 1512,
3 DT_ADM = '15/01/99'
4 WHERE CD_MAT = 1;
1 linha atualizada.
2.12) Inclua-se como funcionário. Preencha todas as colunas da tabela. O número da matrícula deve corresponder
ao dia do seu aniversário somado ao ano.
Listagem-resposta 2.12A
SQL> INSERT INTO FUNC
2 VALUES
3 (1994, 'DANIEL', 'FERNANDES', 'A00', 1512,
4 '12/02/99', 55, 19, 'M', '07/03/87', 1700, 'c:\windows\esteira.bmp');
1 linha criada.
2.13) Tente trocar o código do departamento associado a você para um código de departamento inválido. O que
acontece? Por quê?
Listagem-resposta 2.13A
SQL> UPDATE FUNC
2 SET CD_DEPTO = 'D02'
3 WHERE CD_MAT = 1994;
UPDATE FUNC
*
ERRO na linha 1:
ORA-02291: restrição de integridade (DESENV.SYS_C002817) violada - chave-pai
não localizada
O erro ORA-02291: restrição de integridade (DESENV.SYS_C00643) violada – chave-pai não localizada, ocorre
porque existe um relacionamento entre a tabela Funcionário e a tabela Departamento, onde cd_depto na tabela
Funcionário é chave estrangeira (foreign key) em relação à coluna cd_depto da tabela Departamento, que é pri-
mary key. Desta forma, qualquer tentativa de atribuição de valor à coluna cd_depto de Func resultará em erro se o
valor não for encontrado na coluna cd_depto da tabela Departamento.
2.14) Inclua todos os funcionários do departamento D11 no departamento D01, acrescentando ao número da
matrícula o valor 340.
Listagem-resposta 2.14A
SQL> INSERT INTO FUNC
2 SELECT CD_MAT + 340, NM_FUNC, NM_SOBRENOME, 'D01',
3 NR_RAMAL, DT_ADM, NR_CARGO, NR_GIT,
4 IN_SEXO, DT_NASC, VL_SAL, NM_FOTO
5 FROM FUNC
6 WHERE CD_DEPTO = 'D11';
9 linhas criadas.
Listagem-resposta 2.15A
SQL> UPDATE FUNC
2 SET NR_RAMAL = 1437
3 WHERE CD_DEPTO = 'D11';
9 linhas atualizadas;
Listagem-resposta 2.16A
SQL> DELETE FROM HST_PROMO PARTITION (ANOS80);
2 linhas deletadas;
Listagem-resposta 2.17A
SQL> UPDATE FUNC
2 SET VL_SAL = VL_SAL * 1.1;
45 linhas atualizadas.
2.18) Exclua todos os funcionários que ganhem mais que o funcionário cuja matrícula é 200. O que ocorre? Por quê?
Listagem-resposta 2.18A
SQL> SELECT VL_SAL FROM FUNC
2 WHERE CD_MAT = 200;
VL_SAL
------
3051,4
2.19) Deseja-se atualizar o salário de todos os funcionários que são gerentes de departamento em 5%.
Listagem-resposta 2.19A
SQL> UPDATE FUNC
2 SET VL_SAL = VL_SAL * 1.05
3 WHERE CD_MAT IN (SELECT CD_GERENTE FROM DEPTO);
8 linhas atualizadas.
2.20) Deseja-se excluir todos os departamentos que não possuam funcionários alocados.
Listagem-resposta 2.20A
SQL> DELETE FROM DEPTO
2 WHERE CD_DEPTO NOT IN (SELECT DISTINCT CD_DEPTO
3 FROM FUNC);
1 linha deletada.
2.21) Deseja-se uma lista (matrícula, nome e salário) de todos os funcionários que ganhem mais que todos os
funcionários do departamento parametrizado. Ordene o resultado por salário. Os funcionários sem salário devem
ser apresentados no início da relação.
Listagem-resposta 2.21A
SQL> SELECT CD_MAT, NM_FUNC, VL_SAL
2 FROM FUNC
3 WHERE VL_SAL > ALL (SELECT VL_SAL FROM FUNC
4 WHERE CD_DEPTO = '&DEPTO')
5 ORDER BY VL_SAL NULLS FIRST;
Entre o valor para depto: D11
antigo 4: WHERE CD_DEPTO = '&DEPTO')
novo 4: WHERE CD_DEPTO = 'D11')
2.22) Deseja-se uma lista (matrícula, nome e cargo) dos funcionários que possuam cargo igual ao cargo de algum
dos funcionários do departamento D11.
Listagem-resposta 2.22A
SQL> SELECT CD_MAT, NM_FUNC, NR_CARGO
2 FROM FUNC
3 WHERE NR_CARGO = ANY (SELECT NR_CARGO FROM FUNC
4 WHERE CD_DEPTO = 'D11');
2.23) Deseja-se uma lista contendo matrícula, nome, departamento e salário de todos os funcionários que sejam
responsáveis por projeto (tabela Proj), mas não sejam gerentes (tabela Depto). Ordene o resultado por salário. Os
funcionários sem salário devem ser apresentados no fim da relação.
Listagem-resposta 2.23A
SQL> SELECT CD_MAT, NM_FUNC, CD_DEPTO, VL_SAL
2 FROM FUNC
3 WHERE CD_MAT IN (SELECT CD_RESP FROM PROJ)
4 AND CD_MAT NOT IN (SELECT CD_GERENTE FROM DEPTO
5 WHERE CD_GERENTE IS NOT NULL)
6 ORDER BY VL_SAL NULLS LAST;
Observe na Listagem-resposta 2.23 que o subselect apresentado possui na cláusula Where uma restrição para que
sejam trazidos apenas os códigos de gerente preenchidos. Isto é necessário todas as vezes em que for feita a
comparação com NOT IN ou <> ALL, pois a comparação com NULL (= NULL ou <> NULL) retorna FALSE e
nenhuma linha é selecionada. Como teste, inclua um departamento sem gerente, retire a restrição e execute
novamente o comando. Nenhuma linha será selecionada.
2.24) Deseja-se uma lista (código e nome) dos departamentos que iniciaram projetos em janeiro de 1996.
Listagem-resposta 2.24A
SQL> SELECT CD_DEPTO, NM_DEPTO
2 FROM DEPTO
3 WHERE CD_DEPTO = SOME (SELECT CD_DEPTO FROM PROJ
4 WHERE DT_INI BETWEEN '01/01/96') AND '31/01/96';
2.25) Deseja-se uma lista contendo matrícula, nome e salário de todos os funcionários que ganhem mais que a
média salarial da empresa.
Listagem-resposta 2.25A
SQL> SELECT CD_MAT, NM_FUNC, VL_SAL
2 FROM FUNC
3 WHERE VL_SAL > (SELECT AVG(VL_SAL) FROM FUNC);
2.26) Produza uma lista contendo a média salarial, total de salários e quantidade de linhas selecionadas por
departamento, de todos os funcionários que tenham em seu primeiro nome a letra “A”.
Listagem-resposta 2.26A
SQL> SELECT AVG(VL_SAL), SUM(VL_SAL), COUNT(*), CD_DEPTO
2 FROM FUNC
3 WHERE NM_FUNC LIKE '%A%' OR
4 NM_FUNC LIKE '%a%'
5 GROUP BY CD_DEPTO;
2.27) Produza uma lista contendo o cargo, a média salarial e o número de funcionários grupados por cargo para os
departamentos D01, D11, D21 e E11. Todos os cargos com menos de três funcionários devem ser excluídos do
resultado. A lista deve vir ordenada descendentemente por média salarial.
Listagem-resposta 2.27A
SQL> SELECT NR_CARGO, AVG(VL_SAL), COUNT(*)
2 FROM FUNC
3 WHERE CD_DEPTO IN ('D01', 'D11', 'D21', 'E11')
4 GROUP BY NR_CARGO
5 HAVING COUNT(*) >= 3
6 ORDER BY 2 DESC;
Listagem-resposta 2.28A
SQL> SELECT CD_PROJ, COUNT(DISTINCT CD_ATIV) Atividades
2 FROM PRJATV
3 GROUP BY CD_PROJ;
Listagem-resposta 2.29A
SQL> SELECT AVG(COUNT(*)) Média
2 FROM FUNC
3 GROUP BY CD_DEPTO;
2.30) Deseja-se obter uma lista (nr_cargo) de todos os cargos que possuam mais de duas funcionárias.
Listagem-resposta 2.30A
SQL> SELECT NR_CARGO, COUNT(*)
2 FROM FUNC
3 WHERE IN_SEXO = 'F'
4 GROUP BY NR_CARGO
5 HAVING COUNT(*) > 2;
2.31) Deseja-se uma lista (cd_mat, vl_sal, nr_git) dos funcionários mais graduados (com maior grau de instrução)
da empresa.
Listagem-resposta 2.31A
SQL> SELECT CD_MAT, VL_SAL, NR_GIT
2 FROM FUNC
3 WHERE NR_GIT = (SELECT MAX(NR_GIT) FROM FUNC);
2.32) Deseja-se saber qual departamento possui maior média salarial da empresa.
Listagem-resposta 2.32A
SQL> SELECT CD_DEPTO, AVG(VL_SAL)
2 FROM FUNC
3 GROUP BY CD_DEPTO
4 HAVING AVG(VL_SAL) = (SELECT MAX(AVG(VL_SAL))
5 FROM FUNC
6 GROUP BY CD_DEPTO);
2.33) Deseja-se saber quais os funcionários (matrícula, nome, sobrenome e data de admissão) que possuem mais de
nove anos de empresa.
Listagem-resposta 2.33A
SQL> SELECT CD_MAT, NM_FUNC, NM_SOBRENOME, DT_ADM
2 FROM FUNC
3 WHERE DT_ADM > TO_DATE('10031990', 'DDMMYYYY');
2.34) Deseja-se uma relação contendo matrícula, nome completo e idade do funcionário na data de admissão.
Listagem-resposta 2.34A
SQL> SELECT CD_MAT, CONCAT(NM_FUNC, ' ')||NM_SOBRENOME NOME,
2 DT_ADM, DT_NASC,
3 ROUND((DT_ADM - DT_NASC) / 365.25) “Idade Adm”
4 FROM FUNC;
2.35) Deseja-se o total salarial e a média salarial por quantidade de anos trabalhados e por cargo dos funcionários
que tenham menos de 10 anos de casa e cargo superior a 50. Devem ser informados, simultaneamente, totais por
cargo e por quantidade de ano, além de um acumulado geral.
Listagem-resposta 2.35A
SQL> COL CARGO FOR 999
SQL> COL ANOS FOR 999
SQL> SELECT TRUNC((SYSDATE - DT_ADM)/365.25) ANOS,
2 NR_CARGO CARGO,
3 SUM(VL_SAL) TOTAL, AVG(VL_SAL) MEDIA
4 FROM FUNC
5 WHERE (SYSDATE - DT_ADM) < 3652.5
6 AND NR_CARGO > 50
7 GROUP BY ROLLUP(TRUNC((SYSDATE - DT_ADM)/365.25), NR_CARGO);
Listagem-resposta 2.36A
SQL> SELECT TRUNC((SYSDATE - DT_ADM)/365.25) ANOS,
2 IN_SEXO SEXO,
3 COUNT(*) QTD
4 FROM FUNC
5 GROUP BY CUBE(TRUNC((SYSDATE - DT_ADM)/365.25), IN_SEXO);
Neste exemplo nos utilizamos, novamente, de uma expressão dentro da cláusula Cube.
2.37) Repita os dois exercícios anteriores de tal forma que os totais provenientes da quebra seja identificados
diferentemente dos valores gerados em função de valores NULL.
Listagem-resposta 2.37A
SQL> SELECT TRUNC((SYSDATE - DT_ADM)/365.25) ANOS,
2 NR_CARGO CARGO,
3 SUM(VL_SAL) TOTAL, AVG(VL_SAL) MEDIA,
4 GROUPING(TRUNC((SYSDATE - DT_ADM)/365.25)) TOTCARGO,
5 GROUPING(NR_CARGO) TOTANO
6 FROM FUNC
7 WHERE (SYSDATE - DT_ADM) < 3652.5
8 AND NR_CARGO > 50
9 GROUP BY ROLLUP(TRUNC((SYSDATE - DT_ADM)/365.25), NR_CARGO);
Para identificarmos o total apresentado usamos a função Grouping. Quando a coluna NR_CARGO, por exemplo,
aparece com NULL no resultado devemos olhar o valor da coluna TOTANO. Se estiver preenchido com 1 significa
que é um total para o ano que estiver preenchido na coluna Anos, e caso contrário indica que é uma linha de
agregação para o cargo NULL.
2.38) Um novo funcionário foi contratado na empresa, o cargo definido para ele foi 55 e seu salário deve ser 2700,
2800 ou 2900. Determine qual dos três salários se enquadra nos requisitos estabelecidos pela gerência de projetos:
a) Seu salário deve ser superior ao quarto maior salário dentre os funcionários com o mesmo cargo.
b) Pelo menos 60% do grupo de funcionários com o mesmo cargo deve ter salário menor que o dele.
Listagem-resposta 2.38A
SQL> SELECT CUME_DIST(2700) WITHIN GROUP(ORDER BY VL_SAL ASC NULLS LAST) S2700,
2 CUME_DIST(2800) WITHIN GROUP(ORDER BY VL_SAL ASC NULLS LAST) S2800,
3 CUME_DIST(2900) WITHIN GROUP(ORDER BY VL_SAL ASC NULLS LAST) S2900,
4 DENSE_RANK(2700) WITHIN GROUP(ORDER BY VL_SAL DESC NULLS LAST) R2700,
5 DENSE_RANK(2800) WITHIN GROUP(ORDER BY VL_SAL DESC NULLS LAST) R2800,
6 DENSE_RANK(2900) WITHIN GROUP(ORDER BY VL_SAL DESC NULLS LAST) R2900
7 FROM FUNC
8 WHERE NR_CARGO = 55;
Em relação à solicitação B, tanto o salário de 2800 quanto o de 2900 atendem à solicitação pois abaixo de 2800
temos 60% do grupo e abaixo de 2900 temos 70% do grupo. Com relação à solicitação A, concluímos que o salário
do funcionário deve ser 2900 pois este valor o classifica na quarta posição em relação à ordem descendente de
salário. O valor de 2800 o colocaria logo após (5) o quarto salário atual, o que foi solicitado que não acontecesse.
2.39) Para determinar o percentual de promoção dos funcionários, o departamento Pessoal solicitou:
a) o menor, o maior e a média salárial do menor cargo.
b) o menor, o maior e a média salárial do maior cargo.
Listagem-resposta 2.39A
SQL> SELECT MAX(VL_SAL)
2 KEEP (DENSE_RANK FIRST ORDER BY NR_CARGO ASC NULLS LAST) XSALMCARGO,
3 MIN(VL_SAL)
4 KEEP (DENSE_RANK FIRST ORDER BY NR_CARGO ASC NULLS LAST) MSALMCARGO,
5 MAX(VL_SAL)
6 KEEP (DENSE_RANK LAST ORDER BY NR_CARGO ASC NULLS LAST) XSALXCARGO,
7 MIN(VL_SAL)
8 KEEP (DENSE_RANK LAST ORDER BY NR_CARGO ASC NULLS LAST) MSALXCARGO
9 FROM FUNC;
2.40) O novo diretor do Departamento pessoal deseja estabelecer faixas salariais para futuro enquadramento dos
funcionários. Com este objetivo deseja obter informações sobre a distribuição salarial atual. Considerando-se
intervalos de 20% (.20, .40, .60, .80 ou 1) deseja-se saber qual o salário correspondente.
Listagem-resposta 2.40A
SQL> SET NUMWIDTH 7
SQL> SELECT PERCENTILE_CONT(.20) WITHIN GROUP (ORDER BY VL_SAL ASC) PA20,
2 PERCENTILE_DISC(.20) WITHIN GROUP (ORDER BY VL_SAL ASC) PM20,
3 PERCENTILE_CONT(.40) WITHIN GROUP (ORDER BY VL_SAL ASC) PA40,
4 PERCENTILE_DISC(.40) WITHIN GROUP (ORDER BY VL_SAL ASC) PM40,
5 PERCENTILE_CONT(.60) WITHIN GROUP (ORDER BY VL_SAL ASC) PA60,
6 PERCENTILE_DISC(.60) WITHIN GROUP (ORDER BY VL_SAL ASC) PM60,
7 PERCENTILE_CONT(.80) WITHIN GROUP (ORDER BY VL_SAL ASC) PA80,
8 PERCENTILE_DISC(.80) WITHIN GROUP (ORDER BY VL_SAL ASC) PM80,
9 PERCENTILE_CONT(1) WITHIN GROUP (ORDER BY VL_SAL ASC) PA100,
10 PERCENTILE_DISC(1) WITHIN GROUP (ORDER BY VL_SAL ASC) PM100
11 FROM FUNC;
PA20 PM20 PA40 PM40 PA60 PM60 PA80 PM80 PA100 PM100
------- ------- ------- ------- ------- ------- ------- ------- ------- -------
2005 1995 2417,6 2384 2759,6 2774 3176,8 3225 5275 5275
Observe o resultado: utilizamos Percentile_Cont e Percentile Disc para os mesmos valores. Somente na faixa 100%
ocorre a paridade entre os dois percentuais. Nas demais faixas isto indica que existe mais de um salário na posição
20%, sendo que a média é 2005 e o menor deles é 1995. Para a posição 40% encontramos como ponto central da
faixa um valor que não existe como salário, ou seja, 2417,60. Para chegar a este valor o Oracle fez uma interpolação
entre 2384 e 2468 (próximo salário). Os demais resultados são similares em raciocínio.
2.41) Deseja-se uma relação contendo matrícula, nome, idade atual e tempo de serviço para aqueles funcionários
que tenham sido admitidos com menos de 21 anos.
Listagem-resposta 2.41A
SQL> SELECT CD_MAT, NM_FUNC||' '||NM_SOBRENOME NOME,
2 ROUND((SYSDATE - DT_NASC)/365.25) “Idade Atual”,
3 ROUND(MONTHS_BETWEEN(SYSDATE, DT_ADM) / 12) “Tempo Serviço”
4 FROM FUNC
5 WHERE (DT_ADM - DT_NASC) < 21 * 365.25;
2.42) Deseja-se uma relação contendo nome, sobrenome, data e hora do nascimento, mês e ano de admissão em
algarismos romanos e o salário editado (contendo moeda) para todos os funcionários que possuam mais de quatro
vogais em seu sobrenome.
Listagem-resposta 2.42A
SQL> SELECT NM_FUNC, NM_SOBRENOME,
2 TO_CHAR(DT_NASC, 'DD/MM/YYYY HH24:MI') “Nasc”,
3 LTRIM(RTRIM(TO_CHAR(DT_ADM, 'RM'))) || ' - ' ||
4 LTRIM(RTRIM(TO_CHAR(TO_NUMBER(TO_CHAR(DT_ADM, 'YYYY')), 'RN'))) “Adm”,
5 LTRIM(RTRIM(TO_CHAR(VL_SAL, 'L999G990D00',
6 'NLS_CURRENCY = R$'))) “Salário”
7 FROM FUNC
8 WHERE LENGTH(NM_SOBRENOME) -
9 LENGTH(TRANSLATE(UPPER(NM_SOBRENOME), 'XAEIOU', 'X')) > 4;
2.43) Deseja-se uma relação contendo nome completo do funcionário (centralizado sob o título Nome), data de
nascimento formatada com hora, minuto e segundo (alinhado à direita sob o título Nascimento), o código do
departamento (alinhado à esquerda e de tal forma que o título Depto seja apresentado).
Listagem-resposta 2.43A
SQL> SELECT RPAD(LPAD(NM_FUNC||' '|| NM_SOBRENOME,
2 (20+LENGTH(NM_FUNC||' '||NM_SOBRENOME))/2),20) “ Nome”,
3 TO_CHAR(DT_NASC,
2.44) Deseja-se uma relação contendo o nome e sobrenome de todos os funcionários, sendo que todas as vogais
devem ser apresentadas em minúsculas e as consoantes em maiúsculas. As informações sobre salário devem ser
criptografadas da seguinte forma: 22 será transformado na letra Z; 0,1 serão transformados na letra A; 2,3 serão
transformados na letra B; 4,5,6 serão transformados na letra C, e os demais números na letra D.
Listagem-resposta 2.44A
SQL> SELECT TRANSLATE(UPPER(NM_FUNC||' '||NM_SOBRENOME), 'AEIOU', 'aeiou') “Nome”,
2 TRANSLATE(REPLACE(TO_CHAR(VL_SAL), '22', 'Z'),
3 '0123456789', 'AABBCCCDDDD') “Salário”
4 FROM FUNC;
2.45) Deseja-se uma relação contendo nome completo do funcionário usando letras maiúsculas e minúsculas, sexo
por extenso, número de dias entre a data de admissão e o último dia do mês da data corrente e o valor do salário
(se houver definido; caso contrário, 0) formatado. Esta relação deve ser ordenada do menor salário para o maior.
Listagem-resposta 2.45A
SQL> UPDATE FUNC
2 SET VL_SAL = NULL
3 WHERE VL_SAL IN (1725, 1775);
2 linhas atualizadas.
2.46) Deseja-se uma relação com as seguintes informações: linguagem em uso no banco de dados, o conjunto de
caracteres nacionais e o do banco de dados, o endereço da linha do funcionário com matrícula 100, a data de hoje
(com dia, mês e ano por extenso), a data da próxima quinta-feira, o seno, cosseno e tangente do ângulo de 30 graus.
Listagem-resposta 2.46A
SQL> SELECT USERENV('LANGUAGE') “Linguagem”,
2 NLS_CHARSET_NAME(NLS_CHARSET_ID('CHAR_CS')) “Charset DB”,
3 NLS_CHARSET_NAME(NLS_CHARSET_ID('NCHAR_CS')) “National”,
4 ROWIDTOCHAR(ROWID) “Rowid”,
5 TO_CHAR(SYSDATE, 'DD-DAY-MONTH-YEAR') “Hoje”,
6 NEXT_DAY(SYSDATE, 'quinta-feira') “Próxima Quinta”,
7 SIN(30), COS(30), TAN(30)
8 FROM FUNC
9 WHERE CD_MAT = 100;
2.47) Deseja-se realizar o enquadramento dos funcionários da empresa em uma faixa salarial. O grupo será dividido
em 10 faixas iguais, sendo o intervalo salarial apreciável entre 1500 e 5000. Determine a faixa de cada funcionário.
Listagem-resposta 2.47A
SELECT CD_MAT, VL_SAL, WIDTH_BUCKET(VL_SAL, 1500, 5000, 10) FAIXAS
FROM FUNC
ORDER BY 2;
Observe, no resultado, que o salário 5275 (maior salário da empresa) foi incluído na faixa salarial 11 (fora do
intervalo estipulado). Todos os valores acima do limite estabelecido são incluídos nesta décima-primeira faixa,
sem distinção.
2.48) Deseja-se obter o valor numérico e nome da zona de tempo da sessão e do banco de dados.
Listagem-resposta 2.48A
SQL> COL REGIAO_DB for a20
SQL> COL REGIAO_SESSAO for a20
SQL> SELECT TZ_OFFSET(DBTIMEZONE) DBTIMEZONE,
2 TZ_OFFSET(SESSIONTIMEZONE) SESSIONTIMEZONE,
3 EXTRACT(TIMEZONE_ABBR FROM FROM_TZ(LOCALTIMESTAMP, DBTIMEZONE)) REGIAO_DB,
4 EXTRACT(TIMEZONE_ABBR FROM FROM_TZ(LOCALTIMESTAMP, SESSIONTIMEZONE)) REGIAO_SESSAO
5 FROM DUAL;
Neste exercício usamos a função TZ_OFFSET para retornar a zona de tempo em formato numérico. Usamos a
função FROM_TZ para montar um Timestamp na zona de tempo especificada (Localtimestamp não tem zona de
tempo) e, em seguida, usamos a função EXTRACT para obter o nome da zona de tempo que desejávamos.
2.49) Receba um timestamp como parâmetro e sua zona de tempo e retorne este timestamp convertido para o
horário de Greenwich.
Listagem-resposta 2.49A
SQL> SELECT SYS_EXTRACT_UTC(
2 TO_TIMESTAMP_TZ('&DATA '||'&HORA '||'&TZONE',
3 'DD/MM/YYYY HH24:MI:SS TZH:TZM')) HORAGMT
4 FROM DUAL;
Entre o valor para data: 15/03/2001
Entre o valor para hora: 15:30:20
Entre o valor para tzone: -05:00
antigo 2: TO_TIMESTAMP_TZ('&DATA '||'&HORA '||'&TZONE',
novo 2: TO_TIMESTAMP_TZ('15/03/2001 '||'15:30:20 '||'-05:00',
HORAGMT
---------------------------
15/03/01 20:30:20,000000000
2.50) Deseja-se saber (somente para os cargos 55) o salário do funcionário com grau de instrução imediatamente
inferior e superior ao seu; o resultado deve vir ordenado pelo nome do funcionário.
Listagem-resposta 2.50A
SQL> SELECT cd_mat, nm_func, nr_git,
2 LAG(VL_SAL) over (order by NR_GIT ASC nulls last) ANTERIOR,
3 vl_sal,
4 LEAD(VL_SAL) over (order by NR_GIT ASC nulls last) POSTERIOR
5 FROM FUNC
6 WHERE NR_CARGO = 55
7 ORDER BY 2;
2.51) Ainda estudando uma forma de enquadramento salarial o departamento Pessoal deseja dividir o grupo em
três faixas, considerando ordenação decrescente de cargo. Apresente o enquadramento para os funcionários dos
departamentos A00 e D11 e ordene o resultado pelo nome do funcionário.
Listagem-resposta 2.51A
SQL> SELECT CD_MAT, NM_FUNC, NR_CARGO, VL_SAL,
2 NTILE(3) over (order by NR_CARGO DESC nulls last) FAIXA
3 FROM FUNC
4 WHERE CD_DEPTO IN ('A00', 'D11')
5 ORDER BY 2;
2.52) Deseja-se saber quanto o salário de cada funcionário representa (percentualmente) em relação ao seu próprio
departamento e em relação à empresa.
Listagem-resposta 2.52A
SQL> SELECT CD_MAT, NM_FUNC, VL_SAL,
2 TRUNC(RATIO_TO_REPORT(VL_SAL)
3 over (PARTITION BY CD_DEPTO)* 100,2) “% PARA DEPTO”,
4 TRUNC(RATIO_TO_REPORT(VL_SAL)
5 over () * 100, 2) “% PARA EMPRESA”
6 FROM FUNC;
Listagem-resposta 2.53A
SQL> SELECT cd_mat, nm_func, vl_sal,
2 max(vl_sal) over(order by vl_sal nulls last
3 rows between 2 preceding and 1 preceding) MaxSal,
4 min(vl_sal) over(order by vl_sal nulls last
5 rows between 1 following and 2 following) MinSal,
6 max(nr_cargo) over(order by nr_cargo nulls last
7 rows between 2 preceding and 1 preceding) MaxCrg,
8 min(nr_cargo) over(order by nr_cargo nulls last
9 rows between 1 following and 2 following) MinCrg,
10 dense_rank() over(partition by cd_depto
11 order by vl_sal DESC nulls last) rank_depto,
12 dense_rank() over(order by vl_sal DESC nulls last) rank_emp
13 FROM FUNC
14 ORDER BY 2;
2.54) Deseja-se uma lista contendo o nome do projeto, o nome das atividades e tempo de duração de cada atividade
(fornecido em número de horas). Ordene o resultado por projeto e atividade.
Listagem-resposta 2.54A
SQL> SELECT PROJ.NM_PROJ “Projeto”,
2 ATIV.TX_DESCRICAO “Atividade”,
3 TRUNC((PRJATV.DT_FIM - PRJATV.DT_INI) * 24) Horas
4 FROM PROJ, ATIV, PRJATV
5 WHERE PRJATV.CD_PROJ = PROJ.CD_PROJ
6 AND PRJATV.CD_ATIV = ATIV.CD_ATIV
7 ORDER BY “Projeto”, “Atividade”;
Listagem-resposta 2.54B
SQL> SELECT PROJ.NM_PROJ “Projeto”,
2 ATIV.TX_DESCRICAO “Atividade”,
3 TRUNC((PRJATV.DT_FIM - PRJATV.DT_INI) * 24) Horas
4 FROM PRJATV JOIN ATIV USING (CD_ATIV)
5 JOIN PROJ USING(CD_PROJ)
6 ORDER BY “Projeto”, “Atividade”;
A subtração de datas fornece o resultado em número de dias (parte inteira). Multiplicamos por 24 para transformar
dias para horas e truncamos o resultado para que não fossem apresentados minutos e segundos. Observe que neste
segundo resultado não usamos a cláusula Where pois não havia qualquer restrição específica, apenas as cláusulas
relativas ao Join.
2.55) Deseja-se uma lista contendo o código e nome de cada departamento, nome e sobrenome do gerente, ordenado
por código de departamento.
Listagem-resposta 255A
SQL> SELECT D.CD_DEPTO, D.NM_DEPTO,
2 F.NM_FUNC, F.NM_SOBRENOME
3 FROM DEPTO D, FUNC F
4 WHERE D.CD_GERENTE = F.CD_MAT
5 ORDER BY 1;
Listagem-resposta 255B
SQL> SELECT D.CD_DEPTO, D.NM_DEPTO,
2 F.NM_FUNC, F.NM_SOBRENOME
3 FROM DEPTO D JOIN FUNC F ON D.CD_GERENTE = F.CD_MAT
4 ORDER BY 1;
A ligação entre departamento e funcionário foi estabelecida através do código do gerente; assim, apenas os gerentes
foram selecionados.
2.56) Deseja-se uma lista contendo nome, sobrenome, salário e departamento de todos os funcionários que sejam
responsáveis por projeto, porém não sejam gerentes.
Listagem-resposta 2.56A
SQL> SELECT F.NM_FUNC, F.NM_SOBRENOME, F.VL_SAL, F.CD_DEPTO
2 FROM FUNC F, DEPTO D, PROJ P
3 WHERE P.CD_RESP = F.CD_MAT
4 AND D.CD_DEPTO = F.CD_DEPTO
5 AND D.CD_GERENTE <> F.CD_MAT;
Listagem-resposta 2.56B
SQL> SELECT F.NM_FUNC, F.NM_SOBRENOME, F.VL_SAL, F.CD_DEPTO
2 FROM FUNC F JOIN DEPTO D ON D.CD_DEPTO = F.CD_DEPTO AND
3 D.CD_GERENTE <> F.CD_MAT
4 JOIN PROJ P ON P.CD_RESP = F.CD_MAT;
A ligação com a tabela de departamento foi necessária para que verificássemos se o funcionário era gerente. Ob-
serve que o relacionamento foi feito com o código do departamento do funcionário e não com o código do
departamento do projeto.
2.57) Deseja-se uma lista contendo o nome e departamento do gerente e nome e salário de todos os funcionários
subordinados a ele. Apresente o resultado ordenado por departamento e salário (descendente).
Listagem-resposta 2.57A
SQL> SELECT G.CD_DEPTO, G.NM_FUNC “Gerente”,
2 F.NM_FUNC, F.VL_SAL
3 FROM FUNC G, FUNC F, DEPTO D
4 WHERE G.CD_MAT = D.CD_GERENTE
5 AND F.CD_DEPTO = D.CD_DEPTO
6 ORDER BY 1, 4 DESC;
Listagem-resposta 2.57B
SQL> SELECT G.CD_DEPTO, G.NM_FUNC “Gerente”,
2 F.NM_FUNC, F.VL_SAL
3 FROM FUNC G INNER JOIN DEPTO D ON G.CD_MAT = D.CD_GERENTE
4 JOIN FUNC F ON F.CD_DEPTO = D.CD_DEPTO
5 ORDER BY 1, 4 DESC;
2.58) Deseja-se uma lista contendo o nome do projeto, o nome do departamento responsável e o nome do
funcionário responsável, desde que ele trabalhe no departamento responsável pelo projeto.
Listagem-resposta 2.58A
SQL> SELECT P.NM_PROJ Projeto, D.NM_DEPTO Departamento,
2 F.NM_FUNC Responsavel
3 FROM PROJ P, DEPTO D, FUNC F
4 WHERE P.CD_DEPTO = D.CD_DEPTO
5 AND P.CD_DEPTO = F.CD_DEPTO
6 AND P.CD_RESP = F.CD_MAT
7 UNION
9 SELECT P.NM_PROJ, D.NM_DEPTO,
10 'Outro Depto'
11 FROM PROJ P, DEPTO D, FUNC F
12 WHERE P.CD_DEPTO = D.CD_DEPTO
13 AND P.CD_DEPTO <> F.CD_DEPTO
14 AND P.CD_RESP = F.CD_MAT;
Neste exercício, precisamos realizar uma operação de união, pois no primeiro Select estabelecemos uma restrição
de tal forma que só seriam apresentados os projetos em que o responsável trabalhasse no mesmo departamento.
Mas foi solicitado que apenas o nome do funcionário fosse omitido. Por esse motivo, unimos o resultado do
primeiro Select com o segundo, em que foram selecionados os projetos em que o responsável não trabalhava no
departamento responsável.
Para que este exercício tenha conteúdo, devemos alterar uma linha na tabela de projeto para criar a condição adequada.
2.59) Deseja-se saber quais os departamentos que não possuem funcionários (usar Minus).
Listagem-resposta 2.59A
SQL> SELECT CD_DEPTO, NM_DEPTO
2 FROM DEPTO
3 MINUS
4 SELECT DEPTO.CD_DEPTO, DEPTO.NM_DEPTO
5 FROM DEPTO, FUNC
6 WHERE FUNC.CD_DEPTO = DEPTO.CD_DEPTO;
2.60) Deseja-se saber quais os departamentos (código e nome) responsáveis por mais de dois projetos e que,
simultaneamente, possuam mais de três funcionários (usar Intersect).
Listagem-resposta 2.60A
SQL> SELECT D.CD_DEPTO, D.NM_DEPTO
2 FROM PROJ, DEPTO D
3 WHERE PROJ.CD_DEPTO = D.CD_DEPTO
4 GROUP BY D.CD_DEPTO, D.NM_DEPTO
5 HAVING COUNT(*) > 2
6 INTERSECT
7 SELECT D.CD_DEPTO, D.NM_DEPTO
8 FROM FUNC, DEPTO D
9 WHERE FUNC.CD_DEPTO = D.CD_DEPTO
10 GROUP BY D.CD_DEPTO, D.NM_DEPTO
11 HAVING COUNT(*) > 3;
2.61) Deseja-se saber o código e nome do projeto, código e nome da atividade e o tempo de duração da atividade
durante o ano de 1996. Ordene o resultado por nome do projeto e nome da atividade. Se uma atividade se iniciou
antes de 1996 e terminou durante o ano de 1996, desejamos saber apenas quanto tempo ela durou de 01/01/96 até
a data de término. Se uma atividade começou durante o ano de 1996 e terminou em outro ano, desejamos saber
apenas o tempo da data de início da atividade até dia 31/12/1996. Se uma atividade começou antes de 1996 e
terminou depois de 1996, sua duração será de 01/01 a 31/12, e, finalmente, se uma atividade começou e terminou
em 1996, sua duração será desde a data de início até a data de término.
Listagem-resposta 2.61A
SQL> SELECT P.CD_PROJ, P.NM_PROJ,
2 A.CD_ATIV, A.TX_DESCRICAO,
3 DECODE(TO_NUMBER(TO_CHAR(PJ.DT_FIM, 'YYYY')),
4 1996, PJ.DT_FIM, '31/12/96') -
5 DECODE(TO_NUMBER(TO_CHAR(PJ.DT_INI, 'YYYY')),
6 1996, PJ.DT_INI, '01/01/96') + 1 Tempo
7 FROM PROJ P, ATIV A, PRJATV PJ
8 WHERE PJ.CD_PROJ = P.CD_PROJ
9 AND PJ.CD_ATIV = A.CD_ATIV
10 AND PJ.DT_FIM > TO_DATE('01/01/96') - 1/86400
11 AND PJ.DT_INI < TO_DATE('01/01/97') - 1/86400;
Nesse exercício, utilizamos a função Decode para efetuar a subtração desejada. Se o ano final do projeto fosse 1996,
então a função retornaria dt_fim; caso contrário, retorna 31/12/96. O mesmo procedimento foi adotado para data
de início do projeto (considerando a data de 01/01/96). Desta forma, a subtração entre os dois decodes resulta nas
quatro hipóteses formuladas acima. A restrição da cláusula Where garante que não serão selecionados projetos que
tenham início após 1996 nem término anterior a 1996.
2.62) Sabendo-se que os códigos de departamento são subdivididos em depto (letra) e centro de custo (número),
deseja-se uma lista organizada por centro de custo contendo nome e sobrenome do funcionário, código do
departamento, salário e cargo. Deve ser apresentada uma única coluna para nome e sobrenome, salário deve ser
editado, deve ser feita uma separação de página para cada centro de custo. Deseja-se uma totalização dos salários,
numeração de página e o mês vigente no cabeçalho.
Listagem-resposta 2.62A
SQL> SET LINESIZE 70
SQL> BREAK ON “C.CUSTO” SKIP PAGE
SQL> COMPUTE SUM LABEL SOMA OF VL_SAL ON “C.CUSTO”
SQL> COL VL_SAL FOR L999G990D00
SQL> COL MES_ATUAL NOPRINT NEW_VALUE MES
SQL> COL “C.CUSTO” FOR A7
SQL> REPHEADER OFF
SQL> TTITLE CENTER MES RIGHT “PÁG.: “ FORMAT 99 SQL.PNO -
> SKIP 2
SQL> SELECT LPAD(SUBSTR(CD_DEPTO,2),7) “C.CUSTO”,
2 NM_FUNC||' '||NM_SOBRENOME NOME, CD_DEPTO,
3 VL_SAL, NR_CARGO,
4 INITCAP(TO_CHAR(SYSDATE, 'MONTH')) MES_ATUAL
5 FROM FUNC
6 ORDER BY SUBSTR(CD_DEPTO,2);
2.63) Gere um arquivo a ser utilizado para carga de dados em outro ambiente contendo as seguintes informações:
matrícula, nome e sobrenome (única coluna), salário, cargo, grau de instrução e data de nascimento. As informações
devem ser apresentadas alinhadas por coluna e separadas por vírgula. Faça um script para criação deste arquivo
(usar Spool). O arquivo gerado deve ter o nome de carga.sql.
Listagem-resposta 2.63A
SPOOL CARGA.SQL
SET NEWPAGE NONE
SET FEEDBACK OFF
SET HEADING OFF
SET ECHO OFF
SET PAGESIZE 999
SET TAB OFF
SET TERMOUT OFF
SET TRIMSPOOL ON
SET NUMWIDTH 3
SET WRAP OFF
SET COLSEP “,”
COL M FOR 099
COL C FOR 09
COL G FOR 09
SELECT CD_MAT M, RPAD(NM_FUNC||' '||NM_SOBRENOME,20),
TO_CHAR(VL_SAL, '9999.99',
'NLS_NUMERIC_CHARACTERS = .,'),
NR_CARGO C, NR_GIT G,
TO_CHAR(DT_NASC, ' DDMMRRRR')
FROM FUNC
/
SPOOL OFF
2.64) Montar uma lista dos aniversariantes por mês, contendo para cada mês (apresentado por extenso em português)
o nome, idade e departamento do funcionário, ordenada por número de mês. Não deve haver repetição do nome
do mês. A página deve ser mudada quando ocorrer a mudança do mês.
Listagem-resposta 2.64A
SQL> SPOOL OFF
SQL> BREAK ON MES SKIP PAGE
SQL> SELECT TO_CHAR(DT_NASC, 'MONTH') MES,
2 NM_FUNC,
3 TRUNC((SYSDATE - DT_NASC)/365.25) IDADE,
4 CD_DEPTO
5 FROM FUNC
6 ORDER BY TO_NUMBER(TO_CHAR(DT_NASC, 'MM'));
2.65) Crie um relatório que forneça a média salarial, o maior salário e o menor salário do departamento informado
como parâmetro. O usuário poderá informar o departamento em letras maiúsculas ou minúsculas e sem aspas. A
solicitação do parâmetro deve ser formatada e deve ser enviada mensagem antes do início da execução.
Listagem-resposta 2.65A
SQL> BTITLE OFF
SQL> TTITLE OFF
SQL> ACCEPT DEP PROMPT 'Informe o código do Departamento: '
Informe o código do Departamento: d11
SQL> PAUSE 'Início'
'Início'
2.67) Criar um arquivo a ser usado toda vez que abrirmos o SQL*Plus com as seguintes características:
♦ O tamanho de cada linha deve estar limitado a 70 caracteres.
♦ Deve ser apresentada mensagem indicativa da quantidade de linhas selecionadas para qualquer número de
linhas selecionadas.
Listagem-resposta 2.67A
SQL> SET LINESIZE 70
SQL> SET FEEDBACK 1
SQL> SET NULL “< NULL>”
SQL> SET NUMWIDTH 10
SQL> SET PAGESIZE 20
SQL> SET SQLPROMPT “Plus> “
Plus> SET TIME ON
17:58:51 Plus> SET SUFFIX “TXT”
17:58:51 Plus> SET SERVEROUT ON SIZE 10000
Para que o arquivo seja executado toda vez que iniciarmos o SQL*Plus, seu nome deve ser Login.Sql.
2.68) Crie um relatório com as seguintes características:
♦ Capa: “Capa do Relatório”.
♦ Número de página em todas as folhas (direita).
♦ Título do relatório: Relação de Funcionários e Projetos (centralizado).
♦ Apresentar a versão do Oracle em todas as páginas (esquerda).
♦ Datar todas as páginas (esquerda).
♦ Quebrar por Projeto e colocar o nome do Projeto no título de cada página.
♦ No rodapé de cada página, deve constar também o nome do departamento, além do título “Confiden-
cial”(centralizado).
♦ Apresentar nome do responsável (nome e sobrenome – alinhados à esquerda) e data de admissão (dd/mm/yyyy
– centralizado), nome do funcionário (nome e sobrenome – centralizado) e salário (formatado).
♦ Deve ser apresentado um total salarial e uma média por projeto no final do relatório. Deseja-se, também, a
quantidade de funcionários por projeto e no final do relatório.
♦ Ordenar o relatório por projeto, responsável e salário (descendente).
Listagem-resposta 2.68A
TTITLE LEFT “VERSÃO “ FORMAT 999G999G999G999 SQL.RELEASE -
RIGHT “Pág.: “ FORMAT 99 SQL.PNO SKIP 2 LEFT DT_HOJE SKIP 2 -
CENTER “Relação de Funcionários e Projetos” SKIP 2 -
CENTER “Projeto: “ NOME_ANTES SKIP 2
BTITLE CENTER “Projeto: “ NOME_DEPOIS SKIP 2 -
CENTER “CONFIDENCIAL”
COL VL_SAL FOR L999G999G990D00
COL PROJETO NEW_VALUE NOME_ANTES OLD_VALUE NOME_DEPOIS FOR A30
COL NOME FOR A20
COL RESPONSAVEL FOR A20
COL SYSDATE NEW_VALUE DT_HOJE NOPRINT
BREAK ON PROJETO SKIP PAGE ON RESPONSAVEL ON REPORT
COMPUTE SUM LABEL SOMA -
AVG LABEL “Média” OF VL_SAL ON PROJETO REPORT
COMPUTE COUNT LABEL QTD OF CD_MAT ON PROJETO REPORT
SELECT NM_PROJ PROJETO,
R.NM_FUNC||' '||R.NM_SOBRENOME REPONSAVEL,
TO_CHAR(F.DT_ADM, 'DD/MM/YYYY') DT_ADM,
LPAD(F.NM_FUNC||' '||F.NM_SOBRENOME,
Listagem-resposta 2.69A
sqlplus -s -m “html on head '<title>teste de html</title>' body BGCOLOR=#ff0000 entmap off spool on” desenv/desenv
@R02_69A.SQL
Com o comando anterior disparamos a execução do arquivo R02_69A que é similar ao script da Resposta 2.68, com a
diferença de que incluímos o comando Spool para que o arquivo HTM fosse gerado. Certamente, você encontrará ajustes
a fazer para que o resultado fique mais amigável (troque o fundo da tela para uma cor mais suave, vermelho é muito forte).
2.70) Deseja-se uma lista com todos os gerentes e seus respectivos funcionários, contendo nome e sobrenome do
gerente, código e nome do departamento, nome e sobrenome do funcionário. Todos os departamentos devem ser
apresentados (mesmo que não haja gerentes ou funcionários) e todos os funcionários devem ser apresentados
(mesmo que estejam sem departamento).
Listagem-resposta 2.70A
SQL> SET LINESIZE 200
SQL> SELECT D.CD_DEPTO, D.NM_DEPTO,
2 G.NM_FUNC ||' '|| G.NM_SOBRENOME GERENTE,
3 F.NM_FUNC ||' '|| F.NM_SOBRENOME FUNCIONÁRIO
4 FROM FUNC F, DEPTO D, FUNC G
5 WHERE G.CD_MAT (+) = D.CD_GERENTE
6 AND F.CD_DEPTO(+) = D.CD_DEPTO
7 UNION ALL
8 SELECT NULL, NULL,
9 NULL GERENTE,
10 F.NM_FUNC||' '||F.NM_SOBRENOME FUNCIONÁRIO
11 FROM FUNC F
12 WHERE F.CD_DEPTO IS NULL
13 ORDER BY 1, 4;
Houve necessidade do Union porque não podemos colocar o sinal indicativo de Outer Join (+) nos dois lados da
igualdade. Tente resolver com a nova sintaxe da versão 9i.
Foram incluídas linhas em Depto e Func para que fossem apresentadas todas as situações.
2.71) Deseja-se remover todas as atividades que não estejam em uso.
Listagem-resposta 2.71A
SQL> DELETE FROM ATIV A
2 WHERE NOT EXISTS (SELECT 0 FROM PRJATV
3 WHERE CD_ATIV = A.CD_ATIV);
2.72) Deseja-se uma lista contendo nome, matrícula, cargo e salário dos funcionários que possuam o maior salário
da empresa e daqueles que possuam o menor salário da empresa.
Listagem-resposta 2.72A
SQL> SELECT CD_MAT, NM_FUNC, NR_CARGO, VL_SAL
2 FROM FUNC
3 WHERE VL_SAL = (SELECT MAX(VL_SAL) FROM FUNC)
4 OR VL_SAL = (SELECT MIN(VL_SAL) FROM FUNC)
5 ORDER BY 4 DESC;
2.73) Deseja-se uma relação hierárquica de todos os departamentos da empresa (código e nome), considerando-se
que os departamentos estão subordinados aos seus respectivos departamentos contábeis. A relação deve apresentar
endentação de três espaços para identificar subordinação. O departamento no mais alto nível da hierarquia não
possui indicação de departamento contábil (Null). Apresente o caminho da hierarquia. Ordene o resultado pelo
nome do departamento.
Listagem-resposta 2.73A
SQL> COL PATH FOR A15
SQL> SELECT RPAD(LPAD(' ', 3*LEVEL -3)||NM_DEPTO, 45) DEPARTAMENTO,
2 CD_DEPTO, CD_DEPTO_CTB, SYS_CONNECT_BY_PATH (CD_DEPTO, '/') PATH
3 FROM DEPTO
4 CONNECT BY PRIOR CD_DEPTO = CD_DEPTO_CTB
5 START WITH CD_DEPTO_CTB IS NULL
6 ORDER SIBLINGS BY DEPARTAMENTO ASC;
2.74) Deseja-se uma lista contendo nome, sobrenome, matrícula, ramal, código e nome do departamento, código
e nome do projeto de todos os funcionários que sejam responsáveis por projeto e, simultaneamente, gerentes.
Listagem-resposta 2.74A
SQL> SELECT F.CD_MAT, F.NM_FUNC||' '||F.NM_SOBRENOME “GER. RESPONSÁVEL”,
2 D.CD_DEPTO, D.NM_DEPTO,
3 P.CD_PROJ, P.NM_PROJ
4 FROM FUNC F INNER JOIN DEPTO D ON F.CD_MAT = D.CD_GERENTE
5 AND F.CD_DEPTO = D.CD_DEPTO
6 INNER JOIN PROJ P ON F.CD_MAT = P.CD_RESP
7 AND P.CD_DEPTO = D.CD_DEPTO;
2.75) Deseja-se uma lista contendo nome, sobrenome, matrícula, ramal, código e nome do departamento, código
e nome do projeto de todos os gerentes que sejam responsáveis por projeto não pertencentes ao seu departamento.
Listagem-resposta 2.75A
SQL> SELECT F.CD_MAT, F.NM_FUNC||' '||F.NM_SOBRENOME “GER. RESPONSÁVEL”,
2 D.CD_DEPTO, D.NM_DEPTO,
3 P.CD_PROJ, P.NM_PROJ
4 FROM FUNC F, DEPTO D, PROJ P
5 WHERE F.CD_DEPTO <> D.CD_DEPTO
6 AND F.CD_MAT = P.CD_RESP
7 AND P.CD_DEPTO = D.CD_DEPTO
8 AND F.CD_MAT IN (SELECT CD_GERENTE FROM DEPTO);
O departamento do projeto MA2110 foi substituído de D11 para D21 para que houvesse alguma linha no resultado.
2.76) Produza uma lista contendo nome, sobrenome, cargo e salário de todos os funcionários do sexo feminino
que ganhem mais que todos os funcionários do sexo masculino.
Listagem-resposta 2.76A
SQL> SELECT NM_FUNC, NM_SOBRENOME, NR_CARGO, VL_SAL
2 FROM FUNC
3 WHERE IN_SEXO = 'F'
4 AND VL_SAL > (SELECT MAX(VL_SAL) FROM FUNC
5 WHERE IN_SEXO = 'M');
Observe que, para receber salário acima de todos os funcionários do sexo masculino, basta que ganhe mais que o
maior salário dos funcionários do sexo masculino.
2.77) Produza uma lista contendo nome, sobrenome e salário de todos os funcionários que possuam mais de cinco
anos de casa e que recebam menos que a média dos funcionários com o mesmo cargo.
Listagem-resposta 2.77A
SQL> SELECT NM_FUNC, NM_SOBRENOME, NR_CARGO
2 FROM FUNC F
3 WHERE (SYSDATE - DT_ADM) > (5 * 365.25)
4 AND VL_SAL < (SELECT AVG(VL_SAL) FROM FUNC
5 WHERE NR_CARGO = F.NR_CARGO);
2.78) Deseja-se obter a média de idade, maior e menor salário e média salarial dos funcionários do sexo feminino,
grupando por grau de instrução e cargo (somente dos cargos com mais de duas funcionárias).
Listagem-resposta 2.78A
SQL> SELECT NR_CARGO “CARGO”, NR_GIT “GRAU”,
2 AVG(TRUNC((SYSDATE - DT_ADM)/365.25)) “MÉDIA IDADE”,
3 MAX(VL_SAL) “MAIOR SALÁRIO”,
4 MIN(VL_SAL) “MENOR SALÁRIO”,
5 AVG(VL_SAL) “MÉDIA SALARIAL”
6 FROM FUNC
7 WHERE IN_SEXO = 'F'
8 AND NR_CARGO IN (SELECT NR_CARGO FROM FUNC
9 WHERE IN_SEXO = 'F'
10 GROUP BY NR_CARGO
11 HAVING COUNT(*) > 2)
12 GROUP BY NR_GIT, NR_CARGO;
Listagem-resposta 2.79A
SQL> SELECT CD_DEPTO “DEPTO”, IN_SEXO “SEXO”, COUNT(*) “QTD”
2 FROM FUNC
3 GROUP BY CD_DEPTO, IN_SEXO;
2.80) Deseja-se uma lista das atividades que estejam associadas a mais de dois departamentos.
Listagem-resposta 2.80A
SQL> SELECT PA.CD_ATIV, COUNT(DISTINCT PJ.CD_DEPTO)
2 FROM PROJ PJ INNER JOIN PRJATV PA USING (CD_PROJ)
3 GROUP BY PA.CD_ATIV
4 HAVING COUNT(DISTINCT PJ.CD_DEPTO) > 2;
2.81) Atualize o salário dos funcionários com mais de cinco anos de casa (exceto os gerentes) para que ganhem salário
semelhante ao do funcionário com maior cargo do seu próprio departamento (usar um único comando UPDATE).
Listagem-resposta 2.81A
SQL> UPDATE FUNC F
2 SET VL_SAL = (SELECT MAX(VL_SAL) FROM FUNC
3 WHERE CD_DEPTO = F.CD_DEPTO
4 AND NR_CARGO = (SELECT MAX(NR_CARGO) FROM FUNC
5 WHERE CD_DEPTO = F.CD_DEPTO))
6 WHERE CD_MAT NOT IN (SELECT CD_GERENTE FROM DEPTO
7 WHERE CD_GERENTE IS NOT NULL);
2.82) Criar uma view sobre a tabela de funcionários que selecione apenas os funcionários com salário superior a R$
2.000,00. Garanta que a atualização através desta view somente possa incluir ou alterar funcionários cujo salário
seja superior a R$ 2.000,00.
Listagem-resposta 2.82A
SQL> CREATE VIEW SAL_2000 AS
2 SELECT * FROM FUNC
3 WHERE VL_SAL > 2000
4 WITH CHECK OPTION;
View criada.
2.83) Incluir dados na tabela Depto provenientes da tabela Dept do usuário Scott, prefixando os departamentos
com “D”. Caso exista um departamento com o mesmo código, apenas atualize o nome; caso contrário, inclua o
novo departamento. O valor do departamento contábil para todos os novos departamentos é D01.
Listagem-resposta 2.83A
SQL> MERGE INTO DEPTO D
2 USING (SELECT DEPTNO,DNAME FROM SCOTT.DEPT)
3 ON (CD_DEPTO = ('D'||DEPTNO))
4 WHEN MATCHED THEN UPDATE SET NM_DEPTO = DNAME
5 WHEN NOT MATCHED THEN INSERT (CD_DEPTO, D.NM_DEPTO, CD_DEPTO_CTB)
6 VALUES ('D'||DEPTNO, DNAME, 'D01');
2.84) Em mais um estudo salarial, o departamento Pessoal solicitou a relação de funcionários com a indicação de
sexo (por extenso) e uma classificação dos funcionários por idade, da seguinte forma: funcionários com menos de
30 anos (jovem), entre 30 e 45 (maduro), entre 46 e 60 (meia idade) e maior que 60 anos (idoso). Ordene o
resultado pelo nome do funcionário.
Listagem-resposta 2.84A
SQL> SELECT CD_MAT, NM_FUNC, VL_SAL,
2 CASE IN_SEXO WHEN 'F' THEN 'Feminino'
3 WHEN 'M' THEN 'Masculino'
4 ELSE 'Indefinido' END “Sexo”,
5 CASE WHEN EXTRACT(YEAR FROM CURRENT_TIMESTAMP) -
6 EXTRACT(YEAR FROM DT_NASC) > 60 THEN 'IDOSO'
7 WHEN EXTRACT(YEAR FROM CURRENT_TIMESTAMP) -
8 EXTRACT(YEAR FROM DT_NASC) BETWEEN 46 AND 60 THEN 'MEIA IDADE'
9 WHEN EXTRACT(YEAR FROM CURRENT_TIMESTAMP) -
10 EXTRACT(YEAR FROM DT_NASC) BETWEEN 30 AND 45 THEN 'MADURO'
11 ELSE 'JOVEM' END “IDADE”
12 FROM FUNC
13 ORDER BY NM_FUNC;
2.85) Deseja-se saber o total salarial por cargo, sexo e departamento. Apresente uma amostragem contendo 30%
do total de funcionários da empresa.
Listagem-resposta 2.85A
SQL> COL CARGO FOR 9999
SQL> SELECT SUM(VL_SAL), NR_CARGO CARGO,
2 IN_SEXO SEXO, CD_DEPTO DEPTO
3 FROM FUNC SAMPLE(30)
4 GROUP BY NR_CARGO, IN_SEXO, CD_DEPTO;
2.86) Deseja-se uma lista de todas as tabelas do usuário contendo a quantidade de colunas, a quantidade de
relacionamentos e a quantidade de índices desta tabela.
Listagem-resposta 2.86A
SQL> SELECT T.TABLE_NAME,
2 COUNT(DISTINCT C.COLUMN_NAME) “COLUMNS”,
3 COUNT(DISTINCT R.CONSTRAINT_NAME) “CONSTRAINTS”,
4 COUNT(DISTINCT I.INDEX_NAME) “INDEXES”
5 FROM SYS.USER_TABLES T,
6 SYS.USER_TAB_COLUMNS C,
7 SYS.USER_CONSTRAINTS R,
8 SYS.USER_INDEXES I
9 WHERE T.TABLE_NAME = C.TABLE_NAME
10 AND T.TABLE_NAME = R.TABLE_NAME
11 AND R.CONSTRAINT_TYPE = 'R'
12 AND T.TABLE_NAME = I.TABLE_NAME
13 GROUP BY T.TABLE_NAME;
2.87) Deseja-se obter, para cada restrição de integridade, a tabela associada, a tabela correspondente (no caso de
relacionamento), o nome da restrição, o texto da restrição ordenado por tabela associada e nome da restrição.
Listagem-resposta 2.87A
SQL> SET ECHO ON
SQL> COL CONSTRAINT_NAME FOR A15
SQL> COL TABLE_NAME FOR A15
2.88) Determinar, para cada tabela particionada, seu nome, o nome de cada partição e as regras do particionamento.
Listagem-resposta 2.88A
SQL> COL HIGH_VALUE FOR A50
SQL> COL PARTITION_NAME FOR A15
SQL> SELECT TABLE_NAME, PARTITION_NAME,
2 HIGH_VALUE, PARTITION_POSITION “POSITION”
3 FROM USER_TAB_PARTITIONS
4 ORDER BY 4;
2.89) Deseja-se informações sobre as views criadas no schema do usuário, contendo nome, texto associado, colunas
que podem ser atualizadas.
Listagem-resposta 2.89A
SQL> COL VIEW_NAME FOR A11
SQL> COL COLUMN_NAME FOR A15
SQL> COL TEXT FOR A35
SQL> SET LONG 1000
SQL> SET LONGCHUNKSIZE 1000
SQL> SET MAXDATA 2000
SQL> BREAK ON TEXT
SQL> SELECT V.VIEW_NAME, V.TEXT,
2 U.COLUMN_NAME, U.UPDATABLE,
3 U.INSERTABLE, U.DELETABLE
4 FROM SYS.USER_VIEWS V,
5 SYS.USER_UPDATABLE_COLUMNS U
6 WHERE V.VIEW_NAME = U.TABLE_NAME
7 AND (U.UPDATABLE = 'YES' OR
8 U.INSERTABLE = 'YES' OR
9 U.DELETABLE = 'YES')
10 ORDER BY 1, 3;
2.90) Coloque outra cópia do SQL*PLUS ativa no usuário DESENV (sessão 2).
Para realizar esta operação, basta efetuar um double-click no ícone do SQL*Plus e, após o login, dimensionar as
janelas para que fiquem lado a lado.
2.91) Atualize sua tabela Depto (sessão 1), mas não dê Commit. O que o outro usuário (sessão 2) vê? Por quê?
O usuário da sessão 2 vê a linha com a informação de antes da modificação, porque o usuário da sessão 1 ainda não
efetivou esta modificação. Quando for feito um Commit, o outro user terá acesso à modificação realizada.
2.92) Dê Commit sobre suas atualizações (sessão 1). A visibilidade na sessão 2 é possível agora? Por quê?
Sim. Pois a informação modificada se torna disponível para todos os usuários após sua efetivação (Commit).
2.93) Atualize sua tabela Depto (sessão 1), mas não dê Commit. Através da sessão 2, tente atualizar a mesma linha
alterada anteriormente. O que acontece? Por quê? Dê Rollback nas duas sessões.
Isto acontece porque, quando uma linha está sendo modificada, ela fica bloqueada para os demais processos que
desejem atualizar a mesma linha. Esse mecanismo de bloqueio chama-se Lock. Dizemos, então, que a linha ficará
locked até que o usuário da sessão 1 encerre a transação (Commit ou Rollback).
2.94) Atualize sua tabela Depto (sessão 1), mas não dê Commit. Na sessão 2, execute um SELECT ….. FOR UPDATE.
Qual a diferença?
O bloqueio se repete. Isto acontece porque a cláusula FOR UPDATE adicionada ao comando Select funciona, para
efeito de LOCK, da mesma forma que um comando de atualização (update, insert, delete). Desta forma, este comando
Select permite que o usuário tenha acesso à informação real que está no banco de dados e impede que outros
processos modifiquem aquela informação enquanto ele tiver o controle da linha.
2.95) Explique, com suas palavras, o que acontece nos trechos de programa abaixo:
Listagem-resposta 2.95A
SQL> UPDATE FUNC
3 SET VL_SAL = VL_SAL * 1.10;
33 linhas atualizadas;
SQL> COMMIT;
Validação completa.
Todos os funcionários da tabela Func tiveram seus salários aumentados em 10%. Após esta modificação, os dados
estão sendo efetivados (Commit).
Listagem-resposta 2.95B
SQL> DELETE FROM FUNC WHERE NR_GIT = 21;
1 linhas deletada.
SQL> ROLLBACK;
Rollback completo.
Foi feita a exclusão dos funcionários com grau de instrução igual a 21. Como a transação não havia sido efetivada
(Commit), foi possível ao usuário desistir deste resultado e desmanchar a modificação (Rollback). Após o comando
Rollback a tabela fica com as mesmas características que tinha antes do início da exclusão.
Listagem-resposta 2.95C
SQL> UPDATE DEPTO
2 SET CD_GERENTE = 200
3 WHERE CD_DEPTO = 'A00';
1 linha atualizada.
Na seqüência, temos:
1. Atualização da tabela de departamento, com a alteração do gerente para 200 no departamento A00.
2. Marcação de um ponto de controle (Savepoint) de nome Altera_gerente.
3. Atualização do funcionário de matrícula 300, com um aumento de 50% em seu salário.
4. O comando Rollback desfaz a última atualização (item 3). A modificação feita no passo 1 não é desmanchada,
porém ainda não foi efetivada; ainda está pendente.
5. Atualização do funcionário de matrícula 200, com um aumento de 20% em seu salário. Só no momento do
Commit 1 e 5 serão realmente efetivados.
2.96) Para que serve o comando SET TRANSACTION READ ONLY?
Este comando indica ao Oracle que todos os comandos desta transação devem ter como referência de tempo o
momento do Set Transaction e não o momento de início de cada um deles (como é o default). Todos os comandos
da transação são apenas de consulta.
Listagem-resposta 2.98A
SQL> ALTER SESSION SET NLS_LANGUAGE = French;
Listagem-resposta 2.99A
SQL> ALTER SESSION
2 SET NLS_DATE_FORMAT = 'DD/MM/RRRR';
2.100) Deseja-se uma relação dos aniversariantes da empresa, contendo o nome e sobrenome de cada funcionário,
o dia do aniversário e o mês do aniversário (por extenso, em português). Ordene a relação por número de mês e
estabeleça quebra de página a cada troca de mês.
Listagem-resposta 2.100A
SQL> ALTER SESSION
2 SET NLS_DATE_LANGUAGE = 'BRAZILIAN PORTUGUESE';
Session modifiée.
2.101) Deseja-se uma relação para a folha de pagamento, contendo a matrícula, nome, sobrenome, salário bruto,
INSS (8% do salário), FGTS (10% do salário), Ticket (8,00 por dia do mês), Vale Transporte (2,00 por dia do mês). O
mês será fornecido como parâmetro. Os valores financeiros deverão ser formatados, devendo ser apresentado o
símbolo financeiro (R$).
Listagem-resposta 2.101A
SQL> ALTER SESSION SET NLS_CURRENCY = 'R$';
Session modifiée.
Listagem-resposta 2.102A
SQL> ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'DD/MM/YYYY HH24:MI:SSXFF TZH:TZM';
Session modifiée.
2.103) Iguale a zona de tempo da sessão à zona de tempo do banco de dados. Verifique o resultado em seguida.
Listagem-resposta 2.103A
SQL> ALTER SESSION SET TIME_ZONE = DBTIMEZONE;
Session modifiée.
2.104) Incluir dados na tabela TLOB com o formato especificado abaixo, a partir da tabela Func:
f) c_number deve receber cd_mat.
g) c_clob1 deve receber nm_func concatenado com nm_sobrenome.
h) c_clob2 deve receber o nome do departamento em que o funcionário trabalha.
i) c_nclob1 deve receber o projeto que o funcionário coordena (se for o caso).
j) c_nclob2 deve receber a concatenação de data de nascimento, data de admissão, cargo, grau de instrução e salário.
Listagem-resposta 2.104A
SQL> INSERT INTO TLOB (C_NUMBER, C_CLOB1, C_CLOB2, C_NCLOB1, C_NCLOB2)
2 SELECT CD_MAT, NM_FUNC ||' '|| NM_SOBRENOME CLOB1,
3 NM_DEPTO CLOB2, NM_PROJ C_NCLO1,
4 TO_CHAR(DT_NASC, 'DD/MM/YYYY')||'-'||TO_CHAR(DT_ADM, 'DD/MM/YYYY')||'-'||
5 NR_CARGO||'-'||NR_GIT||'-'||VL_SAL
6 FROM FUNC F INNER JOIN DEPTO D USING (CD_DEPTO)
7 LEFT OUTER JOIN PROJ P ON CD_MAT = CD_RESP;
35 ligne(s) créée(s).
Observe que não precisamos determinar nenhum tipo de conversão explicitamente para os tipos de dados. A
conversão foi feita automaticamente.
2.105) Associar a coluna C_BFILE1 ao arquivo correspondente indicado pela coluna nm_foto.
Listagem-resposta 2.105A
SQL> CREATE DIRECTORY WIN AS 'C:\WINDOWS';
Répertoire créé.
2.108) Transforme este usuário em um usuário comum (acesso à role Connect apenas).
Listagem-resposta 2.108A
SQL> GRANT CONNECT TO PROD;
2.109) Autorize o acesso para leitura sobre sua tabela Funcionário para o user PROD.
Listagem-resposta 2.109A
SQL> GRANT SELECT ON FUNC TO PROD;
2.110) Estabeleça conexão como PROD. Crie um sinônimo para a tabela Func do user DESENV.
Listagem-resposta 2.110A
SQL> CONNECT PROD/PROD
Conectado.
SQL> CREATE SYNONYM DFUNC FOR DESENV.FUNC;
2.111) Ainda com a conexão PROD. Faca um select (join) entre sua tabela FUNC e a tabela FUNC do user DESENV,
listando todos os funcionários (seus) que tenham ou não correspondência na tabela do outro user. Inverta o teste.
O resultado é o mesmo?
Listagem-resposta 2.111A
SQL> CREATE TABLE FUNC
2 AS SELECT * FROM DFUNC
3 WHERE MOD(CD_MAT,4) = 0;
Tabela criada.
SQL> COMMIT;
Validação completa.
Na Listagem-resposta 2.111, criamos uma tabela Func baseada na tabela do usuário Desenv. Quando usamos o
sinal de mais (+) na chave da tabela Dfunc (Func do usuário Desenv), obtemos todas as linhas de Func do usuário
Prod mesmo que não tenham correspondência com as linhas de Dfunc. Quando colocamos o sinal de mais (+) na
chave da tabela Func (do usuário Prod), obtemos todas as linhas de Dfunc do usuário Desenv mesmo que não
tenham correspondência com as linhas de Func. Esta é a regra do Outer Join.
2.112) Agora com a conexão DESENV, autorize a atualização da tabela Depto pelo user PROD.
Listagem-resposta 2.112A
SQL> CONNECT DESENV/DESENV
Conectado.
SQL> GRANT INSERT, UPDATE, DELETE ON DEPTO
2 TO PROD;
Physical files são os arquivos físicos (visíveis pelo sistema operacional) para armazenamento dos dados de um
banco de dados Oracle. Estes arquivos estão associados a um objeto lógico dentro do Oracle, os tablespaces. Cada
arquivo físico está associado a um e somente um tablespace; por outro lado um tablespace pode ser composto de
mais de um arquivo físico.
Desta forma, um tablespace é uma área lógica, corresponde a um espaço para armazenamento de objetos (tabelas,
índices, segmentos de rollback, etc.). Nessa área, podemos definir diversas tabelas, índices e outros objetos do
banco de dados.
Capítulo 3
PL/SQL
Neste capítulo, estudaremos a linguagem de programação PL/SQL, além de alguns comandos de SQL que nos
permitirão o armazenamento de códigos (escritos em PL/SQL) no banco de dados.
Neste capítulo também travaremos conhecimento com alguns pacotes utilitários fornecidos pela Oracle, tais como
Dbms_Output, Utl_File e Dbms_Lob, dentre outros.
Para que o estudo seja proveitoso, é indispensável que o leitor já tenha concluído o estudo do Capítulo 2.
INTRODUÇÃO
A PL/SQL é uma linguagem procedural da Oracle que estende a SQL com comandos que permitem a criação de
procedimentos de programação.
Com ela, podemos usar comandos de SQL DML para manipular os dados da base de dados Oracle e estabelecer
fluxos de controle para processar estes dados.
A linguagem permite a declaração de constantes, variáveis, subprogramas (procedures e funções), que favorecem a
estruturação de código, e possui mecanismos para controle de erros de execução. Incorpora os novos conceitos de
objeto, encapsulamento e, ainda, permite a interface com rotinas escritas em outras linguagens.
ESTRUTURA
A PL/SQL é estruturada em blocos. Cada bloco pode conter outros blocos. Em cada um desses blocos, podemos
declarar variáveis que deixam de existir quando o bloco termina.
A Sintaxe 3.01 apresenta a estrutura de um bloco PL/SQL, que é composto de três partes:
♦ Uma parte declarativa, onde definimos as variáveis locais àquele bloco.
♦ Uma parte de lógica, onde definimos a ação que aquele bloco deve realizar, incluindo a declaração de outros
blocos subordinados (ou embutidos) a este.
♦ Uma parte de tratamento de erros, que permite que tenhamos acesso ao erro ocorrido e à determinação de uma
ação de correção. Nessa parte, também podemos declarar outros blocos subordinados.
MODULARIDADE
Modularidade é um conceito que determina a divisão do programa em módulos com ações bem definidas, que
visam a facilitar o entendimento e a manutenção. Um problema complexo poderia ser subdividido em problemas
menos complexos que, por sua vez, poderiam ser novamente subdivididos até que obtivéssemos problemas simples
com soluções de fácil implementação.
A PL/SQL, por possuir uma estrutura de blocos, favorece a modularidade. Além de blocos anônimos, temos a
possibilidade de criar procedures e funções armazenadas na base de dados e compartilhadas por outras aplicações,
ou packages que permitem que grupemos procedures, funções e variáveis relacionadas.
ARQUITETURA
A PL/SQL não é um produto independente; podemos considerá-la um módulo executor de blocos e subprogramas.
Esse módulo pode ser instalado no Oracle Server e nas ferramentas de desenvolvimento da Oracle (Forms Builder,
Report Builder, etc.). Estes dois ambientes são independentes e podem conter até mesmo versões diferentes da PL/SQL.
Esse módulo, no entanto, trabalha da mesma forma: ele é capaz de tratar os comandos de PL/SQL, mas não os
comandos de SQL, que devem ser resolvidos por mecanismos internos do Oracle Server.
Em ferramentas que possuem esse módulo embutido, a ferramenta passa para seu módulo executor local o bloco de
PL/SQL que pode ser processado no próprio ambiente, com a exceção dos comandos de SQL encontrados. Grande
parte do trabalho é realizada localmente, sem necessidade de envio de informações para o ambiente servidor.
Em ferramentas que não têm esse módulo embutido, tais como SQL*Plus e Enterprise Manager, torna-se necessário o
envio de todo o bloco para o servidor, para que este acione o seu módulo executor local e processe o bloco de PL/SQL.
VANTAGENS DA PL/SQL
A PL/SQL oferece as seguintes vantagens:
PERFORMANCE
A utilização da PL/SQL pode reduzir o tráfego na rede pelo envio de um bloco contendo diversos comandos de SQL
grupados em blocos para o Oracle. Isto é possível em um Oracle Precompiler ou OCI (Oracle Call Interface).
A PL/SQL também adiciona performance às ferramentas que possuem um módulo executor local, pois não necessitam
enviar comandos de PL/SQL para serem processados pelo servidor, sendo enviados apenas os comandos de SQL.
Adicionalmente, a criação de programas armazenados no banco de dados (stored subprogram) pode reduzir não só
o tráfego na rede como também a programação quando estabelecemos ações que podem ser compartilhadas em
diversas aplicações.
PORTABILIDADE
Aplicações escritas em PL/SQL são portáveis para qualquer sistema operacional e plataforma nos quais o Oracle
execute. Não há necessidade de customização.
Isso significa que podemos escrever programas ou bibliotecas de programas que podem ser utilizados em ambientes
diferentes.
PRODUTIVIDADE
O aprendizado da PL/SQL pode ser aproveitado no desenvolvimento de aplicações batch, online, relatórios, etc.
No desenvolvimento de um programa utilizando uma ferramenta tal como Forms Builder ou Report Builder, já
estaremos familiarizados com as construções da lógica de programação, pois trata-se da mesma PL/SQL usada para
desenvolvimento das aplicações em batch.
IDENTIFICADORES
Um identificador consiste em uma letra seguida de outras letras, números, $ (dólar), _ (sublinhado) e # (símbolo
numérico). Possui um limite máximo de 30 caracteres.
As letras podem ser maiúsculas ou minúsculas indiscriminadamente, pois a linguagem não é sensível à forma.
Opcionalmente, os identificadores podem ser declarados (e usados) entre aspas. Com essa sintaxe, podemos declarar
variáveis com outros caracteres além daqueles estabelecidos no início do texto (exceto aspas). O tamanho con-
tinua limitado a 30 caracteres (excluindo-se as aspas).
No exemplo da Listagem 3.01, observamos que, quando declaramos uma variável entre aspas, seu uso passa a ser sensível
à forma de escrever, ou seja, ficamos limitados à forma como declaramos a variável em relação às maiúsculas e minúsculas.
PALAVRAS RESERVADAS
Alguns identificadores possuem um significado especial em PL/SQL e não devem ser utilizados na declaração de variáveis.
Na Listagem 3.02, podemos observar que o uso de um identificador com o nome de END causou vários erros de
compilação. A utilização de END como parte do nome de identificadores não causa maiores prejuízos.
Alternativamente, podemos declarar palavras reservadas como identificadores, desde que seu nome seja posto
entre aspas. Essa forma de utilização das aspas não é encorajada pela Oracle.
LITERAIS
Corresponde à representação explícita de um número, caracter, string ou boleano.
NÚMERO
Podemos usar dois tipos de literais numéricos: inteiros e reais. Podemos, ainda, representá-los usando notação científica.
♦ Inteiros: {3, 100, 017, -125, +096}
♦ Reais: {12.5, +020.30, .78, 17., -05.32}
♦ Notação Científica: 12E3 (= 12*103 = 12000) ou 500e-4(=500*10-4 = 500/10000 = .05)
A letra E utilizada na notação científica indica o expoente de 10 que será usado para multiplicar o número que
aparece antes da letra.
CARACTER
Um literal caracter corresponde a um único caracter apresentado entre aspas simples (apóstrofos). Nesse caso PL/
SQL é sensível à forma, isto é, ‘A’ e ‘a’ são diferentes.
Como exemplo de literais caracteres, temos: ‘$’, ‘@’, ‘S’, ‘8’, ‘(‘, ‘s’.
STRING
Literais strings são uma seqüência de zero ou mais caracteres apresentados entre aspas simples (apóstrofes).
Como exemplo de literais string, temos: ‘abc’, ‘ abc ‘, ‘ABC’, ‘ A B C ‘, ‘$5.000,00’, ‘aspas “ duplas’.
BOLEANO
Literais boleanos são os valores TRUE, FALSE e a indicação de ausência de valor NULL.
COMENTÁRIOS
Um comentário em PL/SQL pode ser informado de duas formas:
♦ Dois hifens em qualquer ponto da linha torna o restante dela comentário.
♦ /* (início) e */ (fim) marcam uma região que será ignorada pelo compilador.
Como restrição, temos que não podemos embutir um comentário em outro e, ainda, não podemos utilizar
comentários com dois hifens em blocos de PL/SQL que venham a ser processados dinamicamente por um Oracle
Precompiler, porque os caracteres de fim de linha são ignorados (não são considerados) e, desta forma, o fim do
comentário não é percebido até o fim do bloco. Neste caso, devemos usar /* e */.
FIM DE LINHA
A indicação de fim de linha de comando em PL/SQL é feita com um ponto-e-vírgula (;). Observe que o
comportamento do SQL*Plus mudará quando encontrar o primeiro comando de PL/SQL, pois não aguardará mais
o ponto-e-vírgula (;) para indicação de fim de comando. Para concluirmos a digitação de um programa, deveremos
utilizar a barra (/) para encerrar e executar, ou o ponto (.) para encerrar sem executar.
ESCALARES
São um conjunto de tipos de dados predefinidos e que não possuem componentes internos (não são subdivididos).
BINARY_INTEGER
Tipo de dado numérico para armazenamento de inteiros válidos no seguinte intervalo de valores: de -231 +1 (-
2147483647) e 231 -1 (2147483647).
Um Binary_Integer possui um conjunto de subtipos (derivado do tipo básico Binary_Integer):
♦ Natural – Com intervalo de valores válidos entre 0 a 231 -1.
♦ NaturalN – Com intervalo de valores válidos entre 0 a 231 -1 e sem a possibilidade de associação de valores NULLS.
♦ Positive – Com intervalo de valores válidos entre 1 a 231 -1.
♦ PositiveN – Com intervalo de valores válidos entre 1 a 231 -1 e sem a possibilidade de associação de valores NULLS.
♦ SignType – Restrito à seguinte lista de valores: -1, 0 e 1.
No exemplo da Listagem 3.05, a declaração das variáveis de tipo NaturalN e PositiveN necessitou de um valor inicial
(:=), uma vez que não admite NULL, e toda variável de PL/SQL sem valor inicial definido está implicitamente NULL.
NUMBER
Tipo de dado numérico para armazenamento de valores fixos ou em ponto flutuante com precisão de até 38
dígitos e magnitude de 1.0E-130 a 9.99E125.
Podemos especificar precisão e escala. Se não especificarmos precisão, o default é 38 (ou o maior tamanho válido
para o sistema operacional, o que for menor). Escala pode variar de -84 a 127. Escalas negativas causam o
arredondamento da parte inteira.
SQL> PRINT
P1
----------
9,990E+125
P2
----------
40000
P3
----------
1,235E-113
Na Listagem 3.06, declaramos três variáveis no SQL*Plus para recebermos o resultado das atribuições feitas no programa.
O comando Print (de SQL*Plus) nos mostra o resultado. A variável wnum1 não teve seu valor alterado, pois a
declaramos sem qualquer restrição quanto à precisão ou escala. Já a variável wnum2, por possuir uma escala
negativa, causou o arredondamento da parte inteira do número que passou de 38.925 para 40.000. A variável
wnum3 perde os três últimos números informados, pois a escala é 127 e o valor é multiplicado por 10-130. Observe
o resultado do exemplo da Listagem 3.07.
SQL> PRINT P1
P1
----------
0
O tipo Number também possui um conjunto de subtipos (derivados do tipo básico Number):
♦ Decimal, Dec e Numeric – armazenamento em ponto fixo com uma precisão máxima de 38 dígitos decimais.
♦ Double Precision, Float – armazenamento em ponto flutuante com uma precisão máxima de 126 dígitos binários,
o que equivale a 38 dígitos decimais. Para efetuarmos a conversão de precisão binária para precisão decimal,
devemos multiplicar a precisão binária por 0.30103 e para realizar a operação inversa devemos multiplicar a
precisão decimal por 3.32193.
♦ Real – armazenamento em ponto flutuante com uma precisão máxima de 63 dígitos binários, o que equivale a
18 dígitos decimais.
♦ Integer, Int e Smallint – armazenamento de inteiros com uma precisão máxima de 38 dígitos.
PLS_INTEGER
Tipo de dado numérico para armazenamento de inteiros válidos no seguinte intervalo de valores: de -231 + 1 (-
2.147.483.647) e 231 -1 (2.147.483.647).
É similar ao tipo Binary_Integer, porém é mais rápido para efetuar cálculos que um Binary_Integer ou um Number,
pois utiliza machine arithmetic, enquanto os demais usam library arithmetic.
Possui uma outra diferença em relação ao Binary_Integer no que se refere à detecção de Overflow. Quando efetuamos
um cálculo usando variáveis Pls_Integer e o valor ultrapassa a capacidade máxima da variável, ocorre um erro de
Overflow mesmo que a área receptora tenha capacidade de armazenamento (seja um Number, por exemplo). Já
com Binary_Integer não ocorrerá qualquer erro se atribuirmos o resultado a um Number.
A recomendação da Oracle é que passemos a utilizar variáveis do tipo Pls_Integer nas novas aplicações para que
possamos obter ganhos de performance.
CHAR
Tipo de dado alfanumérico de tamanho fixo com comprimento de até 32.767 bytes. Podemos especificar o tamanho
máximo na declaração de uma variável com esse tipo. Caso isso não seja especificado, o comprimento default é de 1 byte.
O comprimento é especificado em bytes e não em caracteres. Isso é importante quando armazenamos valores multibyte.
2 WCHAR CHAR(5);
3 BEGIN
4 WCHAR := 'ABC';
5 :P1 := '*'||WCHAR||'*';
6 END;
7 /
Procedimento PL/SQL concluído com sucesso.
SQL> PRINT P1
P1
-------------
*ABC *
Na Listagem 3.09, observamos que a variável é completada com brancos à direita até atingir o comprimento
especificado pelo tipo.
VARCHAR2
Tipo de dado alfanumérico de tamanho variável com comprimento de até 32.767 bytes. A especificação de tamanho
é obrigatória para uma variável declarada com esse tipo.
O comprimento é especificado em bytes e não em caracteres. Isso é importante quando armazenamos valores multibyte.
O conjunto de valores válidos para armazenamento depende do charset do banco de dados.
A definição de uma coluna do tipo Varchar2 no banco de dados está limitada a 4.000 bytes.
SQL> PRINT P1
P1
-------------
*ABC*
Observe que, neste caso, somente é armazenado para a variável o que realmente foi atribuído.
LONG
Tipo de dado alfanumérico de tamanho variável com comprimento de até 32.767 bytes. Podemos especificar o
tamanho máximo na declaração de uma variável com esse tipo.
Uma coluna Long no banco de dados armazena até 2 GB (2.147.483.647 bytes).
Podemos fazer referência a colunas Long em comandos de DML Insert, Update e muitos comandos Select, mas não
em expressões, chamadas de funções SQL, ou em certas cláusulas, tais como Where, Group By e Connect By.
3 BEGIN
4 WLONG := 'ABC';
5 :P1 := '*'||WLONG||'*';
6 END;
7 /
SQL> PRINT P1
P1
-------------
*ABC*
RAW
Tipo de dado binário de tamanho variável com comprimento de até 32.767. A especificação de tamanho na
declaração de uma variável com esse tipo é obrigatória. São semelhantes a colunas Varchar2, porém a PL/SQL não
interpreta seu conteúdo. O SQL*Net8 não realiza conversão entre charsets quando transmitimos dados Raw de um
sistema para outro.
Uma coluna Raw no banco de dados armazena até 2.000 bytes.
LONG RAW
Tipo de dado binário de tamanho variável com comprimento de até 32.767. A especificação de tamanho na
declaração de uma variável com este tipo é obrigatória. São semelhantes a colunas Long, porém a PL/SQL não
interpreta seu conteúdo.
ROWID
Para armazenamento de valores Rowid do banco de dados. Cada tabela criada no banco de dados possui uma
pseudocoluna Rowid que armazena valores hexadecimais que correspondem ao endereço de cada linha (row).
A partir do Oracle8, os Rowids foram estendidos para suportar particionamento de tabelas e índices. Desta forma,
foi adicionado ao valor já existente na release 7.3 um data object number, que identifica o segmento. Objetos
criados no mesmo segmento, tais como as tabelas criadas em um cluster, possuem o mesmo data object number.
CD_MAT ROWID
---------- ------------------
10 AAAH3bAAIAAAAAyAAA
20 AAAH3bAAIAAAAAyAAB
30 AAAH3bAAIAAAAAyAAC
50 AAAH3bAAIAAAAAyAAD
60 AAAH3bAAIAAAAAyAAE
70 AAAH3bAAIAAAAAyAAF
90 AAAH3bAAIAAAAAyAAG
100 AAAH3bAAIAAAAAyAAH
110 AAAH3bAAIAAAAAyAAI
9 linhas selecionadas.
UROWID
Armazena um Rowid lógico. Usado para captura do Rowid (lógico) de tabelas Index Organized. Veja no Capítulo 2.
NCHAR
Tipo de dado alfanumérico de tamanho fixo com comprimento de até 32.767 bytes. Podemos especificar o tamanho
máximo na declaração de uma variável com este tipo. Caso isso não seja especificado, o comprimento default é de 1 byte.
O comprimento é especificado em bytes e não em caracteres. Isto é importante quando armazenamos valores multibyte.
O conjunto de valores válidos para armazenamento depende do national charset (criado na versão 8 do Oracle e
que permite o armazenamento de valores simultaneamente em dois charsets diferentes) definido para o banco de
dados. As colunas alfanuméricas Nchar e Nvarchar2 obedecem ao national charset e as colunas Char, Varchar2 e
Long, ao database charset.
A definição de uma coluna do tipo Nchar no banco de dados está limitada a 2.000 bytes.
A definição de uma coluna do tipo Nchar no banco de dados está limitada a 2.000 bytes. Podemos intercambiar
valores entre colunas Nchar e Char, porém pode haver perda de informação se o charset da coluna Char não puder
representar todo o conteúdo da coluna Nchar (aparecerão caracteres com ?).
NVARCHAR2
Tipo de dado alfanumérico de tamanho variável com comprimento de até 32.767 bytes. A especificação de tamanho
é obrigatória para uma variável declarada com este tipo.
O comprimento é especificado em bytes e não em caracteres. Isso é importante quando armazenamos valores
multi-byte.
O conjunto de valores válidos para armazenamento depende do national charset (criado na versão 8 do Oracle e
que permite o armazenamento de valores simultaneamente em dois charsets diferentes) definido para o banco de
dados. As colunas alfanuméricas Nchar e Nvarchar2 obedecem ao national charset e as colunas Char, Varchar2 e
Long, ao database charset.
A definição de uma coluna do tipo Nvarchar2 no banco de dados está limitada a 4.000 bytes.
BOOLEAN
É um tipo de dado para variáveis (não podem ser definidas como colunas em uma base de dados). Armazena
valores lógicos True e False e a ausência de valor Null. Não possui tamanho e nem qualquer tipo de parâmetro.
DATE
Tipo de dado para armazenamento de valores de data e hora. Os valores válidos variam de 01 de janeiro de 4712
A.C. até 31 de dezembro de 9999 D.C.
Na definição de uma variável de tipo data, não especificamos comprimento.
Podemos operar com variáveis tipo data (da mesma forma que com colunas Date) adicionando ou subtraindo
valores inteiros, usando as funções de SQL para data e subtraindo duas datas para obter o intervalo de dias.
Quando associamos uma data a uma variável alfanumérica, ocorre a conversão automática de tipo, da mesma
forma que ocorre quando associamos uma variável alfanumérica a uma variável de data. O layout default para a
conversão depende do valor de Nls_Date_Format em vigor para a sessão.
SQL> PRINT P1
P1
-------------------
01/01/87 - 05021987
Na Listagem 3.13, percebemos que o formato default de data para a sessão era dd/mm/rr, uma vez que a atribuição
de uma variável Varchar2 a uma variável Date foi interpretada corretamente.
TIMESTAMP
Extensão ao tipo Date. Ano, mês e dia assim com hora, minuto, segundo e fração de segundo. Podemos indicar o
número de dígitos da parte fracionária do segundo.
SQL> PRINT P1
P1
-------------------------------------------------------------------------------------
17/11/01 12:09:16,000001 | 17/11/01 12:09:18,000000 -02:00 | 17/11/01 12:09:18,000000
SQL> PRINT P2
P2
-------------------------------------------------------------------------------------
+00 18:45:18.000000 | +02-01
Na Listagem 3.14 podemos observar que o padrão de apresentação para valores de timestamp já compreende data,
hora, minuto, segundo e, para alguns, a zona de tempo. A variável Day To Second armazena um valor que pode
conter dia (não é data), hora, minuto, segundo e fração. Já a variável do tipo Year To Month armazena anos e meses.
LOBS
São um conjunto de tipos de dados predefinidos e que armazenam valores chamados locators, os quais especificam
a localização dos lobs (large objects) armazenados na linha ou fora dela.
Armazenam valores com comprimento de até 4 GB. Permitem o acesso randômico a trechos do dado.
São diferentes dos tipos Long e Long Raw nos seguintes aspectos:
♦ Podem ser atributos (exceto Nclob) de tipos objeto, Longs não podem.
♦ O comprimento máximo é de 4 GB e o dos Longs é 2 GB.
♦ Lobs suportam acesso randômico, enquanto Longs suportam somente acesso seqüencial.
♦ Pode-se declarar diversas colunas Lob em uma mesma tabela; Longs não são permitidos (somente 1).
A PL/SQL opera com lobs através dos locators, ou seja, quando recuperamos o valor de uma coluna Lob, o que é
obtido é o locator. Como restrição, temos que locators não podem ser guardados de uma transação (ou sessão) para
outra: não podemos ler a informação, efetuar um Commit e utilizar a informação lida.
Para manusearmos as informações de uma variável Lob, usaremos as rotinas presentes no pacote Dbms_Lob, que
será visto no tópico Usando Pacotes.
BLOB
O tipo Blob tem a capacidade de armazenar grandes valores binários. O tamanho máximo não pode exceder 4 GB.
O armazenamento da informação pode ser feito na própria linha ou em outro espaço específico.
CLOB
O tipo Clob tem a capacidade de armazenar grandes volumes de dados alfanuméricos single-byte. O tamanho máximo
não pode exceder 4 GB. O armazenamento da informação pode ser feito na própria linha ou em outro espaço específico.
NCLOB
O tipo Nclob tem a capacidade de armazenar grandes volumes de dados alfanuméricos single-byte ou multibyte do
tipo Nchar. O tamanho máximo não pode exceder 4 GB. O armazenamento da informação pode ser feito na
própria linha ou em outro espaço específico.
BFILE
O tipo Bfile tem a capacidade de armazenar grandes volumes de dados binários fora do banco de dados. O locator de
um Bfile inclui um diretório que especifica o caminho completo do arquivo no servidor. O arquivo endereçado por
um Bfile fica fora do banco de dados. No banco de dados, armazenamos apenas um locator (endereço) para o arquivo.
Bfiles são read-only. Não podemos modificá-los. O Oracle não modifica o arquivo físico associado com o locator. O
locator, naturalmente, pode ser modificado. O número máximo de Bfiles abertos é determinado pelo parâmetro de
inicialização do banco de dados Session_Max_Open_Files.
Bfiles não participam de transações. A integridade é de responsabilidade do sistema operacional do ambiente
servidor. O tamanho do arquivo não pode exceder 4 GB.
O DBA deve garantir que o arquivo exista e que o Oracle tenha permissão para acesso de leitura no diretório especificado.
COMPOSTOS
São aqueles tipos que possuem componentes internos que podem ser manuseados individualmente.
Nesse grupo, se encontram os tipos definidos pelo usuário: Table, Record e Varray. Serão vistos em tópicos específicos.
REFERENCE
São aqueles tipos que armazenam valores chamados ponteiros, que apontam para outros itens do programa ou do
banco de dados.
Fazem parte deste grupo os tipos Ref Cursor e Ref <object>, que também serão vistos em tópicos específicos.
SQL> PRINT P1
P1
-------------------------------
TESTE DE SUBTIPO-12345-17/11/01
Podemos definir subtipos de um tipo básico e, posteriormente, uma variável com aquele tipo. As restrições
estabelecidas para o subtipo devem ser respeitadas pelo item (veja Listagem 3.16).
CONVERSÃO IMPLÍCITA
Quando atribuímos uma variável de um determinado tipo a uma outra variável de outro tipo, ocorre uma conversão
implícita de tipo de dado.
A conversão implícita é possível em PL/SQL, mas não é recomendada, porque pode dificultar a performance e,
ainda, sofrer modificações de uma versão para outra do software.
Tipo B_Integer Blob Char CLOB Date Long Number P_Integer Raw Urowid Varchar2
B_Integer S S S S S
Blob S
Char S S S S S S S S S
Clob S S
Date S S S
Long S S S
Number S S S S S
P_Integer S S S S S
Raw S S S S
Urowid S S
Varchar2 S S S S S S S S S
Devemos tomar cuidado adicional com as conversões implícitas, pois o PL/SQL utiliza as funções de SQL, porém
com os parâmetros de formato defaults. Assim, a execução de uma rotina em um servidor pode produzir um
resultado, enquanto em outro poderá produzir outro em função de parâmetros de ambiente (Nls, por exemplo).
4 CD_MAT NUMBER(5) := 0;
5 BEGIN
6 CD_MAT := DESCRICAO;
7 DESCRICAO := DT_HOJE;
8 :P1 := DESCRICAO||'-'||CD_MAT||'-'||DT_HOJE;
9 END;
10 /
SQL> PRINT P1
P1
---------------------
17/11/01-123-17/11/01
Na Listagem 3.17, as atribuições não resultaram em erros, pois os valores eram compatíveis. Qual o resultado
obtido se a variável Descrição fosse inicializada com o valor ‘abc’ em vez de ‘123’?
INTRODUÇÃO
A parte declarativa de um bloco de PL/SQL precede a parte executiva e deve conter todas as variáveis necessárias à
execução do bloco. A PL/SQL não declara, implicitamente, variáveis como ocorre em outras linguagens.
VARIÁVEIS E CONSTANTES
Podemos declarar variáveis e constantes na parte declarativa de qualquer bloco, subprograma ou pacote.
A Sintaxe 3.02 permite a declaração de variáveis e constantes. Observe que uma constante, obrigatoriamente, deve
ter um valor inicial, e no entanto, seu valor não poderá ser alterado ao longo do programa.
O valor inicial poderá ser um fixo ou uma expressão, inclusive utilizando funções.
7 BEGIN
8 V_COD := ZERO;
9 END;
10 /
Na Listagem 3.18, declaramos duas constantes informando imediatamente um valor inicial. As variáveis podem receber
ou não valor inicial. Caso a declaração da variável receba a cláusula Not Null, a atribuição de valor inicial se torna obrigatória.
Quando não informamos valor inicial para uma variável, seu valor é considerado desconhecido, ou seja, Null.
%TYPE
O atributo %Type copia o tipo de dado de uma variável ou coluna do banco de dados.
Podemos, desta forma, declarar outra variável baseada na definição de uma coluna do banco de dados ou baseada
na definição de outra variável.
Isso é particularmente usado quando declaramos variáveis que venham a receber informações de colunas do
banco de dados.
A utilização de %Type favorece a independência de dados, uma vez que não precisamos saber exatamente o tipo de
dado da variável a ser declarada e, caso haja modificações no objeto original, a modificação da variável Cópia é
feita automaticamente.
Observe que a variável wdata se baseou na variável v_data, cuja cláusula Not Null também foi copiada (esta a causa
do erro). Já a variável wdep, que é baseada na coluna cd_depto da tabela Depto, não tem a obrigatoriedade de Not
Null, apesar de esta restrição estar presente na coluna do banco de dados.
Concluímos, então, que, quando a variável está baseada em uma coluna do banco de dados, são copiados apenas
seu tipo e tamanho, enquanto a restrição existente também é copiada quando a variável original é local.
ESCOPO E VISIBILIDADE
O escopo de uma variável é a região (bloco, subprograma ou pacote) onde a referência a ela é válida. Dentro de um
mesmo escopo, todas as variáveis devem ter nomes únicos.
Uma variável declarada em um bloco é visível nesse e em todos os blocos subordinados a ele. Se uma variável é
redefinida em um sub-bloco, ambas são acessíveis. No sub-bloco, porém, qualquer referência não qualificada fará
acesso à variável de nível mais interno.
Uma variável declarada em um bloco deixa de existir quando o bloco termina.
MSG
----------------
WCHAR INTERNA-15
Na Listagem 3.20, pudemos comprovar que no bloco interno, por default, a referência é sempre à variável local. Já
na Listagem 3.21 a seguir, fizemos referência à variável wtotal no bloco principal e recebemos um erro indicando
que neste bloco não havia sido declarada nenhuma variável wtotal. Esta variável deixou de existir quando passamos
pelo End do sub-bloco.
QUALIFICAÇÃO
Para controlarmos a visibilidade e termos acesso às variáveis dos blocos de nível superior, devemos qualificar
qualquer referência às variáveis externas nos blocos internos.
MSG
---------
DIFERENTE
A qualificação pode ser feita com o uso de um Label ou com o nome de um subprograma (será visto no tópico
referente a subprogramas).
RESTRIÇÕES
O PL/SQL não admite referências a variáveis não declaradas, mesmo que elas venham a ser declaradas posteriormente.
Para que utilizemos uma variável (mesmo sendo na declaração de outra), devemos ter efetuado sua declaração primeiro.
A declaração de variáveis deve ser feita de forma unitária. Não podemos declarar, de uma vez, diversas variáveis
referentes a um mesmo tipo.
Na Listagem 3.25 a seguir, fizemos a declaração de três variáveis boleanas. As primeira e segunda formas de atribuição
são ilegais, porque não é possível a conversão de valores entre valores numéricos e variáveis boleanas ou entre valores
alfanuméricos e variáveis boleanas (veja a tabela de conversão apresentada no item Conversão Implícita), porém a
terceira forma de atribuição é válida; se a expressão for verdadeira, será atribuído True à variável, e caso contrário, False.
ATRIBUIÇÃO
A atribuição de valor a uma variável é feita com a notação :=.
As variáveis e constantes são criadas e recebem seu valor inicial cada vez que for iniciado o bloco no qual estão declaradas.
Na ausência de atribuição de valor inicial, a variável é considerada sem valor ou Null.
É muito importante, portanto, que as variáveis sejam inicializadas antes do uso.
4 BEGIN
5 V1 := V1 + V2;
6 :RETORNO := V1 * 2;
7 END;
8 /
Procedimento PL/SQL concluído com sucesso.
RETORNO
----------
O resultado do programa apresentado pela Listagem 3.26 foi Null, porque fizemos uma operação incluindo uma
variável sem valor; desta forma, o resultado torna-se também sem valor. Isto ocorrerá sempre que fizermos uma
operação incluindo uma variável sem valor.
IF
O comando IF verifica uma condição, e dependendo do resultado realiza uma ou outra ação. Permite a execução
condicional de uma determinada ação.
Existem três sintaxes válidas de IF em PL/SQL.
Sintaxe 3.03 – IF
A Sintaxe 3.03 contém as formas básicas de um comando IF. Nas três formas sintáticas, observamos a presença do
End If para encerrar o comando. Na terceira forma sintática (IF..ELSIF…END IF), mais especificamente, apenas um
End If é necessário, independente da quantidade de Elsif’s presentes no comando. Devemos considerar que o End
If encerra o IF isolado.
Na Listagem 3.27, declaramos, mais uma vez, uma variável no ambiente SQL*Plus e a utilizamos dentro do programa
PL/SQL; este tipo de variável é chamado de Bind, pois está declarada no ambiente e não no programa. Usaremos
freqüentemente este tipo de variável para retornar informação para o SQL*Plus.
Listagem 3.27 – If
SQL> VARIABLE MSG VARCHAR2(100)
SQL> DECLARE
2 VALOR NUMBER := &VAL;
3 BEGIN
4 IF VALOR > 0 THEN
5 :MSG := 'Valor maior que zero';
6 ELSIF VALOR = 0 THEN
7 :MSG := 'Valor igual a zero';
8 ELSE
9 :MSG := 'Valor menor que zero';
10 END IF;
11 END;
12 /
Entre o valor para val: -5
antigo 2: VALOR NUMBER := &VAL;
novo 2: VALOR NUMBER := -5;
MSG
--------------------
Valor menor que zero
A Sintaxe 3.04 complementa a forma básica do comando IF com a lista de expressões válidas.
SELECT INTO
Dentro da PL/SQL, o comando Select ganha a cláusula Into a fim de obter dados da linha lida para variáveis do
programa. Desta forma, poderemos manusear os dados obtidos.
A cláusula Into segue imediatamente a lista de variáveis da cláusula Select e precede a cláusula From.
Devemos informar uma área de recepção capaz de comportar todos os dados lidos; caso contrário, receberemos
erro na execução.
O comando Select Into somente faz leitura de uma row. Caso venhamos a selecionar mais de uma row usando este
comando, ocorrerá um erro (Too Many Rows) indicando o excesso. A leitura de diversas rows é feita com o uso do
Cursor (será visto mais adiante).
Na Listagem 3.28, fizemos uma leitura e aproveitamos para trazer o Rowid da linha, de tal forma que a atualização
se processasse de forma mais rápida. O comando Select fez referência a duas colunas; portanto, na cláusula Into,
informamos duas variáveis para receber os dados lidos na mesma ordem da seleção.
Nesse Select, tínhamos a certeza da quantidade de linhas retornadas uma vez que a pesquisa foi feita pela PK,
resultando em uma única linha de retorno.
GOTO
O comando GoTo efetua um desvio incondicional para um Label. O Label deve ser único dentro do escopo e deve
preceder um comando ou um bloco PL/SQL. Além de ser usado para desvios, um Label também serve como
qualificador de variáveis, como foi mostrado no item Qualificação do tópico Declarações.
Veremos no próximo tópico que a PL/SQL possui diversas estruturas de iteração e que raramente teremos necessidade
de utilizar um comando GoTo.
Na Listagem 3.29, aparece um Label (início) que deve ser codificado entre << e >>. No comando GoTo, os símbolos
(<< e >>) não devem ser usados.
RESTRIÇÕES
Existem algumas situações em que o comando GoTo não pode ser usado:
NULL
Este comando, explicitamente, indica que não há ação a ser feita. Serve para compor certas situações em que um
comando é exigido, mas nenhuma ação é, realmente, necessária.
11 GOTO INICIO;
12 <<FIM>>
13 NULL;
14 END;
15 /
Já vimos anteriormente que todo Label deve preceder um comando ou um bloco de PL/SQL. No exemplo da
Listagem 3.30, a presença do comando Null teve a finalidade de validar o posicionamento do Label Fim. Caso o
comando não fosse adicionado, não poderíamos programar o Fim antes de End (não é um comando), que é, na
verdade, fim de bloco.
FUNÇÕES
Em PL/SQL, podemos utilizar quase todas as funções de SQL diretamente nos comandos de atribuição ou em IFs.
SQLCODE
Retorna o código associado ao último erro ocorrido. Só pode ser usada em PL/SQL (não disponível em SQL).
Quando ocorre um erro na execução de um programa PL/SQL, podemos ter acesso ao código para adotarmos as
ações apropriadas. Isto se dá através da cláusula Exception.
MSG
-----------------
100
Na Listagem 3.32, o comando Select executado não retornou nenhuma linha; desta forma, recebemos o erro
NotFound, que corresponde ao código 100 (SqlCode).
Quando ocorre um erro na execução de um programa PL/SQL, podemos ter acesso ao código para adotarmos as
ações apropriadas. Isso se dá através da cláusula Exception, que será tratada em detalhes em outro tópico.
A função SqlCode obtém o código ocorrido, o que permite o acesso à mensagem de erro.
SQLERRM
A função SqlErrm retorna o texto correspondente ao erro ocorrido. Só pode ser usada em PL/SQL (não disponível em SQL).
Retorna o texto correspondente ao erro ocorrido. Recebe como parâmetro o código do erro que desejamos decodificar.
MSG
--------------------------------
ORA-01403: dados não encontrados
O exemplo da Listagem 3.33 é o mesmo da anterior, com a diferença de que, além do código do erro, obtivemos
também a mensagem correspondente.
A função SqlErrm recebe como parâmetro o código do erro que desejamos decodificar. O default é SqlCode.
CASE
A cláusula Case permite a montagem de uma estrutura similar a IF..THEN …ELSE. Ao observarmos a Sintaxe 3.05
veremos que existem duas formas sintáticas de utilizarmos o comando.
Na primeira forma usamos uma expressão que será comparada em cada uma das cláusulas When, funcionando
como um “seletor” indicativo dos comandos a serem executados. Caso não venhamos a definir uma cláusula Else
e nenhuma das expressões for compatível com a expressão seletora, o retorno será Null.
Na Segunda forma não temos uma expressão de comparação; neste caso, cada cláusula When conterá uma condição
a ser verificada. Cada cláusula When é executada uma única vez e em ordem de apresentação. Quando uma condição
é satisfeita, os comandos subordinados são executados e as cláusulas When subseqüentes não são avaliadas. Caso
nenhuma condição seja satisfeita e não tenhamos definido uma cláusula Else, ocorrerá a exception Case_Not_Found.
MSG
-----------------
Valor zero
Nesta primeira forma a comparação é feita pela igualdade. Se valor = 0 ou valor = 1 ou etc.
--------------------
Valor menor que zero
Nesta forma sintática, podemos definir uma condição diferente para cada cláusula When.
EXERCÍCIOS
Neste conjunto de exercícios, passaremos informações para os programas usando variáveis de substituição e o
retorno da informação será feito através de variáveis Bind. Antes de iniciar, para que as tabelas não fiquem
demasiadamente cheias, refaça a base de dados com o script L01_17.
3.01) Observe as declarações a seguir. Indique quais delas não estão corretas e por quê.
Listagem-resposta 3.01A
DECLARE
ID NUMBER(04);
X, Y, Z VARCHAR2(10) := “ABC”;
END DATE NOT NULL;
IND_ESTOQUE BOOLEAN := 1;
99_MES DATE;
%TOTAL NUMBER := 21V99;
TOTAL_DE_PECAS_VENDIDAS_POR_SEMESTRE NUMBER := 0;
BEGIN
NULL;
END;
/
3.02) Observe o programa PL/SQL apresentado na Listagem-resposta 3.02A e avalie o escopo das variáveis, como se pede.
Listagem-resposta 3.02A
SQL> DECLARE
2 PESO VARCHAR2(3) := '600';
3 MSG VARCHAR2(255);
4 BEGIN
5 DECLARE
6 PESO NUMBER(3) := 1;
7 MSG VARCHAR2(255);
8 LOCAL VARCHAR2(50) := 'RIO DE JANEIRO';
9 BEGIN
10 PESO := PESO + 1; -- (A)
11 MSG := PESO || ' ESTÁ ACIMA DO PADRÃO'; -- (B)
12 LOCAL:= 'SÃO PAULO '|| LOCAL; -- (C)
13 END;
14 PESO := PESO + 1; -- (D)
15 MSG := PESO || ' ESTÁ ACIMA DO PADRÃO'; -- (E)
16 LOCAL:= 'SÃO PAULO '|| LOCAL; -- (F)
17 END;
18 /
O código do departamento é de preenchimento obrigatório, mas o nome é opcional. Se não for informado, deve
ser gravado ‘Departamento sem valor’.
3.05) Crie um bloco PL/SQL que retorne a quantidade de funcionários alocados a um determinado departamento
recebido como parâmetro. O código do departamento é de preenchimento obrigatório. Lembre-se que o usuário
poderá passar a informação em letras maiúsculas ou minúsculas.
3.06) Crie um bloco de PL/SQL que cadastre novos departamentos ou consulte dados de departamento, conforme
os parâmetros recebidos:
Parâmetros:
♦ Código do departamento, preenchimento obrigatório.
♦ Operação (I ou C), preenchimento obrigatório.
♦ Nome do departamento, obrigatório na inclusão.
♦ Código do gerente, opcional.
Críticas:
♦ Na inclusão, deve ser verificado se o departamento já existe.
♦ Na consulta, deve ser verificada a existência do departamento.
♦ Se o código do gerente for preenchido na inclusão, deve ser garantido que esta matrícula exista na tabela de funcionários.
3.07) Crie um bloco PL/SQL que calcule a seqüência de Fibonacci (1 1 2 3 5 8 13 21 34 55 ...) para um determinado
número de elementos, recebido como parâmetro e variando de 1 a 30.
3.08) Crie um bloco PL/SQL que receba como parâmetro uma data e calcule o número de dias úteis no mês correspondente.
3.09) Num triângulo ABC tem-se A= 15º, sen B = (√3) /2 e sen C = (√2) / 2. Determine os ângulos B e C montando
um bloco de PL/SQL.
3.10) Monte um bloco de PL/SQL que receba um ângulo como parâmetro e forneça o seno, cosseno e tangente do
ângulo. O ângulo será fornecido em graus. Se for informado um valor de ângulo negativo, devemos convertê-lo
em positivo e prosseguir o cálculo.
3.11) Crie um bloco de PL/SQL que receba como parâmetro um valor alfanumérico com até três caracteres de
comprimento e transforme-o em numérico (use a seqüência do alfabeto: A = 1, B = 2 e assim por diante).
3.12) Crie um bloco de PL/SQL que receba como parâmetro um nome e indique quantas partes o compõem. A
separação entre as palavras do nome é feita com espaços em branco (lembre-se que podem haver vários espaços em
branco antes, depois e entre as palavras).
3.13) Crie um bloco de PL/SQL que receba como parâmetro um número de mês e verifique quantos funcionários
fazem aniversário no mês especificado.
3.14) Crie um bloco de PL/SQL que inclua novos departamentos na tabela Depto, com as seguintes características:
♦ Receba como parâmetro o código do gerente e o nome do departamento (ambos obrigatórios).
♦ Obtenha o último código do departamento gravado na tabela e adicione 1, gerando um novo código (F01 será
transformado em F02, F26 será transformado em G00 e assim por diante).
♦ O código do departamento contábil não deve ser preenchido.
3.15) Faça um bloco PL/SQL que receba como parâmetro um código de departamento e calcule o total de salários
dos funcionários. Arredonde o resultado para a ordem de grandeza das centenas.
3.16) Faça um bloco PL/SQL que receba como parâmetro uma opção alfanumérica e calcule um dos seguintes valores:
a) o timestamp atual;
b) o nome por extenso da timezone do banco de dados;
c) o mês e o dia em que o exercício está sendo feito.
3.17) Repita o exercício anterior usando “expressão case” .
CURSOR
As linguagens convencionais, tais como Cobol e PL/1, não estão preparadas para trabalhar com tabelas. Sabemos,
no entanto, que o resultado de uma operação relacional é sempre uma tabela composta de zero, uma ou mais rows,
de acordo com o critério de restrição informado.
A fim de solucionar este problema, foi criado um artifício chamado cursor, que permitisse às linguagens
convencionais fazerem acesso a uma base de dados relacional.
A PL/SQL utiliza este artifício para acesso a um conjunto de linhas resultante de uma operação com o banco de dados.
DECLARAÇÃO
Na declaração de um cursor, já é feita a associação com o comando Select capaz de obter as linhas do banco de dados.
O cursor deve ser criado antes de ser usado, e por isso é necessário que a declaração esteja presente no bloco em que
usaremos o cursor ou em um bloco mais externo.
O tipo do retorno deve representar um registro correspondendo às colunas trazidas pelo comando Select.
A manipulação de um cursor é semelhante àquela usada para arquivos convencionais: abrir (Open), ler uma linha
(Fetch into) e fechar (Close).
ABERTURA
A abertura de um cursor é realizada com o comando Open. Os parâmetros devem ser fornecidos a tempo de Open
para que seja possível a execução do comando Select.
Os parâmetros declarados com valor inicial podem, a tempo de Open, não receber nenhum valor e utilizar os
valores iniciais previamente declarados.
Para a passagem dos parâmetros, podemos usar a notação posicional ou a notação nomeada.
A notação nomeada aparece na Listagem 3.37. Quando utilizamos o nome do parâmetro e o símbolo “=>”, podemos
passar os parâmetros em qualquer ordem.
FETCH
Associa os valores da linha atual às variáveis do programa e, posteriormente, posiciona o cursor na próxima linha
do conjunto de linhas resultantes da operação de Select.
As variáveis devem ser informadas no Fetch na mesma ordem das expressões correspondentes no comando Select.
Para cada expressão, deve haver uma variável receptora. O tipo de dado da variável e da expressão deve ser compatível.
%ROWTYPE
A fim de facilitar a recepção de informações das linhas lidas, a PL/SQL implementa o atributo %Rowtype, que gera
uma área (registro) capaz de armazenar, exatamente, uma linha com o layout da linha de uma tabela do banco de
dados ou com o layout apenas das colunas (ou expressões) referenciadas no Select associado a um cursor.
No exemplo da Listagem 3.39, foram declarados dois registros: um baseado no layout dos dados selecionados pelo
cursor C2 (Rtotal) e outro no layout da linha da tabela Func (Rfunc).
Observe que a referência às colunas presentes no registro declarado é feita com o nome da coluna ou expressão
selecionada precedida do nome da área (rtotal.count).
Quando o comando Select for composto por expressões, é importante que utilizemos alias para as expressões a fim
de termos condições de referenciá-las posteriormente.
Na Listagem 3.40, não abrimos o cursor C1 (verbo Open). Neste caso, a área (Rowtype) está com Null, assim como
todas as variáveis de PL/SQL. Como sabemos, qualquer comparação com Null retorna False.
FECHAMENTO
Para fecharmos um cursor, devemos utilizar o verbo Close. Esse verbo libera a área reservada para a montagem do
conjunto de dados selecionados.
CURSORES IMPLÍCITOS
Existem dois tipos de cursores em PL/SQL: um explícito, que acabamos de conhecer e que é declarado nos programas
de aplicação, e outro implícito, que é declarado implicitamente pelo Oracle.
O Oracle implicitamente abre um cursor para cada comando de SQL que não tenha associado um cursor explícito,
inclusive para Select Into. Podemos referenciar este cursor usando a palavra SQL.
Não podemos usar esta referência para executar os comandos Open, Fetch ou Close, porém podemos utilizá-la
para obter informações sobre o último comando executado.
Essas informações, as quais veremos a seguir, estão disponíveis tanto para cursores implícitos quanto para cursores
explícitos e são ditas atributos de cursor.
%FOUND
É um atributo de cursor que indica se a última operação de Fetch foi bem-sucedida (para cursores explícitos) ou se
alguma linha foi afetada pelo último comando Insert, Update ou Delete ou, ainda, se o comando Select Into
retornou uma ou mais linhas (para cursores implícitos).
Antes do primeiro Fetch, o valor do atributo é Null para cursores explícitos e também é Null antes de o comando
(Insert, Update, Delete ou Select Into) ser executado.
%NOTFOUND
É um atributo de cursor com lógica inversa ao atributo %Found. %Notfound retornará False se o último comando
Fetch retornar uma linha (para cursores explícitos) ou se o último comando Insert, Update ou Delete não afetar
nenhuma linha ou, ainda, se o último comando Select Into não retornar nenhuma linha (para cursores implícitos).
9 IF SQL%NOTFOUND THEN
10 GOTO FIM;
11 END IF;
12 OPEN C1;
13 <<LOOP>>
14 FETCH C1 INTO RC1;
15 IF C1%NOTFOUND THEN
16 GOTO FIM;
17 END IF;
18 :MSG := :MSG ||' - '||RC1.CD_MAT;
19 GOTO LOOP;
20 <<FIM>>
21 NULL;
22 END;
23 /
Entre o valor para depto: D11
antigo 2: VCD_DEPTO VARCHAR2(3) := '&DEPTO';
novo 2: VCD_DEPTO VARCHAR2(3) := 'D11';
Antes do primeiro Fetch, o valor do atributo é Null para cursores explícitos e também é Null antes de o comando
(Insert, Update, Delete ou Select Into) ser executado.
%ISOPEN
Permite que se verifique se um cursor está aberto ou não. Para cursores implícitos, o resultado será sempre False
uma vez que o Oracle fecha o cursor imediatamente após a operação e antes de a ação retornar ao programa.
MSG
------------------------------------------------------------------
Matrículas = - 60 - 150 - 160 - 170 - 180 - 190 - 200 - 210 - 220
%ROWCOUNT
Indica o número de linhas já lidas (Fetched) para os cursores explícitos ou o número de linhas afetadas por um
comando Insert, Update ou Delete ou, ainda, o número de linhas retornadas por um comando Select Into (para
cursores implícitos).
MSG
------------------------------
Matrículas = - 10 - 110 - 120
Quando o cursor é aberto, o atributo %Rowcount é zerado. Antes do primeiro Fetch, o atributo continua com zero.
O valor só é incrementado após o Fetch ter sido efetuado com sucesso.
Até que o primeiro comando de DML seja executado, o valor do atributo é Null para cursores implícitos.
A cláusula Where Current OF indica que será atualizada a linha atualmente apontada pelo cursor. Para que esta
operação seja legal, devemos utilizar a cláusula For Update no comando Select do cursor associado.
A cláusula For Update adicionada ao comando Select indica que todas as linhas escolhidas através da condição
presente na cláusula Where devem sofrer bloqueio (Lock) contra atualizações concorrentes. A sintaxe OF (presente
na cláusula For Update) indica que a coluna vl_sal será modificada na cláusula Set do comando Update. Poderíamos,
alternativamente, ter utilizado apenas For Update sem mencionar qualquer coluna, que o efeito seria o mesmo. A
sintaxe que inclui a palavra OF é compatível com o padrão ANSI.
No caso do exemplo da Listagem 3.45, todas as linhas da tabela Func foram bloqueadas e impedidas de ser atualizadas
até que o programa efetue um Commit.
Precisamos garantir que a linha a ser removida esteja bloqueada contra atualizações concorrentes antes de efetuarmos
o comando Delete. Desta forma, a cláusula For Update deve ser usada no comando Select do cursor.
7 <<LOOP>>
8 FETCH C1 INTO RC1;
9 IF C1%FOUND THEN
10 IF RC1.VL_SAL IS NULL THEN
11 DELETE FROM FUNC WHERE CURRENT OF C1;
12 END IF;
13 GOTO LOOP;
14 END IF;
15 COMMIT;
16 END;
17 /
A cláusula For Update adicionada ao comando Select indica que todas as linhas escolhidas através da condição
presente na cláusula Where devem sofrer bloqueio (Lock) contra atualizações concorrentes. A sintaxe OF neste
caso não foi usada. Seu uso é possível, da mesma forma que ocorreu no comando Update. Poderíamos ter mencionado
qualquer coluna na indicação de bloqueio uma vez que o comando Delete não faz menção a qualquer coluna
especificamente. A sintaxe que inclui a palavra OF é compatível com o padrão ANSI.
No caso do exemplo da Listagem 3.46, todas as linhas da tabela Func foram bloqueadas e impedidas de ser atualizadas
até que o programa efetue um Commit.
LOOP
A seqüência de comandos é executada um número infinito de vezes ou até que seja interrompida por um comando Exit.
EXIT
O comando Exit tem a finalidade de encerrar um Loop (qualquer das formas). Quando o comando Exit é executado,
o loop é completado incondicionalmente e o controle passa para o próximo comando.
A presença do Label indica que o comando também é qualificável com a utilização de um Label precedente e, desta
forma, o processo repetitivo pode ser nomeado.
13 END IF;
14 END LOOP;
15 END;
16 /
MSG
-----------------------------------------------------------
Matrículas = 10 - 20 - 30 - 50 - 60 - 70 - 90 - 100 - 110 -
120 - 130 - 140 - 150 - 160 - 170 - 180 - 190 - 200 - 210 -
220 - 230 - 240 - 250 - 260 - 270 - 280 - 290 - 300 - 310 -
320 - 330 - 340 - 7844 - 7788 - 7698 - 7566 - 7839 - 7499 -
7782 - 7521 - 7654 - 7369 -
O exemplo da Listagem 3.47 usa a forma básica do comando Exit. Nos próximos exemplos, usaremos sintaxes alternativas.
WHILE
O comando While corresponde a uma outra forma de Loop em que estabelecemos uma condição de interrupção
na própria sintaxe do comando.
MSG
---------------------------------------------------------------------
Matrículas = 7839 - 10 - 110 - 20 - 50 - 220 - 90 - 30 - 7782 - 120 -
No exemplo da Listagem 3.48, o comando While estabelece que o loop deve prosseguir enquanto houver linhas a
serem lidas. Já o comando Exit determina que, quando efetuarmos a leitura da décima primeira linha, o
processamento deve ser interrompido. O comando Exit está, desta forma, associado a uma condição. Somente
quando a condição se tornar verdadeira, o comando Exit é acionado.
FOR LOOP
O comando For Loop determina que a seqüência de comandos seja executada um número fixo de vezes. O número
de iterações é conhecido (determinado) antes de o Loop ter início.
Na sintaxe, observamos que deve ser fornecido um valor inferior e um valor superior que corresponderão,
respectivamente, ao valor inicial e ao valor final de contador, que é incrementado de 1 a cada iteração. Caso a
palavra Reverse seja utilizada na sintaxe, o valor inicial de contador será o valor superior e a cada iteração o
contador será decrementado de 1 até atingir o valor inferior.
A variável Contador é implicitamente declarada como variável local ao Loop e com tipo de dado Integer. Não pode
ser utilizada fora da iteração, porque sua declaração se extingue quando o processamento executar o End Loop.
Os valores referentes a valor inferior e valor superior podem ser fornecidos por constantes ou variáveis.
MSG
------------------
O valor de I é = 5
No exemplo da Listagem 3.49, usamos o Label do bloco externo para qualificar a variável i declarada fora da
iteração. A variável i interna, utilizada na soma, não precisa de qualificação. A seqüência de comandos é realizada
três vezes, com i sendo declarado com valor inicial igual a 1, incremento de 1 e o valor limite 3.
14 /
Entre o valor para inicio: 1
antigo 3: INICIO NUMBER := '&INICIO';
novo 3: INICIO NUMBER := '1';
Entre o valor para fim: 4
antigo 4: FIM NUMBER := '&FIM';
novo 4: FIM NUMBER := '4';
MSG
--------------------
O valor de VEZES é 4
No exemplo apresentado na Listagem 3.50, utilizamos variáveis no lugar de constantes para determinar os valores
inicial e final. A primeira iteração é executada quatro vezes, com i variando de 1 a 4.
A segunda iteração não é executada, porque o valor inicial de i é 3 e o valor final é 1, inferior, portanto, ao valor
inicial. Nesta situação, a iteração não é realizada.
MSG
-----------------------
Valores de I: 5 4 3 2 1
No exemplo da Listagem 3.51, utilizamos a cláusula Reverse para que I adquirisse valor inicial 5 e fosse decrementado
de 1 até atingir 1.
O label foi usado para qualificação do comando Loop e serviu para que a interrupção da iteração se processasse
simultaneamente para os dois Loops. Quando o teste (J > I) resulta em verdadeiro, tanto o Loop interno quanto o
externo são encerrados, passando o controle para o comando presente após o End do Loop externo (linha 19).
CURSOR LOOP
Este comando é similar ao comando For Loop, mas é específico para utilização com cursores.
O registro presente na sintaxe é declarado implicitamente pelo Oracle (como um registro tipo <cursor>%rowtype)
e tem vida útil até o End ser atingido. Esse comando realiza todas as operações vistas relativas a cursor: quando a
iteração inicia, o cursor é aberto e feito Fetch na primeira linha; se a operação (de leitura) for bem-sucedida, é
executada a seqüência de comandos presente entre o Loop e o End Loop. Esse processo se repete até que a última
linha seja processada. Após este processamento, o cursor é automaticamente fechado.
O cursor pode ser declarado previamente e utilizado no comando, ou pode ser incluído o comando Select desejado
no próprio comando For.
MSG
------------------------
VEZES = 42 - VEZES = 84
Nos dois exemplos de iteração da Listagem 3.52, o comando For leu todas as linhas da tabela Func. No primeiro
caso, declaramos explicitamente o cursor c1 e, no segundo, declaramos o cursor dentro do comando For. A segunda
sintaxe perde a possibilidade de utilizarmos os atributos do cursor uma vez que não declaramos um nome de
cursor para utilizar. O cursor implícito SQL não se aplica ao caso.
Este comando permite até a passagem de parâmetros caso o comando Select associado ao cursor seja executado em
relação a um valor parametrizado.
EXERCÍCIOS
Todos os exercícios deste grupo devem ser feitos utilizando-se os atributos %ROWTYPE ou %TYPE.
3.18) Leia os n maiores salários da tabela de funcionários e apresente-os em ordem ascendente.
3.19) Crie uma tabela com o comando apresentado abaixo para receber os n maiores salários da tabela de
funcionários. O parâmetro n deve ser recebido através de Accept. Na coluna total deve ser armazenado o somatório
de todos os salários lidos.
Listagem-resposta 3.19A
SQL> CREATE TABLE TABTOTAL
2 (NOME VARCHAR2(25),
3 SALARIO NUMBER(8),
4 TOTAL NUMBER(11)
5 );
Tabela criada.
Inclua todos os dados e posteriormente atualize a coluna total com o valor obtido na soma.
3.20) Faça um programa PL/SQL que receba um código de departamento como parâmetro e apresente o nome do
gerente do departamento e todos os funcionários (matrícula e nome) alocados àquele departamento.
Utilize cursor com parâmetro.
3.21) Crie um bloco de PL/SQL que faça o enquadramento dos funcionários de acordo com os seguintes critérios:
♦ O piso salarial será de 1.000,00 para os cargos inferiores a 51. Para os demais, o piso salarial será de 1.500,00.
♦ Para cada nível de cargo superior a 55, deverá ser acrescido 250 ao salário.
♦ Para cada nível de instrução superior a 15, deverá ser acrescido 30 ao salário.
O salário do funcionário não poderá ser diminuído. Se o funcionário já receber acima do valor calculado, deve-se
manter o salário anterior.
Deve-se apresentar, simultaneamente, todos os enquadrados (com o velho e novo salário) e aqueles não enquadrados
(com o salário antigo).
3.22) Crie uma tabela com o comando apresentado abaixo para receber a quantidade de funcionários por
departamento. O código do departamento deverá ser convertido (de alfanumérico para numérico).
Utilize Loop e Exit When. Use a função AscII para a conversão do código.
Listagem-resposta 3.22A
SQL> CREATE TABLE RESULTADO
2 (CD_DEPTO NUMBER,
3 QT_FUNC NUMBER,
4 VL_SAL NUMBER,
5 AV_SAL NUMBER);
Tabela criada.
3.23) Utilizando a mesma tabela já parcialmente preenchida do exercício anterior, complete-a com o total de
salários e a média salarial.
Utilize Cursor Loop. Inicie a leitura pela tabela resultado e trabalhe com Update Where Current.
3.24) Crie um bloco de PL/SQL que receba como parâmetro um número de mês e verifique quais os funcionários
aniversariantes. Apresentar o nome e dia de nascimento ordenado por dia de nascimento. Usar While.
3.25) Crie um bloco de PL/SQL que receba como parâmetro (de substituição) um grau de instrução e um código de
departamento e determine o cargo, salário e matrícula deste funcionário. Se existir mais de um, escolha o funcionário
mais novo. Se não existir nenhum, apresente mensagem correspondente.
METODOLOGIA
♦ Descrição da parte da linguagem capaz de efetuar tratamento de erro.
TÉCNICA
♦ Análise das diversas opções disponibilizadas através de pequenos programas.
INTRODUÇÃO
Cada bloco de PL/SQL possui uma área específica para tratamento de erro. Toda vez que ocorre um erro no programa, a
seqüência de execução é interrompida e o controle é transferido para esta área especial do bloco onde o erro foi adquirido.
Os erros, em um programa PL/SQL, são chamados de exceptions. Estas exceptions podem corresponder a erros
predefinidos, como por exemplo No_Data_Found, ou a erros definidos pelo usuário, como por exemplo Salario_Invalido.
Os erros predefinidos são de conhecimento do Oracle e, portanto, quando o erro ocorre, a PL/SQL percebe a
ocorrência do erro e faz o desvio para a área de tratamento. Já os erros do usuário não são percebidos pela PL/SQL,
a não ser que o programa explicitamente cause o erro.
No exemplo da Listagem 3.53, foi previsto tratamento para dois tipos de erro passíveis de ocorrer na seleção de dados da
tabela Func: nenhum funcionário ser encontrado no departamento especificado ou mais de um funcionário ser encontrado.
Os dois tipos de erro são predefinidos e conhecidos pela PL/SQL, correspondendo aos códigos +100 e -1422.
Quando ocorre um desvio para a área de exception de um determinado bloco, não é possível o retorno para a área de lógica do mesmo bloco.
DEFININDO EXCEPTIONS
Uma exception corresponde a uma condição de erro. Podemos declarar estas condições de erro na parte declarativa
de qualquer bloco PL/SQL.
Apesar de a declaração de uma exception ser similar à declaração de uma variável, elas não podem ser utilizadas em
comandos de atribuição nem em comandos de SQL; seu uso é bem específico.
No exemplo da Listagem 3.54, observamos a declaração da condição E_Length que foi utilizada na área de tratamento
da mesma forma que as exceptions predefinidas (When E_Length Then).
A diferença está na presença do comando Raise E_Length, que tem a finalidade de causar o erro quando o
comprimento da variável for diferente de 3.
EXCEPTIONS PREDEFINIDAS
Quando criamos um programa PL/SQL, são incorporadas a ele algumas condições de erro predefinidas, que
conheceremos a seguir.
Access_into_null ORA-06530 -6530 É causada se ocorrer uma associação de valores a atributos de um objeto não-inicializado (Null).
Case_not_found ORA-6592 -6592 É causada se nenhuma das opções da cláusula When for satisfeita e não houver sido declarada
nenhuma cláusula Else.
Collection_is_null ORA-06531 -06531 É causada se forem aplicados métodos (exceto Exists) ou associação de valores a uma Nested
Table ou Varray não-inicializados.
Cursor_already_open ORA-06511 -6511 É causada se for executado um Open para um cursor já aberto.
continua
continuação
Dup_val_on_index ORA-00001 -1 É causada se for tentada a inclusão de valores duplicados em uma coluna do banco de dados
que contém uma restrição de unicidade.
Invalid_cursor ORA-01001 -1001 É causada se for tentada uma operação ilegal com um cursor. Como, por exemplo, fechar um
cursor não aberto.
Invalid_number ORA-01722 -1722 É causada se algum comando de SQL tentou uma conversão de string para numérico quando a
string não representava um número válido. Em comandos procedurais, a exception adquirida é
Value_Error.
Login_denied ORA-01017 -1017 É causada se houver uma tentativa de conexão ao Oracle com um user/password inválidos.
No_data_found ORA-01403 +100 É causada se num comando Select Into nenhuma linha foi retornada ou foi feita referência a um
elemento inexistente (deletado) de uma Nested Table ou uma referência a um elemento não
inicializado em uma tabela PL/SQL.
Not_logged_on ORA-01012 -1012 É causada se um programa de PL/SQL tenta fazer acesso ao banco de dados sem estabelecer conexão.
Program_error ORA-06501 -6501 É causada se ocorrer um problema interno.
Rowtype_mismatch ORA-06504 -6504 É causada se a host variável cursor e a PL/SQL variável cursor usadas em uma associação
tiverem tipos de retorno incompatíveis.
Self_is_null ORA-30625 -30625 É causada se o programa tentar fazer uma chamada a um método de um objeto não
identificado (instância Null), ou seja, o parâmetro Self (que é sempre o primeiro parâmetro
passado para os métodos) está null.
Storage_error ORA-06500 -6500 É causada se a PL/SQL sair da memória ou se a memória estiver corrompida.
Subscript_beyond_count ORA-06533 -6533 É causada se for feita uma referência a um elemento de uma Nested Table ou Varray usando
um número maior que o número de elementos da coleção.
Subscript_outside_limit ORA-06532 -6532 É causada se for feita uma referência a um elemento de uma nested Table ou Varray usando um
número fora do intervalo legal (por exemplo, -1).
Sys_invalid_rowid ORA-1410 -1410 É causada quando a conversão de uma string em um rowid falha.
Timeout_on_resource ORA-00051 -51 É causada se ocorrer timeout enquanto o Oracle estiver aguardando por um recurso.
Too_many_rows ORA-01422 -1422 É causada se um comando Select Into retornar mais de uma linha.
Value_error ORA-06502 -6502 É causada se uma operação aritmética, conversão, constraint error, truncation ocorrerem.
Zero_divide ORA-01476 -1476 É causada se houver uma tentativa de divisão por zero.
Uma vez que estas condições de erro já estão previamente definidas, podemos utilizá-las livremente nos programas.
MSG
---------------------------------------
INÍCIO - DUPLICATES - INÍCIO - INSERT -
Na Listagem 3.55, criamos um bloco externo que contém o label <<Inicio>> e um bloco interno para realizar o tratamento
do erro no caso da duplicidade. Quando o erro foi adquirido, foi dada uma solução de contorno (Max), porém havia
necessidade de retornarmos ao processo de inclusão. Como o retorno para o mesmo bloco não é possível (como
veremos na Listagem 3.56), o programa foi construído com dois blocos para que o retorno fosse possível.
O VERBO RAISE
Este verbo causa a exception no momento em que é aplicado. Isso pode ser feito tanto para uma exception definida
pelo usuário quanto para uma exception predefinida.
10 RAISE INVALID_NUMBER;
11 EXCEPTION
12 WHEN E_MATRICULA OR INVALID_NUMBER THEN
13 :MSG := 'Matrícula não informada ou já existente';
14 WHEN NO_DATA_FOUND THEN
15 INSERT INTO FUNC(CD_MAT) VALUES(MATRICULA);
16 :MSG := 'Matrícula incluída';
17 END;
18 /
Entre o valor para mat: 10
antigo 2: MATRICULA NUMBER := '&MAT';
novo 2: MATRICULA NUMBER := '10';
MSG
---------------------------------------
Matrícula não informada ou já existente
No exemplo da Listagem 3.57, utilizamos o verbo Raise para causar uma exception definida pelo usuário (E_Matricula)
e também para causar a exception predefinida Invalid_Number.
EXCEPTION_INIT
A lista de exceptions predefinidas é limitada e muitas vezes desejamos controlar a ocorrência de outros erros
conhecidos do ambiente, tais como deadlock ou constraint error.
Como não temos condições de erro predefinidas para tratamento destas situações, é muito comum encontrarmos
nos programas o uso de testes do código do erro ocorrido para efetuar uma ou outra ação (Sqlcode e When Others,
que serão vistos mais adiante).
As pragmas são diretivas de compilação, isto é, são instruções fornecidas ao compilador, que modifica a forma de
execução do programa.
A pragma Exception_Init nos proporciona uma forma mais legível de realizarmos o controle dos erros previstos,
mas sem condições de erro predefinidas.
MSG
--------------------------------
Chave de relacionamento inválida
No exemplo da Listagem 3.58, associamos o código de erro ORA-2291 à variável de exception E_Relation, indicando
ao compilador PL/SQL que na ocorrência do erro -2291 deveria ser causada a exception E_Relation. Desta forma,
pudemos realizar o tratamento adequado para que o programa não fosse abortado.
Observe que a diretiva Pragma é definida na parte declarativa do bloco, pois será usada pelo compilador e não a
tempo de execução.
A PROCEDURE RAISE_APPLICATION_ERROR
Esta procedure permite que seja feito o fornecimento de mensagens de erro a partir de subprogramas armazenados
no banco de dados ou de database triggers.
Onde:
♦ <erro> – Corresponde ao número do erro, podendo variar de -20000 a -20999. Deve ser um número inteiro.
Neste intervalo de valores, não existem erros do Oracle. Este intervalo foi reservado para erros do usuário.
♦ <mensagem> – Corresponde à mensagem que desejamos enviar. Pode ser uma string de até 2.048 bytes de
comprimento.
♦ TRUE / FALSE – O terceiro parâmetro é opcional. Se for enviado True, indica que o erro será colocado na pilha de
erros anteriores. Caso o valor seja False (default), o erro substituirá todos os erros anteriores.
Se uma aplicação executar uma stored procedure que use a raise_application_error, esta (a aplicação) receberá o
código e a mensagem de erro enviada pelo subprograma e poderá realizar o tratamento adequado, da mesma
forma que faz com os demais erros do Oracle.
*
ERRO na linha 1:
ORA-20000: Matrícula não informada ou já existente
ORA-06512: em line 9
Na Listagem 3.59, quando a matrícula já existe na tabela Func, o programa é abortado com a mensagem adequada.
Observe que a mensagem de erro aparece na forma ORA-20000, da mesma forma que as mensagens de erro do
banco de dados.
PROPAGAÇÃO DA EXCEÇÃO
Quando uma exception é adquirida em um determinado bloco e é tratada, a condição de erro é cancelada. Se não
for dado tratamento, o erro é propagado para o bloco imediatamente superior (onde o atual está contido) com a
condição de erro marcada, ocorrendo, então, o desvio para a área de tratamento de erro desse bloco em busca de
tratamento para o erro.
Este procedimento se repete enquanto houver blocos embutidos. Quando atinge o bloco principal, sem tratamento,
o programa é abortado.
O exemplo da Listagem 3.60 foi executado três vezes para que possamos acompanhar todas as ocorrências.
MSG
-----------------------
INICIO- EXECUTOU WHEN A
Nesta primeira execução, a variável Vnum recebeu o valor 1. A exception A foi causada e tratada no bloco mais
interno. O programa seguiu terminando normalmente.
MSG
-----------------------
INICIO- EXECUTOU WHEN B
Nesta segunda execução, a variável Vnum recebeu o valor 2. A exception B foi causada no bloco mais interno,
porém não foi encontrado tratamento para essa condição de erro nesse bloco. Desta forma, a exception foi propagada
para o bloco externo. Como neste momento foi encontrado tratamento, o programa termina normalmente.
Na terceira execução, a variável Vnum recebeu o valor 3. A exception C foi causada no bloco mais interno, porém
não foi encontrado tratamento para essa condição de erro nesse bloco. A exception foi propagada para o bloco
externo e também aí não foi encontrado tratamento; mais uma vez o erro foi propagado, desta vez para o ambiente,
abortando o programa.
MSG
--------------------------------
ORA-01403: dados não encontrados
WHEN OTHERS
Podemos utilizar a sintaxe When Others se desejarmos capturar, dentro do programa, qualquer outra ocorrência
não prevista dentro da lista de exceptions (predefinidas ou do usuário). É muito comum a utilização conjunta da
sintaxe When Others e das funções SqlCode e SqlErrm.
MSG
--------------------------------------------------------------------
ORA-01400: não é possível inserir NULL em (“DESENV”.”FUNC”.”CD_MAT”)
MSG
-------------------------------
Erro capturado no bloco externo
No exemplo da Listagem 3.66, só foi possível a captura do erro no bloco externo (criado por fora da aplicação da
Listagem 3.65). Como teste, execute o exemplo da Listagem 3.65 passando para a variável MAT o valor A.
EXERCÍCIOS
Os exercícios deste tópico ainda utilizarão variáveis de substituição para recebimento das informações.
Listagem-resposta 3.26A
SQL> DECLARE
2 X NUMBER(3) := '&X';
3 A EXCEPTION;
4 B EXCEPTION;
5 C EXCEPTION;
6 BEGIN -- INICIO BLOCO PRINCIPAL
7 BEGIN -- INICIO BLOCO INTERNO
8 IF X = 1 THEN
9 RAISE A;
10 ELSIF X = 2 THEN
11 RAISE B;
12 ELSIF X = 3 THEN
13 RAISE C;
14 END IF;
15 :VALOR := 100;
16 EXCEPTION
17 WHEN A THEN
18 :VALOR := 300;
19 END; -- FIM BLOCO INTERNO
20 EXCEPTION
21 WHEN B THEN
22 :VALOR := 400;
23 END; -- FIM BLOCO EXTERNO
24 /
Listagem-resposta 3.28A
SQL> DECLARE
2 DUMMY NUMBER := '&NUMERO';
3 BEGIN
4 IF DUMMY > 5 THEN
5 :VALOR := 0;
6 END IF;
7 EXCEPTION
8 WHEN OTHERS THEN
9 RAISE_APPLICATION_ERROR(-20999, 'ERRO DE ATRIBUIÇÃO NA DECLARAÇÃO');
10 END;
11 /
Entre o valor para numero: A
antigo 2: DUMMY NUMBER := '&NUMERO';
novo 2: DUMMY NUMBER := 'A';
DECLARE
*
ERRO na linha 1:
ORA-06502: PL/SQL: error: erro de conversão de caractere em número numérico ou
de valor
ORA-06512: em line 2
3.29) Qual a solução de contorno que permita que controlemos o tipo de erro do Exercício 3.28?
3.30) Crie um programa para cadastramento de funcionários. Somente informe dois parâmetros: Matrícula e Código
do departamento. O programa não deve abortar se a matrícula já existir (Dup_Val_On_Index) ou se o código do
departamento não existir na tabela Depto (use a diretiva Exception_Init para definir este controle).
3.31) Faça um programa que receba três números e os apresente em ordem ascendente. Para tal, estabeleça todas as
críticas necessárias para que o usuário forneça dados corretos.
INTRODUÇÃO
Uma coleção é um grupo ordenado de elementos todos do mesmo tipo. Cada elemento possui um único subscrito
que determina o posicionamento do elemento na coleção.
A PL/SQL trabalha com três tipos de coleções: Nested Tables, Varrays e Index-By Tables (também chamadas de
tabelas de PL/SQL).
As coleções Nested Tables e Varrays podem ser criadas no banco de dados e utilizadas em PL/SQL ou criadas
diretamente em PL/SQL. Consideramos que para melhor entendimento seu estudo deve ser feito após a conceituação
e estudo de objetos no banco de dados; portanto, este assunto foi incluído no Capítulo 4. Neste tópico estudaremos
apenas a coleção nativa da própria PL/SQL, isto é, a Index-By Table.
INDEX-BY TABLES
Index-By Tables são semelhantes às outras coleções em diversos pontos.
DECLARAÇÃO E ATRIBUIÇÃO
No exemplo da Listagem 3.67 a seguir, declaramos um tipo referente à coleção. Após a declaração do tipo de dados
desejado, devemos declarar as variáveis com o tipo definido.
MSG
-----------------------------------------
A coleção foi implicitamente inicializada
Observe que a Index-By Table foi inicializada implicitamente, e por este motivo já podemos utilizá-la imediatamente
após a declaração; e só fazer a atribuição a cada elemento do array em particular.
MSG
--------------------------------
BBAA
Na Listagem 3.68, podemos observar que a referência a um determinado elemento da coleção (Index-By Table) é
feita com o uso de um indexador. A Index-By Table é inicializada diretamente com a atribuição de valor a um
índice qualquer, que não precisa ser seqüencial.
MSG
---------------------
TÉRMINO NORMAL -> AAA
Na Listagem 3.69, efetuamos a comparação para Null atribuindo um valor a uma das posições da coleção e, em
seguida, fizemos a atribuição de uma coleção para outra. Isto é possível porque ambas são do mesmo tipo (Ttable).
O erro que aparece na Listagem 3.70 indica que uma coleção não pode ser comparada com outra, mesmo que as duas
correspondam ao mesmo tipo. Podemos, no entanto, comparar posições específicas do array de cada uma delas.
MÉTODOS
As coleções possuem métodos, que são funções predefinidas com ações específicas que agem sobre as coleções
facilitando sua manipulação.
Os seguintes métodos são aplicáveis a coleções. Nem todos os métodos, porém, são aplicáveis a Index-By Tables.
EXISTS
Este método retorna True se o elemento correspondente ao parâmetro existe na coleção.
Observe pela Listagem 3.71 que o método Exists verifica a inicialização de um elemento qualquer em uma Index-
By Table. Caso façamos acesso a um elemento sem que tenhamos feito uma atribuição anterior a este índice,
receberemos um erro. Veja o exemplo da Listagem 3.72 a seguir.
11 TTEXTO(I) := RC1.NM_FUNC;
12 END IF;
13 END LOOP;
14 END;
15 /
DECLARE
*
ERRO na linha 1:
ORA-01403: dados não encontrados
ORA-06512: em line 10
Para que possamos utilizar uma determinada posição do array devemos ter atribuído dados a ele ou utilizar o
método Exists para verificar o preenchimento.
COUNT
Este método retorna o número de elementos que a coleção contém atualmente e ignora os elementos deletados.
MSG
----------------------------------
Quantidade de elementos lidos : 43
Podemos usar o método Count em todos os locais em que uma expressão inteira é permitida (como, por exemplo,
em um For i in 1..Ttexto.Count Loop).
O método Count retorna a quantidade de elementos ativos, que poderá ser inferior ao índice do último elemento.
A atribuição de Null a um determinado elemento não o remove da lista de elementos ativos. Somente o método Delete realiza esta ação.
LIMIT
Este método somente retorna um valor para Varrays. Para as demais coleções, o resultado é Null, pois nem Nested
Tables nem Index-By Tables possuem limite.
FIRST E LAST
Retorna o índice do primeiro e/ou do último elemento preenchido da coleção. Se a coleção estiver vazia, estes
métodos retornam Null. Se a coleção contiver um único elemento, First e Last retornam o mesmo índice.
O método First retornará o índice do primeiro elemento ativo e o método Last o índice do último elemento ativo.
MSG
-------------------------------
LIMITE = QTD = 43 ULTIMO = 430
Neste exemplo, ao preenchermos a Index-By Table, não utilizamos índices seqüenciais; o incremento foi 10. Isso
só é possível para Index-By Tables.
PRIOR E NEXT
Retorna o índice que precede ou sucede o índice passado como parâmetro. Se o índice passado como parâmetro for
o primeiro, o método Prior (n) retornará Null, o mesmo ocorrendo para Next (n), onde n é o último elemento ativo
da coleção. Estes métodos ignoram os elementos Null.
MSG
------------------------------------------------------------
10-20-30-40-50-60-70-80-90-100-110-120-130-140-150-160-170-1
80-190-200-210-220-230-240-250-260-270-280-290-300-310-320-3
30-340-350-360-370-380-390-400-410-420-430-
Na Listagem 3.75, preenchemos os elementos com intervalos no indexador de 10. O método Next foi utilizado
para navegação pelos elementos da coleção e, ainda, para controlar o término da pesquisa.
Esse método é aplicável às três coleções da PL/SQL.
EXTEND
Este método incrementa o tamanho de uma coleção. Esse método não é aplicável Index-By Tables.
TRIM
Este método remove um ou mais elementos do fim da coleção. Se utilizado sem parâmetros, remove um elemento.
O parâmetro, se usado, indica a quantidade de elementos finais a serem removidos. Este método não é aplicável a
Index-By Tables.
DELETE
Este método admite três sintaxes:
♦ O formato sem parâmetros remove todos os elementos da coleção.
♦ O formato com um parâmetro remove o n-ésimo elemento da coleção, onde n é o parâmetro informado.
♦ O formato com dois parâmetros remove todos os elementos no intervalo m a n, sendo m e n os parâmetros informados.
MSG
---------------------
QTD = 33 ULTIMO = 42
Exception Condição
Collection_is_null É causada se forem aplicados métodos (exceto Exists) ou associação de valores a uma Nested Table ou Varray não-inicializados.
No_data_found É causada se foi feita referência a um elemento inexistente (deletado) de uma Nested Table ou uma referência a um elemento
não inicializado em uma Index-By Table.
Subscript_beyond_count É causada se for feita uma referência a um elemento de uma coleção usando um índice maior que o número de elementos da coleção.
Subscript_outside_limit É causada se for feita uma referência a um elemento de uma Nested Table ou Varray usando um número fora do intervalo legal
(por exemplo –1).
Value_error É causada se um subscrito é Null ou não-inteiro.
MSG
-------------------------------------
Acesso a uma posição não inicializada
No exemplo da Listagem 3.77, fizemos uma tentativa de acesso a uma posição que não recebeu atribuição inicial.
O tratamento é similar a uma pesquisa sem sucesso a tabelas de SQL. A exception No_Data_Found é adquirida na
linha 5 do exemplo e tratada adequadamente.
CRIANDO MATRIZES
A partir da versão 9i podemos criar um array dentro de outro array, isto é, podemos criar uma Index-By Table cujo
elemento é uma coleção (do tipo Index-By table ou não).
MSG
------------------------------------------------------------
HENDERSON-TEIXEIRA-KWAN-GOMES-SOUZA-PEREIRA-HONOFRE-SIQUEIRA
-LOURENCO-OLIVA-QUEIROZ-NOVAES-AZEVEDO-PINTO-YVES-SANTOS-WIL
ARES-BARBOSA-JONES-LUZ-JANUARIO-MEDEIROS-SANTANA-JUVENTO-PAR
ENTE-SEVERO-PONTES-SARAIVA-SALGADO-MARQUES-LOPES-GONCALVES—
Neste exemplo declaramos uma matriz para receber 3 colunas da tabela Func (nome, sobrenome e nascimento).
Pudemos observar que o método First utilizado sem indicação de posição se refere ao nível mais externo da matriz,
assim como o método Next. Se desejássemos navegar em uma “linha” específica, deveríamos usar Mtexto(i).First e
Mtexto(i).Next(j).
MSG
----------------------------------
MTRI.LAST=3
MTRI(2).LAST=4
MTRI(2)(3).LAST=6
P-2-3-6
No exemplo da Listagem 3.79 criamos uma matriz tridimensional. Observe o uso do método Last aplicável a cada
“nível” da matriz.
REGISTROS
Um registro nada mais é que uma área estruturada, um grupo de itens de dados relacionados e armazenados em
campos contendo seu próprio nome e tipo de dados.
O atributo %Rowtype permite a declaração de um registro com o layout de uma tabela definida no banco de dados
ou das colunas selecionadas em um cursor.
A definição de registro permite total flexibilidade na declaração da área. Podemos definir nomes próprios e tipos e
tamanhos que desejarmos.
DECLARAÇÕES
Na declaração de um registro, podemos associar nessa estrutura elementos com os tipos escalares, Varrays, Nested
Tables e objetos.
6 RAMAL NUMBER(04) );
7 VREG TREG;
8 CURSOR C1 IS SELECT NM_FUNC||' '||NM_SOBRENOME, CD_MAT,
9 TO_CHAR(DT_NASC, 'DD-MM-YYYY'),
10 CD_DEPTO, NR_RAMAL FROM FUNC;
11 BEGIN
12 OPEN C1;
13 FETCH C1 INTO VREG;
14 END;
15 /
No exemplo da Listagem 3.80, definimos um registro semelhante à linha a ser lida através do cursor.
Na Listagem 3.81, definimos um registro que contém um elemento que é uma coleção.
Observe que em ambos os exemplos a declaração de tipo não cria uma área para recepção dos dados. Apenas cria
o layout da área. É indispensável a criação da variável com o tipo Treg para que seja possível a utilização da área.
A coluna Mat foi definida como Not Null, tornando obrigatória a especificação de um valor inicial.
REFERENCIANDO REGISTROS
Os campos em um registro são referenciados pelo nome.
MSG
----------------------------------------------------------------------
WILIAM JONES; JOANA LUZ; ELINE SEVERO; JOAO PONTES; FELIPE SARAIVA; MA
RINA SALGADO;
No exemplo da Listagem 3.82, fazemos referência aos elementos do registro Vreg usando o nome do elemento
qualificado pelo nome do registro Vreg.Nome, Vreg.Mat e Vreg.Dep.
No exemplo da Listagem 3.83, fazemos referência aos elementos Index-By Table da mesma forma que aos elementos
escalares, ou seja, qualificando o elemento com o nome do registro.
No exemplo da Listagem 3.84, criamos um registro como elemento de outro registro. Desta forma, houve necessidade
de dupla qualificação: Vreg faz referência à variável com o tipo Treg e Reg corresponde ao campo do registro Treg
que é do tipo Tobj, que também é um registro.
Assim a referência ao elemento Mat é feita com a qualificação Vreg.Mat, pois está diretamente definido em Treg. Já
Nome é um elemento de Tobj, que por sua vez é um elemento de Treg; sua referência então é feita com Vreg.Reg.Nome.
MSG
----------------------------------
5
No exemplo da Listagem 3.85, invertemos as definições feitas até agora; declaramos um registro como elemento de
uma Index-By Table. Com isso, cada elemento da Index-By Table possui o layout do registro Treg. Observe que a
qualificação é feita pelo elemento da tabela Ntab(n).
MANIPULANDO REGISTROS
A manipulação de um registro é similar à utilização do %RowType que corresponde, na verdade, a um registro
(com o layout da tabela ou das colunas selecionadas pelo cursor).
MSG
----------------------------------
29/05/71
Neste primeiro exemplo, declaramos um registro (%RowType) como elemento da Index-By Table. Os nomes dos
elementos deste registro correspondem às colunas selecionadas do banco de dados.
MSG
-------------
DANIEL-AD3112
No exemplo da Listagem 3.87, repetimos a mesma operação realizada anteriormente, substituindo o registro implícito
(%RowType) pela definição explícita de Treg. Os nomes dos elementos foram alterados, mas sintaticamente não
houve diferença de utilização.
Observe que acrescentamos um array dentro do registro, o qual foi incluído dentro de outro array. Esta forma
sintática somente é permitida a partir da versão 9i.
A leitura realizada nos dois exemplos permitiu que toda a tabela fosse carregada na memória para manipulação.
Na Listagem 3.88, observamos que a atribuição de um registro para outro é possível se as duas variáveis fizerem
referência ao mesmo tipo registro. A comparação, porém, não é possível.
EXERCÍCIOS
3.32) Quais os três tipos de coleções existentes em PL/SQL? Cite duas características das Index-By Tables.
3.33) O que são registros em PL/SQL?
3.34) Crie um bloco de PL/SQL que receba números (quantidade qualquer) e apresente-os em ordem ascendente. O
programa deve receber um único parâmetro alfanumérico contendo os números separados por vírgula (use coleção).
3.35) Leia a tabela de funcionários e preencha a seguinte tabela em memória:
CONCEITOS
A associação de valores a variáveis de PL/SQL em comandos de SQL é chamada Bind. A associação de uma coleção
inteira de uma única vez é chamada Bulk Bind.
O objetivo de um Bulk Bind é aumento de performance. Observe o bloco de PL/SQL apresentado na Listagem 3.89.
No exemplo da Listagem 3.89, o comando Delete é executado 2.000 vezes; isto significa que o PL/SQL (Engine)
envia um comando SQL Delete para cada valor da lista. Cada vez que a PL/SQL Engine tem necessidade de estabelecer
uma interrupção para acionar a SQL Engine, ocorre um overhead. Sendo assim, quando trabalhamos com coleções
(Nested Tables, Index-By, Varray e Host Arrays) e utilizamos iterações (loops) usando elementos destas coleções
como variáveis Bind (em comandos de SQL), adicionamos um overhead à nossa execução.
Se a iteração afetar cinco ou mais linhas do banco de dados, o uso de Bulk Binds pode aumentar a performance
consideravelmente.
Observe o mesmo trecho de programa em que substituímos o comando For pelo comando ForAll.
No exemplo da Listagem 3.90, a coleção Wcd_Lista é passada inteira de uma única vez para a SQL Engine.
SQL> DECLARE
2 TYPE L_NUM IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 TYPE L_CHAR IS TABLE OF VARCHAR2(200) INDEX BY BINARY_INTEGER;
4 WCD_LISTA L_NUM;
5 WTX_LISTA L_CHAR;
6 T1 NUMBER;
7 T2 NUMBER;
8 T3 NUMBER;
9 BEGIN
10 — Preenche as tabelas em memória —
11 FOR I IN 1..20000 LOOP
12 WCD_LISTA(I) := I;
13 WTX_LISTA(I) := 'TEXTO DA LINHA '||TO_CHAR(I);
14 END LOOP;
15 — Inclui as linhas na tabela usando For Loop
16 SELECT TO_CHAR(CURRENT_TIMESTAMP, 'SSSSS') INTO T1 FROM DUAL;
17 FOR I IN 1..20000 LOOP
18 INSERT INTO LISTA VALUES (WCD_LISTA(I), WTX_LISTA(I));
19 END LOOP;
20 — Inclui as linhas na tabela usando ForAll
21 SELECT TO_CHAR(CURRENT_TIMESTAMP, 'SSSSS') INTO T2 FROM DUAL;
22 FORALL I IN 1..20000
23 INSERT INTO LISTA VALUES(WCD_LISTA(I), WTX_LISTA(I));
24 SELECT TO_CHAR(CURRENT_TIMESTAMP, 'SSSSS') INTO T3 FROM DUAL;
25 :MSG := 'Tempo para Insert com For Loop = '||TO_CHAR(T2 - T1)||CHR(10)||
26 'Tempo para Insert com ForAll = '||TO_CHAR(T3 - T2);
27 END;
28 /
Procedimento PL/SQL concluído com sucesso.
MSG
-----------------------------------
Tempo para Insert com For Loop = 33
Este exemplo mostra uma significativa diferença de tempo entre as duas operações. É claro que esta diferença terá
variações para maior ou menor de acordo com a configuração do equipamento; no entanto, não devemos nos
esquecer que a performance das aplicações pode ser melhorada com o uso deste recurso.
O COMANDO FORALL
Este comando indica à PL/SQL Engine para preparar toda a coleção de entrada (Bulk Bind) antes de enviá-la à SQL Engine.
Na Listagem 3.92, utilizamos a cláusula Bulk Collect Into em um comando Select. Observe que a coleção (Index-By
Table) não precisou ser inicializada. A SQL Engine realiza esta operação implicitamente.
MSG
------------------------------------
Códigos lidos: 20000; 1; 2; 3; 4; 5;
A SQL Engine montará todas as linhas da tabela Lista (40.000) em uma Index-By Table antes de retornar esta
coleção para a PL/SQL Engine.
MSG
----------------------------------------------------------
Cógidos lidos: 30; 33; 36; 39; 42; 45; 48; 51; 54; 57; 60;
Na Listagem 3.93, utilizamos o comando Fetch juntamente com a cláusula Bulk Collect Into. Observe que não foi
necessário um Loop para obtenção de todas as linhas. A leitura das informações para a PL/SQL Engine foi realizada
em um único passo.
A cláusula Bulk Collect juntamente com o comando Fetch permite que limitemos a quantidade de linhas lidas. A
cláusula Limit estabeleceu que apenas 200 linhas seriam lidas uma vez que somente nos interessávamos por uma
parte do conteúdo do arquivo.
O ATRIBUTO %BULK_ROWCOUNT
Para processar qualquer comando de SQL, a PL/SQL Engine abre um cursor implícito (isto já sabemos) de nome
SQL. Posteriormente, podemos usar os atributos do cursor (%Found, %IsOpen, %NotFound e %RowCount) para
obter informações sobre as operações realizadas. Este cursor implícito SQL ganha agora um atributo composto
chamado %Bulk_RowCount, que indica o resultado do processamento para cada elemento da coleção.
MSG
--------------------------------------------------
SQL%BULK_ROWCOUNT (1)=34 (2)=33 (3)=0 (4)=0 (5)=0
No exemplo da Listagem 3.94, a coleção Index-By Table criada possui cinco elementos, preenchida com os valores 1 a 5.
Quando ocorre a execução do comando ForAll, para cada elemento da lista é iniciada a execução de um comando
Update para o banco de dados que pode atualizar n linhas. O atributo %Bulk_RowCount nos indicará quantas
linhas foram atualizadas para cada uma das posições da coleção.
Como resultado, temos que para a posição 1 ocorreram 34 atualizações; para a posição 2 ocorreram 33 atualizações
e para as demais, nenhuma atualização.
O atributo %Bulk_RowCount e o comando ForAll usam os mesmos subscritos, ou seja, se o comando ForAll utilizar
os subscritos de -5 a 10, o atributo %Bulk_RowCount informará a quantidade de processamento para os elementos
dos atributos -5 a 10.
O ATRIBUTO %BULK_EXCEPTIONS
Durante a execução de um comando For All podemos decidir interromper a execução do comando quando a primeira
exception for encontrada ou podemos prosseguir e armazenar todas as exceptions ocorridas para posterior tratamento.
Para esta segunda forma devemos incluir a cláusula Save Exceptions na execução do comando For All. A presença
da cláusula Save Exceptions fará com que a execução prossiga até o fim e todas as exceptions sejam armazenadas
(em ordem de ocorrência) em uma coleção.
O acesso a esta coleção é feito com o atributo %Bulk_Exceptions. Nesta coleção encontraremos um registro para
cada erro adquirido. O índice desta coleção navega seqüencialmente pela lista de erros encontrados. A propriedade
Count do atributo %Bulk_Exceptions indica a quantidade total de erros; desta forma o primeiro erro é obtido com
SQL%Bulk_Exceptions(1) e o último com SQL%Bulk_Exceptions(SQL%Bulk_Exceptions.Count).
Cada registro da coleção possui dois campos:
♦ O primeiro, %Bulk_Exceptions(i).ERROR_INDEX, indica a iteração que recebeu a exception.
♦ O segundo, %Bulk_Exceptions(i).ERROR_CODE, contém o código do erro.
Listagem 3.95 – SQL%Bulk_Exceptions
SQL> VARIABLE MSG VARCHAR2(300)
SQL> DECLARE
2 TYPE L_NUM IS TABLE OF LISTA.CD_LISTA%TYPE
3 INDEX BY BINARY_INTEGER;
4 WCD_LISTA L_NUM;
5 BEGIN
6 DELETE FROM LISTA;
7 FOR I IN 1..5 LOOP
8 WCD_LISTA(I) := I;
9 END LOOP;
10 FOR I IN 1..100 LOOP
11 INSERT INTO LISTA
12 VALUES (MOD(I, 4), CURRENT_TIMESTAMP||'LINHA ' ||
13 I||' DA LISTA '||CURRENT_TIMESTAMP);
14 END LOOP;
15 FORALL I IN WCD_LISTA.FIRST..WCD_LISTA.LAST SAVE EXCEPTIONS
16 UPDATE LISTA
17 SET TX_LISTA = TX_LISTA||TX_LISTA||TX_LISTA||'NOVA TXLISTA '
18 WHERE CD_LISTA = WCD_LISTA(I);
19 EXCEPTION
20 WHEN OTHERS THEN
21 :MSG := 'COUNT= '||SQL%BULK_EXCEPTIONS.COUNT||' SQL%BULK_EXCEPTIONS ';
22 FOR I IN 1..SQL%BULK_EXCEPTIONS.COUNT LOOP
23 :MSG := :MSG || ' ('||SQL%BULK_EXCEPTIONS(I).ERROR_INDEX||')='
24 || SQL%BULK_EXCEPTIONS(I).ERROR_CODE;
25 END LOOP;
26 END;
27 /
Procedimento PL/SQL concluído com sucesso.
MSG
--------------------------------------------------------
COUNT= 3 SQL%BULK_EXCEPTIONS (1)=1401 (2)=1401 (3)=1401
Neste exemplo da Listagem 3.95 repetimos o exemplo anterior, porém atribuímos um texto bastante longo à
coluna Tx_Lista no momento do Update para forçar a ocorrência de algum erro.
A inclusão do texto Save Exceptions garantiu que a interrupção não ocorresse no primeiro erro e sim no fim de
toda a operação (no caso de atualização). Houve o desvio para a área de tratamento de erro e lá obtivemos a
quantidade total de erros ocorridos com sql%bulk_exceptions.count e as duas informações sobre os erros: a iteração
com erro e o código do erro.
No nosso caso a iteração com erro coincide com o indexador I pois foram, exatamente, os três primeiros comandos
Update que geraram erro; no entanto se alterássemos o preenchimento do array Wcd_lista (invertendo a ordem de
preenchimento), as iterações com erro seriam 3, 4 e 5. Neste caso você notaria a diferença entre o indexador e a
iteração. Teste substituindo a linha 8 do programa por wcd_lista(I) := 6 - I;
OS DEMAIS ATRIBUTOS
Podemos utilizar os demais atributos de cursor (%Found, %IsOpen, %NotFound e %RowCount) juntamente com
Bulk Binds:
♦ %RowCount – Retorna o número total de linhas processadas por todas as execuções do comando SQL.
♦ %Found e %NotFound – Referem-se apenas à última execução do comando SQL.
Para sabermos se uma determina execução não produziu resultados, podemos utilizar %Bulk_Rowcount, que, para
o elemento indicado (se nenhuma linha for afetada), retornará zero.
CARACTERÍSTICAS OU RESTRIÇÕES
Como características ou restrições, temos:
♦ Quando a SQL Engine inicializa a coleção, ela destrói (grava por cima) qualquer elemento preexistente e começa
o preenchimento da coleção pelo elemento 1, e consecutivamente de 1 em 1.
♦ A coleção Bulk Bind deve ser uma coleção de valores escalares. Não podem ser valores compostos.
♦ Não podemos Bulk Fetch de um cursor em um Registro (Record), mesmo que este Record faça referência a uma
coleção (Nested Table, Varray ou Index-By).
♦ Não podemos usar o comando Select .... Bulk Collect em um comando ForAll.
♦ Podemos usar ForAll e Bulk Bind juntos. Veja o exemplo da Listagem 3.96.
♦ %Bulk_RowCount não pode ser associado a outras coleções, além de não poder ser passado como parâmetro
para subprogramas.
MSG
---------------------------
TEXTOS
(1)=LINHA 1 DA LISTA-NOVA
(2)=LINHA 4 DA LISTA-NOVA
(3)=LINHA 7 DA LISTA-NOVA
(4)=LINHA 10 DA LISTA-NOVA
(5)=LINHA 13 DA LISTA-NOVA
Na Listagem 3.96, a cada atualização, a SQL Engine guarda todas as modificações ocorridas em cada uma das linhas
envolvidas e as vai adicionando ao fim da lista da atualização anterior. Desta forma, obtivemos informação de
todas as linhas atualizadas e não apenas da última.
EXERCÍCIOS
3.39) Crie um bloco de PL/SQL que receba como parâmetro uma série de matrículas separadas por vírgula em um
único parâmetro. Monte este número em um array e faça uma consulta ao banco de dados, obtendo o nome e
salário de todos os funcionários que existam na lista. Use ForAll e Bulk Collect.
CONCEITO
Subprogramas são blocos de PL/SQL que têm nome e, portanto, podem ser chamados de outros blocos. Além desta
característica, os subprogramas podem receber parâmetros formais em vez das variáveis de substituição que foram
usadas até agora.
A PL/SQL possui dois tipos de subprogramas: Procedures e Functions.
♦ Uma procedure é acionada como um comando de PL/SQL, isto é, isolada. Não faz parte de expressões.
♦ Uma função, para ser acionada, deve fazer parte de uma expressão PL/SQL (por exemplo, uma atribuição a
uma variável).
♦ Uma função deve, obrigatoriamente, executar o comando Return para transferir a informação de volta para o
programa acionador.
A Sintaxe 3.21 nos mostra que as definições de procedure e function são bastante similares, diferindo apenas na
presença da cláusula Return para funções onde devemos determinar o tipo de retorno esperado.
MSG
----------------------------------
CRISTINA;
No exemplo da Listagem 3.97, vemos a declaração de uma função dentro de um bloco anônimo. A função recebe
dois parâmetros de entrada (IN) e retorna um valor numérico (Return Number). O comando de PL/SQL Return
(Return Vinss) foi usado para retornar o resultado do cálculo para o bloco de onde a função foi acionada.
No bloco anônimo, a função foi utilizada em uma expressão IF. Isso pode ser feito porque a função retorna um
valor. A variável Vinss foi declarada localmente na função Inss e tem vida útil até o End da função. A cláusula End
da função foi acompanhada do nome da função Inss (isso é opcional).
MSG
----------------------------------
CRISTINA;
No exemplo da Listagem 3.98, utilizamos uma procedure para realizar a mesma tarefa anterior. Primeiramente,
tivemos de incluir um novo parâmetro na procedure (tipo In Out) que pudesse retornar informação para o bloco
principal. A chamada da procedure não pode ser feita diretamente no comando IF. Desta forma, a procedure foi
acionada e atribuiu à variável Vinss (declarada no bloco principal) o cálculo do Inss realizado dentro da procedure.
PARÂMETROS
Os subprogramas recebem informação dos blocos que os acionaram através de parâmetros. Esses parâmetros são
ditos formais. Nesse item, trataremos dos modos como um parâmetro pode ser passado, a notação para chamada
dos subprogramas que possuem parâmetros e valores defaults.
14 CALC(VPREC);
15 END;
16 /
VALOR := 5;
*
ERRO na linha 8:
ORA-06550: linha 8, coluna 8:
PLS-00363: a expressão 'VALOR' não pode ser usada como um destino de atribuição
ORA-06550: linha 8, coluna 8:
PL/SQL: Statement ignored
No exemplo da Listagem 3.99, tentamos atribuir 5 ao parâmetro Valor e recebemos um erro de compilação pois
esta ação não é válida para este modo de parâmetro. Observe, ainda, que a transferência de informações entre o
bloco principal e a procedure pode ser feita de duas formas: com o valor (30) ou através de uma variável (Vprec).
Essas duas sintaxes são válidas porque o parâmetro é de entrada.
♦ OUT – Indica um parâmetro de saída. Dentro do subprograma, um parâmetro do tipo OUT pode receber
atribuições, funciona como uma variável local que tanto pode receber atribuições como pode ser lida.
MSG
----------------------------------
2400
No exemplo da Listagem 3.100 o parâmetro valor pode ser usado, internamente na procedure, como se fosse uma
variável local, tanto para atribuição como para leitura. O conteúdo da variável VINSS, no entanto, foi perdido (ob-
serve que ela possui um valor inicial) porque a passagem do parâmetro não é feita por referência. Na verdade é criada
uma variável local cujo valor (após o término do subprograma) é copiado para a variável externa (no caso, VINSS).
Outra característica do modo Out é que, ao iniciar o subprograma, o Oracle associa Null ao parâmetro Out. Desta
forma, se associarmos, dentro do subprograma, um valor ao parâmetro, ao encerrarmos a rotina o valor atribuído
será retornado ao bloco chamador; porém, se esta ação não for feita, será retornado Null.
♦ IN OUT – Indica um parâmetro que será usado simultaneamente como entrada e como saída. Dentro do
subprograma, poderemos ler seu valor e atribuir um novo valor a ele.
12 INSS(3000, VINSS);
13 INSS(SALARIO, VINSS);
14 END;
15 /
Procedimento PL/SQL concluído com sucesso.
Na Listagem 3.101, modificamos o modo do parâmetro para IN OUT; desta forma, para passarmos valor do bloco
principal para o subprograma, obrigatoriamente, devemos passar o parâmetro através de uma variável (Vinss),
porque o valor, apesar de ser lido, também receberá uma atribuição. E, para que o resultado seja transferido para o
bloco principal, há necessidade de se informar uma variável.
MSG
----------------------------------
240
Isto pode trazer ganhos de performance para aplicações que passem grandes estruturas de dados, como parâmetros
IN OUT e OUT.
VALOR DEFAULT
Quando definimos um parâmetro com o modo IN, podemos atribuir um valor default para o caso de o parâmetro
não ser informado.
10 UPDATE FUNC
11 SET VL_SAL = (VL_SAL * VALOR) / 100 + VL_SAL;
12 END IF;
13 END CALC;
14 BEGIN
15 :MSG := '';
16 CALC(30);
17 CALC(VPREC);
18 CALC;
19 END;
20 /
Procedimento PL/SQL concluído com sucesso.
MSG
----------------------------------
030,00- 000,07- 000,10-
Na Listagem 3.103, acionamos a procedure Inss de três formas diferentes: passando um valor diretamente, passando
uma variável e não passando parâmetro.
No terceiro caso, o valor recebido pelo subprograma será exatamente o valor definido como default (0.10).
Na Listagem 3.104, acionamos a rotina CALC de 5 formas diferentes: na primeira, sem parâmetros, pois os dois
parâmetros são de entrada e possuem valor default; na segunda, informamos apenas o primeiro parâmetro, pois o
segundo é de entrada e possui valor default; na terceira, informamos os dois parâmetros; a quarta forma é inválida
em PL/SQL; a quinta forma é inválida em PL/SQL.
♦ Nomeada – Indica que a passagem se dará em uma ordem aleatória de acordo com o nome do parâmetro que
será informado na passagem.
6 END INSS;
7 BEGIN
8 INSS(3000, VINSS);
9 INSS(VALOR => VINSS);
10 END;
11 /
Procedimento PL/SQL concluído com sucesso.
Na Listagem 3.105, acionamos a rotina Inss de duas formas: na primeira, informamos os dois parâmetros usando
a notação posicional; na segunda, informamos apenas o segundo parâmetro e usamos a notação nomeada, isto é,
o nome do parâmetro é seguido dos símbolos igual e maior (=>) e do valor a ser transferido. Observe que o segundo
parâmetro não pode deixar de ser informado, pois é um parâmetro de saída.
Esta sintaxe permite, adicionalmente, que informemos os parâmetros na ordem que desejarmos.
DECLARAÇÕES FORWARD
A PL/SQL exige que se declare um subprograma antes de podermos utilizá-lo. Se desejássemos criar dois
procedimentos mutuamente recursivos, esta regra impediria esta forma de utilização.
Como solução de contorno para este tipo de situação, a PL/SQL fornece uma forma de declaração parcial chamada
de declaração Forward, que interrompe a declaração da procedure ou função após a definição dos parâmetros (para
as procedures) ou do tipo de retorno (para as funções), permitindo que o compilador realize a validação da chamada
do subprograma mesmo sem ter informações sobre o corpo (ou lógica) deste.
Posteriormente, repete-se a definição do subprograma, agora contendo a chamada e a lógica.
MSG
----------------------------------
A-5; A-10;
Observe na Listagem 3.106 que a procedure B foi declarada duas vezes. Na primeira declaração, foram especificados
apenas o nome da procedure e os parâmetros formais. Na segunda declaração, foi repetida a especificação do nome
e dos parâmetros e completada com a definição do corpo da procedure.
Este procedimento foi necessário uma vez que a procedure B chamava a procedure A e a procedure A chamava a
procedure B. Não poderíamos, portanto, realizar este tipo de utilização sem o recurso da declaração Forward.
A declaração Forward pode ser útil para outras situações, tais como:
♦ Definição dos subprogramas em ordem alfabética.
♦ Grupamento dos subprogramas em um package.
♦ Definição de programas mutuamente recursivos (como no exemplo).
OVERLOADING
A PL/SQL permite a definição de dois subprogramas com o mesmo nome, desde que seus parâmetros formais
sejam diferentes em número, ordem ou tipo familiar (por exemplo, Integer e Real são tipos diferentes, porém
pertencem ao mesmo grupo familiar). Essa característica é chamada de Overloading.
Como restrição, temos que esta técnica só se aplica a subprogramas locais ou subprogramas definidos em pacotes
(serão vistos em outro tópico). Além disso, não podemos “overload” dois subprogramas se seus parâmetros diferirem
apenas em relação aos nomes ou aos modos dos parâmetros. E, finalmente, não podemos “overload” duas funções
em que a única diferença entre elas seja o tipo de retorno (mesmo que estejam em grupos familiares diferentes).
MSG
----------------------------------------------------------
PRIMEIRA CALC; PRIMEIRA CALC; PRIMEIRA CALC; SEGUNDA CALC;
Na Listagem 3.107, criamos duas rotinas com o nome de CALC subordinadas ao mesmo programa principal. Os
parâmetros das duas são diferentes (na primeira, varchar e number e, na segunda, number e number), o que
tornou o “overloading” possível.
Observe, porém, que na chamada dos programas não podemos informar apenas o segundo parâmetro, pois é o
primeiro que define qual das duas rotinas deve ser acionada. Teste retirar os comentários das duas últimas chamadas
para verificar o erro adquirido.
STORED SUBPROGRAM
O objetivo de armazenarmos uma procedure ou function no banco de dados é permitir que a rotina seja
compartilhada por diversas aplicações.
Na Sintaxe 3.22, observamos que a forma de criação de uma rotina no banco de dados é semelhante à sintaxe para
criação de uma rotina dentro de um bloco principal. A diferença está na cláusula Create, que estabelece o
armazenamento da rotina no banco de dados.
Como vantagem do armazenamento no banco de dados, temos:
♦ A produtividade pode ser incrementada à medida que uma determinada rotina pode ser compartilhada por
diversas aplicações, reduzindo a redundância de codificação.
♦ A performance pode ser incrementada uma vez que as rotinas armazenadas no banco de dados podem diminuir
a necessidade de tráfego de informações pela rede. Elas são executadas no ambiente servidor e, quando acionadas,
executam os vários comandos de SQL e PL/SQL diretamente no servidor sem necessidade de transitar essas
informações pela rede.
♦ Em relação à segurança, também podemos ter vantagens uma vez que o DBA pode restringir o acesso direto a
determinadas tabelas e autorizar a utilização apenas de rotinas que façam acesso, dentro de regras previamente
estabelecidas, a essas tabelas.
Na Listagem 3.108, vemos a criação de uma função no banco. A utilização dessa função pode ser feita em outras
aplicações que utilizem PL/SQL ou diretamente em um comando de SQL.
CD_MAT DEPARTAMENTO
---------- -------------------------------
10 DIRETORIA DA EMPRESA
20 ASSESSORIA
30 CENTRO DE INFORMACAO
50 DIRETORIA DE SUPORTE/PRODUCAO
60 GERENCIA DE SISTEMAS COMERCIAIS
Funções podem ser utilizadas em comandos de SQL (Insert, Update, Select e Delete), como vemos no exemplo da
Listagem 3.109. Procedures não retornam valores, e desta forma devem ser utilizadas em outros blocos de PL/SQL.
LINE/COL ERROR
-------- -------------------------------------------------------
6/6 PL/SQL: Statement ignored
6/15 PLS-00201: o identificador 'PERCENT' deve ser declarado
No exemplo da Listagem 3.110, o procedimento criado contém erros de compilação. Para verificarmos quais os
erros encontrados, devemos usar o comando Show (de SQL*Plus). Veja a sintaxe completa no Capítulo 2.
A sintaxe Or Replace permite que façamos modificações na rotina e executemos o processo de criação de novo. O
Oracle fará o armazenamento no banco de dados se a rotina não existir (mesmo com erros de compilação), ou a
modificação se a rotina já existir anteriormente.
DESENV.SALARIO(100)
-------------------
8198,46
No exemplo da Listagem 3.111, criamos dois usuários (Davi e Daniel). Em seguida, criamos a rotina Salário (no
usuário Desenv – Owner da rotina). Os usuários Davi e Daniel receberam autorização de execução sobre a função
Salário, porém não receberam autorização de uso da tabela Func.
Observe, no entanto, que ambos puderam executar a rotina e efetuar a leitura da tabela Func, cujo dono é Desenv.
Observe ainda que o Oracle descobriu que a tabela Func, a ser usada na função, pertencia ao usuário Desenv
(mesmo que houvesse uma tabela Func no schema de Davi ou Daniel, a tabela Func lida seria a de Desenv).
8 EXCEPTION
9 WHEN NO_DATA_FOUND THEN
10 RETURN -1;
11 END;
12 /
Função criada.
No exemplo acima, suponha que tenhamos retornado ao usuário Desenv e feito a criação da rotina Salário utilizando
a cláusula AuthId Current_User.
Quando o usuário Daniel tentou executar a função, recebeu um erro (não em relação à função) em relação à tabela
Func a que a função faz acesso. A mensagem de erro indica que a tabela (ou view) não foi encontrada no schema
do usuário Daniel, onde a pesquisa foi feita.
REFERÊNCIAS EXTERNAS
Quando especificamos a cláusula AuthId Current_User, os privilégios do executor da rotina são verificados a tempo
de execução e as referências externas são resolvidas no schema deste executor, presentes em:
♦ Comandos que manipulam os dados: Select, Insert, Update e Delete.
♦ Comando para controle de transações: Lock Table.
♦ Comandos para controle de Cursores: Open e Open-For.
♦ Comandos de SQL dinâmicos: Execute Immediate e Open-For-Using.
♦ Comandos de SQL “parseados” pela rotina Parse do pacote Dbms_Sql.
Para os outros comandos, os privilégios do dono da rotina são verificados a tempo de compilação e as referências
externas são resolvidas no schema do dono da rotina. Por exemplo, suponhamos que nossa rotina Salário tivesse
a atribuição “Sal := Scott.Soma(Sal);” (sem as aspas). Essa referência externa é resolvida no schema do usuário
Desenv (dono da rotina Salário), ou seja, quem deve ter direito de execução da rotina Soma é o usuário Desenv.
CUIDADOS ADICIONAIS
Neste tópico, listaremos alguns cuidados que deveremos observar na criação e uso da cláusula AuthId com a
opção Current_User.
♦ Apesar de a rotina ser executada com os privilégios do executor, o criador da rotina precisa ter os privilégios
referentes aos objetos acionados pela rotina a tempo de compilação, pois esta verificação será feita. Suponha,
portanto, que os usuários Davi e Daniel possuam uma tabela Func em seus schemas e que o usuário Desenv não
possua essa tabela. A criação da rotina Salario não seria possível, apesar de a tempo de execução cada usuário
(Davi e Daniel) fazer acesso à sua própria tabela. Uma solução de contorno para este problema seria a criação de
uma tabela Func no schema do usuário Desenv, contendo pelo menos as colunas utilizadas na rotina.
♦ Outra questão a ser analisada seria a situação inversa a esta anterior. Suponhamos que desejássemos que os
usuários que executassem esta rotina fizessem acesso exatamente à tabela Func do usuário Desenv. Para tal
deveríamos usar, na cláusula From, o texto Desenv.Func para ter esta garantia ou, ainda, criar um sinônimo
público para a tabela (esta segunda opção só não resolveria a situação se o usuário executor tivesse uma tabela
própria com o nome de Func).
Observe no exemplo da Listagem 3.113 que o usuário Davi recebeu o privilégio de acesso à tabela Func do usuário
Desenv, mas esta ação não foi suficiente para que a execução da rotina Salário fosse bem-sucedida. Houve necessidade
da criação do sinônimo que indicasse ao Oracle (a tempo de execução) a que tabela Func deveria ser feito o acesso.
No exemplo da Listagem 3.114, criamos uma rotina no banco de dados chamada Teste. Essa rotina declara
internamente uma procedure (Aumento) que recebe como parâmetro uma Index-By Table derivada de um Record.
Os dois tipos são declarados dentro da procedure Teste, antes da declaração da procedure Aumento.
De um modo geral, devemos declarar os tipos, as variáveis e os cursores antes das procedures e functions em
qualquer bloco de PL/SQL. As rotinas devem ser as últimas definições presentes na parte declarativa.
Da mesma forma que nesse exemplo, poderíamos definir um tipo que fosse usado na cláusula Return de uma função.
Observe que a passagem de parâmetro ocorre da mesma forma que para um escalar. A variável passada como
parâmetro possui o tipo da Index Table.
No exemplo da Listagem 3.115, observamos a criação de uma procedure Verifica que declara internamente a
função Nome. Essa função recebe como parâmetro uma Index-By Table baseada em um escalar (varchar2) e retorna
outra Index-By Table também baseada em um escalar (varchar2).
A chamada da função, nesse caso, pode ser feita de duas formas (linhas 26 e 27). Na primeira, usamos uma área
receptora de formato idêntico ao retorno da função, isto é, uma Index-By Table baseada em um Varchar2. No
segundo caso, utilizamos como área receptora um escalar simples (Texto) que receberá a segunda posição da Nested
Table retornada e não a tabela inteira. A segunda sintaxe, apesar de menos elegante e à primeira vista confusa,
pode ser usada se desejarmos obter apenas uma determinada informação do array retornado.
Nesse caso, utilizamos a soma das colunas cargo e grau de instrução na criação do índice.
Finalmente, no exemplo da Listagem 3.118, criamos um índice baseado em uma função definida pelo usuário.
Observe que a função possui a cláusula Deterministic; esta utilização é necessária, pois esta cláusula indica que se
repetirmos os mesmos parâmetros para a função ela produzirá o mesmo resultado.
Se o índice fará o cálculo da função para todas as linhas da tabela, é indispensável que o valor gerado pela função
se mantenha constante independentemente do ambiente ou do usuário que estiver executando.
EXERCÍCIOS
3.40) Qual a diferença entre Procedures e Functions?
3.41) Crie uma função armazenada no banco de dados que retorne o nome do departamento, cujo código deve ser
passado como parâmetro. Caso o departamento não exista, a função deve retornar ‘Departamento Inexistente’.
3.42) Crie uma função ou procedure na base de dados que determine o departamento que possui menos funcionários.
3.43) Crie uma função ou procedure na base de dados que receba como parâmetro um código de departamento e
determine o ramal do gerente do departamento. Caso o departamento não tenha gerente, deverá ser escolhido o
ramal do funcionário com maior cargo deste departamento (se existir mais de um, obtenha o ramal do funcionário
mais velho e com maior cargo).
3.44) Crie uma função ou procedure na base de dados que receba como parâmetro um grau de instrução e um
código de departamento e determine o cargo e o salário correspondentes a estes parâmetros. Se existir mais de um,
escolha o do funcionário mais novo. Se não existir nenhum, retorne Null.
3.45) Crie um programa na base de dados que realize a admissão dos funcionários. Esse programa deverá receber
como parâmetro nome completo (nome e sobrenome), data de nascimento, sexo e grau de instrução.
Para a construção do programa, as seguintes regras devem ser estabelecidas:
♦ Usar a rotina do Exercício 3.42 para determinar o departamento.
♦ Usar a rotina do Exercício 3.43 para determinar o ramal.
♦ Usar a rotina do Exercício 3.44 para determinar o salário e o cargo.
♦ A data de admissão corresponde ao dia do cadastramento.
♦ A matrícula deverá ser gerada a partir da última cadastrada.
♦ Os parâmetros são opcionais (exceto nome) e devem ter valores defaults.
O programa deve ser testado com passagem nomeada dos parâmetros.
3.46) Crie uma função que receba como parâmetro uma Index-By Table e retorne os dados da Index-By Table em
ordem crescente.
3.47) Faça uma rotina que receba como parâmetro um número de cargo e determine o nome do funcionário mais
velho com aquele cargo. Se não houver ninguém, o programa deve abortar com o erro Oracle correspondente.
Faça um programa que acione o programa anterior, e de acordo com seu resultado mostre o nome do funcionário
ou a mensagem “Nenhum funcionário para o cargo Informado”.
3.48) Crie um programa para gravar informações na tabela criada na Listagem-resposta 3.48A.
Listagem-resposta 3.48A
SQL> CREATE TABLE RESULTADO
2 (COD NUMBER,
3 QTD NUMBER);
Tabela criada.
METODOLOGIA
♦ Apresentação teórica dos conceitos de Packages, seguida da sintaxe necessária ao seu uso.
TÉCNICA
♦ Apresentação de exemplos que abordem a amplitude de uso dos pacotes.
CONCEITO
Um package é uma área para armazenamento de subprogramas, tipos, constantes, cursores e variáveis de PL/SQL.
Um package é definido em duas partes: uma parte de especificação e uma parte de corpo.
PACKAGE SPECIFICATION
A especificação é a interface com as aplicações. É nela que declaramos os tipos, variáveis, constantes, exceções,
cursores e subprogramas que desejamos que sejam visíveis e compartilháveis pelas aplicações. Tudo que for definido
na parte de especificação pode ser compartilhado.
A definição dos subprogramas e cursores não é completa; fazemos apenas uma definição do tipo Forward uma vez
que as aplicações só necessitam saber quais os parâmetros a serem passados para a rotina (ou cursor) e quais os
retornos fornecidos. Não há necessidade de se saber como a rotina efetua a operação.
Na Sintaxe 3.23, está definida a parte de especificação de um pacote. Apesar de a sintaxe do pacote lembrar a
sintaxe de definição de rotinas, os pacotes diferem das rotinas nos seguintes aspectos: não podem ser chamados,
parametrizados ou definidos dentro de outros pacotes.
Na Listagem 3.119, criamos um pacote contendo as rotinas necessárias para a manutenção da tabela Func. Podemos
incluir novos funcionários e removê-los. O cursor definido permite a consulta das informações.
Observe que as informações declaradas no pacote determinam quais os nomes das rotinas e itens, os parâmetros
recebidos e o retorno esperado. Não definimos detalhes de implementação. Isto será feito no corpo.
PACKAGE BODY
Na parte de corpo do pacote, definimos por completo todas as rotinas. Não só aquelas declaradas na parte de
especificação como também todas aquelas rotinas que serão chamadas pelas outras, mas que não desejamos
disponibilizar diretamente para as aplicações.
Definimos também, agora, os cursores por completo, além de todas as variáveis que venham a ser usadas pelas
rotinas e que não desejamos disponibilizar para as demais aplicações.
O corpo implementa detalhes e declarações privadas que são invisíveis pelas aplicações.
Na Sintaxe 3.24, observamos que a definição da especificação e do corpo do pacote são similares.
A diferença é que na parte de especificação as definições são do tipo Forward, enquanto na parte de corpo as
definições são completas.
No corpo, aparece ainda a possibilidade de definirmos uma área de lógica (<inicialização>) que será executada na
primeira vez em que o pacote for utilizado em uma sessão do usuário. Nesta área, podemos estabelecer ações para
inicialização de variáveis, cursores, etc.
Na Listagem 3.120, vemos parte da definição do corpo do pacote Pfunc, onde completamos a definição do cursor
e das rotinas declaradas na especificação.
Uma vez que apenas a parte de especificação é utilizada para compilação dos programas que façam uso dos pacotes,
podemos alterar o corpo do pacote sem haver necessidade de recompilar os programas que o usam.
RESTRIÇÕES
Como restrições à definição e acesso a pacotes, temos:
♦ Um pacote não pode ser chamado diretamente. Faremos referência aos objetos declarados dentro do pacote.
♦ Um pacote não pode receber parâmetro. Somente as rotinas declaradas no pacote podem fazê-lo.
♦ Um pacote não pode ser “aninhado”. Não podemos declarar um pacote dentro de outro pacote.
♦ Não podemos fazer referência remota a variáveis definidas em pacotes (direta ou indiretamente). Se utilizarmos
remotamente uma rotina que faça referência a uma variável de pacote, receberemos erro.
♦ Não podemos fazer referência a variáveis Bind dentro de pacotes. Variáveis Bind são aquelas variáveis definidas
no ambiente do aplicativo (por exemplo, :msg no SQL*Plus).
USANDO PACKAGES
Para fazermos referência aos tipos, objetos e subprogramas definidos dentro da área de especificação de um pacote,
devemos mencionar o nome do pacote como qualificador do item, como no exemplo da Listagem 3.121.
No exemplo da Listagem 3.121, fizemos uma referência ao cursor Cfunc definido dentro do pacote Pfunc usando
o nome do pacote como qualificador (Pfunc.Cfunc).
A Oracle organiza as rotinas utilitárias (predefinidas) em pacotes. Nos tópicos seguintes, conheceremos alguns
destes pacotes que possuem rotinas de grande utilidade para o desenvolvimento de aplicações no ambiente Oracle.
No exemplo da Listagem 3.121 usamos a rotina Put_Line de um pacote chamado Dbms_Output com o objetivo de
obter o valor da coluna Nome lida no comando Select (associado ao cursor Cfunc declarado no pacote).
Na Listagem 3.123, a seguir utilizamos o cursor Cfunc do pacote Pfunc e a rotina Exclui.
5 OPEN PFUNC.CFUNC(MAT);
6 FETCH PFUNC.CFUNC INTO RFUNC;
7 IF PFUNC.EXCLUI(MAT) THEN
8 :MSG := TO_CHAR(RFUNC.NASC, 'DD/MM/YYYY');
9 END IF;
10 CLOSE PFUNC.CFUNC;
11 EXCEPTION
12 WHEN OTHERS THEN
13 CLOSE PFUNC.CFUNC;
14 END;
15 /
Entre o valor para mat: 140
antigo 3: MAT FUNC.CD_MAT%TYPE := &MAT;
novo 3: MAT FUNC.CD_MAT%TYPE := 140;
Procedimento PL/SQL concluído com sucesso.
MSG
-----------------------------
19/01/1956
Observe a criação da área Rfunc com o layout do cursor Cfunc declarado no package Pfunc. O cursor não precisa
ser declarado no programa uma vez que sua especificação já está feita no package. Dentro do programa, faremos
apenas a abertura do cursor, obtenção das linhas e fechamento do cursor. Observe que houve uma preocupação
com o fechamento do cursor (em caso de qualquer erro, o cursor é fechado). Isto foi feito porque as variáveis do
pacote e o estado do cursor permanecem disponíveis até que a sessão seja fechada.
SQL> /
Entre o valor para mat: 160
antigo 3: MAT FUNC.CD_MAT%TYPE := &MAT;
novo 3: MAT FUNC.CD_MAT%TYPE := 160;
DECLARE
*
ERRO na linha 1:
ORA-06511: PL/SQL: cursor já aberto
ORA-06512: em “DESENV.PFUNC”, line 3
ORA-06512: em line 5
Observe que na Listagem 3.124 o programa foi executado a primeira vez e não houve fechamento do cursor. Na
segunda execução, recebemos um erro indicando que o cursor ainda permanecia aberto.
Isso ocorre exclusivamente com objetos de pacotes. Quando mencionamos pela primeira vez um elemento de um
pacote em uma sessão, todo o pacote é carregado na memória. Os elementos definidos no pacote podem ser
compartilhados pelos diversos procedimentos que forem executados nesta sessão. Seus valores não são reinicializados
até que a sessão conclua. Desta forma podemos utilizar pacotes para troca de informações entre processos que
executem na mesma sessão.
3 NOME VARCHAR2(100);
4 NUMERO NUMBER;
5 CURSOR C1 RETURN FUNC%ROWTYPE;
6 END PGLOBAL;
7 /
Pacote criado.
As variáveis foram inicializadas na parte de inicialização do pacote da seguinte forma: a data recebeu a data corrente,
o nome indica vazio e o número foi inicializado com zero.
Na Listagem 3.126, apresentamos um programa que consulta e modifica o valor das variáveis do pacote. O primeiro
passo do programa é verificar o valor atual das três variáveis (a função CHR com o valor 10 inclui uma quebra de
linha no texto armazenado na variável MSG). O segundo passo do programa é modificar o valor das três variáveis
de acordo com um valor de matrícula recebido como parâmetro.
MSG
-----------------------
DATA = 18/11/2001 13:50
NOME = VAZIO
NUMERO=0
SQL> /
Entre o valor para mat: 10
antigo 6: IF R1.CD_MAT = &MAT THEN
novo 6: IF R1.CD_MAT = 10 THEN
Procedimento PL/SQL concluído com sucesso.
MSG
-----------------------
DATA = 18/10/1962 00:00
NOME = SILVIO OLIVA
NUMERO=58
Na primeira execução, verificamos que o valor das variáveis do pacote correspondem aos valores da inicialização.
Em seguida, repetimos a execução e observamos que os valores apresentados correspondem aos dados do funcionário
de matrícula 120, passado como parâmetro na primeira execução.
Qualquer referência às variáveis definidas nesse pacote durante a sessão atual recuperará os valores correntes
destas variáveis. Seus valores somente serão perdidos quando houver uma troca de sessão. Veja Listagem 3.128.
MSG
-----------------------
DATA = 18/11/2001 13:53
NOME = VAZIO
NUMERO=0
OVERLOADING
Já sabemos que a PL/SQL permite a definição de dois subprogramas com o mesmo nome, desde que seus parâmetros
formais sejam diferentes em número, ordem ou tipo familiar (por exemplo, Integer e Real são tipos diferentes,
porém pertencem ao mesmo grupo familiar). Essa característica é chamada de Overloading.
Como restrição, temos que esta técnica só se aplica a subprogramas locais ou subprogramas definidos em pacotes.
A característica de Overloading pode ser bastante explorada quando definimos as rotinas dentro de pacotes.
Na Listagem 3.129, criamos três funções todas com o nome de Display. A primeira recebe como parâmetro uma
data, a segunda um texto e a terceira um número.
MSG
---------------------
DATA = 18/11/01 13:55
MSG
----------------------------
TEXTO = TESTE DE OVERLOADING
MSG
----------------------------------
NUMERO = Cr$1.234.567,00
Na Listagem 3.130, verificamos que as três execuções da rotina Display retornaram informações diferentes, de acordo
com o parâmetro informado. O Oracle determina o tipo do parâmetro recebido e aciona a rotina Display correspondente.
NÍVEL DE PUREZA
Para que uma função possa ser utilizada em um comando de SQL DML, ela deve respeitar determinadas regras:
♦ A função não pode modificar tabelas do banco de dados, ou seja, não pode executar os comandos INSERT,
UPDATE ou DELETE.
♦ Funções que lêem ou modificam os valores de variáveis em pacotes não podem ser executadas remotamente ou
em paralelo.
♦ Somente funções chamadas nas cláusulas SELECT, VALUES ou SET podem modificar o valor de variáveis de pacotes.
♦ A função não poderá chamar outro subprograma que fira uma das regras acima. Da mesma forma, a função não
poderá fazer referência a uma VIEW que fira uma das regras acima (o Oracle substitui a referência a uma VIEW
por um stored SELECT que pode incluir uma chamada de função).
As funções isoladas, isto é, armazenadas diretamente no banco de dados podem ter estas regras verificadas quando
acionadas por alguma aplicação (ou diretamente por um comando de SQL), ou seja, quando uma aplicação (ou
comando de SQL) menciona uma função armazenada no banco de dados, o Oracle faz a verificação do nível de
pureza da função e retorna ou não um erro, dependendo do emprego (ver as regras do nível de pureza).
Quando armazenamos funções em pacotes, a verificação não é possível uma vez que, para efeito de compilação de
uma aplicação ou de um comando de SQL, tudo que precisamos ter definido é a parte de especificação do pacote. Na
parte de especificação não sabemos, ainda, se a rotina atualiza ou não o banco de dados, se modifica ou não variáveis
de pacotes, etc.; seria necessária uma verificação do corpo da rotina. Para que essa ação não seja necessária (o que
feriria todo o conceito de package), devemos adicionar na parte de especificação uma pragma (diretiva de compilação,
já comentada anteriormente) chamada Restrict_References a fim de garantir o nível de pureza que desejarmos. Quando
o corpo do pacote for compilado, as restrições que tivermos estabelecido serão verificadas. Houve modificações no
uso desta pragma como veremos mais adiante (a partir da 8i). Seu uso foi bastante reduzido.
Na Listagem 3.131, observamos que a pragma incluída na parte de especificação possui cinco parâmetros que
indicam qual o nível de pureza desejado.
O primeiro parâmetro determina o nome da função que estamos verificando e é de preenchimento obrigatório.
O segundo parâmetro (WNDS – Write no database state) indica que a função não atualizará o banco de dados e
também é obrigatório se desejarmos que a função possa vir a ser utilizada em algum comando de SQL. Os demais
parâmetros são opcionais e indicam:
♦ WNPS – write no package state – indica que a função não deverá modificar variáveis de pacotes.
♦ RNDS – read no database state – indica que a função não fará leituras de tabelas do banco de dados.
♦ RNPS – read no package state – indica que a função não fará leituras a variáveis de pacotes.
Por exemplo, se desejarmos que a função seja utilizada remotamente em comandos de SQL DML, devemos garantir
que ela não leia ou modifique o valor de variáveis de pacotes (WNPS e RNPS).
A tempo de compilação do Body, as três rotinas devem obedecer aos critérios estabelecidos na diretiva de
compilação correspondente.
O fato de não precisarmos utilizar a pragma não quer dizer que podemos atualizar o banco de dados em um
comando Select. O exemplo da Listagem 3.134 nos mostra que a leitura foi executada normalmente, pois não feria
o nível de pureza; porém, a gravação foi impedida. Não precisamos, no entanto, definir a pragma para que essas
validações sejam realizadas.
A pragma Restrict_References permanece disponível para garantir que a rotina desenvolvida possua apenas os
efeitos desejados.
RESTRIÇÕES
Quando um comando de SQL é executado, algumas verificações são feitas para saber se o comando está logicamente
embutido dentro da execução de um comando SQL já em execução. Isto ocorre se o comando está sendo executado
de um trigger ou de uma função que já foi chamada de um outro comando SQL. Estas verificações são realizadas,
implicitamente, sem a necessidade da Pragma (se desejarmos restrições adicionais, devemos usar a pragma).
Nestes casos, as seguintes restrições são aplicáveis:
♦ Uma função chamada de uma query ou um comando DML não pode encerrar a transação corrente, criar um
savepoint ou retornar (rollback) para um savepoint. Nem efetuar um comando Alter System ou Alter Session.
♦ Uma função chamada de uma query (SELECT) ou de um comando DML executado em paralelo não pode
executar um comando de DML que modifique o banco de dados.
♦ Uma função chamada de um comando DML não pode ler ou modificar uma tabela que esteja sendo modificada
pelo comando DML que a chamou.
Estas restrições se aplicam independentemente de qual mecanismo for usado para a execução do comando de SQL
dentro da função ou trigger:
♦ Se aplicam a comandos SQL chamados de PL/SQL quando embutidos diretamente no texto (de uma rotina ou trigger)
ou que estejam embutidos em strings para execução dinâmica (usando Execute Immediate ou o pacote Dbms_Sql).
♦ Se aplicam a comandos embutidos em Java com sintaxe SQLJ ou que executem usando JDBC.
♦ Se aplicam a comandos executados com OCI usando CallBack Context de dentro de uma função “External” C.
Como solução de contorno para estas situações temos o uso de transações Autônomas, que são executadas em uma
sessão independente daquela que a chamou (ver tópico deste assunto).
O ARGUMENTO TRUST
A Pragma Restrict_References ganhou mais um argumento, além dos quatro anteriores (WNDS, WNPS, RNPS,
RNDS). O argumento Trust facilita a chamada de funções que tenham a declaração Restrict_References para aquelas
que não têm. Este argumento “promete” ao compilador que as restrições declaradas na pragma serão respeitadas,
não havendo necessidade real de o compilador efetuar a verificação.
Isto pode ser útil quando temos um código que está usando a pragma e que aciona outro que não está. Temos duas
formas de resolver esta situação:
No exemplo da Listagem 3.135, observamos que a rotina Grava utilizou a pragma Restrict_References com a
finalidade de permitir a compilação do pacote (ela “mentiu” para o compilador).
Como teste, retire o texto PRAGMA RESTRICT_REFERENCES (GRAVA, WNDS, TRUST); da especificação do pacote
e verifique o erro de compilação recebido. Este erro ocorre porque a rotina chamadora (Call_Grava) possui a
indicação da pragma sem a nova cláusula Trust. Isto faz com que o compilador verifique não só o código dela
como também o código dos programas chamados por ela.
A solução apresentada na Listagem 3.135 é uma das formas de resolver a questão. A segunda opção seria a colocação
da pragma apenas para a rotina Call_Grava, porém com a inclusão da opção Trust.
MSG
-----------------------
1
A execução apresentada pela Listagem 3.137 indica que a chamada funcionou. Não houve erro porque, nas condições
de uso da rotina, a atualização do banco de dados é permitida.
A utilização feita pela Listagem 3.138, no entanto, retorna um erro, porque houve violação do nível de pureza.
PACKAGE STANDARD
Esse pacote define o ambiente PL/SQL. Todas as funções de SQL que se aplicam a PL/SQL estão nele definidas.
A parte de especificação desse pacote define tipos, condições de erro e subprogramas que se tornam disponíveis,
automaticamente, para cada aplicação escrita em PL/SQL.
Como o conteúdo do pacote é diretamente visível pelas aplicações, podemos acioná-lo de um database trigger
(veremos mais adiante), um subprograma armazenado na base de dados, uma aplicação escrita em uma linguagem
Host (usando Oracle Precompiler), uma aplicação OCI e de várias ferramentas, incluindo Forms Builder, Reports
Builder e SQL*Plus.
Nas aplicações, não temos necessidade de mencionar o nome do pacote para que as funções sejam utilizadas
(Standard.To_Char). No entanto, este procedimento pode ser feito sem problemas.
MSG
-----------------------
FUNÇÃO CORRETA
Na Listagem 3.139, criamos uma função ABS local e comparamos o resultado desta função com o resultado da
função ABS presente no pacote Standard.
PACKAGE DBMS_STANDARD
Este pacote fornece facilidades para a linguagem PL/SQL que ajudam as aplicações a interagirem com o Oracle Rdbms.
Na Listagem 3.140, vemos uma parte das funções e procedures presentes no pacote Dbms_Standard.
PACKAGE DBMS_OUTPUT
Com este pacote, podemos trocar informação entre aplicações ou obter informações (display) para efeito de
depuração. Podemos visualizar as informações enviadas por uma aplicação PL/SQL no SQL*Plus se usarmos o
comando SET com a opção SERVEROUTPUT ON.
No exemplo da Listagem 3.141, usamos o comando Set Serveroutput On no SQL*Plus e a execução do bloco de PL/
SQL utilizou a procedure Put_Line do pacote DBMS_OUTPUT. Ao término do programa, o texto “Função Correta”
foi apresentado. Essa forma de utilização é muito útil para depuração de aplicações.
PACKAGE DBMS_PIPE
Este pacote permite a troca de informações entre aplicações de diferentes sessões e até de diferentes usuários
através de uma área de memória chamada Pipe.
PACKAGE UTL_FILE
Com este pacote podemos gerar e/ou ler informações de arquivos de texto externos ao banco de dados. Oferece
uma variedade de rotinas que nos permitem a abertura, leitura, fechamento e gravação de dados no arquivo.
PACKAGE DBMS_SQL
Tem a finalidade de permitir que aplicações executem comandos de SQL DML e DDL dinamicamente a tempo de
execução. A execução de um comando dinamicamente significa que o comando que desejamos executar será
passado para o Oracle em uma string e não explicitamente codificado dentro do aplicativo.
PACKAGE DBMS_ALERT
Permite que acionemos database triggers quando valores específicos forem modificados no banco de dados.
PACKAGE DBMS_RANDOM
Permite a geração de números randômicos.
PACKAGE DBMS_FLASHBACK
Permite que tenhamos acesso a informações anteriores ao Commit que efetivou a alteração.
PACKAGE DBMS_LOB
Manipulação de Lobs.
PACKAGE DBMS_ROWID
Consulta e conversão de valores de Rowid.
PACKAGE UTL_HTTP
Esse pacote permite que programas PL/SQL façam chamadas HTTP. Podemos usá-lo para recuperar dados da Internet
ou efetuar chamada ao Oracle Web Server.
EXERCÍCIOS
3.52) Crie um pacote que tenha uma rotina que receba como parâmetro:
A) Um numérico e retorne um alfanumérico com o valor editado para o formato monetário brasileiro e símbolo
financeiro “R$”.
B) Um alfanumérico e retorne um alfanumérico com o texto apresentado de trás para a frente.
C) Uma data e retorne um alfanumérico com as seguintes características: dia da semana, dia no ano, mês por
extenso, mês em algarismos romanos, ano por extenso e ano ISO.
Use Overloading.
3.53) Crie duas funções em um pacote. A primeira deverá ler o funcionário cuja matrícula foi recebida como
parâmetro. Se o funcionário tiver mais de dez anos de casa, salário inferior a 2.500,00 e não tiver recebido promoção
no último ano, a segunda rotina deverá ser acionada. A segunda rotina recebe como parâmetro um código de
matrícula e efetua a promoção do funcionário gerando um aumento de 10% e registrando esta atualização no
histórico. Garanta que estas rotinas sejam disponibilizadas para todos os usuários, mas que somente aqueles com
acesso às tabelas mencionadas possam atualizá-las.
3.54) Crie uma função em um pacote que receba um texto e retorne o mesmo texto com todas as letras maiúsculas.
Essa função deve ser testada em um comando Update para atualização dos nomes e sobrenomes dos funcionários.
3.55) Crie um pacote que declare uma variável Date, uma variável Varchar2(100) e uma variável Number.
Essa rotina deve ser usada em um relatório a ser gerado para disco que apresente o nome do funcionário completo
e sua idade no dia da admissão e no dia de hoje.
CONCEITO
Este pacote tem a finalidade de enviar mensagens a partir de procedures, packages ou triggers. Ele se utiliza de um
buffer em memória para transferência das mensagens.
Quando um programa envia mensagens através do pacote Dbms_Output, essas mensagens são armazenadas na
área de buffer e somente apresentadas ao término do programa.
Caso estejamos executando o programa no SQL*Plus ou Server*Manager, basta que executemos o comando Set
Serveroutput On para que todas as mensagens enfileiradas pelo programa sejam apresentadas.
Se estivermos executando rotinas encadeadas ou blocos anônimos, podemos obter as linhas geradas pelo programa
anterior usando a rotina Get_Line do próprio pacote.
A Sintaxe 3.25 mostra as rotinas que compõem o pacote com seus respectivos parâmetros.
ENABLE
Esta procedure habilita chamadas para Put, Put_Line, New_Line, Get_Line e Get_Lines.
As chamadas a estas procedures são ignoradas se o package DBMS_OUTPUT não estiver habilitado.
Devemos especificar o tamanho da área de buffer em bytes. Esse tamanho pode variar de 2.000 (default) até
1.000.000. Se esse tamanho for excedido, receberemos uma mensagem de erro (ORU-10027: Buffer overflow, Limit
of buffer_limit bytes).
Podemos executar essa procedure diversas vezes. O maior valor de buffer especificado dentre as múltiplas chamadas
é o que será utilizado.
Na Listagem 3.142, a procedure Enable alocou uma área de buffer de 2.000 bytes. Seu uso é dispensado para
tamanhos inferiores a 20000 bytes pois este é o tamanho default da área de buffer. A procedure Put_Line incluiu o
texto “Teste” na área de buffer e esse texto foi apresentado ao término da execução do programa.
DISABLE
Esta procedure desabilita as chamadas para Put, Put_Line, New_Line, Get_Line e Get_Lines e limpa o buffer.
Na Listagem 3.143, utilizamos a procedure Disable. Observe que, mesmo executando um Put_Line posteriormente,
nenhum resultado foi apresentado. A utilização dessa procedure pode ser útil quando estivermos depurando um programa
e não desejarmos mais que algumas mensagens sejam informadas. Como a chamada da rotina Disable é um comando,
este pode ser incluído dentro de um IF estabelecendo uma situação condicional de aparecimento ou não das mensagens.
PUT
Estas procedures estão “overloading” no pacote. São três rotinas, cada qual recebendo um tipo de parâmetro. O
parâmetro enviado será armazenado na área de buffer imediatamente após a última informação. Não é incluído
qualquer caracter indicativo de fim de linha.
O uso da rotina Put deve levar em consideração que, a tempo de leitura, as procedures Get_Line e Get_Lines não
retornam uma linha que não tenha sido terminada com o caracter newline.
Se o tamanho especificado pelo buffer for excedido, será recebida uma mensagem de erro.
Devemos lembrar que, ao passarmos uma data ou um numérico para a rotina Put (ou Put_Line) correspondente,
esta fará a conversão default (To_Char) para string. Se desejarmos um formato específico, devemos usar
explicitamente a rotina To_Char e passar o parâmetro como alfanumérico.
Neste exemplo (Listagem 3.144), usamos a procedure Put cinco vezes, cada uma delas com uma letra da palavra
Teste. O resultado foi apresentado em uma única linha contendo todos os caracteres armazenados individualmente.
NEW_LINE
Esta procedure coloca uma marca de fim de linha no buffer. Normalmente, usamos esta procedure após uma ou
mais chamadas à procedure Put para indicar fim de mensagem.
Cada chamada a New_Line gerará uma linha a ser retornada pelo Get_Line.
PUT_LINE
Estas procedures enviam o parâmetro informado para a área de buffer, acrescentando, automaticamente, um caracter
indicativo de fim de linha após o texto enviado.
Devemos lembrar que, ao passarmos uma data ou um numérico para a rotina Put (ou Put_Line) correspondente,
esta fará a conversão default (To_Char) para string. Se desejarmos um formato específico, devemos usar
explicitamente a rotina To_Char e passar o parâmetro como alfanumérico.
Na Listagem 3.145, utilizamos o mesmo exemplo anterior, substituindo a procedure Put pela Put_Line. O resultado
apresentou cinco linhas, pois após cada texto enviado para o buffer foi acrescido um indicador de fim de linha.
GET_LINE
Esta procedure recupera uma única linha da informação do buffer, excluindo o caracter newline final. O tamanho
máximo da linha é de 255 bytes.
Se a procedure concluir com sucesso, o status retornado é zero, e caso contrário 1, indicando que não existem linhas
no buffer.
Quando reutilizamos a área de buffer após uma leitura, todas as linhas restantes, ainda presentes no buffer, são
descartadas para que a área possa ser preenchida novamente.
MSG
-------------------------------------------------------
18/11/01; 12345; TESTE; 18/11/2001 17:39; Cr$12.345,00;
Na Listagem 3.146, criamos dois blocos dentro de um programa. No primeiro bloco, preenchemos o buffer com
Sysdate, um número, um texto, uma data formatada e um número formatado. No segundo bloco, utilizamos a
rotina Get_Line para obter uma linha de cada vez e concatenamos a linha obtida na variável de ambiente msg.
Observe a diferença de formatação quando enviamos diretamente a data (ou número) e quando formatamos o
resultado. Observe, ainda, que, quando recuperamos a linha do buffer, a rotina Get_Line remove o caracter indicativo
de quebra de linha do texto retornado.
GET_LINES
Esta procedure recupera um conjunto de linhas e pode ser usada no lugar da Get_Line para reduzir o número de
chamadas ao servidor. Devemos especificar o número de linhas que desejamos recuperar do buffer.
A procedure retorna também o número real de linhas recuperado. Se esse número for menor que o número de
linhas requisitado, significa que não existem mais linhas no buffer.
Quando reutilizamos a área de buffer após uma leitura, todas as linhas restantes ainda presentes no buffer são
descartadas para que a área possa ser preenchida novamente.
Cada linha no array pode ter até 255 bytes de comprimento.
12 BEGIN
13 :MSG := '';
14 DBMS_OUTPUT.GET_LINES(LINHAS, ACHOU);
15 FOR I IN 1..ACHOU LOOP
16 :MSG := :MSG || LINHAS(I) || '; ';
17 END LOOP;
18 END;
19 END;
20 /
Procedimento PL/SQL concluído com sucesso.
MSG
-------------------------------------------------------
18/11/01; 12345; TESTE; 18/11/2001 17:41; Cr$12.345,00;
No exemplo (Listagem 3.147), substituímos o uso da rotina Get_Line pela chamada da Get_Lines. Solicitamos a
leitura de dez linhas (valor inicial da variável Achou). O resultado mostrou que havia apenas três linhas na área de
buffer. Observe que o tipo da variável Linhas é Dbms_Output.Chararr, ou seja, um tipo Table definido dentro do
pacote Dbms_Output. Cada linha desta tabela PL/SQL tem comprimento máximo de 255 bytes.
Função criada.
Na Listagem 3.148, criamos uma função de base que está preenchendo a área de buffer com dados da leitura da
tabela Func.
TOTAL
----------
40286,86
Na Listagem 3.149, fizemos uma execução da função no SQL*Plus para verificar o resultado acumulado.
As mensagens são apresentadas na linha do SQL*PLUS.
MSG
----------------------------------------------------------------------
LOOP: LOOP N. = 1; ACUMULADO = 9327,14; LOOP N. = 2; ACUMULADO = 17556
,95; LOOP N. = 3; ACUMULADO = 22366,29; LOOP N. = 4; ACUMULADO = 27931
,21; LOOP N. = 5; ACUMULADO = 32916,14; TOTAL DE SALÁRIOS = 32916,14;
Neste bloco anônimo, fizemos uma chamada à função Deptosal gerada anteriormente. A função preenche a área de
buffer. Essa área é visível pelo bloco (ou rotina) que acione a rotina ou bloco que preenche o buffer. Com a rotina
Get_Lines, fizemos a leitura das linhas presentes no buffer e atribuímos as diversas linhas à variável de ambiente Msg.
EXERCÍCIOS
3.59) Descreva com suas palavras o pacote DBMS_OUTPUT.
3.60) Crie um programa que receba como parâmetro um número de mês e emita uma carta parabenizando o
funcionário pela data do seu aniversário (use DBMS_OUTPUT). Não deve ser usada stored procedure.
3.61) Usando o pacote DBMS_OUTPUT, gere um arquivo contendo o nome, data de nascimento e salário dos
funcionários. Alinhe os dados por coluna.
3.62) Faça uma rotina que usa a DBMS_OUTPUT para colocar no buffer o nome dos aniversariantes do mês (recebido
como parâmetro).
3.63) Faça um programa que leia a área de buffer do programa anterior e verifique se o funcionário cujo nome será
fornecido como parâmetro é aniversariante. Informe o resultado em uma variável Bind.
3.64) Faça um script que coloque no prompt do SQL*PLUS o nome do usuário e a linguagem em que está o banco
de dados atualmente. Garanta que este script seja executado todas as vezes em que o SQL*Plus for acionado (utilize
seus conhecimentos de SQL*Plus).
3.65) Gere uma área de buffer com o seguinte layout: nome, sobrenome, data de nascimento (formato dd/mm/
yyyy), sexo e salário.
Os dados devem ser separados pelo símbolo #.
Caso uma determinada coluna não tenha valor (Null), deve ser substituído por “**” para colunas alfanuméricas e
-1 para colunas numéricas.
3.66) Faça um programa que leia o buffer gerado pelo programa anterior e crie novas linhas na tabela Func. O
número da matrícula deve ser gerado a partir do último armazenado em Func.
CONCEITO
O pacote Utl_File possui um conjunto de rotinas que têm a finalidade de permitir o acesso ou geração de arquivos
externos ao banco de dados. As rotinas são similares aos processos de manipulação de arquivos convencionais.
Para utilização deste package o DBA deve acrescentar o parâmetro UTL_FILE_DIR ao arquivo de inicialização INIT.ORA a fim de determinar quais
diretórios estão disponíveis para acesso.
Sabemos que a PL/SQL executa no ambiente Server; desta forma, os arquivos lidos ou gravados com o uso deste pacote serão lidos ou gerados
no ambiente servidor (no ambiente em que se acha o banco de dados).
Este pacote não declara apenas procedures e funções, são declaradas exceções e tipos também.
O quadro abaixo apresenta um resumo dos diversos objetos presentes no pacote.
continua
continuação
O conteúdo do tipo File_Type é privativo do pacote Utl_File. Os usuários do pacote não devem fazer referência ou
modificar seus componentes.
A Sintaxe 3.26 a seguir apresenta as rotinas presentes no pacote e seus respectivos parâmetros.
Esse pacote trabalha de forma semelhante ao pacote Dbms_Output no que se refere à área de trabalho. Ele se utiliza
de um buffer em memória para transferência dos dados a serem armazenados ou lidos do arquivo em disco.
Quando um programa envia linhas para gravação através do pacote Utl_File, essas linhas são armazenadas na área
de buffer e transferidas para disco quando o buffer se enche ou quando acionamos a rotina Fflush, que força a
gravação do buffer para disco.
A seguir, veremos cada uma das rotinas que compõem o pacote, sua ação e as condições de erro que podem ser
adquiridas em cada caso.
Para que possamos ler e gravar arquivos com este pacote, nosso primeiro passo será modificar o arquivo Init.ora
presente no diretório C:\oracle\admin\oracle. Esse arquivo contém diversos parâmetros para inicialização do
banco de dados.
Na Figura 3.01, apresentamos um trecho deste arquivo em que acrescentamos a linha Utl_File_Dir = *. Esta sintaxe
permite o acesso a qualquer diretório da máquina. Como estamos trabalhando com o Personal Oracle9i, a máquina
cliente e a servidora são uma só; desta forma o diretório a ser utilizado para leitura ou gravação pode ser o disco corrente.
Se desejarmos limitar o acesso para determinados diretórios, devemos usar a sintaxe Utl_File_Dir = <nome dos diretórios>.
O arquivo init.ora somente é lido uma vez pelo banco de dados quando o Oracle entra em atividade. Desta forma
não temos outra alternativa a não ser retirar o banco do ar e colocá-lo novamente. Você pode executar o programa
Services (Iniciar Painel de Controle Ferramentas Administrativas Serviços) e selecionar o serviço OracleService-
ORACLE (se você tiver instalado o banco de dados mantendo os mesmos nomes sugeridos no Capítulo 1). Na parte
superior da janela pressione o botão Reiniciar Serviço que irá interromper o serviço e ativá-lo novamente ou faça
isso você mesmo com os botões Interromper Serviço e Iniciar Serviço. O banco de dados será encerrado e ativado
juntamente com o serviço.
FOPEN
A função Fopen abre um arquivo para leitura ou gravação. O Path do diretório já deve existir, uma vez que não é
feita criação pelo Fopen.
A função retorna um file handle que deve ser usado em todas as operações de I/O subseqüentes no arquivo.
Na sintaxe apresentada, observamos que essa função recebe três parâmetros, a saber:
♦ <location> – Indica o diretório do arquivo a ser aberto.
♦ <file> – Indica o nome do arquivo (incluindo a extensão). Não deve ser incluído o caminho (Path).
♦ <open_mode> – Indica o modo como o arquivo será usado. Os valores válidos são: ‘r’ para leitura, ‘w’ para
gravação e ‘a’ para acrescentarmos dados ao fim do arquivo.
♦ <max_linesize> – na versão 9i foi criada uma outra função Fopen com um quarto parâmetro que indica o tamanho
máximo da linha lida ou gravada. O valor default para este parâmetro é 1023 bytes e o valor máximo é 32767.
Na Listagem 3.151, fizemos um pequeno programa que grava uma linha em um arquivo de saída. Como primeiro
passo do programa, declaramos o file handle (Saída) com o tipo Utl_File.File_Type. A segunda etapa é definir como
o arquivo deve ser aberto usando-se a rotina Fopen. No nosso caso, usamos a opção “A”, indicando que se o
arquivo não existir deve ser criado e se já existir os dados devem ser adicionados.
As condições de erro definidas dizem respeito apenas à abertura.
FOPEN_NCHAR
A função Fopen_Nchar abre um arquivo para leitura ou gravação. Sua sintaxe e forma de trabalho é similar à da
função Fopen vista anteriormente, a diferença é que o arquivo de entrada é formato Unicode em vez do formato
do charset do banco de dados.
IS_OPEN
Testa um file handle para ver se ele identifica um arquivo aberto. Essa função indica apenas se o arquivo está aberto
ou não, ou seja, se o file handle é válido ou não. Ela não garante que uma operação de I/O posterior usando o file
handle não venha a receber um erro de sistema operacional.
Essa função não adquire qualquer tipo de condição de erro.
FCLOSE
A procedure Fclose fecha um arquivo identificado por um file handle.
A função Fclose pode causar uma das seguintes condições de erro:
♦ Invalid_Filehandle – O handle do arquivo está inválido.
♦ Write_Error – Um erro de sistema operacional ocorreu durante a operação de gravação.
Podemos receber uma exceção do tipo WRITE_ERROR se existirem buffers de dados ainda não gravados quando o comando Fclose for executado.
O exemplo da Listagem 3.152 é semelhante ao anterior, com a diferença de que o tratamento das condições de erro
diz respeito agora aos possíveis erros gerados a tempo de close do arquivo. Observe, também, que determinamos
um tamanho máximo de 2000 bytes para a linha a ser gravada.
FCLOSE_ALL
Esta procedure fecha todos os file handle abertos na sessão. A procedure Fclose_All não altera o estado de um file
handle adquirido (aberto) pelo usuário. Isto significa que um teste com Is_Open poderá retornar True mesmo após
o arquivo ter sido fechado, porém nenhuma operação de leitura ou gravação será válida até que um novo Fopen
seja realizado para aquele file handle.
A função Fclose_All pode causar a seguinte condição de erro:
♦ Write_Error – Um erro de sistema operacional ocorreu durante a operação de gravação.
MSG
-------------------------------
ARQUIVO ABERTO
No exemplo da Listagem 3.153, substituímos o fechamento específico pela rotina Fclose_All. Após o fechamento,
testamos o estado do file handle e percebemos que ele indica que o arquivo está aberto. Esta situação não ocorre se
usarmos o fechamento específico de um arquivo empregando Fclose.
GET_LINE
Esta procedure lê uma linha de texto de um arquivo aberto identificado pelo file handle e coloca o texto no buffer
de saída (parâmetro).
O tamanho default do texto para leitura é de 1.023 bytes. Para que venhamos a obter uma linha maior que esta devemos
ter informado este limite ao tempo de abertura do arquivo. A leitura de uma linha em branco gerará uma string vazia.
MSG
-------------------------------
GRAVAÇÃO EXEMPLO 2
GRAVAÇÃO EXEMPLO 2
Na Listagem 3.154, lemos as linhas geradas pelas execuções dos exemplos anteriores. Observe que a utilização das condições
de erro Invalid_Filehandle, Invalid_Operation e Read_Error precisam da presença do nome do pacote precedendo o nome
da exception, uma vez que estas condições estão declaradas dentro do pacote. Já as exceptions Value_Error e No_Data_Found
não necessitam deste prefixo, pois são condições de erro predefinidas para todos os blocos de PL/SQL.
A condição de erro No_Data_Found ocorre quando for feita uma tentativa de leitura e já não houver linhas a serem
lidas. Quando isto ocorre no programa, aproveitamos para fechar o arquivo.
GET_LINE_NCHAR
Esta procedure é similar em funcionalidade e sintaxe à procedure Get_Line vista anteriormente. Deve ser usada
quando abrirmos o arquivo com Fopen_Nchar (arquivos Unicode).
PUT
Esta procedure armazena o texto presente no buffer no arquivo identificado pelo file handle. A linha incluída não
recebe nenhum caracter de fim de linha. É necessária a execução da rotina New_Line para gerar este caracter quando
desejado. Esta rotina tem a mesma funcionalidade da rotina com o mesmo nome existente no pacote Dbms_Output.
A operação de gravação pode receber uma das seguintes exceções:
♦ Invalid_Filehandle – O handle do arquivo está inválido.
♦ Invalid_Operation – O arquivo não pode ser aberto ou operado como requisitado.
♦ Write_Error – Um erro de sistema operacional ocorreu durante a operação de gravação.
♦ CharsetMismatch – Este erro pode ocorrer se houvermos aberto o arquivo para Unicode e houvermos usado esta
rotina em seguida (devemos usar Put_Nchar).
No exemplo da Listagem 3.155, anexamos ao buffer as letras T, E, S, T, E, S separadamente, uma em cada comando Put.
MSG
-------------------------------
GRAVAÇÃO EXEMPLO 2
GRAVAÇÃO EXEMPLO 2
TESTES
Ao repetirmos o programa de leitura do arquivo, observamos que o resultado foi gravado em uma única linha
dentro do arquivo.
PUT_NCHAR
Esta procedure é similar em funcionalidade e sintaxe à procedure Put vista anteriormente. Deve ser usada quando
abrirmos o arquivo com Fopen_Nchar (arquivos Unicode).
NEW_LINE
Esta procedure grava um ou mais caracteres de fim de linha para o arquivo identificado pelo file handle.
A operação de gravação pode receber uma das seguintes exceções:
♦ Invalid_Filehandle – O handle do arquivo está inválido.
♦ Invalid_Operation – O arquivo não pode ser aberto ou operado como requisitado.
♦ Write_Error – Um erro de sistema operacional ocorreu durante a operação de gravação.
No exemplo da Listagem 3.157, a rotina New_Line está sendo usada sem o segundo parâmetro, o que significa a
inclusão de apenas um caracter de fim de linha no arquivo (1 é o valor default do parâmetro).
PUT_LINE
Esta procedure grava o texto presente no buffer para o arquivo. Esse comando já adiciona um caracter de fim de
linha ao texto.
A operação de gravação pode receber uma das seguintes exceções:
♦ Invalid_Filehandle – O handle do arquivo está inválido.
♦ Invalid_Operation – O arquivo não pode ser aberto ou operado como requisitado.
♦ Write_Error – Um erro de sistema operacional ocorreu durante a operação de gravação.
♦ CharsetMismatch – Este erro pode ocorrer se houvermos aberto o arquivo para Unicode e houvermos usado esta
rotina em seguida (devemos usar Put_Line_Nchar).
Na Listagem 3.157, utilizamos o mesmo exemplo criado para teste da rotina Put. Veremos a seguir o resultado
gravado no arquivo.
MSG
-------------------------------
GRAVAÇÃO EXEMPLO 2
GRAVAÇÃO EXEMPLO 2
TESTES
T
E
S
T
E
S
Observe que cada uma das letras foi incluída em uma linha diferente e, ao fim do arquivo, foi anexado mais um
caracter de fim de linha, gerando uma linha em branco final.
PUT_LINE_NCHAR
Esta procedure é similar em funcionalidade e sintaxe à procedure Put_Line vista anteriormente. Deve ser usada
quando abrirmos o arquivo com Fopen_Nchar (arquivos Unicode).
FFLUSH
Esta procedure grava fisicamente todos os dados pendentes para aquele arquivo. O Fflush faz com que os dados no
buffer sejam descarregados em disco.
A operação de gravação pode receber uma das seguintes exceções:
♦ Invalid_Filehandle – O handle do arquivo está inválido.
♦ Invalid_Operation – O arquivo não pode ser aberto ou operado como requisitado.
♦ Write_Error – Um erro de sistema operacional ocorreu durante a operação de gravação.
PUTF
Essa procedure age de forma similar à procedure Put, com a diferença de que realiza formatações na linha a ser
incluída no arquivo. Trabalha de forma semelhante a um “printf” (do C), porém com limitações. A string de
formatação pode conter qualquer texto.
Os caracteres ‘%s’ e ‘\n’ têm um significado especial neste comando:
♦ %s – Marca um ponto para substituição, no texto, pelo próximo argumento da lista.
♦ \n – É substituído (de acordo com a plataforma) pelo caracter de fim de linha.
Observe na sintaxe do comando que esta rotina recebe até sete parâmetros, sendo o primeiro o file handle (já conhecido):
♦ <formato> – Indica uma string que pode conter os caracteres %s e \n.
♦ <arg> – De um a cinco argumentos para substituição no %s. Se houver mais %s que argumentos, o local será
ocupado por uma string de comprimento zero.
A operação de gravação pode receber uma das seguintes exceções:
♦ Invalid_Filehandle – O handle do arquivo está inválido.
♦ Invalid_Operation – O arquivo não pode ser aberto ou operado como requisitado.
♦ Write_Error – Um erro de sistema operacional ocorreu durante a operação de gravação.
♦ CharsetMismatch – Este erro pode ocorrer se houvermos aberto o arquivo para Unicode e houvermos usado esta
rotina em seguida (devemos usar Putf_Nchar).
Na Listagem 3.159, utilizamos o comando Putf duas vezes para geração de linhas formatadas. No primeiro caso,
fizemos a substituição de três argumentos no texto e utilizamos a rotina New_Line para encerrar a linha impressa
e ainda deixar uma linha em branco. No segundo caso, quebramos a linha usando o símbolo \n para que os
argumentos fossem gravados em linhas distintas. Observe que, ao término da execução, não definimos o caracter
de fim de linha. Esta ação é feita, automaticamente, quando o Fflush descarrega o restante do buffer.
6 :MSG := '';
7 LOOP
8 UTL_FILE.GET_LINE(SAIDA, LINHA);
9 :MSG := :MSG || LINHA || CHR(10);
10 END LOOP;
11 EXCEPTION
12 WHEN NO_DATA_FOUND THEN
13 UTL_FILE.FCLOSE_ALL;
14 END;
15 /
MSG
-------------------------------
GRAVAÇÃO EXEMPLO 2
GRAVAÇÃO EXEMPLO 2
TESTES
T
E
S
T
E
S
PUTF_NCHAR
Esta procedure é similar em funcionalidade e sintaxe à procedure Putf vista anteriormente. Deve ser usada quando
abrirmos o arquivo com Fopen_Nchar (arquivos Unicode).
UM EXEMPLO DE LEITURA
Criaremos agora um exemplo completo de um programa que fará a carga de dados na tabela de Projetos e Atividades
(PrjAtv) a partir de um arquivo externo ao banco de dados. O layout do arquivo de entrada é apresentado a seguir:
Informação Coluna
Na Listagem 3.161, vemos o conteúdo do arquivo a ser lido, de acordo com o layout estabelecido anteriormente.
3 LINHA VARCHAR2(50);
4 R1 PRJATV%ROWTYPE;
5 BEGIN
6 ARQ := UTL_FILE.FOPEN('D:\TESTE', 'CARGA.SQL', 'R');
7 LOOP
8 UTL_FILE.GET_LINE(ARQ, LINHA);
9 R1.CD_PROJ := SUBSTR(LINHA, 1, 6);
10 R1.CD_ATIV := TO_NUMBER(SUBSTR(LINHA, 7, 3));
11 R1.DT_INI := TO_DATE(SUBSTR(LINHA, 10, 10), 'DD/MM/YYYY');
12 R1.DT_FIM := TO_DATE(SUBSTR(LINHA, 20, 10), 'DD/MM/YYYY');
13 INSERT INTO PRJATV (CD_PROJ, CD_ATIV, DT_INI, DT_FIM)
14 VALUES (R1.CD_PROJ, R1.CD_ATIV, R1.DT_INI, R1.DT_FIM);
15 END LOOP;
16 EXCEPTION
17 WHEN NO_DATA_FOUND THEN
18 COMMIT;
19 UTL_FILE.FCLOSE_ALL;
20 END;
21 /
Na Listagem 3.162, temos um programa que faz a leitura de uma linha e prepara a gravação da tabela PrjAtv
utilizando uma variável com o mesmo layout de uma linha da tabela (RowType). De acordo com o layout fornecido
utilizamos a função Substr para recortar a linha nas diversas colunas da tabela.
UM EXEMPLO DE GRAVAÇÃO
No exemplo a seguir, desejamos enviar uma carta para todos os funcionários aniversariantes do mês a ser fornecido como
parâmetro. Para cada funcionário, será gerado um arquivo em separado de tal forma que possa ser transmitido via e-mail.
Depto Pessoal.
Na Listagem 3.163, vemos o layout da carta que deve ser gerada individualmente por funcionário.
25 END LOOP;
26 END;
27 /
Entre o valor para mes: 5
Na Listagem 3.164, apresentamos o programa criado para a geração do arquivo conforme o layout estabelecido.
Depto Pessoal.
EXERCÍCIOS
3.67) Faça um programa que gere um arquivo contendo as seguintes colunas da tabela de funcionários: cd_mat,
nm_func, nm_sobrenome, dt_nasc, vl_sal.
3.68) Faça um programa que leia um arquivo e realize a carga na tabela de funcionários, completando os dados de
acordo com as seguintes especificações: Data de admissão (será igual à data do cadastramento), Ramal (fixo igual a
1354), salário (fixo igual a 1.000,00) e cargo (fixo igual a 55).
Caso uma determinada coluna esteja sem valor (Null), deve ser feita substituição por: “**” para as colunas
alfanuméricas e -1 para as colunas numéricas.
INTRODUÇÃO
O pacote DBMS_PIPE permite que duas ou mais sessões na mesma instância se comuniquem. As informações são
enviadas através de uma área de memória chamada Pipe. Estas áreas são armazenadas na SGA.
De acordo com os requisitos de segurança de nossa instalação, podemos usar pipes públicos ou privados.
PIPES PÚBLICOS
Podemos criar um Pipe público explicita ou implicitamente.
A criação implícita ocorre quando fizermos a primeira referência ao Pipe e desaparecerá quando não mais contiver dados.
A criação explícita ocorre quando utilizamos a função Create_Pipe e informamos o parâmetro Private com o valor
False. Sua destruição também deverá ser explícita com a rotina Remove_Pipe.
O domínio do Pipe público é o schema no qual ele foi criado, implicitamente ou explicitamente.
Cada Pipe público trabalha assincronamente. Qualquer número de usuários (schemas) poderá gravar para um Pipe
público (se tiver permissão de Execute no pacote Dbms_Pipe e conhecer seu nome).
Qualquer usuário com os privilégios e conhecimentos apropriados poderá ler informações de um Pipe público.
Porém, uma vez que a informação é lida, o Pipe é esvaziado e a informação não fica mais disponível para outros
leitores do mesmo Pipe.
O pacote Dbms_Pipe fornece as rotinas necessárias aos procedimentos de criação, leitura e gravação de informações
em um Pipe (seja ele Público ou Privativo).
PIPES PRIVATIVOS
A criação de Pipe privativo é explícita através da chamada da função Create_Pipe. Uma vez criado, o Pipe privativo
permanece na memória compartilhada (SGA) até que seja explicitamente removido (Remove_Pipe ou que a instância
seja shutdown).
Não poderemos criar um Pipe privativo se existir na memória um Pipe Público com o mesmo nome.
O acesso a um Pipe privativo é restrito a:
♦ Sessões que estiverem executando sob o mesmo userid que o criador do Pipe.
♦ Stored subprograms executando no mesmo privilégio de domínio do userid criador do Pipe.
♦ Os usuários que estabeleceram conexão como SYSDBA ou INTERNAL.
FUNCIONAMENTO DO PACOTE
Este pacote funciona com uma área de buffer local, da mesma forma que os pacotes estudados até agora. As
mensagens a serem enviadas para um determinado Pipe devem ser armazenadas localmente e posteriormente
enviadas, como um pacote, para o Pipe desejado.
Inicialmente, usamos a procedure Pack_Message, que armazena a mensagem para a área de buffer local da sessão.
Após termos juntado todas as mensagens desejadas no buffer, podemos enviá-las com a procedure Send_Message.
Esta rotina envia todas as mensagens armazenadas no buffer local.
A leitura se processa de forma inversa: devemos obter a informação do Pipe, usando a procedure Receive_Message,
e armazená-la no buffer local da sessão e, em seguida, desmembrá-la com a procedure Unpack_Message.
O quadro a seguir apresenta os diversos componentes deste pacote.
CREATE_PIPE
Esta função cria explicitamente um Pipe, que pode ser público ou privado, dependendo do valor do parâmetro <privativo>.
Se este parâmetro receber o valor True, indicamos que o Pipe será privativo e somente poderá ser utilizado pelos
seguintes grupos de usuários:
♦ Sessões que estiverem executando sob o mesmo userid que o criador do Pipe.
♦ Stored subprograms executando no mesmo privilégio de domínio do userid criador do Pipe.
♦ Os usuários que estabeleceram conexão como SYSDBA ou INTERNAL.
Não devemos usar nomes de pipes começando com ORA$, uma vez que estes nomes são reservados pela Oracle.
Esta função pode receber até três parâmetros, sendo o primeiro de preenchimento obrigatório correspondendo ao
nome do Pipe, que deve ser único em relação a toda a instância. Os demais têm os significados a seguir:
♦ <maxpipesize> – Especifica o tamanho máximo (em bytes) do Pipe. O tamanho total de todas as mensagens no
Pipe não poderá exceder a este tamanho. O <maxpipesize> torna-se uma parte das características do Pipe e
persiste pela vida do Pipe. As chamadas à função Send_Message com tamanhos maiores fazem com que
<maxpipesize> seja incrementado. As chamadas com tamanhos de mensagem menores simplesmente usam o
tamanho existente.
♦ <private> – Com o valor default (True), criaremos um Pipe privado. Os Pipes públicos podem ser implicitamente
criados quando usarmos a Send_Message.
O resultado dessa função, ou seja, seu retorno, será zero se a criação for realizada com sucesso. Ocorrerá um erro
(ORA-23322) se houver conflito de nome.
MSG
-------------------------------------------
Pipe1 = 0; Pipe3 = 0; Pipe2 = 0 E -23322
Na Listagem 3.166, criamos um Pipe privativo com o nome de Teste. Criamos um Pipe público com o nome de
Público. Quando tentamos criar um Pipe público com o nome de Teste, ocorreu conflito de nome e recebemos um
erro de execução que foi capturado pela condição de erro Others.
Para que possamos nomear os parâmetros, devemos obter o nome com que foram definidos na criação de cada uma das rotinas. Para tal,
devemos usar o comando Desc do SQL*Plus que nos fornecerá a descrição correta do pacote e das rotinas definidas dentro dele (veja uma parte
destas rotinas na Listagem 3.167).
PACK_MESSAGE
Existem quatro procedures Pack_Message definidas no pacote Dbms_Pipe e duas procedures específicas chamadas
Pack_Message_Raw e Pack_Message_Rowid.
Todas elas têm a mesma finalidade, diferindo apenas em seus parâmetros formais.
O objetivo dessas rotinas é enviar o parâmetro recebido para a área de buffer local com a finalidade de posterior
envio ao Pipe.
Os itens enviados para o buffer local não são convertidos para o formato texto. São armazenados incluindo um
byte extra indicativo do tipo e dois bytes extras para armazenamento do tamanho.
O tamanho do buffer local é de 4.096 bytes e não pode ser redimensionado. Desta forma, devemos controlar o
tamanho da mensagem armazenada e, se necessário, efetuar um envio parcial para o Pipe (podemos enviar diversas
mensagens). O SqlCode recebido em caso de estouro no tamanho do buffer local é -6558.
3 RETORNO NUMBER;
4 VROWID ROWID;
5 BEGIN
6 SELECT ROWID INTO VROWID FROM DUAL;
7 RETORNO := DBMS_PIPE.CREATE_PIPE(PIPE, PRIVATE => TRUE);
8 :MSG := 'Pipe = '||RETORNO||'; ';
9 DBMS_PIPE.PACK_MESSAGE('Texto a ser enviado para o pipe privativo');
10 DBMS_PIPE.PACK_MESSAGE(SYSDATE);
11 DBMS_PIPE.PACK_MESSAGE(123456789);
12 DBMS_PIPE.PACK_MESSAGE_ROWID(VROWID);
13 EXCEPTION
14 WHEN OTHERS THEN
15 :MSG := :MSG ||'ERRO = '||SQLCODE;
16 END;
17 /
Procedimento PL/SQL concluído com sucesso.
MSG
---------------------------
Pipe = 0;
Na Listagem 3.168, usamos diversas rotinas Pack_Message para armazenamento no buffer de uma área varchar2,
um numérico, uma data e um rowid.
SEND_MESSAGE
Esta função envia uma mensagem para um determinado Pipe. Se o Pipe não existir, crie-o como público.
Pode receber até três parâmetros, sendo o primeiro obrigatório e indicativo do nome do Pipe para onde a mensagem
deve ser enviada. Os demais têm o seguinte significado:
♦ <timeout> – Especifica o tempo (em segundos) de espera (máximo) enquanto são feitas tentativas de envio da mensagem
para o Pipe. O valor default é a constante MAXWAIT, que é definida como 86.400.000 segundos (1.000 dias).
♦ <maxpipesize> – Especifica o tamanho máximo (em bytes) do Pipe. O tamanho total de todas as mensagens no
Pipe não poderá exceder a este tamanho. O <size> torna-se uma parte das características do Pipe e persiste pela
vida deste. Chamadas à função Send_Message com tamanhos maiores fazem com que <size> seja incrementado.
As chamadas com tamanhos de mensagem menores simplesmente usam o tamanho existente.
Os valores retornados por esta função podem ser:
♦ 0 – Indica que o Pipe (implícito) foi criado com sucesso. Se o Pipe já existia e o usuário tentou recriá-lo, foi
autorizado a fazê-lo. Qualquer dado existente no Pipe é mantido. Se um usuário privilegiado (SYSDBA ou SYSOPER)
recriar um Pipe, o Oracle retorna 0, mas o Owner (dono) do Pipe permanece inalterado.
♦ 1 – Indica que o Pipe sofreu um timeout. Isto pode ter ocorrido porque não foi possível a obtenção de um lock
para o Pipe ou porque o Pipe está muito cheio para ser usado. Se o Pipe tiver sido criado implicitamente e estiver
vazio, ele é removido.
♦ 3 – Indica que ocorreu uma interrupção. Se o Pipe foi criado implicitamente e estiver vazio, ele é removido.
♦ Erro ORA-23322 – Indica insuficiência de privilégios para gravar no Pipe. Se um Pipe com o mesmo nome já
existir e tiver sido criado por outro usuário, o Oracle sinaliza com este erro, indicando conflito de nome.
11 DBMS_PIPE.PACK_MESSAGE(123456789);
12 DBMS_PIPE.PACK_MESSAGE_ROWID(VROWID);
13 RETORNO := DBMS_PIPE.SEND_MESSAGE(PIPE, 20);
14 :MSG := :MSG ||'Envio = '||RETORNO||'; ';
15 EXCEPTION
16 WHEN OTHERS THEN
17 :MSG := :MSG ||'ERRO = '||SQLCODE;
18 END;
19 /
Procedimento PL/SQL concluído com sucesso.
MSG
---------------------------
Pipe = 0; Envio = 0;
Na Listagem 3.169, completamos o programa que vinha sendo montado até então com o envio da mensagem para
o Pipe privativo Teste. Iniciaremos o processo inverso para leitura da informação armazenada.
RECEIVE_MESSAGE
Esta função recebe uma mensagem do Pipe e a coloca no buffer local do usuário. Quando executamos esta função,
a mensagem também é removida do Pipe. Isso significa que a mensagem só pode ser recebida uma vez. Se o Pipe foi
criado implicitamente, ele é removido após o último registro ser removido do mesmo.
Se o Pipe informado não existir, o Oracle cria o Pipe e aguarda pela chegada da mensagem até que <tempo> tenha
expirado. Caso isso aconteça (isto é, o tempo expire) e nenhuma mensagem seja recebida, o programa recebe um
erro e o Pipe é removido.
MSG
-------------------------------
MENSAGEM RECEBIDA NA ÁREA LOCAL
Na Listagem 3.170, recebemos a mensagem do Pipe Teste, porém não fazemos o desmembramento. Esta ação é
necessária para que possamos obter as diversas partes da mensagem. Até esse ponto, apenas retiramos a mensagem
do Pipe e a colocamos na área de buffer local.
Na sintaxe referente a esta função, verificamos os seguintes parâmetros:
♦ <pipename> – Especifica o nome do Pipe para receber a mensagem.
♦ <timeout> – Especifica o tempo (em segundos) de espera (máximo) enquanto aguarda que chegue alguma
mensagem para o Pipe. O valor default é a constante MAXWAIT, que é definida como 86.400.000 (1.000 dias).
Os valores retornados por essa função podem ser:
♦ 0 – Indica que a mensagem foi recebida com sucesso.
♦ 1 – Indica que o Pipe sofreu um timeout. Se o Pipe tiver sido criado implicitamente e estiver vazio, ele é removido.
NEXT_ITEM_TYPE
Após termos utilizado a função Receive_Message para colocar a informação do Pipe no buffer local, devemos usar
a função Next_Item_Type para determinar o tipo de dado do próximo item no buffer local.
Quando o resultado da função for zero, indica que o buffer local está vazio.
UNPACK_MESSAGE
As procedures Unpack_Message têm a finalidade de desmembrar a mensagem recebida no buffer local. A cada vez
que acionarmos Unpack_Message, uma parte da mensagem é transferida para a área do programa.
Para realizarmos o desmembramento apresentado na Listagem 3.171, repetimos o exemplo da Listagem 3.169 a
fim de preencher o Pipe Teste com dados de diferentes tipos.
MSG
-----------------------------------------------------------------------------------
MENSAGEM RECEBIDA NA ÁREA LOCAL; TEXTO = Texto a ser enviado para o pipe privativo;
DATA = 30/08/99; NUMERO = 123456789; ROWID = AAAACsAABAAAATmAAA;
No trecho de programa apresentado na Listagem 3.171, verificamos que a função Next_Item_Type é utilizada para
determinar o trecho de dado que será copiado para o programa. Quando o código é identificado, ocorre o
desmembramento e uma próxima pesquisa. Quando o código de retorno não é identificado, o Loop é encerrado
com uma apresentação do número de retorno.
Após cada identificação, executamos uma das procedures Unpack_Message que retorna o trecho de mensagem
identificado e, simultaneamente, efetua o posicionamento no buffer para o próximo item de dado.
Se executarmos uma procedure Unpack_Message quando não existirem mais trechos de mensagem ou quando o
item não corresponder ao tipo esperado, ocorrerá uma mensagem de erro.
O valor de retorno para Nchar, nesta versão, também é 9 (o mesmo de Varchar2), porém como o parâmetro da
rotina Unpack_Message é diferente, não devemos misturar estes dois tipos em uma mesma mensagem. Nos scripts,
adicionais ao livro, foram incluídos os números 169a e 171a para que você possa testar a recepção de Nchar.
REMOVE_PIPE
Quando criamos um Pipe implicitamente e o esvaziamos, ele é removido automaticamente.
Já os Pipes criados através da rotina Create_Pipe devem ser removidos explicitamente (ou quando a instância for
shutdown). Todos os registros não utilizados existentes no Pipe são removidos antes de o Pipe ser removido.
PURGE
Esta procedure esvazia o conteúdo do Pipe e aciona a função Receive_Message para transferência do conteúdo do
Pipe para a área de buffer local antes de limpar seu conteúdo.
Caso façamos a tentativa de esvaziar o conteúdo de um Pipe para o qual não tenhamos privilégios, receberemos a
condição de erro ORA-23322.
RESET_BUFFER
Esta rotina limpa o buffer local e posiciona os indicadores de início de mensagem em zero.
Uma vez que todos os Pipes a que o usuário tenha acesso enviam as mensagens para o mesmo buffer local da
sessão, é conveniente que, antes de efetuarmos acesso a um novo Pipe, esvaziemos o buffer local para que não
ocorra a possibilidade de enviarmos uma mensagem inválida que ainda permaneça no buffer.
UNIQUE_SESSION_NAME
Esta função retorna um nome único (dentre todas as sessões ativas).
Múltiplas chamadas a esta mesma função na mesma sessão retornarão o mesmo valor.
Procedimento criado.
Para a criação de um procedimento usando o pacote Dbms_Pipe é necessário que o usuário tenha autorização explícita de uso do pacote (Grant
execute on Dbms_Pipe to Desenv); portanto estabeleça conexão como Sys(password change_on_install) e execute o comando Grant.
Na Listagem 3.172, criamos a procedure. Podemos enviar várias mensagens até que o segundo parâmetro receba
True quando, então, todo o conteúdo do buffer será enviado ao Pipe. Observe que não fizemos a criação explícita
do Pipe. Nesse caso, ele será criado implicitamente e será público.
VROWID
------------------
AAAH5dAAIAAAAAyAAA
VROWID
------------------
AAAH5dAAIAAAAAyAAA
Na Listagem 3.173, executamos a rotina diversas vezes a fim de enviar vários trechos de mensagem para o Pipe.
Procedimento criado.
Observe que o programa ficará em Loop enquanto houver trechos de mensagens a serem desmembrados. Quando
todo o trecho tiver sido manuseado, o programa terminará.
*
ERRO na linha 1:
ORA-20002: Erro na recepção da mensagem do Pipe - 1
ORA-06512: em “DESENV.RECEBE”, line 7
ORA-06512: em line 1
Uma segunda execução da rotina Recebe causa o erro de execução previsto (-20002), indicando que o Pipe já não
tem mais mensagens a enviar.
EXERCÍCIOS
3.71) Faça uma rotina que envie mensagem para um Pipe público de nome “Publico”. Pode-se enviar dados
numéricos, alfanuméricos ou datas.
Foram criadas três rotinas Envia dentro do pacote PIPE, uma para enviar dados alfanuméricos, outra para envio de
dados numéricos e a última para datas.
3.72) Faça uma rotina que envie mensagem para um Pipe privativo de nome “Interno”. Pode-se enviar dados
numéricos, alfanuméricos ou datas.
3.73) Faça uma rotina que receba dados de um Pipe informado como parâmetro. Se não for informado o nome do
Pipe, faça a leitura do Pipe público.
3.74) Teste as rotinas usando os usuários Desenv e System (password = manager).
ROWID
Cada linha no banco de dados tem um endereço. Esse endereço é fornecido pela pseudocoluna Rowid.
Ao consultarmos o valor de Rowid para uma determinada linha, obtemos uma informação que representa seu endereço.
Na versão 8, ainda são aceitas manipulações com o formato da versão 7, porém para qualquer acesso que venhamos
a fazer nesta pseudocoluna para tabelas no banco de dados receberemos a versão estendida.
Este pacote ainda foi mantido nesta versão do livro em virtude de muitos usuários ainda trabalharem com a
versão 7, porém a tendência é de que seu uso seja decrescente à medida que formos migrando para versões mais
recentes do Oracle.
A Listagem 3.177 mostra a diferença nos formatos das duas versões para o mesmo endereço de linha.
O PACOTE
Este pacote tem a finalidade de desmembrar esta pseudocoluna chamada Rowid. Podemos obter informações
sobre cada uma das partes que compõem essa pseudocoluna ou, ainda, convertê-la do formato restrito (versão 7 e
anteriores) para o formato estendido desta versão (ou vice-versa).
O quadro a seguir apresenta um resumo de todos os componentes desse pacote e sua finalidade.
A maioria das rotinas desse pacote é composta de funções. Essas funções podem ser usadas tanto em PL/SQL quanto em comandos de SQL.
Na Sintaxe 3.28 são apresentadas as sintaxes de todas as rotinas que compõem o pacote.
ROWID_CREATE
Esta função cria um Rowid com as informações passadas como parâmetro. Seu uso está restrito a teste.
Se desejarmos criar um Rowid restrito, o parâmetro Rowid_Type deve receber o valor 0 (nesse caso, o valor de
<object_number> será ignorado) e para um Rowid estendido, 1.
Listagem 3.178
SQL> SELECT DBMS_ROWID.ROWID_CREATE(0,0,1,10,2) Restrito,
2 DBMS_ROWID.ROWID_CREATE(1,5,1,10,2) Extendido
3 FROM DUAL;
RESTRITO EXTENDIDO
------------------ ------------------
0000000A.0002.0001 AAAAAFAABAAAAAKAAC
ROWID_INFO
Esta rotina desmembra o valor de Rowid passado como parâmetro. Como se trata de uma procedure, deve ser
usada apenas em PL/SQL.
As próximas cinco funções retornam um valor independente para cada um dos parâmetros de retorno desta procedure.
ROWID_TYPE
Esta função retornará 0 se o Rowid passado como parâmetro for restrito e 1 se estendido.
ROWID_OBJECT
Esta função retorna o número do objeto. Se o Rowid passado como parâmetro for estendido, o objeto terá um valor
no retorno. Caso o Rowid passado como parâmetro seja restrito, o número do objeto voltará zerado.
ROWID_RELATIVE_FNO
Retorna o número do arquivo em relação ao Tablespace para o Rowid informado como parâmetro.
ROWID_BLOCK_NUMBER
Esta função retorna o número do bloco dentro do arquivo, de acordo com o Rowid passado como parâmetro.
ROWID_ROW_NUMBER
Esta função extrai o número da linha relativamente ao Rowid passado como parâmetro.
Estendido Objeto E Fno E Block E Row E Restrito Objeto R Fno R Block R Row R
--------- -------- ----- ------- --- - -------- ------ - --- - ------- -----
1 221 1 871 0 0 0 1 871 0
Na Listagem 3.180, apresentamos a execução de cada uma das rotinas anteriores, executadas para um Rowid
estendido e para um Rowid restrito.
ROWID_TO_ABSOLUTE_FNO
Esta função obtém o número absoluto do arquivo a partir de um Rowid. Este número é absoluto para uma
determinada linha em um determinado schema e tabela.
ROWID_TO_EXTENDED
Esta função converte um Rowid restrito, que corresponde ao endereço de uma linha em um schema e tabela, para
um Rowid estendido.
Se o schema e o nome do objeto forem fornecidos, essa função converte o Rowid restrito em um Rowid estendido,
usando o data object number da tabela.
Essa função não garante que o Rowid resultante corresponda a uma linha válida na tabela.
Se o schema e o nome do objeto não forem fornecidos (Null), essa função tratará o número de arquivo armazenado
neste Rowid com um número de arquivo absoluto. Isso pode causar problemas se o arquivo tiver sido removido e
seu número tiver sido reutilizado antes da migração. Se a leitura ao bloco endereçado pelo Rowid de entrada
corresponder a uma tabela válida, o data object number desta tabela será usado na conversão para o valor do
Rowid estendido. Esta forma não é recomendada pela Oracle. Sua utilização deve ser restrita à situação de não se
conhecer a que tabela o Rowid faz referência.
Se for fornecido um valor de Rowid estendido (em vez de restrito), o data object number do Rowid fornecido é
verificado contra o data object number calculado a partir do nome da tabela. Se os dois números não forem iguais,
um erro será adquirido (exception Invalid_Rowid). Se combinarem, o Rowid da entrada é retornado.
ROWID_TO_RESTRICTED
Esta função converte um Rowid estendido em um Rowid restrito.
ROWID_VERIFY
Esta função retorna zero se o Rowid restrito informado como parâmetro de entrada puder ser convertido para o
formato estendido (a partir do nome da tabela e schema). Retorna 1 se a conversão não for possível.
O exemplo da Listagem 3.181 obtém um Rowid do banco de dados (estendido), transforma-o em restrito e começa
a verificar para cada uma das tabelas do schema se a conversão é válida. Se for possível, converte considerando a
tabela testada.
No final da Listagem 3.181, vemos o resultado da execução do programa. Observe que para a tabela Func (de onde
foi obtido o Rowid original) o resultado confere.
EXERCÍCIOS
3.75) Faça um programa que ordene as linhas da tabela Func por bloco e linha. Estabeleça uma quebra por bloco.
3.76) Suponhamos que regularmente recebêssemos para atualização o seguinte arquivo de layout:
Informação Coluna
Operação 1-1
Rowid (versão 7) 3-20
Nome 22-33
Sobrenome 35-46
Salário 48-59
3.77) Gere uma massa de dados para atender ao exercício anterior. Obtenha os dados da própria tabela Func. Não
inclua na massa os gerentes de departamento e os responsáveis por projeto.
Na massa devem estar presentes, pelo menos, três alterações e duas exclusões.
LOBS
Large Objects ou Lobs são tipos de dados que podem armazenar informações de até 4 GB de dados binários
(imagens, sons, vídeos, etc.) ou caracteres.
Podem ser subdivididos em duas categorias:
♦ Internos – São aqueles armazenados em tablespaces, dentro do banco de dados (Blob, Clob ou Nclob).
♦ Externos – São armazenados fora do banco de dados (Bfiles). Na coluna com este tipo, existe uma referência ao
arquivo existente no sistema operacional (Bfile).
TIPOS DE LOBS
Os tipos de lobs são os seguintes:
♦ Blob – Contém dados binários.
♦ Clob – Contém dados caracteres compatíveis com o charset do banco de dados (single-byte).
♦ Nclob – Contém dados caracteres compatíveis com o national charset definido para o banco de dados.
♦ Bfile – Contém dados binários armazenados fora do banco de dados em arquivos do sistema operacional.
LOCATOR
Um lob é composto de duas partes:
♦ Dado – O que realmente é armazenado.
♦ Locator – Um indicador da localização do lob armazenado no banco de dados.
Quando inicializamos uma coluna Lob, seu valor pode ser:
♦ Null, indicando que não existe valor nem locator associado.
♦ Empty, indicando que existe um locator, porém o dado está vazio.
♦ Um valor, quando ambas as informações estão preenchidas.
LOB INDEX
O Lob Index é criado implicitamente. É usado para encontrar o dado do lob em seu segmento.
O lob index contém o Rowid (endereço) da tabela que contém a coluna Lob, o offset e o endereço da parte de dados.
Na Listagem 3.182, observamos que podemos determinar um nome para este índice. Isto pode ser interessante
para obtermos informações físicas a respeito do índice gerado e, se necessário, alterá-las.
SOBRE O PACOTE
O pacote DBMS_LOB possui um conjunto de rotinas que visam a facilitar a manipulação de lobs.
Para lobs dos tipos Blob, Clob e Nclob as rotinas deste pacote permitem tanto consultas quanto atualizações. Para
Bfiles poderemos efetuar consultas.
Todas as rotinas do pacote esperam tratar de um locator já existente. Desta forma, a manipulação prevê a criação
e inicialização prévia das colunas deste tipo.
A cláusula %CHARSET, presente em muitos dos parâmetros, indica que a forma dos parâmetros com %CHARSET
deve ser compatível com a forma dos parâmetros ANY_CS correspondente, isto é, se uma função recebe um buffer
e um lob e o lob é do tipo NCLOB, o buffer deve conter dados NCHAR ou se o lob é do tipo CLOB, o buffer deve
conter dados CHAR, e assim por diante.
COMPONENTES DO PACOTE
A tabela a seguir apresenta as rotinas, condições de erro e constantes componentes do pacote Dbms_Lob.
Call Constante Lobs Temporários Indica que o Lob é válido somente durante aquela execução.
File_readonly Constante Bfiles Determina se o arquivo deve ser usado somente para leitura. O valor atual é 0,
indicando que somente leituras são permitidas.
Lobmaxsize Constante Todos Determina o tamanho máximo de um Lob. Atualmente seu valor é 4 GB (4294967295).
Read_Only Constante Todos Indica que o modo de abertura é leitura.
Read_Write Constante Todos Indica que o modo de abertura é gravação.
Session Constante Lobs Temporários Indica que o Lob é mantido até o fim da sessão.
Access_Error Exception Todos Tentativa de leitura ou gravação de um Lob com tamanho superior ao permitido (-22925).
Invalid_argval Exception Todos Indica que o parâmetro informado é inválido, fora do intervalo possível ou Null (-21560).
Invalid_directory Exception Todos Diretório inválido (-22287).
Invalid_operation Exception Todos Falha na execução da operação (-22288).
No_Data_Found Exception Todos Fim de arquivo em uma operação de leitura (-1403).
Noexist_Directory Exception Todos Diretório não existe (-22285).
Nopriv_Directory Exception Todos Privilégios insuficientes para o diretório (-22286).
Open_TooMany Exception Todos Número limite de arquivos abertos atingido (-22290).
Unopened_file Exception Todos A operação não pode ser efetuada em um arquivo que não foi aberto (-22289).
Compare Function Compara o conteúdo de dois Lobs.
Fileexists Function Bfiles Verifica se o arquivo existe no servidor.
Fileisopen Function Bfiles Verifica se o arquivo foi aberto.
GetChunkSize Function Blobs e Clobs Retorna a quantidade de espaço usado em um Lob Chunk para armazenamento do
valor do Lob.
Getlength Function Todos Obtém o comprimento do Lob.
Instr Function Todos Retorna a posição da n-ésima ocorrência do elemento pesquisado dentro do Lob.
IsOpen Function Todos Esta função indica se o Lob já está aberto. Esta rotina é aplicável a Lobs internos e externos.
IsTemporary Function Lobs Temporários Indica se o Lob é temporário.
Substr Function Todos Retorna parte do Lob iniciando na posição especificada.
Append Procedure Blobs, Clobs e NClobs Anexa o conteúdo do Lob de origem ao Lob de destino.
Close Procedure Todos Fecha um Lob (interno ou externo) aberto previamente. Nenhum erro é retornado se o
Bfile existir, mas não estiver aberto. Ocorrerá um erro se o Lob não estiver aberto.
Copy Procedure Blobs, Clobs e Nclobs Copia o Lob de origem para o Lob de destino, total ou parcialmente.
continua
continuação
CreateTemporary Procedure Blobs e Clobs Cria um Blob ou Clob temporário e seu correspondente índice no tablespace temporário
default do usuário.
Erase Procedure Blobs, Clobs e Nclobs Esvazia um Lob, parcialmente ou totalmente.
Fileclose Procedure Bfiles Fecha o arquivo especificado.
Filecloseall Procedure Bfiles Fecha todos os arquivos abertos.
Filegetname Procedure Bfiles Obtém o nome do arquivo.
Fileopen Procedure Bfiles Abre o arquivo especificado no servidor.
FreeTemporary Procedure Lobs Temporários Libera o Lob temporário (Blob ou Clob) do tablespace temporário default do usuário.
Após a execução desta rotina, o locator liberado é marcado como inválido.
Loadfromfile Procedure Blobs, Clobs e Nclobs Carrega o dado de um arquivo Bfile para dentro de um Internal Lob.
Open Procedure Todos Esta rotina abre um Lob (interno ou externo) no modo indicado.
Read Procedure Todos Lê o dado do Lob a partir da posição especificada.
Trim Procedure Blobs, Clobs e Nclobs Comprime o valor do Lob para o tamanho especificado.
Write Procedure Blobs e Clobs Grava uma determinada quantidade de dados em um ponto específico de um Lob interno.
WriteAppend Procedure Blobs e Clobs Grava uma determinada quantidade de dados ao fim de um Lob interno.
As funções do pacote DBMS_LOB retornam Null se quaisquer dos valores dos parâmetros para estas rotinas forem Null ou inválidos. Já as
procedures causam exceptions.
APPEND
Esta procedure tem a finalidade de adicionar o conteúdo de um Lob (<lob_origem>) ao fim de outro Lob (<lob_destino>).
Os parâmetros desta rotina indicam:
♦ <dest_lob> – Locator do Lob de destino.
♦ <src_lob> – Locator do Lob de origem.
No caso de Clob (ou Nclob), o charset da origem e do destino devem ser iguais. Essa rotina poderá causar a
exception Value_Error se os dois Lobs forem Null.
SQL> DECLARE
2 LOB_ORIGEM CLOB;
3 LOB_DESTINO CLOB;
4 BEGIN
5 SELECT C_CLOB1, C_CLOB2 INTO LOB_ORIGEM, LOB_DESTINO
6 FROM TLOB WHERE C_NUMBER = 3 FOR UPDATE;
7 DBMS_LOB.APPEND(LOB_DESTINO, LOB_ORIGEM);
8 COMMIT;
9 END;
10 /
Procedimento PL/SQL concluído com sucesso.
Observe que não foi necessário efetuar um Update na tabela TLOB. Isto ocorre porque, ao lermos um Lob, o que
obtemos é um locator; portanto, o que a rotina faz é copiar o conteúdo do Lob apontado pelo locator origem para
o fim da área apontada pelo locator.
CLOSE
Essa rotina fecha um Lob (interno ou externo) aberto previamente. Nenhum erro é retornado se o Bfile existir mas
não estiver aberto. Ocorrerá um erro se o Lob não estiver aberto.
Onde:
♦ <lob_loc> – Indica o Lob locator.
COMPARE
Esta função tem a finalidade de comparar dois Lobs. Essa comparação poderá ser total ou parcial de acordo com os
parâmetros fornecidos.
A comparação somente será permitida se os dois Lobs forem de mesmo tipo (ambos Blobs ou ambos Clobs, etc.).
Se a comparação for realizada entre Lobs do tipo Bfile, os arquivos deverão ter sido previamente abertos.
Os parâmetros desta função indicam:
♦ <lob_1> – Locator de um Lob para comparação.
♦ <lob_2> – Locator de um Lob para comparação.
♦ <amount> – Quantidade de bytes a ser comparada.
♦ <offset_1> – Posição inicial para comparação no <lob1>.
♦ <offset_2> – Posição inicial para comparação no <lob2>.
Os valores retornados por esta função podem ser:
♦ Zero se os lobs forem iguais.
♦ <> zero se os lobs forem diferentes.
♦ Null, se <amount> menor 1 ou maior que LobMaxSize ou, ainda, se <offset_1> ou <offset_2> menor 1 ou maior
que LobMaxSize.
As seguintes exceptions podem ser causadas pela função:
♦ Unopened_File se o arquivo não estiver aberto.
♦ NoExist_Directory se o diretório não existir.
♦ NoPriv_Directory se o usuário não tiver privilégios sobre o diretório.
♦ Invalid_Directory se o diretório ficar inválido após a abertura do arquivo.
♦ Invalid_Operation se o arquivo não existir ou se o usuário não tiver acesso para o arquivo.
O exemplo a seguir faz a comparação entre arquivos associados a Bfiles da tabela Tlob.
Os arquivos são abertos a tempo de leitura da linha do arquivo. Quando é feita a atribuição à variável local, o
arquivo continua aberto.
Somente ao término do programa os arquivos abertos são fechados. No caso do exemplo, temos oito linhas na
tabela com duas colunas Bfile para cada, no total de 16 arquivos fechados ao término do programa.
O fechamento do arquivo é um ponto de preocupação da programação pois existe um limite máximo de arquivos
abertos, que, se ultrapassado, causa erro no programa.
COPY
Copia parte (ou todo) de um Lob para um Lob de destino. Os Lobs origem e destino devem ser de mesmo tipo
(Blob ou Clob). Esta procedure não está disponível para Bfiles.
CARACTERÍSTICAS
Esta rotina faz a cópia de <lob_src> a partir do ponto <offset-2> para o ponto <offset-1> do <lob_dest>. A quantidade
de bytes copiada é fornecida pelo parâmetro <qtd>.
Se a quantidade de bytes especificada por <amount> for maior que o tamanho de <lob_src>, não haverá erro; será
copiada apenas a quantidade de bytes existente.
A procedure poderá receber uma das seguintes exceptions:
♦ Value_Error se qualquer dos parâmetros for Null.
♦ Invalid_ArgVal se <offset-1> ou <offset-2> forem menores que 1 ou maiores que LobMaxSize ou se <qtd> for
menor que 1 ou maior que LobMaxSize.
COMENTÁRIOS
No caso de Clob, os charsets origem e destino devem ser iguais.
Observe que se <offset-1> for anterior ao final de <lob_destino>, parte de seu conteúdo será recoberto pela cópia.
Caso ocorra o inverso, <offset-1> for posterior ao final de <lob_destino>, a diferença será completada com espaços.
SQL> DECLARE
2 CURSOR C1 IS SELECT C_CLOB1, C_CLOB2
3 FROM TLOB FOR UPDATE;
4 BEGIN
5 FOR R1 IN C1 LOOP
6 DBMS_LOB.COPY (R1.C_CLOB1, R1.C_CLOB2, 10, DESTINO = OFFSET-1, ORIGEM = OFFSET-2);
7 DBMS_LOB.COPY (R1.C_CLOB2, R1.C_CLOB1, 10, DESTINO = OFFSET-1, ORIGEM = OFFSET-2);
8 END LOOP;
9 END;
10 /
Procedimento PL/SQL concluído com sucesso.
CREATETEMPORARY
Essa rotina cria um Blob ou Clob temporário e seu correspondente índice no tablespace temporário default do usuário.
Onde:
♦ <lob_loc> – Indica o Lob locator.
♦ <cache> – Especifica se o Lob deve ou não ser lido para o Buffer Cache.
♦ <amount> – Indica a duração do Lob, ou seja, quando este é liberado. Os valores válidos são: Dbms_Lob.Session
(indica que o Lob é mantido até o fim da sessão), Dbms_Lob.Call (indica que o Lob é válido somente durante
aquela execução). Se esse parâmetro for omitido, a duração será a Sessão.
No exemplo da Listagem 3.186, criamos um Lob de trabalho sem qualquer associação com tabelas do banco de
dados. Adicionamos dados a esse Lob (rotina WriteAppend) e verificamos seu tamanho final.
ERASE
Esta rotina tem a finalidade de esvaziar totalmente ou parcialmente o conteúdo de um Lob (Blob ou Clob).
Os parâmetros desta rotina indicam:
♦ <lob_loc> – Locator do lob a ser esvaziado.
♦ <amount> – Quantidade de bytes a ser esvaziada.
♦ <offset> – Posição inicial para limpeza.
O parâmetro <amount> informa a quantidade de bytes a ser esvaziada (ou limpa) e recebe (como retorno) a
quantidade realmente limpa.
Essa rotina pode gerar as seguintes condições de erro:
♦ Value_Error se algum dos parâmetros de entrada for Null.
♦ Invalid_Argval se <amount> for menor que 1 ou maior que LobMaxSize ou se <offset> for menor que 1 ou maior
que LobMaxSize.
COMENTÁRIO
Quando esvaziamos o início ou o centro de um Lob, o valor presente neste ponto é substituído por brancos.
FILECLOSE
Esta rotina fecha um determinado Bfile aberto previamente.
FILECLOSEALL
Esta rotina fecha todos os Bfiles abertos na sessão.
Pode gerar a exception Unopened_File se nenhum arquivo tiver sido aberto na sessão.
FILEEXISTS
Essa função indica se um determinado locator aponta para um arquivo existente no sistema operacional.
Retorna 1 se o arquivo existir, zero se não existir e Null se <arquivo> (locator) for Null ou se não tivermos os
privilégios de sistema operacional necessários no diretório.
FILEGETNAME
Esta rotina retorna o diretório (objeto diretório do Oracle) e o nome do arquivo associado a um determinado locator.
No exemplo anterior, executamos a rotina e obtivemos o diretório Local, que corresponde a um objeto do banco de dados.
Se desejarmos saber a que diretório de disco esse objeto corresponde, devemos consultar a view do dicionário de
dados Dba_Directories.
FILEISOPEN
Esta função indica se o Bfile foi aberto com o locator passado como parâmetro.
Os valores retornados por esta função são 1 quando o locator já foi aberto anteriormente e zero quando não.
Essa rotina pode gerar as seguintes condições de erro:
♦ NoExist_Directory se o diretório não existir.
♦ NoPriv_Directory se não tivermos privilégio para o diretório.
♦ Invalid_Directory se o diretório tiver sido invalidado após a abertura do arquivo.
♦ Invalid_Operation se o arquivo não existir ou não tivermos acesso de leitura para o arquivo.
FILEOPEN
Esta rotina abre um arquivo Bfile, identificado pelo locator, para leitura. O Oracle não grava os arquivos do sistema
operacional (Bfile). São utilizados apenas para leitura.
O parâmetro <open_mode> indica o modo de abertura do arquivo. Atualmente, apenas leitura é permitida (0).
Essa rotina pode gerar as seguintes condições de erro:
♦ Value_Error se o valor de <arquivo> for Null.
♦ Invalid_Argval se o modo de abertura não for leitura (a constante File_ReadOnly = 0).
♦ Open_TooMany se o número de arquivos abertos na sessão vier a exceder o valor de Session_Max_Open_Files.
♦ NoExist_Directory se o diretório não existir.
♦ Invalid_Directory se o diretório tiver sido invalidado após a abertura do arquivo.
♦ Invalid_Operation se o arquivo não existir ou não tivermos acesso de leitura para o arquivo.
FREETEMPORARY
Essa rotina libera o Lob temporário (Blob ou Clob) do tablespace temporário default do usuário. Após a execução
dessa rotina, o locator liberado é marcado como inválido.
Se um Lob locator (A) inválido for associado a outro Lob locator (B) através de uma atribuição (em PL/SQL), o Lob
receptor (B) também será liberado e marcado como inválido.
Onde:
♦ <lob_loc> – Indica o Lob locator.
GETCHUNKSIZE
Quando fazemos a especificação da tabela, podemos especificar um “Chunking Factor” (quantidade de bytes para
manipulação do Lob), que deve ser um múltiplo de Oracle Block especificado. Esse tamanho é utilizado para
acesso ou modificação do valor do Lob. Parte do Chunk é usada para armazenamento de informações do sistema
e o restante para armazenamento do valor.
Essa função retorna a quantidade de espaço usado em um Lob Chunk para armazenamento do valor do Lob.
Onde:
♦ <lob_loc> – Indica o Lob locator.
GETLENGTH
Esta função retorna o comprimento em bytes (ou caracteres, dependendo do charset) de um determinado Lob.
O retorno da função será Null se o parâmetro de entrada for Null.
Para Bfiles, o retorno da função também será Null em um dos seguintes casos:
♦ O locator é Null.
♦ Não tivermos os privilégios necessários para acesso ao diretório ou relativos ao sistema operacional.
♦ Na ocorrência de um erro de I/O na leitura.
Listagem 3.190 – Obtendo o tamanho de um Lob
SQL> DECLARE
2 CURSOR C1 IS SELECT C_CLOB1, C_BFILE1, C_NUMBER
3 FROM TLOB FOR UPDATE;
4 TAM_LOB NUMBER;
5 TAM_FILE NUMBER;
6 BEGIN
7 FOR R1 IN C1 LOOP
8 TAM_LOB := NVL(DBMS_LOB.GETLENGTH(R1.C_CLOB1), 0);
9 TAM_FILE:= NVL(DBMS_LOB.GETLENGTH(R1.C_BFILE1), 0);
10 DBMS_OUTPUT.PUT_LINE('O tamanho do BLOB é '||TAM_LOB||
11 ', o tamanho do BFILE é '||TAM_FILE);
12 END LOOP;
13 END;
14 /
O tamanho do BLOB é 10, o tamanho do BFILE é 16817
O tamanho do BLOB é 20, o tamanho do BFILE é 16817
O tamanho do BLOB é 31, o tamanho do BFILE é 391
INSTR
Esta função é semelhante à função Instr de PL/SQL. Retorna a n-ésima <nth> de <pattern> dentro de <lob_loc>,
começando na posição <offset>.
No caso de Bfiles, o arquivo já deve ter sido aberto anteriormente.
A função retorna a posição inicial de <pattern> dentro do <lob_loc>. Caso não seja encontrada, será retornado zero.
Será retornado Null se um dos parâmetros for Null ou inválido, se <offset> for menor que 1 ou maior que LobMaxSize
ou se <nth> for menor que 1 ou maior que LobMaxSize.
Esta função, para Bfiles, pode gerar as seguintes condições de erro:
♦ Unopened_File se o arquivo não foi aberto.
♦ NoExist_Directory se o diretório não existir.
♦ NoPriv_Directory se não tivermos privilégio para o diretório.
♦ Invalid_Directory se o diretório tiver sido invalidado após a abertura do arquivo.
♦ Invalid_Operation se o arquivo não existir ou não tivermos acesso de leitura para o arquivo.
MSG
---------------------------------------
ID = 3:
ID = 1: POS -> 9; POS -> 13; POS -> 19;
ID = 2: POS -> 15; POS -> 18;
ISOPEN
Essa função indica se o Lob já está aberto. Essa rotina é aplicável a Lobs internos e externos.
Onde:
♦ <lob_loc> – Indica o Lob locator.
ISTEMPORARY
Indica se o Lob é temporário.
Onde:
♦ <lob_loc> – Indica o Lob locator.
LOADFROMFILE
Esta rotina copia um arquivo endereçado por um locator (Bfile) para um lob interno (Blob ou Clob).
A cópia pode ser parcial ou total, dependendo do valor dos parâmetros (<dest_offset> e <src_offset>) e do número
de bytes a ser copiado (parâmetro <bytes>).
Os parâmetros desta rotina indicam:
♦ <dest_lob> – Locator para gravação das informações lidas do arquivo.
♦ <src_file> – Locator do arquivo de onde serão lidos os dados.
♦ <amount> – Quantidade de bytes a ser copiada.
♦ <src_offset> – Posição inicial do arquivo origem para início da cópia.
♦ <dest_offset> – Posição inicial do <dest_lob> para gravação das informações lidas.
O <src file> deve ter sido previamente aberto para que a operação tenha efeito.
OBSERVAÇÕES
Não é feita nenhuma conversão implícita se carregarmos um arquivo binário para um Clob.
O dados do arquivo Bfile devem possuir o mesmo charset que a coluna Clob do banco de dados. Não é feita
nenhuma verificação quanto a isto.
MSG
----------------------------------------------------------
A alteração é feita diretamente no banco de dados, não havendo necessidade de execução de um comando Update,
porém a utilização de Commit não é dispensada.
OPEN
Essa rotina abre um Lob (interno ou externo) no modo indicado. Os valores válidos para <open_mode> são:
Dbms_Lob.Read_Only e Dbms_Lob.Read_Write.
As seguintes restrições devem ser observadas:
♦ Ocorre um erro se o mesmo Lob for aberto duas vezes.
♦ Bfiles só podem ser abertos no modo de leitura (Read_Only).
♦ Se um Lob tiver sido aberto no modo de leitura (Read_Only) e tentarmos efetuar uma gravação para o Lob,
ocorrerá um erro.
Onde:
♦ <lob_loc> – Indica o Lob locator.
♦ <open_mode> – Indica o modo de abertura do Lob.
Listagem 3.193 – Usando a rotina Open com lob temporário
SQL> DECLARE
2 LOB_DEST CLOB;
3 LOB_ARQ BFILE := BFILENAME('LOCAL', 'MARTA.TXT');
4 TAMARQ INTEGER;
5 TAMLINHA INTEGER;
6 BUFFER VARCHAR2(80);
7 LINHA VARCHAR2(80);
8 POS INTEGER :=1;
9 BEGIN
10 DBMS_LOB.CREATETEMPORARY(LOB_DEST,TRUE, DBMS_LOB.CALL);
11 DBMS_LOB.OPEN(LOB_ARQ, DBMS_LOB.LOB_READONLY);
12 --
13 TAMARQ := DBMS_LOB.GETLENGTH(LOB_ARQ);
14 DBMS_LOB.LOADFROMFILE(LOB_DEST,LOB_ARQ, TAMARQ);
15 LOOP
16 TAMLINHA := 80;
17 DBMS_LOB.READ (LOB_DEST, TAMLINHA, POS, LINHA);
18 TAMLINHA := INSTR(LINHA, CHR(13)||CHR(10));
19 POS := POS + TAMLINHA + 1;
20 LINHA := SUBSTR(LINHA,1, TAMLINHA - 1);
21 DBMS_OUTPUT.PUT_LINE(LINHA);
22 END LOOP;
23 EXCEPTION
24 WHEN NO_DATA_FOUND THEN
25 -- DBMS_LOB.CLOSE(LOB_DEST);
26 -- DBMS_LOB.FREETEMPORARY(LOB_DEST);
27 DBMS_LOB.CLOSE(LOB_ARQ);
28 END;
29 /
Rio, 18/11/2001
Prezado(a) Sr(a). MARTA,
Parabéns por seu aniversário dia 26/05.
Seu presente será uma bonificação de R$ 1.716,82 no
mês subseqüente.
Depto Pessoal.
O programa apresentado na Listagem 3.193 lê um arquivo gravado no ambiente servidor para um Lob temporário
e apresenta seu conteúdo. Observe que a abertura do Lob temporário e seu fechamento são opcionais. Já a abertura
do Bfile e fechamento são obrigatórios.
Uma vez que a criação do Lob temporário foi feita com opção de dbms_lob.call, não houve necessidade de liberarmos
o Lob. Ele não fica valendo após o término do programa (Call).
Neste programa, após a carga de todo o arquivo para o Lob temporário, fomos obtendo trechos de 80 bytes e
cortando estes trechos onde encontrávamos os caracteres de quebra de linha (chr(13) + chr(10)). Desta forma,
reproduzimos o texto do arquivo exatamente da forma como as linhas estão gravadas em seu interior (limitado ao
tamanho de 80 bytes).
READ
Esta rotina obtém uma determinada quantidade de bytes de <lob_loc> a partir da posição <offset> e armazena no
parâmetro de saída <buffer>.
A quantidade de bytes realmente lida é retornada no parâmetro <amount>. Caso o fim do Lob seja atingido antes
do tamanho especificado, o parâmetro <amount> receberá 0 e será causada a exception No_Data_Found.
Observe que o resultado desta rotina será do tipo Raw se <lob_loc> for do tipo Bfile ou Blob e Varchar2 se <lob> for
do tipo Clob.
SUBSTR
Obtém um trecho de um Lob. Similar à função Substr de PL/SQL (porém com os parâmetros relativos à posição
inicial e quantidade de bytes invertidos sintaticamente). O comprimento máximo é de 32.767 bytes.
Esta função retorna Raw se o parâmetro de entrada for um Blob ou um Bfile. Caso seja um Clob, o retorno será Varchar2.
O retorno da função será Null se qualquer dos parâmetros for Null ou se <bytes> for inferior a 1 ou superior a
32.767 ou, ainda, se <inicio> for inferior a 1 ou superior a LobMaxSize.
Para Bfiles, esta função pode gerar as exceptions:
♦ Unopened_File se o arquivo não foi aberto.
♦ NoExist_Directory se o diretório não existir.
♦ NoPriv_Directory se não tivermos privilégio para o diretório.
♦ Invalid_Directory se o diretório tiver sido invalidado após a abertura do arquivo.
♦ Invalid_Operation se o arquivo não existir ou não tivermos acesso de leitura para o arquivo.
TRIM
Esta rotina trunca (ou corta) o Lob para o comprimento especificado no parâmetro.
Se tentarmos truncar um Lob vazio, não ocorre erro; porém se o novo comprimento for maior que o comprimento
atual, ocorrerá uma exception.
As seguintes exceptions podem ser causadas por esta procedure:
♦ Value_Error se o locator for Null.
♦ Invalid_Argval se <amount> menor que zero ou maior que LobMaxSize.
Listagem 3.194 – Truncando o conteúdo de um Lob
SQL> SELECT C_CLOB1 FROM TLOB;
C_CLOB1
-------------------------------
TR SFERÊN
TE O QUALORACLEORAC
NO TESTE DE ATUALIZTESTE DE C
SQL> DECLARE
2 CURSOR C1 IS SELECT C_CLOB1 FROM TLOB FOR UPDATE;
3 TAMANHO NUMBER := '&TAM';
4 BEGIN
5 FOR R1 IN C1 LOOP
6 DBMS_LOB.TRIM(R1.C_CLOB1, LEAST(DBMS_LOB.GETLENGTH(R1.C_CLOB1), TAMANHO));
7 END LOOP;
8 END;
9 /
Entre o valor para tam: 15
Procedimento PL/SQL concluído com sucesso.
WRITE
A procedure Write grava uma determinada quantidade de dados em um Lob a partir da posição <offset> determinada.
Essa procedure substitui qualquer dado já existente na posição determinada até o comprimento informado.
Ocorrerá um erro se <amount> for maior que o tamanho de <buffer>. Se, pelo contrário, <bytes> for menor que o
tamanho de <buffer>, somente o tamanho de <amount> será copiado.
Da mesma forma que na rotina Read, se <lob_loc> for do tipo Blob, <buffer> deve ser do tipo Raw. Caso <lob_loc>
seja do tipo Clob, <buffer> deve ser do tipo Varchar2.
Se especificarmos o parâmetro <offset> posterior ao final do Lob, a diferença será completada com brancos.
WRITEAPPEND
Esta rotina grava uma determinada quantidade de dados ao fim de um Lob interno. Ocorrerá um erro se a quantidade
de dados informada no parâmetro <amount> for maior que o tamanho da informação passada pelo parâmetro
<buffer>. Por outro lado, se a situação for inversa, somente a quantidade de bytes especificada por <amount> será
adicionada ao fim do Lob.
Onde:
♦ <lob_loc> – indica o Lob para o qual será feita a adição.
♦ <amount> – determina o número de bytes (para Blobs) ou caracteres (para Clobs) a serem adicionados.
♦ <buffer> – informação a ser adicionada.
RESTRIÇÕES
O uso de Lob está sujeito a algumas restrições:
♦ Lobs distribuídos não são permitidos. Isto significa que não podemos usar um locator remoto nas cláusulas
Select e Where ou nas rotinas do pacote Dbms_Lob.
♦ Em uma operação de Insert ou Update podemos colocar dados de qualquer tamanho a uma coluna Lob, porém
isto não é possível para um atributo Lob de um tipo objeto. Em um comando Insert…As Select podemos colocar
até 4000 bytes de dado em colunas Lob.
♦ Se uma tabela possui uma coluna Long e colunas Lob, não podemos tratar mais de 4000 bytes para ambas as
colunas no mesmo comando de SQL, porém podemos manuserar, isoladamente, mais de 4000 bytes para cada
uma das colunas.
Lobs não podem ser usados nos seguintes locais:
♦ Não são permitidos em tabelas incluídas em um Cluster.
♦ Não são permitidos em Group By, Order By, Select Distinct, agregações ou Joins. Porém, podemos efetuar a
operação de Union All em tabelas com Lobs. Union, Minus e Select Distinct são permitidos para atributos Lobs
desde que o objeto tenha uma função Map ou Order.
♦ Lobs não são analisados em comandos Analyze.
♦ Nclobs não são permitidos como atributos em tabelas objetos, mas podem ser parâmetros em métodos.
♦ Triggers não são suportados para Lobs, isto é, não podemos associar um trigger a uma coluna Lob. Podemos,
porém, usar um Lob no corpo de um trigger do tipo Before para leitura de valores Old (valores New não podem
ser lidos nem gravados) ou no corpo de um trigger Instead Of ou do tipo After row (valores New e Old podem
ser lidos, mas não gravados).
♦ Lobs não podem ser PKs e nem fazer parte, diretamente, de chave de índice; no entanto podemos construir um
índice baseado em uma função que leia e manuseie Lobs.
♦ Não podemos criar Varrays de Lobs.
♦ Não podemos armazenar Lobs em tablespaces autogerenciáveis.
EXERCÍCIOS
Para desenvolvimento dos exercícios deste tópico crie as tabelas Tlob_E e Func_Lob. Preencha a tabela Func_Lob a
partir das tabelas Func e Depto. Use o script R03_00.SQL.
Id Number(03)
C_Blob Blob
S_Blob Number
C_BFile BFile
S_BFile Number
C_Clob Clob
S_Clob Number
SQL> COMMIT;
Validação completa.
3.78) Faça um bloco de PL/SQL que receba como parâmetro uma matrícula e um texto. Adicione o texto ao fim do
nome do funcionário. Use Dbms_Lob.Write (tabela Func_Lob).
3.79) Faça um bloco de PL/SQL que apresente o nome do funcionário e o nome do departamento em que ele
trabalha. O programa recebe como parâmetro a matrícula do funcionário. Use Dbms_Lob.Read (tabela Func_lob).
3.80) Faça um bloco de PL/SQL que receba como parâmetro uma letra e uma matrícula. Verifique quantas vezes a
letra recebida existe em Nome_Depto. Use Dbms_Lob.Instr (tabela Func_Lob).
3.81) Faça uma rotina que receba como parâmetro um ID e um nome de arquivo (o diretório em uso será Win-
dows). Carregue esse arquivo para a coluna Bfile e para a coluna Blob do ID especificado. Se este ID já existir efetue
uma alteração. Calcule o tamanho dos objetos incluídos ou recalcule para os alterados.
3.82) Faça um programa que receba como parâmetro um texto e um ID e atualize o Clob do ID correspondente.
Não deve ser feita substituição, somente adição é permitida. Recalcule o tamanho do objeto.
3.83) Faça um programa que pesquise um texto em um Clob ou pesquise um trecho binário em um Blob. Determine:
A) A quantidade de elementos encontrados.
B) Para os textos, os dez primeiros bytes após o texto e a posição inicial.
C) Para os binários, a posição encontrada.
3.84) Faça um programa que copie o Clob de uma linha para outra da tabela Tlob_E. Os parâmetros são: ID da
origem, ID do destino e posição inicial da origem.
3.85) Suponhamos que desejássemos salvar os fontes dos programas dentro do banco de dados. Os fontes podem
ser texto ou arquivos binários, com as extensões: Txt, Fmb (binário), Mmb (binário). Faça um programa que receba
como parâmetro o diretório, o nome do arquivo (sem a extensão) e seu tipo (corresponde à extensão do arquivo)
e carregue-o para a coluna Blob ou para a coluna Clob, dependendo do tipo do arquivo.
Utilize as tabelas apresentadas na Listagem-resposta 3.85A.
Listagem-resposta 3.85A
SQL> CREATE TABLE COFRE
2 (FONTE VARCHAR2(200) PRIMARY KEY,
3 FBIN BLOB,
4 FTEXTO CLOB);
Tabela criada.
3.86) Obtenha todos os textos presentes na tabela Tlob, retire os brancos encontrados e concatene em um único
campo. Apresente o tamanho do texto resultante.
INTRODUÇÃO
Este pacote tem a finalidade de gerar números randômicos. Este gerador produz números inteiros de 8 dígitos.
Para que a geração tenha sucesso, devemos, como primeira etapa, inicializar a geração fornecendo um número de
mais de 5 dígitos.
Ao término da etapa de obtenção dos números randômicos devemos encerrar a execução do pacote com o uso da
rotina Terminate.
Initialize Procedure Inicializa o gerador. Deve-se fornecer como parâmetro um número com mais de 5 dígitos.
Seed Procedure Reinicializa o processo de geração.
Random Function Obtém o número randômico.
Terminate Procedure Deve ser executada ao término do processo de geração.
Se você executou o comando Desc Dbms_Random no SQL*PLUS, observará que o pacote possui mais rotinas que estas apresentadas pela Sintaxe
3.31. Porém, como as demais rotinas não estão presentes na documentação desta versão, elas não serão abordadas neste livro.
O primeiro exemplo (Listagem 3.195) aborda os requisitos necessários à geração randômica; utilizamos a rotina de
inicialização e ao término a rotina de encerramento (conforme as regras).
MSG
------------------------------------------------------------------------
NÚMERO INICIAL = 58,000000396
NÚMEROS GERADOS = 2094597532 -737445201 -749618916 -933022339 –494765930
Observe que os números gerados tanto podem ser positivos quanto negativos. Você pode usar a função ABS para já
obter os números somente positivos após a geração, se necessário.
MSG
------------------------------------------------------------------------
NÚMERO INICIAL = 49,00000041
NÚMEROS GERADOS = 136827126 105051806 915477936 764390053 786008727
Neste exemplo usamos a função ABS para que o resultado fosse sempre positivo. Observe também que apesar de
não termos executado a rotina Initialize não encontramos problemas na geração dos números randômicos (talvez
em virtude de estarmos na mesma sessão, já que se trata de um package); no entanto, isto pode não acontecer na
sua versão do software. O primeiro exemplo é mais seguro de uso, em todas as circunstâncias.
EXERCÍCIOS
3.87) Faça uma rotina que, aleatoriamente, escolha 3 funcionários para premiação de Natal da empresa.
3.88) Sabendo-se que uma roleta contém 25 números vermelhos (ímpares) e 25 números pretos (pares). Determine
o número ganhador e se ele é vermelho ou preto.
SOBRE O PACOTE
Este pacote tem a finalidade de habilitar ou desabilitar um ponto específico do tempo para acesso a informações já
modificadas no banco de dados.
Podemos obter informações de uma versão (ou momento) do banco de dados anterior ao momento atual. Quando
habilitamos este pacote, a sessão do usuário utiliza uma versão Flashback do banco de dados
Este pacote pode ser usado para recuperarmos dados removidos (Delete) incorretamente, versão original de dados
que foram modificados, etc.
Para realizarmos estas ações com sucesso, o DBA deve ser informado, para que tenhamos autorização de uso do
pacote e para habilitar a retenção das informações pelo período de tempo de que viermos a necessitar.
Enable_At_Time Procedure Habilita a sessão para o modo de Flashback. O controle do tempo é feito em relação ao SCN mais próximo
da data e hora informados como parâmetro.
Enable_At_System_Change Procedure Habilita a sessão para o modo de Flashback. Passamos como parâmetro, diretamente, o SCN desejado.
Get_System_Change_Number Function Retorna o SCN atual.
Disable Procedure Encerra o modo Flashback para a sessão.
Quando uma transação que modifica o banco de dados é encerrada com sucesso ela recebe um número de controle
chamado SCN (System Change Number). Este número é gravado no arquivo de Log e era usado, até esta versão,
para controle do processo de recuperação.
Na versão 9i, podemos usar o SCN, também, para identificar um ponto dentro do arquivo de Log onde desejamos
estabelecer uma imagem do banco de dados para obtenção de informações do passado. Este pacote se utiliza desta
informação para determinação deste ponto no tempo.
Sessão alterada.
SQL> COMMIT;
Validação completa.
Neste primeiro exemplo obtivemos o timestamp atual antes de realizar os procedimentos de atualização. Na verdade,
no dia-a-dia talvez não tenhamos toda esta precisão em relação ao momento desejado e não temos essa necessidade,
pois o que precisamos informar é algum momento antes do ponto de atualização do banco de dados.
Esta rotina atua por sessão, o que significa que não afeta os trabalhos dos demais usuários. Para que você comprove
esta atuação, abra outra sessão do SQL*Plus e faça a consulta à tabela Func (você verá os dados de salário atualizados).
No exemplo anterior podemos perceber, também, que a partir do momento em que executamos a rotina
Enable_At_Time, todas as consultas às informações se processam como se estivéssemos retornado no tempo (Flash-
back). Estamos estacionados, temporalmente, no dia 19/11 às 8:53 hs. Qualquer modificação feita na base de
dados após este momento não é perceptível pelas consultas que fizermos aos dados.
VL_SAL
----------
7925,7
Este exemplo (Listagem 3.198) foi executado em seqüência ao anterior sem que tivéssemos desabilitado o retorno
ao passado. Observamos que operações de atualização não podem ser realizadas em quanto estivermos no estado
FlashBack (nem DML e nem DDL). O erro, porém, não desabilita o estado Flashback.
No exemplo da Listagem 3.199 tentamos executar a rotina de Flashback novamente sem desabilitar o estado de
Flashback e recebemos um erro.
VL_SAL
----------
11888,55
Neste exemplo verificamos que o encerramento da sessão (com o Connect), automaticamente, desabilita o estado
de Flashback. Um commit encerra apenas a transação e não a sessão.
Este mesmo resultado pode ser obtido sem que tenhamos de sair da sessão, bastando executarmos a rotina Disable
do pacote Dbms_FlashBack (como no exemplo da Listagem 3.201).
Listagem 3.202
SQL> EXECUTE DBMS_FLASHBACK.ENABLE_AT_TIME(TO_TIMESTAMP('13/10/2001 07:20:00,000000'));
BEGIN DBMS_FLASHBACK.ENABLE_AT_TIME(TO_TIMESTAMP('13/10/2001 07:20:00,000000')); END;
*
ERRO na linha 1:
ORA-08180: nenhum snapshot encontrado com base no tempo especificado
ORA-06512: em “SYS.DBMS_FLASHBACK”, line 0
ORA-06512: em line 1
Para que seja possível termos acesso a dados mais antigos, devemos, previamente, informar ao DBA de que
precisaremos utilizar este tipo de informação em nossas aplicações futuramente.
O DBA deverá criar um tablespace de UNDO para que as informações possam ser consultadas. Este tablespace terá
um tamanho tão longo quanto forem as necessidades de regresso. Alguns parâmetros de inicialização do banco de
dados também deverão ser modificados (Undo_Retention = <período de retenção limite>, undo_management=
AUTO, undo_tablespace=<nome do tablespace de Undo, no caso do Personal: Undotbs).
Com o banco preparado para armazenar as modificações dentro dos limites estabelecidos poderemos incluir estas
rotinas em nossas aplicações normais para, por exemplo, comparar dados atuais com dados do passado. Veja o
exemplo da Listagem 3.203.
MSG
-------------------------------------------------------------
MAT = 150 NOME = BRUNO SAL HOJE = 11888,55 SAL ONTEM = 7925,7
Neste exemplo habilitamos o mecanismo de Flashback, abrimos um cursor “no passado”, encerramos o mecanismo
de Flashback e consultamos, normalmente, a base de dados. Com esta opção pudemos obter e comparar dados
antigos e atuais referentes ao mesmo elemento.
No script 3.203a, além de consultar, atualizamos a base atual com os dados do passado. Use-o e faça um teste.
Nosso último exemplo utiliza uma outra forma de determinar o ponto exato do retorno, que é o SCN. Cada
transação no banco de dados recebe um SCN (system change number) que identifica a transação. Se soubermos
este SCN, a precisão de retorno será maior que a especificação de tempo, se isto for uma necessidade.
SQL> COMMIT;
Validação completa.
VL_SAL
----------
11095,98
EXERCÍCIOS
3.89) Faça uma rotina que coloque no SQL*Prompt, a cada vez que o usuário quiser ou quando este abrir o SQL*Plus
o último SCN.
3.90) Faça uma rotina que a partir de um SCN recebido como parâmetro gere um arquivo com as diferenças
encontradas, na tabela de Funcionários, entre a versão na data do SCN e a atual.
INTRODUÇÃO
Muitas vezes necessitamos enviar aplicações de PL/SQL para instalação em ambientes externos ao de nossa instalação.
O código enviado, de um modo geral, fica exposto e passível de modificações indesejáveis.
A rotina Wrapper tem a finalidade de criptografar o código-fonte de tal forma que somente o Oracle tenha condições
de ler e compilar o texto gerado.
CARACTERÍSTICAS
A rotina Wrapper converte o código-fonte de PL/SQL em uma forma intermediária de código-objeto.
O código-objeto gerado é portável como se fosse o próprio fonte. O compilador PL/SQL reconhece e carrega o
código gerado pelo Wrapper automaticamente.
VANTAGENS
Algumas vantagens da utilização do código-objeto gerado:
♦ Impede que o código-fonte seja manuseado por outros desenvolvedores.
♦ Independência da plataforma, já que se trata de uma versão de código portável.
♦ As referências a variáveis Bind externas são resolvidas a tempo de carga.
♦ Os processos de Import / Export normais aceitam arquivos gerados pela rotina Wrapper.
Não deve haver espaço nem antes nem depois dos sinais de igual.
A extensão default para o arquivo de entrada é .SQL e para o arquivo de saída, .PLB.
Caso o arquivo de saída não seja especificado, será gerado com o mesmo nome do arquivo de entrada, com a
diferença apenas da extensão.
RESTRIÇÕES
Como restrição temos que não podemos passar para a rotina Wrapper um bloco anônimo de PL/SQL.
A Listagem 3.205 apresenta o comando a ser passado para a rotina Wrap. Nos parâmetros INAME e ONAME
podemos informar o diretório completo onde se acham os programas. No exemplo isto não foi feito pois a execução
do comando (no DOS) foi feita dentro do diretório onde se achava o fonte a ser convertido.
0
0
59
2
0 9a b4 55 6a a3 a0 1c
81 b0 a3 a0 51 a5 1c 81
b0 :3 a0 6b 6e 51 a5 b d
a0 7e 51 b4 2e a0 7e 51
b4 2e 6e 7e 6e b4 2e 7e
a0 b4 2e a5 57 b7 :4 a0 6b
d :2 a0 7e 51 b4 2e 2b :2 a0
EXERCÍCIOS
3.91) Crie uma stored procedure que faça a atualização dos salários dos funcionários de acordo com os parâmetros:
cargo e percentual.
Se o funcionário for líder de projeto (cd_resp da tabela Proj), deve ser feito um acréscimo de 3% ao percentual
fornecido. Se o funcionário for gerente de departamento (cd_gerente da tabela Depto), deve ser feita uma adição
de 4% ao percentual acumulado.
Após a criação da rotina, consulte a tabela User_Source. Qual o nível de visibilidade do código?
Autorize o uso desta rotina por outro usuário do seu banco, por exemplo, Scott (password Tiger). Estabeleça conexão
como Scott e consulte a tabela All_Source. Qual o nível de visibilidade do código?
Converta o fonte desta rotina usando o aplicativo Wrapper.
Crie novamente a rotina no usuário Desenv.
Refaça os testes de visibilidade local no usuário Desenv e no usuário Scott.
Autorize o uso deste pacote por outro usuário do seu banco, por exemplo, Scott (password Tiger). Estabeleça
conexão como Scott e consulte a tabela All_Source. Qual o nível de visibilidade do código?
Converta o fonte deste pacote usando o aplicativo Wrapper. Crie novamente a rotina no usuário Desenv.
INTRODUÇÃO
Neste tópico, trataremos da utilização de rotinas criadas fora do banco de dados e utilizadas em PL/SQL. Essas
rotinas são chamadas de External Procedures. A abordagem deste assunto neste material será superficial. Focaremos
principalmente o conceito. Para maiores informações, consulte o Capítulo 10 do manual Application Developer’s
Guide – Fundamentals.
Uma External Procedure nada mais é que uma rotina escrita em uma linguagem de terceira geração e armazenada
em uma DLL (Dynamic Link Library) ou libunit no caso de Java e registrada com a PL/SQL.
Isto significa que existirá um mecanismo controlado pela PL/SQL que acionará a rotina externa. As aplicações que
desejarem fazer uso de uma rotina externa acionarão uma rotina especial declarada em PL/SQL, mas que na verdade
servirá de interface para a verdadeira rotina externa. Veremos a seguir como se dará esta interface.
Quando acionarmos esta rotina PL/SQL, a própria PL/SQL acionará a execução da DLL como se fosse uma sub-
rotina interna sua, passando e recebendo não só os parâmetros como também os erros e transferindo o resultado
para o programa que a acionou. Desta forma, para o programa chamador é indiferente (sintaticamente) a utilização
de uma rotina PL/SQL ou externa.
Atualmente, rotinas chamadas de um código C e Java são suportadas.
CRIANDO A INTERFACE
Para a utilização de rotinas externas, duas etapas são necessárias:
♦ Inicialmente o DBA deve criar uma library no banco de dados que identifique a localização da biblioteca de
rotinas (ou seja, da DLL ou classe).
♦ A segunda etapa refere-se à especificação da rotina para que a PL/SQL possa ativá-la; chama-se registrar o
procedimento (rotina PL/SQL de interface).
DEFININDO A BIBLIOTECA
O comando Create Library identifica o arquivo em disco onde se encontram as rotinas (funções e procedures) que
desejamos ativar.
A especificação de <caminho> deve ser completa para que a DLL possa ser efetivamente encontrada.
Na Listagem 3.208, criamos uma Library no banco de dados que faz referência a uma biblioteca (DLL) existente em
disco e uma referência a uma classe (Util) existente em disco.
Esta cláusula identifica a biblioteca onde está a rotina, seu nome, sua linguagem de programação, parâmetros, etc.
Na Sintaxe 3.35, temos as seguintes informações:
♦ Language Java Name ‘<string>’ – Especifica que a linguagem em que a rotina externa está escrita é Java. A
cláusula Name identifica o método dentro da classe. Observe no exemplo que usamos o nome da classe como
qualificador do método, além de incluirmos a especificação dos parâmetros recebidos (como se fosse a “assinatura”
do método, lembra de declaração forward ?). Caso a classe estivesse em um package, deveríamos, também, usar
o nome do package como por exemplo “<packagename>.<classname>.<metod>”. Não se esqueça que os nomes
em Java são case sensitive.
♦ Language C – Especifica que a linguagem em que a rotina externa está escrita é C.
♦ Name <nome> – Especifica o nome da rotina que desejamos que seja acionada. Essa rotina deve existir na library
informada. Se especificarmos este nome entre aspas, ele se torna Case Sensitive, e caso contrário o nome é pesquisado
em maiúsculas. Se esta cláusula for omitida, o Oracle pesquisará o nome do subprograma PL/SQL em letras maiúsculas.
♦ Library <nome> – Especifica o nome da Library (definida no comando Create Library). Quando a library for criada,
deve ser autorizada (Grant Execute) para todos os usuários (users) que vierem a utilizar as rotinas desta DLL.
♦ Agent in (<argumento>) – O nome do processo agent corresponde ao nome do database link, o que permitirá (se
as especificações de tnsnames e listener estiverem adequadas) que a procedure externa seja acionada em outra
máquina. Quando o nome do agente é especificado nesta cláusula, este nome se sobrepõe ao nome do agente
especificado na library. Se nenhum agente for especificado, o default é “extproc”, agente na mesma máquina
que o programa chamado.
♦ With Context – Especifica que um ponteiro de uma área contendo uma série de informações de ambiente será
passado para a rotina externa. O layout desta área não está disponível para a rotina externa; no entanto, poderá
ser utilizada por rotinas de serviço disponibilizadas pela Oracle para a realização de ações especiais (inclusive
acesso ao banco de dados).
♦ Parameters – Especifica a posição e tipo dos parâmetros passados para a rotina externa. Em função das diferenças
entre as linguagens, podemos especificar propriedades dos parâmetros tais como o comprimento atual, o
comprimento máximo e a forma de transferência dos dados (por valor ou por referência).
Neste primeiro exemplo, identificamos uma rotina fictícia chamada “calcula” que está declarada dentro da library
OraSql (na verdade, da DLL Orasql.DLL). Como o nome da rotina está entre aspas, é desta forma que o Oracle
procurará por esta rotina dentro da DLL.
A referência a funções de Java é bem mais simples devido à compatibilidade entre os datatypes de Java e PL/SQL,
a passagem de parâmetros é simplificada e não precisa de maiores explicações na criação da função, como vimos
acima. No exemplo a seguir já podemos utilizar, no SQL*Plus, os métodos presentes na classe Util.
PARÂMETROS
CARACTERÍSTICAS DAS LINGUAGENS
Existem diferenças relativas aos parâmetros entre as linguagens C e PL/SQL:
♦ O conjunto de tipos da PL/SQL não corresponde exatamente aos tipos de uma rotina C. A tabela a seguir mostra
a compatibilidade entre os tipos da PL/SQL e os do C.
♦ Os parâmetros de PL/SQL podem ser Null, uma vez que o banco de dados possui este conceito. Já os parâmetros
de C não podem.
♦ A rotina C pode necessitar do tamanho atual ou máximo dos parâmetros tipo Char, Varchar2, etc., uma vez que
a linguagem C trata uma string como uma array de caracteres (portanto, necessita saber o tamanho).
♦ A rotina C pode necessitar de informações relativas a charset dos parâmetros Char, Varchar2 e Clob.
♦ Quando a rotina C retornar valores para a PL/SQL, podem ser necessárias informações sobre tamanho atual e
máximo do retorno e, ainda, indicação de preenchimento ou não (Null).
Tipos compostos:
A CLÁUSULA PARAMETERS
Cada subprograma PL/SQL que registra uma rotina externa, ou seja, que serve de interface para a chamada da
rotina externa, pode declarar uma lista de parâmetros formais. A declaração destes parâmetros envolve a especificação
de nome, modo e tipo PL/SQL.
Quando especificamos a cláusula Parameters, podemos:
♦ Substituir o tipo de dado default mapeado. A tabela anterior apresenta para cada tipo de dado da PL/SQL a
correspondência default gerada caso nenhuma especificação adicional seja informada.
♦ Definir que seja passado como parâmetro para a rotina externa o comprimento atual e máximo de determinados
parâmetros. Isto pode ser especialmente útil para parâmetros alfanuméricos.
♦ Indicar ausência de valor (Null).
♦ Informar os charsets em uso na sessão.
♦ Definir a ordem de passagem dos parâmetros para a rotina C.
♦ Indicar se desejamos que os parâmetros do tipo IN sejam passados por valor ou por referência.
A cláusula Parameters não é obrigatória, mas é conveniente que façamos sua especificação, tornando explícita a
interface entre os parâmetros.
PROPRIEDADES
A ligação entre os parâmetros formais da PL/SQL e os parâmetros do C é feita através das propriedades presentes na
cláusula Parameters.
Função criada.
No exemplo da Listagem 3.211, criamos uma rotina de interface (registramos) e especificamos explicitamente cada
informação transferida ou retornada entre as partes.
Observe que a correspondência dos parâmetros é feita posicionalmente em relação à cláusula Parameters.
INDICATOR
Um Indicator tem a finalidade de definir se o parâmetro que ele indica é ou não Null. A PL/SQL não necessita de
indicadores, porque o banco de dados possui o conceito de nulidade na linguagem.
Uma rotina externa (escrita em uma linguagem de terceira geração) necessita saber se um determinado parâmetro
ou resultado de função é ou não Null.
No programa C, os indicadores receberão um valor que identificará se o parâmetro associado é ou não Null. Os
valores-padrão informados pela PL/SQL são OCI_IND_NULL e OCI_IND_NOTNULL, ou seja, se um indicador tiver
o valor igual a OCI_IND_NULL o parâmetro associado está ausente (Null).
A Oracle sugere que associemos um indicador para cada parâmetro formal que possa receber Null. Caso esta
atitude não seja tomada, a PL/SQL assumirá que o parâmetro não receberá Null em nenhuma situação.
LENGTH E MAXLEN
Em PL/SQL, não existe forma de indicarmos o comprimento de um parâmetro raw ou string. Porém, eventualmente,
podemos desejar passar o comprimento de um parâmetro para e de uma rotina externa.
As propriedades Length e MaxLen fornecem informações sobre o tamanho atual, que está sendo transferido, e o
comprimento máximo de um parâmetro formal.
Quando houver parâmetros do tipo Char, Long Raw, Raw ou Varchar2 a serem transferidos para um programa C,
é conveniente que utilizemos a propriedade Length uma vez que na linguagem C strings são arrays de 1 caracter
(char * por exemplo), cujo comprimento é definido pela presença de um \0.
CHARSETID E CHARSETFORM
Se estivermos utilizando parâmetros Char, Clob ou Varchar2, pode ser interessante informarmos o charset em que
os valores serão informados. Isto pode ser obtido com as propriedades CharSetId e CharSetForm.
O atributo OCI para estas propriedades é OCI_ATTR_CHARSET_ID e OCI_ATTR_CHARSET_FORM.
SELF
Self corresponde a um argumento sempre presente na passagem de uma função ou procedure membro de um tipo
objeto. Você verá, no Capítulo 4, que um método nada mais é que uma rotina que tem acesso direto ao objeto
correspondente. Formalmente, o que ocorre é a passagem implícita de um parâmetro (SELF) para esta rotina
(método), de tal forma que o objeto possa ser referenciado normalmente em PL/SQL.
Em muitos casos este argumento é implícito e não é apresentado na lista de argumentos da procedure PL/SQL.
Porém, SELF deve ser, explicitamente, especificado como um argumento da cláusula PARAMETERS.
Tabela 3.13 – Tipos de dados Default para troca de parâmetros do PL/SQL com C
Tipos Externos Permitidos Tipo Default Tipos Permitidos Modos Permitidos Modos
Indicator Short, Int, Long Short Todos os escalares in, By Value
in out, By Reference
out, By Reference
return By Reference
Length [Unsigned] Short, Int Char, in, By Value
[Unsigned] Int, Long Raw, in out, By Reference
[Unsigned] Long Raw, out, By Reference
Varchar2 return By Reference
MaxLen [Unsigned] Short, Int Char, In Out, By Reference
[Unsigned] Int, Long Raw, Out, By Reference
[Unsigned] Long Raw, Return By Reference
Varchar2
CharsetId, [Unsigned] Short, [Unsigned] Int Char, in, By Value
CharsetForm [Unsigned] Int, Clob, in out, By Reference
[Unsigned] Long Varchar2 out, By Reference
return By Reference
Função criada.
Observe que após a definição da propriedade especificamos o tipo do parâmetro que passará esta propriedade.
Caso esta ação não seja realizada explicitamente, o Oracle usará os tipos defaults apresentados na tabela acima
para definir as características dos parâmetros de propriedade.
Procedimento criado.
Em vez do default:
Void find_root (float x);
♦ A PL/SQL necessita de informações sobre o tamanho atual, tamanho máximo e status (Null) dos valores retornados
pela rotina externa.
Função criada.
Apesar de o layout desta área de informações não ser disponibilizado pela Oracle, seu conteúdo pode ser obtido e
disponibilizado para as rotinas de serviço que podem ser chamadas pela rotina externa.
Se incluirmos a cláusula Parameters, devemos especificar o parâmetro Context, que indica a posição do ponteiro para
a área de contexto na lista de parâmetro, que pode ser incluída em qualquer posição desejada. Se omitirmos a
cláusula Parameters, o ponteiro para a área de contexto será o primeiro parâmetro passado para a External Procedure.
No caso do exemplo da Listagem 3.217, a rotina C correspondente teria o formato:
Qualquer bloco de PL/SQL, esteja ele na base de dados (em uma stored procedure ou package) ou em um aplicativo
(Forms, por exemplo), poderá acionar a rotina externa.
Procedimento criado.
♦ A PL/SQL avisa ao processo Listener que deverá acionar um processo específico (agente default) chamado ExtProc.
A PL/SQL passa para este processo o nome da DLL, da rotina externa e dos parâmetros.
♦ A ExtProc carrega a DLL e executa a rotina externa. O resultado da execução é retornado para a PL/SQL.
O Listener executa a ExtProc na mesma máquina em que o Oracle Server executa. A execução da ExtProc em outra
máquina já é suportada com a identificação do agente.
Após o término da ExtProc, esta continua ativa até o término da sessão do usuário.
OCIEXTPROCALLOCCALLMEMORY
Esta rotina aloca n bytes de memória durante a execução da rotina externa. Qualquer memória alocada por ela é
liberada logo que o controle retorna ao PL/SQL.
Para alocarmos ou liberarmos memória em uma rotina externa C, a Oracle recomenda que usemos esta rotina.
Os parâmetros representam respectivamente o ponteiro para a área de contexto e a quantidade de bytes a ser alocada.
A função retorna um ponteiro para a área de memória alocada. Se o valor retornado for zero, indica que ocorreu um erro.
OCIEXTPROCRAISEEXCP
Esta rotina de serviço causa uma condição de erro predefinida, a qual deve ter um número (Oracle error number)
válido no intervalo de 1 a 32.767. Nenhum valor é associado aos parâmetros Out ou In Out. Após a execução desta
rotina, a rotina externa deve encerrar imediatamente.
O programa C para esta função é da seguinte forma:
O parâmetro error_number corresponde ao número do erro Oracle. O valor retornado OCIEXTPROC_ SUCCESS e
OCIEXTPROC_ERROR indica sucesso ou falha.
OCIEXTPROCRAISEEXCPWITHMSG
Esta rotina de serviço causa uma condição de erro do usuário e retorna uma mensagem de erro.
O programa C para esta função é da seguinte forma:
Os parâmetros representam, respectivamente, o ponteiro para a área de contexto, o número do erro, a mensagem.
O parâmetro len armazena o comprimento da mensagem. Se a mensagem é null, o comprimento é zero. Os valores
OCIEXTPROC_SUCCESS e OCIEXTPROC_ERROR indicam sucesso ou falha.
EXERCÍCIOS
3.93) Faça um programa que receba como parâmetro uma opção e um número. Se a opção for “Q” retorne o
quadrado do número e se a opção for “D” retorne o dobro do número. Utilize a classe Util.class externa para a
montagem deste exercício.
CONCEITO
Uma variável cursor (como um cursor) aponta para a linha corrente da “tabela” resultante gerada por uma query
que retorne um número indefinido de linhas.
Uma variável cursor, porém, possui uma diferença marcante em relação a um cursor: não está associada a uma
query específica. Pode ser associada a diversas queries ao longo de sua existência (uma de cada vez). Elas podem,
ainda, ser definidas como parâmetros de procedimentos.
VANTAGENS
A principal vantagem é a possibilidade de passar o resultado de uma query entre um PL/SQL armazenado na base
e as várias aplicações-cliente. Nem o PL/SQL nem qualquer das aplicações-cliente duplicam ou recebem a query
resultante. Eles simplesmente compartilham um ponteiro para a área de trabalho resultante da query. Por exemplo,
um cliente OCI, uma aplicação Oracle Forms e o Oracle Server podem fazer referência à mesma área de trabalho.
DEFINIÇÃO
A criação de uma variável cursor é similar à declaração de outros tipos (Index-By Table, Record). Inicialmente,
devemos definir o tipo e posteriormente as variáveis com aquele tipo.
Na Sintaxe 3.36, temos o formato para definição de um tipo cursor. O <tipo retorno> que aparece na sintaxe
representa o layout da área de retorno, podendo ser definido como um record ou uma row em uma tabela do
banco de dados.
Observe que a cláusula Return é opcional, indicando que o tipo pode determinar ou não o layout do retorno.
Na Listagem 3.223, definimos dois tipos e duas variáveis cursor. No primeiro tipo definido, declaramos o layout
esperado para o retorno. No segundo, deixamos sem especificação o layout da área de retorno.
A tempo de Open da variável cursor é que determinamos a query a ser associada à variável.
Observe que para a variável baseada no primeiro tipo, o comando Select associado, obrigatoriamente, deve selecionar
todas as colunas da tabela Func uma vez que o tipo determina que o layout da área de retorno corresponde a uma
row da tabela Func.
Para a variável baseada no segundo tipo, o layout é livre e definido apenas no momento da associação do comando Select.
Na Sintaxe 3.37, vemos os três comandos para manipulação de variáveis do tipo cursor. Para variáveis cursor não
temos o comando Cursor Loop.
Na Listagem 3.224 vemos o exemplo completo do programa iniciado anteriormente. De acordo com o parâmetro
recebido, abrimos uma variável cursor específica e realizamos a leitura da primeira linha obtida.
Veremos a seguir alguns exemplos simples de utilização das variáveis cursor em subprogramas, packages, passagem
de parâmetros.
Inicialmente, definimos tipos em um pacote e em seguida podemos, livremente, utilizá-los dentro de subprogramas
ou em parâmetros.
Pacote criado.
A Listagem 3.225 cria um pacote Global contendo dois tipos: o primeiro, já com layout de retorno definido. O
segundo, totalmente livre.
Em um pacote podemos definir o tipo cursor, não a variável deste tipo. O que criamos na definição de uma variável
cursor é um ponteiro e não um item, não existindo, desta forma, um estado persistente, o que significa que não
pode ser definida em pacotes.
A Listagem 3.226 apresenta a criação de dois procedimentos independentes. O primeiro recebe como parâmetro
uma variável cursor e lê todas as linhas retornadas por ela. O segundo recebe como parâmetro uma variável cursor
e fecha esta variável.
Observe que para que pudéssemos detectar o fim do processo de leitura utilizamos o atributo Notfound com a
variável cursor. Todos os atributos de cursor estão autorizados para utilização com variável cursor.
Na Listagem 3.227 temos a definição de um procedimento que declara uma variável cursor e passa essa variável
para os demais programas.
No exemplo da Listagem 3.229, definimos uma variável REFCURSOR no SQL*Plus. Este tipo do SQL*Plus permite
que declaremos variáveis cursor com o objetivo de retornar os resultados de uma query armazenada em subprogramas
no banco de dados.
No exemplo da Listagem 3.230, declaramos duas variáveis cursor, abrimos uma delas e com o comando de atribuição
apontamos a segunda variável para a mesma área da primeira. Observe também que usamos uma variável de
sistema chamada SYS_REFCURSOR. Ela representa uma declaração do tipo “type sys_refcursor is ref cursor”, sem
definição de retorno. Podemos usá-la para passagem de parâmetro sem necessidade de declarar um tipo cursor.
Quando declaramos uma variável cursor como parâmetro formal de um subprograma que obtém linhas desta variável, devemos especificar o
parâmetro no modo IN (ou IN OUT). Se o subprograma também abrir a variável cursor, devemos especificar o modo IN OUT.
♦ Não podemos usar operadores de comparação para testar variáveis cursor para igualdade ou desigualdade.
SQL> DECLARE
2 V1 SYS_REFCURSOR;
3 V2 GLOBAL.CTYPE_FUNC;
4 AREA FUNC%ROWTYPE;
5 BEGIN
6 OPEN V1 FOR SELECT * FROM FUNC WHERE CD_DEPTO = 'D11';
7 OPEN V2 FOR SELECT * FROM FUNC;
8 IF V1 IS NULL THEN
9 DBMS_OUTPUT.PUT_LINE('V1 NULL');
10 ELSE
11 DBMS_OUTPUT.PUT_LINE('V1 NÃO É NULL');
12 END IF;
13 END;
14 /
V1 NÃO É NULL
Procedimento PL/SQL concluído com sucesso.
EXPRESSÕES CURSOR
Uma expressão CURSOR retorna um cursor embutido. Cada linha no conjunto resultante poderá ser composta de
dois valores esperados das expressões comuns e, ainda, cursores, resultantes das expressões do tipo CURSOR que
apontam para as subqueries envolvidas na query principal.
A PL/SQL suporta queries com expressões CURSOR como parte da declaração de um cursor, e variáveis cursor.
Também podemos usar estas expressões em SQL dinâmico.
A sintaxe CURSOR (<subquery>) indica que será retornado da query “pai” um ponteiro que fará a manipulação da subquery.
O cursor “embutido” é aberto quando a linha contendo o cursor é obtida, na query “pai”. O cursor “embutido” será
fechado somente quando for explicitamente “closed” ou quando o cursor “pai” for reexecutado ou o cursor “pai” for
fechado ou o cursor “pai” for cancelado ou ocorrer um erro durante a operação de fetch de um dos “pais” do cursor.
Neste exemplo incluímos duas expressões do tipo CURSOR, uma para obter o departamento do funcionário e
outra para obter os projetos que este funcionário em questão coordenava. Não houve necessidade de fecharmos as
variáveis cursor porque uma nova linha da tabela FUNC era lida e um novo ponteiro gerado.
10 —
11 TYPE TCURSOR IS REF CURSOR;
12 VDEPTO TCURSOR;
13 VPROJ TCURSOR;
14 MAT FUNC.CD_MAT%TYPE;
15 NOME FUNC.NM_FUNC%TYPE;
16 DEP FUNC.CD_DEPTO%TYPE;
17 NMDEPTO DEPTO.NM_DEPTO%TYPE;
18 NMPROJ PROJ.NM_PROJ%TYPE;
19 BEGIN
20 OPEN C1;
21 LOOP
22 FETCH C1 INTO MAT, NOME, DEP, VPROJ;
23 EXIT WHEN C1%NOTFOUND;
24 DBMS_OUTPUT.PUT_LINE ('MATRICULA = '||MAT||' NOME = '||NOME||' DEPTO = '||DEP);
25 LOOP
26 FETCH VPROJ INTO NMPROJ, VDEPTO;
27 EXIT WHEN VPROJ%NOTFOUND;
28 DBMS_OUTPUT.PUT_LINE ('PROJETOS = '||NMPROJ);
29 LOOP
30 FETCH VDEPTO INTO NMDEPTO;
31 EXIT WHEN VDEPTO%NOTFOUND;
32 DBMS_OUTPUT.PUT_LINE ('DEPARTAMENTO = '||NMDEPTO);
33 END LOOP;
34 END LOOP;
35 END LOOP;
36 END;
37 /
MATRICULA = 60 NOME = IRACY DEPTO = D11
PROJETOS = PROGRAMACAO
DEPARTAMENTO = GERENCIA DE SISTEMAS COMERCIAIS
PROJETOS = LEVANTAMENTO
DEPARTAMENTO = GERENCIA DE SISTEMAS COMERCIAIS
Procedimento PL/SQL concluído com sucesso.
Neste exemplo embutimos uma expressão cursor em outra expressão cursor; observe que, para cada funcionário,
para cada linha de projeto foi obtido o nome do departamento associado ao projeto (no exemplo anterior obtínhamos
o departamento do funcionário).
Observe que a mudança na definição da expressão CURSOR também acompanhou uma modificação na lógica: o
loop de departamento está embutido no loop de projeto.
EXERCÍCIOS
3.94) Faça um programa que receba como parâmetro o tipo de informação a ser apresentada:
A) Nome e sobrenome.
B) Matrícula, cargo e salário.
C) Nome, grau de instrução e data de nascimento.
Use uma única variável cursor e DBMS_OUTPUT para mostrar os resultados.
3.95) Faça três programas, cada um deles deverá receber uma variável cursor e abri-la para as situações apresentadas
no Exercício 3.94.
3.96) Faça um programa que declare uma variável cursor e, de acordo com o parâmetro recebido, acione cada um
dos programas do Exercício 3.95 e mostre as informações selecionadas.
METODOLOGIA
♦ Apresentação teórica dos conceitos relativos a SQL Dinâmico.
TÉCNICA
♦ Apresentação de situações resolvidas com as sintaxes apresentadas.
CONCEITO
De um modo geral, construímos programas em PL/SQL nos quais incluímos comandos de SQL estáticos, isto é,
comandos que são conhecidos e passíveis de ser compilados durante o desenvolvimento do programa.
Eventualmente, temos aplicações que necessitam processar comandos de SQL que só se completam a tempo de
execução. Por exemplo: imagine que um mesmo programa faça acesso a tabelas residentes em servidores diferentes
(todas com o mesmo layout), sendo a indicação do servidor informada como parâmetro da rotina. A tempo de
execução, o programa tomaria a decisão de estabelecer acesso à tabela desejada. Uma forma de resolver esta situação
seria a construção de um comando SQL que somente fosse “parseado” a tempo de execução, de tal forma que o
programa considerasse a existência de apenas uma tabela. Este tipo de construção é chamado de SQL dinâmico.
Para processarmos comandos de SQL, tais como Insert, Update, Delete ou blocos de PL/SQL, usaremos o comando
Execute Immediate.
Para processarmos SQL Select, usaremos os comandos Open-For, Fetch e Close.
Onde:
♦ <string dinâmica> – Representa um comando SQL qualquer, exceto queries que retornem múltiplas linhas (sem
terminação) ou um bloco de PL/SQL (com terminação). Esta string pode conter referências a argumentos Bind.
Não podemos, porém, usar argumentos Bind para substituir nomes de objetos dentro da string.
♦ <variável> – É uma variável que armazena o valor de uma coluna selecionada.
♦ <record> – Corresponde a um Record definido pelo usuário ou um %Rowtype que armazenará uma linha
(row) selecionada.
♦ <bind> – É uma expressão cujo valor é passado dinamicamente para o comando SQL ou bloco de PL/SQL (o hint
NoCopy não é permitido em um EXECUTE IMMEDIATE). Se não for especificado o modo do parâmetro, o default é IN.
SQL dinâmico suporta todos os tipos de dados de SQL (coleções, Lobs, Refs, objetos), mas não suporta tipos específicos de PL/SQL (boleanos e
tabelas Index-By). Desta forma, tanto <variável> quanto <argumento Bind> devem obedecer a esta regra.
CD_MAT DT_ADM
---------- --------
3 18/11/01
No exemplo da Listagem 3.235, usamos a expressão SYSDATE como argumento para a variável Bind :DT incluída
no texto do comando SQL. Todo o comando foi passado, dinamicamente, durante a execução do programa. O
comando foi preenchido na variável TEXTO. Ao tempo de execução, o trecho de comando foi analisado (Parse) e
executado (Execute).
A utilização de variáveis Bind dentro do texto do comando não é obrigatória, poderíamos ter concatenado o valor
na string dentro da lógica do programa principal; no entanto esta forma de uso é mais flexível pois o tipo da
variável é preservado.
CD_MAT NR_GIT
---------- ----------
3 2
Neste segundo exemplo, a execução dinâmica foi de um trecho de PL/SQL. Nos utilizamos da variável local GRAU
como argumento para a variável Bind :G referenciada no comando.
MSG
------------------------------------
AAAH3bAAIAAAAAyAAr
No exemplo da Listagem 3.237, o trecho de programa executado retornou um valor (Rowid). Sendo assim, a
sintaxe usada para os argumentos indicaram que o primeiro referia-se a um argumento de entrada (Sysdate ® :DT)
e o segundo a um argumento de saída (:R ® :MSG).
Observe que utilizamos uma variável do ambiente SQL*Plus (msg) para receber o Rowid. Não foi necessário que
transferíssemos a informação para uma variável local do programa.
Onde:
♦ <variável cursor> – Corresponde a uma variável definida a partir de um tipo (Type) sem retorno (Return) especificado.
♦ <host variável cursor> – É uma variável definida em ambiente Host para o PLSQL (por exemplo OCI).
♦ <string dinâmica> – É uma string que contém um comando Select que retorna diversas linhas.
♦ < Bind> – É uma expressão cujo valor é passado dinamicamente para o comando SQL.
Qualquer argumento Bind na consulta é avaliado somente quando o cursor é aberto. Desta forma, para obtermos dados do cursor usando
diferentes valores de argumento, devemos reabrir a variável cursor com os argumentos Bind contendo os novos valores desejados.
O comando Fetch retorna uma linha referente ao resultado da consulta de múltiplas linhas, associando os valores
presentes na lista de seleção às variáveis correspondentes na cláusula INTO, incrementando o atributo %Rowcount
e avançando o cursor para a próxima linha.
Onde:
♦ <variável cursor> – Corresponde à variável usada no comando Open.
♦ <host variável cursor> – É uma variável definida em ambiente Host para o PLSQL (por exemplo, OCI), usada no
comando Open.
♦ <variável> – É uma variável que armazena o valor de uma coluna selecionada.
♦ <registro> – Corresponde a um Record definido pelo usuário ou um %Rowtype que armazenará uma linha
(row) selecionada.
Para cada valor retornado pela consulta (associado à variável cursor), deve existir uma variável de tipo correspondente compatível com o valor
a ser-lhe atribuído.
O comando Close desabilita a variável cursor. Após esta ação, o conjunto resultado associado a ela fica indefinido.
MSG
-----------------------------------------------------------------------------------
LINHAS OBTIDAS: CRISTINA; MIGUEL; SANDRA; IRACY; ELIANE; VICENTE; SILVIO; ELIZABET;
JAIRO; DAVI; WILIAM; JOANA; JOAQUIM; SALVADOR; DANIEL; SILVIA; WILSON; DILSON; ; ;
No exemplo da Listagem 3.238, usamos um comando Select que recebe uma variável Bind como parâmetro e para
a qual passamos a expressão Sysdate. Para cada linha obtida, efetuamos a concatenação na variável do SQL*Plus
chamada MSG.
9 OPEN C1 FOR 'SELECT '||COL||' FROM '||TAB||' WHERE CD_MAT > :VAL'
10 USING VAL;
11 :MSG := 'LINHAS OBTIDAS: ';
12 LOOP
13 FETCH C1 INTO TEXTO;
14 EXIT WHEN C1%NOTFOUND;
15 :MSG := :MSG || TEXTO || '; ';
16 END LOOP;
17 CLOSE C1;
18 END;
19 /
Entre o valor para coluna: CD_MAT||'' - ''||NM_FUNC
antigo 2: COL VARCHAR2(1000) := '&COLUNA';
novo 2: COL VARCHAR2(1000) := 'CD_MAT||'' - ''||NM_FUNC';
Entre o valor para tabela: FUNC
antigo 3: TAB VARCHAR2(1000) := '&TABELA';
novo 3: TAB VARCHAR2(1000) := 'FUNC';
Entre o valor para val: 300
antigo 4: VAL VARCHAR2(1000) := '&VAL';
novo 4: VAL VARCHAR2(1000) := '300';
Procedimento PL/SQL concluído com sucesso.
MSG
--------------------------------------------------------------------------------
LINHAS OBTIDAS: 310 - MARINA; 320 - ROBERTO; 330 - WILSON; 340 - DILSON; 7369 -
SMITH; 7499 - ALLEN; 7521 - WARD; 7566 - JONES; 7654 - MARTIN; 7698 - BLAKE; 778
2 - CLARK; 7788 - SCOTT; 7839 - KING; 7844 - TURNER; 7845 - ;
Neste exemplo, desejávamos que a coluna a ser obtida e a tabela fossem variáveis também. Este tipo de ação não
pode ser feito através de variáveis Bind; utilizamos, então, a concatenação para transformar o texto. Para o valor de
salário, pudemos usar, normalmente, um parâmetro Bind. Por este motivo, o comando Open-For só contém
referência a um argumento Bind.
A forma sintática apresentada na Listagem 3.241 recebe um erro porque o literal Null não é permitido na cláusula
Using. Uma forma de resolvermos o problema seria a concatenação do texto e retirada da variável Bind.
A variável Valor poderia receber qualquer valor, inclusive o texto ‘NULL’ (como no exemplo).
Outra forma de contornar a situação seria substituir a palavra NULL pelo nome de uma variável não inicializada
(ou inicializada explicitamente com NULL).
Como a variável A_NULL não foi inicializada, seu valor inicial é NULL.
BULK DINÂMICO
Neste tópico faremos uma junção de assuntos já estudados anteriormente isoladamente, isto é, uniremos a operação
de Bulk Bind com SQL dinâmico. Com pequenas variações nos comandos Execute Immediate, Fetch e ForAll, para
a inclusão da cláusula Bulk Collect, estaremos aptos a manusear listas de valores dinamicamente. Cada um dos
exemplos a seguir abordará uma cláusula em separado.
Com este exemplo (Listagem 3.243) verificamos que o retorno de um conjunto de linhas pode ser feito diretamente
com o comando Execute Immediate sem a necessidade de definição de variável cursor.
14 DBMS_OUTPUT.PUT_LINE('ROWID = '||VROWID(I));
15 END LOOP;
16 END;
17 /
Entre o valor para depto: A00
antigo 7: DEP VARCHAR2(3) := '&DEPTO';
novo 7: DEP VARCHAR2(3) := 'A00';
Entre o valor para pct: 0,25
antigo 8: PCT NUMBER := '&PCT';
novo 8: PCT NUMBER := '0,25';
ROWID = AAAH5dAAIAAAAAyAAA
ROWID = AAAH5dAAIAAAAAyAAI
ROWID = AAAH5dAAIAAAAAyAAJ
A sintaxe do Execute Immediate (com returning bulk collect) apresentada na listagem 3.244 somente poderá ser
usada para os comandos Insert, Update e Delete, pois somente estes comandos podem ter saída com variáveis Bind
(por exemplo :R).
Este exemplo é similar àquele estudado na Listagem 3.243. A diferença está na troca do Execute Immediate pelo
Open-For e Fetch. Observe que não houve necessidade de loop para o fetch pois todos os dados do resultado foram
grupados (Bulk Collect) para as duas tabelas.
19 /
Entre o valor para pct: 0,25
antigo 6: PCT NUMBER := '&PCT';
novo 6: PCT NUMBER := '0,25';
ROWID = AAAH5dAAIAAAAAyAAA
ROWID = AAAH5dAAIAAAAAyAAC
ROWID = AAAH5dAAIAAAAAyAAH
ROWID = AAAH5dAAIAAAAAyAAJ
ROWID = AAAH5dAAIAAAAAyAAT
ROWID = AAAH5dAAIAAAAAyAAd
No exemplo acima executamos dinamicamente um comando de atualização que recebia como parâmetro de
entrada uma lista das matrículas a serem atualizadas e um valor constante para todas as linhas. Este comando
retornou em uma coleção todas as linhas atualizadas.
EXERCÍCIOS
3.97) Faça um programa que receba como parâmetro o nome da tabela, as colunas a serem criadas e a indicação de
permanência ou não. Faça a criação do objeto no schema do usuário.
3.98) Faça um programa que receba como parâmetro o nome das colunas a serem lidas da tabela Func (podem ser
informadas até três colunas separadas por vírgula). Apresente os dados lidos.
CONCEITO
Triggers são códigos de PL/SQL armazenados no banco de dados, associados a uma tabela específica e executados
implicitamente pelo Oracle na ocorrência de um determinado evento.
Os triggers podem ser usados para:
♦ Logar modificações.
♦ Garantir críticas complexas.
♦ Gerar o valor de colunas.
♦ Implementar níveis de segurança mais complexos.
♦ Manter tabelas duplicadas.
A Oracle recomenda que limitemos o tamanho do código de PL/SQL do trigger para algo em torno de 60 linhas.
Caso tenhamos necessidade de definir um trigger mais complexo, devemos criar stored procedures com ações
específicas e acionar estas rotinas dentro do trigger.
Na Sintaxe 3.41 é apresentado o formato para criação de um database trigger. Esta sintaxe é subdividida em três partes:
♦ Evento.
♦ Tipo (só aplicável a eventos de DML).
♦ Ação.
Cada uma das partes será analisada separadamente.
EVENTO
O evento corresponde ao momento em que o database trigger deve ser acionado pelo Oracle.
A Sintaxe 3.42 mostra a parte referente ao evento, que pode ser de DML (o mais comum), de DDL ou Database.
Podemos acionar o bloco de PL/SQL associado ao trigger quando o usuário, utilizando qualquer meio de acesso ao
banco de dados, fizer um Update, um Delete ou um Insert na tabela à qual o database trigger está associado.
O bloco pode ser executado antes ou depois de o comando disparado pelo usuário ser executado (Before ou After).
♦ Analyze (o trigger é disparado quando o Oracle colecionar ou deletar estatísticas ou validar a estrutura de um
objeto do dicionário de dados).
♦ Associate Statistics (o trigger é disparado quando houver associação de estatísticas de determinado tipo a um
objeto do dicionário de dados).
♦ Audit (o trigger é disparado quando ocorrer a auditoria sobre um objeto do dicionário de dados).
♦ Comment (o trigger é disparado quando forem adicionados comentários a um objeto do dicionário de dados).
♦ Disassociate Statistics (o trigger é disparado quando houver desassociação de estatísticas de um objeto do
dicionário de dados).
♦ Grant (o trigger é disparado quando um usuário der autorização a outro usuário ou role).
♦ Noaudit (o trigger é disparado quando houver interrupção do processo de auditoria sobre um objeto do
dicionário de dados).
♦ Rename (o trigger é disparado quando um objeto do dicionário de dados mudar de nome).
♦ Revoke (o trigger é disparado quando um usuário revogar autorizações de outro usuário ou role).
♦ Truncate (o trigger é disparado quando uma tabela tiver todos os dados removidos).
Para esses tipos de evento, temos como restrição que quando forem disparados através de rotinas PL/SQL não
podem ser controlados.
O controle também pode ser efetuado para eventos do banco de dados, tais como:
♦ Servererror (é disparado quando é gravada uma mensagem de erro do servidor).
♦ Logon (é disparado quando uma aplicação cliente estabelece conexão com o banco de dados).
♦ Logoff (é disparado quando uma aplicação cliente fecha a conexão com o banco de dados).
♦ Startup (é disparado quando o banco de dados é aberto).
♦ Shutdown (é disparado quando uma instância do Oracle é fechada).
Como estes eventos estão associados ao DBA, ou seja, estão associados a comandos de criação de objetos no
banco de dados, autorização, auditoria, etc., serão vistos muito superficialmente neste material. Daremos ênfase
aos eventos de DML.
Gatilho criado.
No exemplo da Listagem 3.247, o trigger criado será executado quando o usuário fizer um comando de insert, delete
ou, no caso da atualização, update da coluna vl_sal. O usuário poderá realizar esta modificação usando o SQL*Plus,
Forms, Reports ou qualquer outra ferramenta que estabeleça conexão com o banco de dados. Esta característica
garante que a ação definida no trigger será realizada toda vez que o evento ocorrer, independente de quem o acionou.
No nosso caso, o trigger será executado antes de o evento que causou o disparo do trigger ser executado.
Na Listagem 3.248, alteramos a coluna Salário dos funcionários de matrícula 100 e 200. O trigger foi acionado e
apresentou os valores de salário antes e depois da modificação.
View criada.
Gatilho criado.
A Listagem 3.249 mostra um script com a criação da view Vfunc e do trigger Evento1, que será acionado quando
for feita alguma atualização usando a view Vfunc.
A finalidade deste tipo de trigger é permitir que atualizemos a tabela principal quando a view associada a ela não
puder ser atualizada diretamente (por exemplo, possui uma agregação, um produto cartesiano, não apresenta
todas as colunas, etc.). Esse tipo de trigger substitui a ação associada: Instead of Update, significa que o comando
Update disparado pelo usuário não será executado e sim o programa PL/SQL criado por nós no trigger.
Como vemos no exemplo, quando é acionada a atualização através da view, efetuamos a atualização desejada na tabela.
Na Listagem 3.250, as modificações feitas usando a view atualizaram a tabela. Quando esta atualização ocorre o
trigger da tabela é acionado também. Veja os resultados.
TIPO
Um trigger pode ser de dois tipos: Comando ou Linha.
COMANDO
Um trigger de comando é acionado de acordo com o evento, mas associado ao comando como um todo. Ou seja, será
acionado antes ou depois de um determinado comando, independente de o comando atualizar uma ou mais linhas.
Este tipo de trigger não tem acesso às linhas atualizadas.
Sintaticamente, para indicação deste tipo de trigger basta que não especifiquemos a cláusula For Each Row.
Na Listagem 3.251, criamos um trigger do tipo Comando e verificaremos a seguir como ocorrerá seu acionamento.
Na Listagem 3.252, observamos que a mensagem incluída no trigger somente foi executada uma vez, apesar de 32
linhas serem atualizadas.
LINHA
Um trigger do tipo Row é acionado de acordo com o evento, mas uma vez para cada linha afetada pelo comando
disparado pelo usuário. Isto traz algumas conseqüências que analisaremos a seguir.
Sintaticamente, para indicação deste tipo de trigger basta que especifiquemos a cláusula For Each Row. Observe,
porém, que para este tipo de trigger outras partes da sintaxe podem ser especificadas, tais como Referencing e When.
Quando especificamos um trigger deste tipo, automaticamente, o Oracle cria duas áreas de trabalho associadas ao
bloco de PL/SQL. Essas áreas são do tipo Rowtype da tabela a qual o trigger se refere.
4 BEGIN
5 DBMS_OUTPUT.PUT_LINE('MAT = '||:OLD.CD_MAT);
6 DBMS_OUTPUT.PUT_LINE('SAL OLD = '||:OLD.VL_SAL||' SAL NEW = '||:NEW.VL_SAL);
7 END;
8 /
Gatilho criado.
Na Listagem 3.253 no PL/SQL do trigger criado, fazemos referência a duas áreas, OLD e NEW. Se fossem criadas
dentro do código de PL/SQL teriam a seguinte sintaxe: “<nome area> <tabela>%Rowtype;”. Os nomes de área
padrões seriam OLD e NEW. Estas áreas são preenchidas pelo Oracle com a imagem anterior e posterior da linha
(antes e depois da modificação). Caso o evento seja Insert, haverá valor apenas em NEW (OLD estará Null). Caso o
evento seja Delete, haverá valor apenas em OLD (NEW estará Null).
Estas áreas podem ter seus nomes modificados se utilizarmos a cláusula Referencing, mostrada na sintaxe.
Dentro do código do bloco de PL/SQL, estas áreas devem ser referenciadas com dois-pontos na frente (:), indicando
que não se trata de uma área declarada no bloco, e sim uma área do ambiente.
Na Listagem 3.254, ao criarmos o trigger, estabelecemos que faremos referência à área OLD com o qualificador V e
que faremos referência à área NEW com o qualificador N. Internamente no bloco de PL/SQL usamos:V.cd_mat.
Observe no resultado que o trigger de comando também foi acionado ao término das atualizações.
Imaginemos, agora, que desejamos acionar o trigger a cada atualização da coluna VL_SAL da tabela Func, porém
apenas para os funcionários que trabalham do departamento D11.
Esta característica implica a necessidade de incluirmos uma restrição sobre as linhas atualizadas pelo comando. Essa
restrição é feita na cláusula When. Ela não restringe as linhas a serem atualizadas, apenas aquelas que acionarão o trigger.
Na Listagem 3.255, definimos que somente se o departamento da linha original (OLD) fosse D11 o trigger deveria
ser acionado.
Das três linhas modificadas pelo comando Update, apenas a de matrícula 200 acionou o trigger.
AÇÃO
A última parte de um trigger é composta do bloco de PL/SQL associado ao evento e sobre o qual veremos algumas
particularidades.
PREDICADOS CONDICIONAIS
Quando criamos um trigger associado a mais de um comando de DML (Insert, Update ou Delete), muitas vezes
temos necessidade, dentro do código de PL/SQL, de saber qual o evento causador da execução do trigger. Isso é
possível se usarmos os predicados condicionais:
♦ Inserting – Retorna True se o trigger foi disparado por causa de um comando Insert.
♦ Updating – Retorna True se o trigger foi disparado por causa de um comando Update.
♦ Deleting – Retorna True se o trigger foi disparado por causa de um comando Delete.
Listagem 3.256 – Predicados condicionais
SQL> CREATE OR REPLACE TRIGGER TIPO_ROW
2 BEFORE DELETE OR INSERT OR UPDATE OF VL_SAL ON FUNC
3 REFERENCING OLD AS V
4 NEW AS N
5 FOR EACH ROW
6 WHEN (V.CD_DEPTO = 'D11' OR N.CD_DEPTO = 'D11')
7 BEGIN
8 IF UPDATING THEN
9 DBMS_OUTPUT.PUT_LINE('MAT = '||:V.CD_MAT);
10 DBMS_OUTPUT.PUT_LINE('SAL OLD = '||:V.VL_SAL||' SAL NEW = '||:N.VL_SAL);
11 ELSIF INSERTING THEN
12 DBMS_OUTPUT.PUT_LINE('MAT = '||:N.CD_MAT);
13 DBMS_OUTPUT.PUT_LINE('SAL NEW = '||:N.VL_SAL);
14 ELSE
15 DBMS_OUTPUT.PUT_LINE('MAT = '||:V.CD_MAT);
16 DBMS_OUTPUT.PUT_LINE('SAL OLD = '||:V.VL_SAL);
17 END IF;
18 END;
19 /
Gatilho criado.
No trigger criado na Listagem 3.256, de acordo com o evento acontecido a mensagem é diferente.
MAT = 2
SAL OLD = 2000
1 linha deletada.
Na Listagem 3.257 vemos o resultado das diversas atualizações, com este trigger ativo.
RESTRIÇÕES
Dentro da PL/SQL associada ao trigger temos as seguintes restrições:
♦ Não são permitidos comandos de DDL.
♦ Não são permitidos comandos para controle da transação, como por exemplo Rollback, Commit, Savepoint, etc.
♦ Variáveis não podem ser definidas como Long ou Long Raw.
♦ New e Old não podem ser utilizados com colunas Long ou Long Raw.
♦ Podemos executar um Select que retorne uma coluna Long ou Long Raw somente se a coluna puder ser convertida
para um tipo restrito (por exemplo Varchar2).
♦ Quando o Oracle detecta uma situação de conflito entre uma transação com um comando Update (ou Delete)
e outra transação com um comando Update, ele realiza um Rollback implícito de um dos comandos e sinaliza à
transação para que o comando possa ser reexecutado. Quando essa situação ocorre e existe um trigger associado
ao evento Before <comando>, o Oracle reexecuta esse trigger a cada vez que o comando for disparado (mesmo
na rechamada). Todas as ações realizadas por este trigger na primeira execução são desmanchadas, exceto as
modificações que ele fizer a variáveis de um package. Se não desejarmos que essa modificação se repita, devemos
criar uma variável de controle que consiga detectar essa situação.
Para testarmos esta última restrição, criamos um pacote com duas variáveis e um trigger que adiciona 1 ao valor da
variável I (do pacote Global).
Na figura a seguir, abrimos duas sessões do SQL*PLUS e executamos os procedimentos de forma invertida: na sessão
A, executamos Lock1 e Lock2, na sessão B, executamos Lock 2 e Lock 1, a fim de provocarmos a situação de conflito
(DeadLock). Quando o Oracle “derruba” uma das transações envolvidas, repetimos o programa diversas vezes (sem
encerrar a transação) para verificar se o Oracle estava ou não desmanchando o valor da variável do pacote.
Na Figura 3.03, observamos que, apesar de as execuções sucessivas de Lock1 e Lock2 sofrerem erro, o valor da
variável I continua sendo incrementado, confirmando a restrição.
Uma tabela é considerada restrita ou sob restrição se um trigger precisa efetuar uma leitura para esta tabela ou se
houver necessidade de uma restrição de integridade referencial efetuar uma leitura para a tabela.
Uma tabela só é considerada em mudança ou sob restrição em relação à sessão que executa o comando em desenvolvimento.
Um trigger do tipo <comando> não recebe erro indicando que a tabela está em mudança uma vez que o trigger só
será disparado quando o comando acabar ou antes de todo o comando começar; a não ser que seja disparado em
função de uma restrição Delete Cascade.
Já um trigger do tipo <linha> pode receber um erro indicando que a tabela está em mudança uma vez que este
trigger é disparado a cada modificação de uma linha na tabela, no meio da execução de um comando.
Desta forma, existem algumas restrições que se aplicam a todos os triggers do tipo <linha> e para aqueles triggers
do tipo <comando> que venham a ser disparados em função de uma restrição do tipo Delete Cascade:
♦ Os comandos SQL de um trigger não podem ler ou modificar a tabela em mutação associada ao próprio trigger.
♦ Os comandos de um trigger não podem modificar as colunas primary key, foreign key ou unique key de uma
tabela sob restrição associada ao próprio trigger. Como exceção a essa restrição, temos o caso de um único
comando Insert em que a execução de um trigger Before Row ou After Row não é considerado modificando uma
tabela em mudança. Um comando Insert contendo um Select não é considerado um único comando Insert
mesmo que o comando Select retorne apenas uma linha.
Na Listagem 3.260, criamos um trigger que efetua leitura na mesma tabela em que ocorrem as atualizações.
A execução deste trigger recebe o erro “ORA-04091: a tabela DESENV.FUNC é mutante;” indicando que a tabela
está em mudança quando o comando de leitura foi disparado.
Uma forma bastante utilizada como solução de contorno é a criação de uma tabela de trabalho capaz de armazenar
todas as informações necessárias à realização da operação que precisaríamos fazer. No trigger de linha, em vez de
lermos ou modificarmos a tabela mutante, gravamos as informações necessárias nessa tabela, por exemplo, todas
as linhas que o usuário atualizou ou incluiu ou excluiu e, num trigger de comando, disparado após o evento, lemos
os dados dessa tabela e efetuamos a modificação ou leitura desejada.
COMPILANDO TRIGGERS
Antes da versão 7.3 (do banco de dados), um trigger era compilado todas as vezes em que era disparado, como se
fosse um comando de SQL.
A partir da versão 7.3 (do banco de dados), quando executamos o comando Create Trigger, ocorre a compilação
deste e o código produzido por essa compilação (Pcode) é armazenado no dicionário de dados.
Se ocorrerem erros durante a compilação do trigger, este é gravado, porém em situação de erro. Se um comando de
DML causar a execução deste trigger, o comando de DML falhará.
Quando realizamos uma modificação em um objeto do qual o trigger é dependente, por exemplo, uma stored
procedure chamada do corpo do trigger, o estado do trigger mudará para inválido. Quando forem acionados, serão
automaticamente compilados.
ALTER TRIGGER
O comando Alter Trigger permite que explicitamente façamos a compilação do trigger inválido para que a compilação
não ocorra durante o processamento normal.
Lembre-se, porém, que um trigger é diferente de uma constraint. Ao habilitarmos o trigger novamente, nenhuma ação de verificação sobre os
dados da tabela é realizada. Ele passa a ficar ativo a partir do ponto em que foi habilitado, não verificando qualquer incongruência que possa
existir nos dados armazenados (uma constraint só se torna habilitada se todas as linhas da tabela forem compatíveis com a restrição).
A Oracle disponibilizou um conjunto de funções que permitem que obtenhamos informações sobre o usuário que
realizou a ação, qual a ação, qual o objeto, em que owner e diversas outras. A lista completa com as devidas
explicações você encontrará no Capítulo 16 do manual Oracle9i Application Developer’s Guide – Fundamentals.
Neste exemplo, como primeiro passo criamos uma tabela para armazenamento das ocorrências geradas pelo trig-
ger. Observe o uso das funções ORA_DICT_OBJ_TYPE (retorna o tipo do objeto criado, truncado ou renomeado),
ORA_LOGIN_USER (retorna o nome do usuário que causou o disparo do trigger), etc. Com o uso destas rotinas
podemos monitorar determinadas ações específicas sobre o banco de dados.
Uma vez que o trigger será disparado para todo o banco de dados (pois escolhemos o escopo como ON DATABASE),
faremos algumas intervenções usando o usuário Scott.
SQL> RENAME X TO Y;
Tabela renomeada.
No exemplo da Listagem 3.265 efetuamos quatro ações diferentes que causarão a chamada do trigger TDDL quatro vezes.
DATA TEXTO
-------------------------- -----------------------------------------------------
19/11/01 21:20:41,000001 Autor -> SCOTT; Evento-> LOGON;
19/11/01 21:21:37,000001 Autor -> SCOTT; Evento-> CREATE; Owner do Objeto ->
SCOTT; Tipo do Objeto -> TABLE; Nome do Objeto -> X;
19/11/01 21:21:43,000001 Autor -> SCOTT; Evento-> RENAME; Owner do Objeto ->
SCOTT; Tipo do Objeto -> TABLE; Nome do Objeto -> X;
19/11/01 21:21:49,000000 Autor -> SCOTT; Evento-> TRUNCATE; Owner do Objeto ->
SCOTT; Tipo do Objeto -> TABLE; Nome do Objeto -> Y;
No resultado verificamos as informações gravadas na tabela Tlogs (do usuário Desenv) após os eventos.
Na Listagem 3.268 a seguir encontramos o resultado da inclusão de uma linha na tabela Func.
TRANSAÇÕES AUTÔNOMAS
Uma transação autônoma é uma transação independente iniciada por uma outra transação. Pode executar operações
como Commit ou Rollback sem afetar a transação principal. Ela não compartilha recursos, locks nem commits
com a transação que a disparou. É totalmente independente.
Para definirmos uma transação autônoma, devemos usar a pragma Autonomous_Transaction. Essa pragma (pragmas são
diretivas para o compilador, lembra?) indica ao compilador PL/SQL que marque a rotina como autônoma (ou independente).
Aplicável a:
♦ Blocos anônimos de PL/SQL, porém somente aqueles de nível mais externo (Top-Level). Não se aplica a blocos internos.
♦ Funções e procedimentos isolados no banco de dados.
Gatilho criado.
O trigger da Listagem 3.269 foi associado ao comando Insert na tabela Func e, para cada linha incluída, uma linha é
gravada na tabela Tlogs. Observe que o bloco de PL/SQL do trigger contém o comando Commit. Isso não seria
possível em situações normais. Essa característica somente é válida quando usamos a pragma Autonomous_Transaction.
Nosso próximo passo será a inclusão de linhas em Func. Acompanhe o exemplo da Listagem 3.270.
SQL> ROLLBACK;
Rollback completo.
No exemplo da Listagem 3.270, criamos uma linha na tabela Func e, conseqüentemente, a trigger Isolado criou
uma linha da tabela Tlogs. Até aí, nada demais. Quando, porém, fizemos o Rollback, esperaríamos que ambas as
ações fossem desmanchadas. No entanto, a linha incluída na tabela Logs permanece gravada, enquanto a da tabela
Func foi desmanchada.
♦ Uma transação autônoma não depende da transação principal. Por exemplo, se a transação principal efetua um
Rollback, uma transação dependente seria desmanchada também, o que não ocorre com a transação autônoma.
♦ Todas as modificações feitas pela transação autônoma são visíveis por outras transações imediatamente após
essa ter efetuado um Commit. Em uma transação dependente, essa visibilidade só ocorreria quando a transação
principal realizasse um Commit.
♦ Um comando Rollback executado em uma transação autônoma desfaz somente as modificações realizadas por
ela, não afetando a transação principal (que a chamou).
No exemplo da Listagem 3.271, criamos um pacote contendo uma função autônoma.
Observe que a função só foi definida com a pragma Restrict_References usando os parâmetros Wnds (Write no
database state – não atualiza o banco de dados) e Wnps (write no package state – não atualiza variáveis de pacote).
No entanto, o corpo do pacote foi criado sem erros de compilação e existem um comando Insert e um comando
Commit no corpo da função.
Isto ocorre porque uma rotina autônoma sempre tem direito de acesso para leitura e gravação no banco de dados
(elas nunca violam as regras WNDS e RNDS). Observe a execução do pacote na Listagem 3.272.
PACOTE.SÓ(2,'FUNÇÃOSÓ')
------------------------------
INCLUÍDA LINHA COM MATRÍCULA 2
CD_MAT NM_FUNC
---------- ---------
2 FUNÇÃO SÓ
DATA TEXTO
----------------------------------- -------------
19/11/01 22:42:10,000001 1 - NOVO ITEM
19/11/01 22:46:35,000000 2 - FUNÇÃO SÓ
Executamos a rotina em um comando Select (atualizando o banco de dados). A linha de funcionário foi incluída.
Quando listamos a tabela Logs, verificamos que uma linha também foi incluída nesta tabela, proveniente da
trigger Isolado (outra transação autônoma).
ERROS POSSÍVEIS
As observações a seguir indicam as possibilidades de erro quando utilizamos transações autônomas:
♦ Se uma transação autônoma tentar obter um recurso bloqueado (lock) pela transação principal, que não termina
aguardando o retorno da transação autônoma, pode ocorrer um DeadLock.
♦ O banco de dados possui um parâmetro de inicialização chamado Transactions que especifica o número máximo
de transações concorrentes. O número de transações concorrentes poderá ser significativamente incrementado
(você já percebeu isso com os exemplos anteriores) com o uso de transações autônomas, uma vez que estas
executam concorrentemente com a transação principal.
Esta técnica é mais útil para programas que não gastem muito tempo executando comandos de SQL, isto é, favorece
principalmente os programas que realizam muito processamento.
EXERCÍCIOS
3.99) Faça um trigger para controlar as modificações feitas nos salários dos funcionários.
Para tal crie uma tabela de log com o seguinte layout: operação (I, E ou A), valor anterior, valor atual, matrícula,
timestamp (data + hora).
Se for feita uma inclusão, apenas o valor atual deve ser preenchido. Para alteração, ambos os valores devem ser
preenchidos; para exclusão, apenas o valor anterior deve ser preenchido.
3.102) Faça um trigger que, para cada salário incluído, alterado ou excluído em Funcionário, atualize os valores de
salários do departamento da tabela Depto_Acum, cujo layout é:
cd_depto char(03)
vl_média number
vl_max number
vl_min number
vl_total number
INTRODUÇÃO
Neste tópico, trataremos do controle do processamento realizado em batch.
Os programas de PL/SQL são freqüentemente utilizados para realizar processamentos de atualização, carga de
dados, geração de arquivos, enfim, diversos tipos de processamento longos que necessitam de controles precisos
de checkpoint e restart.
Quando estudamos a linguagem SQL, conhecemos os mecanismos disponíveis que permitirão a criação de
alternativas para reinício. Faremos, agora, uma revisão dos mecanismos que poderemos utilizar em PL/SQL.
COMMIT
O comando Commit garante a efetivação de todas as ações realizadas até o momento de sua execução, tornando-
as permanentes no banco de dados.
Até que executemos o comando Commit, as modificações realizadas no programa atual ficam bloqueadas para
atualização por outras sessões. Essas sessões obtêm uma versão do dado com imagem anterior às modificações
realizadas no programa. Quando o programa efetua um Commit e as modificações se tornam permanentes no
banco de dados, simultaneamente, todas as modificações tornam-se visíveis pelas demais sessões.
11 END IF;
12 IF PCARGO IS NOT NULL THEN
13 RC1.NR_CARGO := PCARGO;
14 END IF;
15 UPDATE FUNC
16 SET NR_CARGO = RC1.NR_CARGO,
17 VL_SAL = RC1.VL_SAL
18 WHERE CURRENT OF C1;
19 COMMIT;
20 END LOOP;
21 END IF;
22 END;
23 /
Procedimento criado.
Neste primeiro exemplo, ao término da atualização da linha, o programa efetua um Commit de tal modo que as
modificações realizadas ficam, automaticamente, liberadas e visíveis por outras transações.
Observe, porém, que bloqueamos e atualizamos apenas uma linha. O impacto desta modificação durante um dia de
processamento é insignificante. Imagine, entretanto, o que aconteceria se atualizássemos 500, 1.000 ou mais linhas.
Dois caminhos poderiam ser seguidos com conseqüências diferentes.
COMMIT NO FIM
Poderíamos bloquear todas as linhas a serem modificadas e realizar um Commit apenas no fim de todo o
processamento.
COMMIT FREQÜENTE
Num ambiente com diversos usuários atualizando simultaneamente o banco de dados, devemos tentar manter
disponibilidade nos recursos para que as aplicações não sejam enfileiradas a fim de aguardarem o recurso.
Desta forma, um programa de aplicação que altera o conteúdo de uma ou mais linhas deve, periodicamente, fixar
essas modificações executando um Commit.
Essa alternativa, porém, traz um outro problema. Caso o programa, por alguma razão, seja interrompido (termine
anormalmente), como saber o que já foi processado e o que ainda não o foi? Como estabelecer um ponto de reinício?
ROLLBACK
Ao contrário do Commit, o comando Rollback desfaz as modificações efetuadas pelo programa que ainda não
foram efetivadas no banco de dados. Isso libera todas as linhas bloqueadas para que possam ser atualizadas por
outras sessões.
O exemplo apresentado na Listagem 3.274 mostra um processamento de diversas linhas em uma única transação.
Caso aconteça algum erro no meio do processo, toda a transação é desfeita. Todas as ações de atualização realizadas,
mas não efetivadas, são desmanchadas (pelo comando Rollback).
SAVEPOINT
O comando Savepoint determina um ponto dentro da transação para onde o programa pode retornar. O Rollback, neste
caso, é parcial. Todas as modificações realizadas antes do ponto de Savepoint continuam pendentes aguardando que
haja um Commit que os efetive. Todos os comandos realizados após este ponto são desmanchados e os locks, liberados.
No exemplo da Listagem 3.275, a cada dez linhas é estabelecido um ponto de controle. Quando o contador atinge
dez, marcamos um Savepoint e, quando atinge 20, efetivamos a transação até o momento. Desta forma, a cada 20
atualizações ocorre um término de transação.
Caso ocorra um erro enquanto o contador estiver entre zero e dez, é realizado um Rollback puro. Quando o
contador é maior que dez, ocorre um Rollback para o Savepoint.
Observe que nos dois casos é feita uma nova leitura do banco de dados. O cursor é aberto novamente. Em vez de
iniciar a leitura no primeiro funcionário, a leitura se inicia a partir do ponto de interrupção. Isso é possível pois
armazenamos o valor da matrícula atual em ambos os pontos de controle. Assim, a leitura se inicia a partir do
funcionário imediatamente posterior ao ponto de retorno.
Nesse exemplo, não utilizamos leitura com a cláusula For Update uma vez que, quando ocorresse o primeiro
Commit, todos os locks adquiridos seriam liberados; desta forma, as linhas ainda não obtidas pelo programa não
estariam mais bloqueadas, tornando-se um cursor simples. Preferimos, então, efetuar o tratamento sem bloqueio.
A cada leitura obtemos o Rowid da linha. A tempo de atualização, a busca não precisa ser repetida, uma vez que
informamos, diretamente, o endereço da linha a ser atualizada (Rowid).
Com este tipo de lógica, estabelecemos uma regra de reinício em caso de erro controlado e delimitamos pontos de
efetivação e sincronismo da transação. Se o programa fosse descontinuado, perderíamos o ponto da interrupção,
pois a última matrícula atualizada não está sendo armazenada em disco.
ROLLBACK IMPLÍCITO
Antes de cada comando de atualização processado pelo Oracle é marcado um Savepoint interno, implícito. Caso
ocorra algum erro no comando, o Oracle realiza, automaticamente, um Rollback para esse Savepoint implícito,
desmanchando qualquer ação realizada pelo comando.
Como primeira etapa do programa, faremos a leitura da tabela de Restart para verificarmos se esse programa já
esteve ativo e foi interrompido. Veremos posteriormente que, quando isto acontece, permanece um registro na
tabela de Restart. A leitura é feita apenas pelo nome do programa.
Se for encontrada uma linha na tabela de Restart para este programa, os dados são lidos na área de trabalho (R1).
Caso contrário (C1%Notfound), devemos criar o registro de controle. As informações gravadas são: o código do
programa, o timestamp e a área de Restart. No nosso caso, precisamos saber apenas quantos registros (do arquivo
de entrada) foram efetivamente gravados no banco. Por esse motivo, a coluna chamada Tx_Restart receberá apenas
um valor numérico referente ao último registro gravado no banco de dados. Como estamos gerando o registro de
Restart neste momento, o valor gravado é zero.
Iniciaremos, então, a leitura das linhas do arquivo. A variável Posição recebeu o valor da quantidade de linhas lidas
e já atualizadas. A variável Lidos recebe a cada leitura a linha atualmente lida do arquivo de entrada. A partir do
momento em que a posição do registro lido for maior que a quantidade de registros gravados, podemos reiniciar o
processo de atualização. Se não existirem registros de Restart, o valor inicial das duas variáveis é zero, e, portanto,
quando o primeiro registro for lido, já poderá ser gravado.
As modificações para a tabela PrjAtv são feitas inicialmente para um Rowtype de nome Reg e, posteriormente,
fazemos a inclusão dos dados na tabela. Esse procedimento é repetido diversas vezes até que todas as linhas
tenham sido lidas e atualizadas.
Quando atingimos um múltiplo de 20 registros lidos (de 20 em 20), devemos efetuar um Commit e liberar os
registros bloqueados. Ao efetuarmos o Commit, devemos, simultaneamente, atualizar a tabela de Restart para
refletir o estado atual. Desta forma, fazemos uma atualização na tabela de Restart e efetuamos o Commit. Neste
momento, tanto as linhas da tabela PrjAtv são fixadas no banco como também o é a linha da tabela de Restart,
garantindo o reinício a partir deste ponto se algum problema ocorrer.
Quando efetuamos um Commit, todas as linhas bloqueadas são liberadas, inclusive a linha de controle da tabela
de Restart. Por este motivo, repetimos o lock a cada 20 linhas.
Quando recebemos a condição No_Data_Found, significa que atingimos o fim do arquivo de entrada. Devemos,
então, remover o registro do arquivo de reinício e efetuar as últimas modificações no banco de dados (Commit).
Essa primeira forma de controle é simples, porque o posicionamento em relação a um arquivo de entrada é,
relativamente, fácil. Só há necessidade de armazenamento da posição do registro lido no arquivo de entrada.
Criamos um procedimento que recebe dois parâmetros, início e fim. Nesse intervalo não efetuamos nenhum
Commit. Assim, se ocorrer erro durante o processamento, toda a transação é desfeita.
O uso de intervalo pode ser interessante, pois podemos regular a quantidade de linhas bloqueadas de acordo com
o processamento que estiver ocorrendo simultaneamente. Durante o dia, quando existem diversos usuários online,
os intervalos são menores. À noite, quando apenas os batch estão em uso, os intervalos são maiores.
Na Listagem 3.279, criamos um script para acionamento do programa Intervalo (como exemplo).
O recurso de gerar um arquivo de Spool permite que verifiquemos, ao término da execução do bloco, se ocorreu
algum problema e se linhas deixaram de ser processadas, como uma auditoria.
CONCLUSÕES
Nos exemplos apresentados, oferecemos idéias bastante simples das soluções possíveis de controle de processamento.
Existem dezenas de outras formas mais sofisticadas, seguras e eficientes que garantem o reinício em caso de falha,
sem que seja necessário que todo o processamento seja feito de uma única vez (Commit no final).
Nossa maior preocupação é garantir um ambiente com a maior possibilidade de concorrência e com o mínimo
possível de contenções, permitindo um processamento eficiente.
SET TRANSACTION
No capítulo de SQL, estudamos o mecanismo de consistência do Oracle e sabemos que ele se restringe a um
único comando.
Para que ampliemos essa consistência em nível de diversos comandos, temos o recurso do comando Set Transac-
tion Read Only. Esse comando garante que a consistência seja considerada em relação ao momento da execução
do comando Set Transaction e não de cada comando individualmente.
As regras de utilização desse comando e suas características também foram estudadas no Capítulo 2.
A Sintaxe 3.44 indica que podemos determinar que a transação seja apenas de consulta, garantindo a consistência
conjunta para todos os comandos executados na transação. Podemos estabelecer que a transação seja de atualização
(este é o default). Neste caso, a consistência se dá em nível de comando.
Outra opção desse comando é indicarmos o nome de um Segmento de Rollback para a transação. Essa opção pode
ser usada com a finalidade de direcionarmos uma transação muito longa para um segmento de rollback maior a
fim de garantirmos (por exemplo) que não haverá falta de espaço para Rollback.
Na Listagem 3.280, após os procedimentos de atualização (rotina Intervalo), efetuamos um Commit para encerrar
a transação anterior, e como primeiro comando da nova transação executamos um Set Transaction Read Only. A
partir desse ponto, realizamos apenas comandos de consulta. Para encerrar a transação de consulta, efetuamos
novamente um Commit. Se desejássemos alguma ação de atualização poderíamos realizá-la então, pois o default
da transação é Read Write.
A Listagem 3.281 apresenta um exemplo de direcionamento do segmento de Rollback para execução de uma
determinada transação. Consulte seu DBA para determinar qual o segmento de Rollback mais adequado ao
processamento que deseja efetuar.
Podemos adquirir o erro “ORA-30019: Operação de Segmento de Rollback ilegal no modo Undo Automático”. Isto
ocorre em função das modificações feitas no init.ora para utilização do pacote Dbms_Flashback. Consulte seu DBA
para determinar a melhor forma de resolver a questão.
EXERCÍCIOS
3.104) Faça um programa que leia a tabela de Projetos e Atividades e gere um arquivo em disco com as seguintes informações:
código e nome do projeto, código e nome da atividade, data de início da atividade, data de fim da atividade.
Estabeleça um procedimento que garanta o reinício deste programa.
A inclusão de linhas nesta tabela pode ser feita a qualquer momento durante o dia pelos programas de carga.
Imediatamente após sua inclusão, o status de cada registro é “C”.
Faça um programa que realize a atualização da base de dados baseado nos dados do movimento.
A atualização dos dados na tabela Func deve efetuar uma crítica e gerar uma tabela de erros contendo o Rowid da
linha e a mensagem de erro. Caso o registro contenha erros, o status deve ser alterado para “E”. Caso seja feita a
atualização de Func, mude o status para “A”.
Críticas:
♦ Cargo deve variar de 42 a 60.
♦ Departamento deve existir na tabela Depto.
♦ Data de nascimento deve ser maior que 1950.
♦ Salário deve ser maior ou igual ao dos demais funcionários com o mesmo cargo do mesmo departamento.
O programa deve atualizar um funcionário de cada vez sem bloquear as demais linhas do movimento. Caso a linha
requisitada esteja bloqueada, passe para a próxima linha. O programa somente poderá encerrar se todas as linhas
do movimento (não bloqueadas) estiverem com status diferente de “C”.
COMENTÁRIOS FINAIS
Alguns dos programas de PL/SQL que encontramos neste material apresentam comandos em uma única linha e
outros artifícios para diminuir o tamanho do código gerado, de tal forma que, na maioria das vezes, o programa
ocupasse poucas linhas.
Nesse conjunto de exercícios, passaremos informações para os programas usando variáveis de substituição e o
retorno da informação (programa para SQL*Plus) será feito através de variáveis Bind.
3.01) Observe as declarações a seguir. Indique quais delas não estão corretas e por quê.
Listagem-resposta 3.01A
DECLARE
ID NUMBER(04);
X, Y, Z VARCHAR2(10) := “ABC”;
DATA_HOJE DATE NOT NULL;
END VARCHAR@(10);
IND_ESTOQUE BOOLEAN := 1;
99_MES DATE;
%TOTAL NUMBER := 21V99;
TOTAL_DE_PECAS_VENDIDAS_POR_SEMESTRE NUMBER := 0;
BEGIN
NULL;
END;
/
X, Y e Z estão incorretas, porque não podemos declarar mais de uma variável simultaneamente.
Data_Hoje está incorreta, porque solicitamos que fosse feita a crítica de NOT NULL e não fornecemos valor inicial
para a variável.
End está incorreto, porque é uma palavra reservada e não pode ser nome de variável.
Ind_Estoque está incorreto, porque um boleano só admite valores True, False e Null.
99_Mes está incorreto, porque as variáveis devem começar com uma letra.
%Total está incorreto, porque não começa com letra e porque o valor inicial da variável não é numérico.
3.02) Observe o programa PL/SQL apresentado na Listagem-resposta 3.02A e avalie o escopo das variáveis, como se pede.
Listagem-resposta 3.02A
SQL> DECLARE
2 PESO VARCHAR2(3) := '600';
3 MSG VARCHAR2(255);
4 BEGIN
5 DECLARE
6 PESO NUMBER(3) := 1;
7 MSG VARCHAR2(255);
8 LOCAL VARCHAR2(50) := 'RIO DE JANEIRO';
9 BEGIN
10 PESO := PESO + 1; -- (A)
11 MSG := PESO || ' ESTÁ ACIMA DO PADRÃO'; -- (B)
12 LOCAL:= 'SÃO PAULO '|| LOCAL; -- (C)
13 END;
14 PESO := PESO + 1; -- (D)
15 MSG := PESO || ' ESTÁ ACIMA DO PADRÃO'; -- (E)
16 LOCAL:= 'SÃO PAULO '|| LOCAL; -- (F)
17 END;
18 /
Listagem-resposta 3.03A
SQL> VARIABLE MSG VARCHAR2(200)
SQL> SET AUTOPRINT ON
SQL> DECLARE
2 VALOR NUMBER := TO_NUMBER('&VALOR');
3 BEGIN
4 IF VALOR IS NULL THEN
5 :MSG := 'Valor não informado';
6 ELSIF VALOR > 0 THEN
7 :MSG := 'Valor maior que zero - '||TO_CHAR(VALOR);
8 ELSIF VALOR = 0 THEN
9 :MSG := 'Valor igual a zero';
10 ELSE
11 :MSG := 'Valor menor que zero - '||TO_CHAR(VALOR);
12 END IF;
13 END;
14 /
Entre o valor para valor:
antigo 2: VALOR NUMBER := TO_NUMBER('&VALOR');
novo 2: VALOR NUMBER := TO_NUMBER('');
Procedimento PL/SQL concluído com sucesso.
MSG
-------------------
Valor não informado
3.04) Crie um bloco PL/SQL para incluir linhas na tabela de departamentos. O código e o nome do departamento
devem ser recebidos como parâmetro (usar Accept). A coluna código de gerente não deve receber valor na inclusão.
O código do departamento é de preenchimento obrigatório, mas o nome é opcional. Se não for informado, deve
ser gravado ‘Departamento sem valor’.
Listagem-resposta 3.04A
SQL> ACCEPT CODIGO PROMPT 'Informe o código do Departamento : '
Informe o código do Departamento : F01
SQL> ACCEPT NOME PROMPT 'Informe o nome do Departamento : '
Informe o nome do Departamento :
SQL> DECLARE
2 CODIGO CHAR(03) := '&CODIGO';
3 NOME VARCHAR2(40) := '&NOME';
4 BEGIN
5 IF CODIGO IS NULL THEN
6 :MSG := 'Código do departamento não informado';
7 GOTO FIM;
8 ELSIF NOME IS NULL THEN
9 NOME := 'Departamento sem valor';
10 END IF;
11 INSERT INTO DEPTO (CD_DEPTO, NM_DEPTO)
12 VALUES (CODIGO, NOME);
13 :MSG := 'Inclusão de novo departamento realizada';
14 COMMIT;
15 <<FIM>>
16 NULL;
17 END;
18 /
antigo 2: CODIGO CHAR(03) := '&CODIGO';
novo 2: CODIGO CHAR(03) := 'F01';
antigo 3: NOME VARCHAR2(40) := '&NOME';
novo 3: NOME VARCHAR2(40) := '';
Procedimento PL/SQL concluído com sucesso.
MSG
---------------------------------------
Inclusão de novo departamento realizada
3.05) Crie um bloco PL/SQL que retorne a quantidade de funcionários alocados a um determinado departamento
recebido como parâmetro. O código do departamento é de preenchimento obrigatório. Lembre-se que o usuário
poderá passar a informação em letras maiúsculas ou minúsculas.
Listagem-resposta 3.05A
SQL> DECLARE
2 CODIGO CHAR(03) := UPPER('&Codigo_Departamento');
3 QTD NUMBER := 0;
4 BEGIN
5 SELECT COUNT(*) INTO QTD
6 FROM FUNC
7 WHERE CD_DEPTO = CODIGO;
8 :MSG := 'A quantidade de funcionários no departamento '||CODIGO
9 ||' é '||TO_CHAR(QTD);
10 END;
11 /
Entre o valor para codigo_departamento: d11
antigo 2: CODIGO CHAR(03) := UPPER('&Codigo_Departamento');
novo 2: CODIGO CHAR(03) := UPPER('d11');
MSG
----------------------------------------------------
A quantidade de funcionários no departamento D11 é 9
3.06) Crie um bloco de PL/SQL que cadastre novos departamentos ou consulte dados de departamento, conforme
os parâmetros recebidos:
Parâmetros:
♦ Código do departamento, preenchimento obrigatório.
♦ Operação (I ou C), preenchimento obrigatório.
♦ Nome do departamento, obrigatório na inclusão.
♦ Código do gerente, opcional.
Críticas:
♦ Na inclusão, deve ser verificado se o departamento já existe.
♦ Na consulta, deve ser verificada a existência do departamento.
♦ Se o código do gerente for preenchido na inclusão, deve ser garantido que esta matrícula exista na tabela de funcionários.
Listagem-resposta 3.06A
SQL> DECLARE
2 CODIGO CHAR(03) := UPPER('&COD_DEPTO');
3 OPERACAO CHAR(01) := UPPER('&OPERACAO');
4 NOME VARCHAR2(40) := UPPER('&NOME_DEPTO');
5 GERENTE NUMBER(5) := TO_NUMBER('&COD_GERENTE');
6 QTD NUMBER(1) := 0;
7 BEGIN
8 IF OPERACAO NOT IN ('I', 'C') THEN
9 :MSG := 'Operação inválida';
10 GOTO FIM;
11 END IF;
MSG
--------------------------------------------------------------
Código = C01 Nome do Depto = CENTRO DE INFORMACAO Gerente = 30
3.07) Crie um bloco PL/SQL que calcule a seqüência de Fibonacci (1 1 2 3 5 8 13 21 34 55 ...) para um determinado
número de elementos, recebido como parâmetro e variando de 1 a 30.
Listagem-resposta 3.07A
SQL> DECLARE
2 MAXIMO NUMBER := TO_NUMBER('&MAXIMO');
3 ATUAL NUMBER := 1;
4 ANTERIOR NUMBER := 1;
5 TOTAL NUMBER := 0;
6 CONTADOR NUMBER := 2;
7 BEGIN
8 IF MAXIMO NOT BETWEEN 2 AND 30 OR
9 MAXIMO IS NULL THEN
10 :MSG := 'Valor máximo inválido';
11 GOTO FIM;
12 END IF;
13 :MSG := '1 - 1';
14 <<INICIO>>
15 IF CONTADOR < MAXIMO THEN
16 CONTADOR := CONTADOR + 1;
17 TOTAL := ATUAL + ANTERIOR;
18 :MSG := :MSG || ' - ' || TO_CHAR(TOTAL);
19 ANTERIOR := ATUAL;
20 ATUAL := TOTAL;
21 GOTO INICIO;
22 END IF;
23 <<FIM>>
24 NULL;
25 END;
26 /
Entre o valor para maximo: 8
antigo 2: MAXIMO NUMBER := TO_NUMBER('&MAXIMO');
novo 2: MAXIMO NUMBER := TO_NUMBER('8');
Procedimento PL/SQL concluído com sucesso.
MSG
-------------------------------
1 - 1 - 2 - 3 - 5 - 8 - 13 - 21
3.08) Crie um bloco PL/SQL que receba como parâmetro uma data e calcule o número de dias úteis no mês correspondente.
Listagem-resposta 3.08A
SQL> DECLARE
2 DATA DATE := TO_DATE('&DATA', 'DD/MM/YYYY');
3 DT_INICIO DATE := TRUNC(DATA, 'MM');
4 DT_FIM DATE := LAST_DAY(DATA);
5 QTD NUMBER := 0;
6 BEGIN
7 <<INICIO>>
8 IF TO_CHAR(DT_INICIO, 'D') NOT IN (1, 7) THEN
9 QTD := QTD + 1;
10 END IF;
11 DT_INICIO := DT_INICIO + 1;
12 IF DT_INICIO <= DT_FIM THEN
13 GOTO INICIO;
14 END IF;
15 :MSG := 'A quantidade de dias úteis no mes '||
16 RTRIM(TO_CHAR(DATA, 'MONTH')) ||' é '|| TO_CHAR(QTD);
17 END;
18 /
Entre o valor para data: 10/03/1999
antigo 2: DATA DATE := TO_DATE('&DATA', 'DD/MM/YYYY');
novo 2: DATA DATE := TO_DATE('10/03/1999', 'DD/MM/YYYY');
Procedimento PL/SQL concluído com sucesso.
MSG
--------------------------------------------
A quantidade de dias úteis no mes MARÇO é 23
3.09) Num triângulo ABC tem-se A= 15º, sen B = (√3) /2 e sen C = (√2) / 2. Determine os ângulos B e C montando
um bloco de PL/SQL.
Listagem-resposta 3.09A
SQL> DECLARE
2 ANGB NUMBER;
3 ANGC NUMBER;
4 ANGA NUMBER := 15;
5 SUPL NUMBER;
6 BEGIN
7 ANGB := TRUNC(ASIN((SQRT(3)/2)) * 57.29578);
8 ANGC := TRUNC(ASIN((SQRT(2)/2)) * 57.29578);
9 IF (ANGA + ANGB + ANGC) <> 180 THEN -- A soma dos ângulos de um
10 SUPL := 180 - ANGB; -- triângulo é 180 graus
11 IF (SUPL + ANGA + ANGC) = 180 THEN
12 ANGB := SUPL; -- O seno de um ângulo
13 ELSE -- obtuso é igual ao
14 ANGC := 180 - ANGC; -- seno do seu complemento
15 END IF;
16 END IF;
17 :MSG := 'ANGB = '|| ANGB || ' ANGC = '||ANGC;
18 END;
19 /
Procedimento PL/SQL concluído com sucesso.
MSG
----------------------------------------------------
ANGB = 120 ANGC = 45
3.10) Monte um bloco de PL/SQL que receba um ângulo como parâmetro e forneça o seno, cosseno e tangente do
ângulo. O ângulo será fornecido em graus. Se for informado um valor de ângulo negativo, devemos convertê-lo
em positivo e prosseguir o cálculo.
Listagem-resposta 3.10A
SQL> DECLARE
2 ANG NUMBER := '&ANG';
3 SENA NUMBER;
4 COSA NUMBER;
5 TANA NUMBER;
6 BEGIN
7 IF ANG < 0 THEN
8 ANG := 360 + ANG;
9 END IF;
10 SENA := ROUND(SIN(ANG / 57.29578), 2);
11 COSA := ROUND(COS(ANG / 57.29578), 2);
12 IF ANG NOT IN (90, 270) THEN
13 TANA := TRUNC(TAN(ANG / 57.29578), 1);
14 :MSG := 'SEN = '||SENA||' COS = '||COSA||
15 ' TAN = '||TANA;
16 ELSE
17 :MSG := 'SEN = '||SENA||' COS = '||COSA;
18 END IF;
19 END;
20 /
Entre o valor para ang: 30
antigo 2: ANG NUMBER := '&ANG';
novo 2: ANG NUMBER := '30';
Procedimento PL/SQL concluído com sucesso.
MSG
---------------------------
SEN = ,5 COS = ,87 TAN = ,5
3.11) Crie um bloco de PL/SQL que receba como parâmetro um valor alfanumérico com até três caracteres de
comprimento e transforme-o em numérico (use a seqüência do alfabeto: A = 1, B = 2 e assim por diante).
Listagem-resposta 3.11A
SQL> DECLARE
2 ALFA VARCHAR2(03) := UPPER('&ALFA');
3 BEGIN
4 :MSG := TRANSLATE(ALFA, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
5 '12345678901234567890123456');
6 END;
7 /
Entre o valor para alfa: ad
antigo 2: ALFA VARCHAR2(03) := UPPER('&ALFA');
novo 2: ALFA VARCHAR2(03) := UPPER('ad');
Procedimento PL/SQL concluído com sucesso.
MSG
---------------------------
14
3.12) Crie um bloco de PL/SQL que receba como parâmetro um nome e indique quantas partes o compõem. A
separação entre as palavras do nome é feita com espaços em branco (lembre-se que pode haver vários espaços em
branco antes, depois e entre as palavras).
Listagem-resposta 3.12A
SQL> DECLARE
2 NOME VARCHAR2(200) := LTRIM(RTRIM('&PNOME'));
3 POS NUMBER := INSTR(NOME, ' ');
4 PARTES NUMBER := 1;
5 BEGIN
6 :MSG := 'O NOME ESTÁ VAZIO';
7 IF NOME IS NOT NULL THEN
8 <<INICIO>>
9 IF POS > 0 THEN
10 NOME := LTRIM(SUBSTR(NOME, POS));
11 PARTES := PARTES + 1;
12 POS := INSTR(NOME, ' ');
13 GOTO INICIO;
14 END IF;
15 :MSG := 'O NOME É COMPOSTO DE '||PARTES||' PARTES';
16 END IF;
17 END;
18 /
Entre o valor para pnome: GG LKAGL Q4IOTYQ ADKHJGA; 777
antigo 2: NOME VARCHAR2(200) := LTRIM(RTRIM('&PNOME'));
novo 2: NOME VARCHAR2(200) := LTRIM(RTRIM('GG LKAGL Q4IOTYQ ADKHJGA; 777'))
Procedimento PL/SQL concluído com sucesso.
MSG
-----------------------------
O NOME É COMPOSTO DE 5 PARTES
3.13) Crie um bloco de PL/SQL que receba como parâmetro um número de mês e verifique quantos funcionários
fazem aniversário no mês especificado.
Listagem-resposta 3.13A
SQL> DECLARE
2 MES NUMBER := '&MES';
3 QTD NUMBER := 0;
4 BEGIN
5 IF MES IS NOT NULL THEN
6 SELECT COUNT(*) INTO QTD
7 FROM FUNC
8 WHERE TO_NUMBER(TO_CHAR(DT_NASC, 'MM')) = MES;
9 :MSG := 'O número de aniversariantes no mês '|| mes
10 ||' é '||QTD;
11 END IF;
12 END;
13 /
Entre o valor para mes: 5
antigo 2: MES NUMBER := '&MES';
novo 2: MES NUMBER := '5';
Procedimento PL/SQL concluído com sucesso.
MSG
----------------------------------------
O número de aniversariantes no mês 5 é 8
3.14) Crie um bloco de PL/SQL que inclua novos departamentos na tabela Depto, com as seguintes características:
♦ Receba como parâmetro o código do gerente e o nome do departamento (ambos obrigatórios).
♦ Obtenha o último código do departamento gravado na tabela e adicione 1, gerando um novo código (F01 será
transformado em F02, F26 será transformado em G00 e assim por diante).
♦ O código do departamento contábil não deve ser preenchido.
Listagem-resposta 3.14A
SQL> DECLARE
2 CODIGO NUMBER := '&GERENTE';
3 NOME VARCHAR2(40) := '&NOME_DEPARTAMENTO';
4 COD_DEPTO VARCHAR2(03);
5 NUM_DEPTO NUMBER(02);
6 TXT_DEPTO CHAR(01);
7 BEGIN
8 IF CODIGO IS NULL OR
9 NOME IS NULL THEN
10 :MSG := 'Parâmetros inválidos';
11 ELSE
12 SELECT MAX(UPPER(CD_DEPTO)) INTO COD_DEPTO FROM DEPTO;
13 TXT_DEPTO := SUBSTR(COD_DEPTO,1,1);
14 NUM_DEPTO := SUBSTR(COD_DEPTO,2,2);
15 IF NUM_DEPTO < 25 THEN
16 NUM_DEPTO := NUM_DEPTO + 1;
17 COD_DEPTO := TXT_DEPTO||LTRIM(TO_CHAR(NUM_DEPTO, '00'));
18 ELSE
19 TXT_DEPTO := TRANSLATE(TXT_DEPTO, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
20 'BCDEFGHIJKLMNOPQRSTUVWXYZ1');
21 COD_DEPTO := TXT_DEPTO || '00';
22 END IF;
23 INSERT INTO DEPTO(CD_DEPTO, NM_DEPTO, CD_GERENTE)
3.15) Faça um bloco PL/SQL que receba como parâmetro um código de departamento e calcule o total de salários
dos funcionários. Arredonde o resultado para a ordem de grandeza das centenas.
Listagem-resposta 3.15A
SQL> DECLARE
2 CODIGO VARCHAR2(03) := UPPER('&DEPTO');
3 SAL NUMBER;
4 BEGIN
5 SELECT SUM(VL_SAL) INTO SAL
6 FROM FUNC
7 WHERE CD_DEPTO = CODIGO;
8 SAL := ROUND(SAL, -2);
9 :MSG := 'O total salarial do departamento '||CODIGO||' é '||SAL;
10 END;
11 /
Entre o valor para depto: D11
antigo 2: CODIGO VARCHAR2(03) := UPPER('&DEPTO');
novo 2: CODIGO VARCHAR2(03) := UPPER('D11');
MSG
--------------------------------------------
O total salarial do departamento D11 é 25000
3.16) Faça um bloco PL/SQL que receba como parâmetro uma opção alfanumérica e calcule um dos seguintes valores:
d) o timestamp atual;
e) o nome por extenso da timezone do banco de dados;
f) o mês e o dia em que o exercício está sendo feito.
Listagem-resposta 3.16A
SQL> DECLARE
2 OPCAO VARCHAR2(1) := UPPER('&OPÇÃO');
3 BEGIN
4 CASE OPCAO
5 WHEN 'A' THEN
6 :MSG := CURRENT_TIMESTAMP;
7 WHEN 'B' THEN
8 :MSG := EXTRACT(TIMEZONE_REGION FROM FROM_TZ(LOCALTIMESTAMP, DBTIMEZONE));
9 WHEN 'C' THEN
10 :MSG := EXTRACT(DAY FROM CURRENT_DATE)||'-'||EXTRACT(MONTH FROM CURRENT_DATE);
11 ELSE
12 :MSG := 'Valor inválido';
13 END CASE;
14 END;
15 /
Listagem-resposta 3.17A
SQL> DECLARE
2 OPCAO VARCHAR2(1) := UPPER('&OPÇÃO');
3 BEGIN
4 :msg := CASE OPCAO
5 WHEN 'A' THEN
6 TO_CHAR(CURRENT_TIMESTAMP)
7 WHEN 'B' THEN
8 EXTRACT(TIMEZONE_REGION FROM FROM_TZ(LOCALTIMESTAMP, DBTIMEZONE))
9 WHEN 'C' THEN
10 TO_CHAR(EXTRACT(DAY FROM CURRENT_DATE)||'-'||EXTRACT(MONTH FROM CURRENT_DATE))
11 ELSE
12 'Valor inválido'
13 END;
14 END;
15 /
Observe que tivemos necessidade de incluir a função TO_CHAR para todos os retornos numéricos.
3.18) Leia os n maiores salários da tabela de funcionários e apresente-os em ordem ascendente.
Listagem-resposta 3.18A
SQL> DECLARE
2 QTD NUMBER := NVL(TO_NUMBER('&QTD'), 0);
3 CURSOR C1 IS SELECT VL_SAL FROM FUNC
4 WHERE VL_SAL IS NOT NULL
5 ORDER BY VL_SAL DESC;
6 BEGIN
7 :MSG := '';
8 FOR RC1 IN C1 LOOP
9 IF QTD > 0 THEN
10 QTD := QTD - 1;
11 ELSE
12 EXIT;
13 END IF;
14 :MSG := RC1.VL_SAL||' '||:MSG;
15 END LOOP;
16 :MSG := 'Os maiores salários são: '|| :MSG;
17 END;
18 /
3.19) Crie uma tabela com o comando apresentado abaixo para receber os n maiores salários da tabela de
funcionários. O parâmetro n deve ser recebido através de Accept. Na coluna total deve ser armazenado o somatório
de todos os salários lidos.
Listagem-resposta 3.19A
SQL> CREATE TABLE TABTOTAL
2 (NOME VARCHAR2(25),
3 SALARIO NUMBER(8),
4 TOTAL NUMBER(11)
5 );
Tabela criada.
Inclua todos os dados e posteriormente atualize a coluna total com o valor obtido na soma.
Listagem-resposta 3.19B
SQL> DECLARE
2 QTD NUMBER := NVL(TO_NUMBER('&QTD'),0);
3 VTOTAL NUMBER := 0;
4 CURSOR C1 IS SELECT NM_FUNC, VL_SAL FROM FUNC
5 WHERE VL_SAL IS NOT NULL
6 ORDER BY 2 DESC;
7 BEGIN
8 DELETE FROM TABTOTAL;
9 FOR RC1 IN C1 LOOP
10 EXIT WHEN C1%ROWCOUNT > QTD;
11 VTOTAL := VTOTAL + RC1.VL_SAL;
12 INSERT INTO TABTOTAL
13 VALUES (RC1.NM_FUNC, RC1.VL_SAL, NULL);
14 END LOOP;
15 UPDATE TABTOTAL
16 SET TOTAL = VTOTAL;
17 COMMIT;
18 END;
19 /
Entre o valor para qtd: 8
3.20) Faça um programa PL/SQL que receba um código de departamento como parâmetro e apresente o nome do
gerente do departamento e todos os funcionários (matrícula e nome) alocados àquele departamento.
Listagem-resposta 3.20A
SQL> DECLARE
2 CD_DEPTO CHAR(03) := '&DEPTO';
3 CURSOR C1 (VCD_DEPTO IN CHAR) IS
4 SELECT CD_DEPTO, CD_GERENTE FROM DEPTO
5 WHERE CD_DEPTO = VCD_DEPTO;
6 CURSOR C2 (VCD_DEPTO IN CHAR, VCD_MAT IN NUMBER) IS
7 SELECT CD_MAT, NM_FUNC,
8 DECODE(CD_MAT, VCD_MAT, 'GERENTE', 'FUNCIONARIO') CARGO
9 FROM FUNC
10 WHERE CD_MAT = VCD_MAT
11 OR CD_DEPTO = VCD_DEPTO;
12 BEGIN
13 :MSG := 'Departamento inválido';
14 FOR RC1 IN C1(CD_DEPTO) LOOP
15 :MSG := '';
16 FOR RC2 IN C2(RC1.CD_DEPTO, RC1.CD_GERENTE) LOOP
17 :MSG := LTRIM(RTRIM(:MSG))||' MAT = '||RC2.CD_MAT||
18 ' NOME = '||RC2.NM_FUNC||' CARGO = '||RC2.CARGO||';';
19 END LOOP;
20 END LOOP;
21 END;
22 /
Entre o valor para depto: A00
antigo 2: CD_DEPTO CHAR(03) := '&DEPTO';
novo 2: CD_DEPTO CHAR(03) := 'A00';
MSG
--------------------------------------------------------------------------------
MAT = 10 NOME = CRISTINA CARGO = FUNCIONARIO; MAT = 110 NOME = VICENTE CARGO = F
UNCIONARIO; MAT = 120 NOME = SILVIO CARGO = FUNCIONARIO; MAT = 200 NOME = DAVI C
ARGO = GERENTE;
3.21) Crie um bloco de PL/SQL que faça o enquadramento dos funcionários de acordo com os seguintes critérios:
♦ O piso salarial será de 1.000,00 para os cargos inferiores a 51. Para os demais, o piso salarial será de 1.500,00.
♦ Para cada nível de cargo superior a 55, deverá ser acrescido 250 ao salário.
♦ Para cada nível de instrução superior a 15, deverá ser acrescido 30 ao salário.
O salário do funcionário não poderá ser diminuído. Se o funcionário já receber acima do valor calculado, deve-se
manter o salário anterior.
Deve-se apresentar, simultaneamente, todos os enquadrados (com o velho e novo salário) e aqueles não enquadrados
(com o salário antigo).
Listagem-resposta 3.21A
SQL> VARIABLE MSG VARCHAR2(2000)
SQL> DECLARE
2 SAL NUMBER;
3 CURSOR C1 IS SELECT CD_MAT, VL_SAL, NR_GIT, NR_CARGO
4 FROM FUNC
5 WHERE VL_SAL IS NOT NULL
6 FOR UPDATE OF VL_SAL;
7 BEGIN
8 :MSG := '';
9 FOR RC1 IN C1 LOOP
MSG
--------------------------------------------------------------------------------
MAT = 10 SALARIO= 5802,5; MAT = 20 SALARIO= 4537,5; MAT = 30 SALARIO= 4207,5; MA
T = 50 SALARIO= 4419,25; MAT = 60 SALARIO= 3547,5; MAT = 70 SALARIO= 3978,7; MAT
= 90 SALARIO= 3272,5; MAT = 100 SALARIO= 2876,5; MAT = 110 SALARIO= 5115; MAT =
120 SALARIO= 3217,5; MAT = 130 SALARIO= 2618; MAT = 140 SALARIO= 3126,2; MAT =
150 SALARIO= 2780,8; MAT = 160 SALARIO= 2447,5; MAT = 170 SALARIO= 2714,8; MAT =
180 SALARIO= 2347,4; MAT = 190 SALARIO= 2249,5; MAT = 200 SALARIO= 3661,68; MAT
= 210 SALARIO= 2009,7; MAT = 220 SALARIO= 3282,4; MAT = 230 SALARIO= 2439,8; MA
T = 240 SALARIO= 3163,6; MAT = 250 SALARIO= 2109,8; MAT = 260 SALARIO= 1897,5; M
AT = 270 SALARIO= 3011,8; MAT = 280 SALARIO= 2887,5; MAT = 290 SALARIO= 1687,4;
MAT = 300 SALARIO= 1952,5; MAT = 310 SALARIO= 1749; MAT = 320 SALARIO= 2194,5; M
AT = 330 SALARIO= 2790,7; MAT = 340 SALARIO= 2622,4;
3.22) Crie uma tabela com o comando apresentado abaixo para receber a quantidade de funcionários por
departamento. O código do departamento deverá ser convertido (de alfanumérico para numérico).
Utilize Loop e Exit When. Use a função AscII para a conversão do código.
Listagem-resposta 3.22A
SQL> CREATE TABLE RESULTADO
2 (CD_DEPTO NUMBER,
3 QT_FUNC NUMBER,
4 VL_SAL NUMBER,
5 AV_SAL NUMBER);
Tabela criada.
Listagem-resposta 3.22B
SQL> DECLARE
2 CODIGO NUMBER;
3 CURSOR C1 IS SELECT CD_DEPTO, COUNT(*) QTD
4 FROM FUNC
5 WHERE CD_DEPTO IS NOT NULL
6 GROUP BY CD_DEPTO;
7 RC1 C1%ROWTYPE;
8 BEGIN
9 OPEN C1;
10 LOOP
11 FETCH C1 INTO RC1;
12 EXIT WHEN C1%NOTFOUND;
13 CODIGO := (ASCII(SUBSTR(UPPER(RC1.CD_DEPTO),1,1)) - 64) * 100;
3.23) Utilizando a mesma tabela já parcialmente preenchida do exercício anterior, complete-a com o total de
salários e a média salarial.
Utilize Cursor Loop. Inicie a leitura pela tabela resultado e trabalhe com Update Where Current.
Listagem-resposta 3.23A
SQL> DECLARE
2 CURSOR C1 IS SELECT * FROM RESULTADO
3 FOR UPDATE OF VL_SAL, AV_SAL;
4 VCD_DEPTO VARCHAR2(5);
5 VSUM NUMBER;
6 VAVG NUMBER;
7 LETRA NUMBER;
8 BEGIN
9 :MSG := '';
10 FOR RC1 IN C1 LOOP
11 VCD_DEPTO := LTRIM(TO_CHAR(RC1.CD_DEPTO));
12 LETRA := TO_NUMBER(SUBSTR(VCD_DEPTO,1,LENGTH(VCD_DEPTO)-2));
13 VCD_DEPTO := CHR(LETRA+64)||SUBSTR(VCD_DEPTO,LENGTH(VCD_DEPTO) -1);
14 SELECT ROUND(SUM(VL_SAL)), ROUND(AVG(VL_SAL))
15 INTO VSUM, VAVG
16 FROM FUNC
17 WHERE CD_DEPTO = VCD_DEPTO;
18 :MSG := :MSG||VCD_DEPTO ||'-'||VSUM||'-'||VAVG||'; ';
19 UPDATE RESULTADO
20 SET VL_SAL = VSUM,
21 AV_SAL = VAVG
22 WHERE CURRENT OF C1;
23 END LOOP;
24 END;
25 /
Procedimento PL/SQL concluído com sucesso.
MSG
--------------------------------------------------------------------------------
A00-14135-4712; B01-4538-4538; C01-9952-3317; D11-25041-2782; D21-16601-2767; E0
1-4419-4419; E11-11549-2310; E21-10484-2621;
3.24) Crie um bloco de PL/SQL que receba como parâmetro um número de mês e verifique quais os funcionários
aniversariantes. Apresentar o nome e dia de nascimento ordenado por dia de nascimento. Usar While.
Listagem-resposta 3.24A
SQL> DECLARE
2 MES NUMBER := '&MES';
3 CURSOR C1 IS SELECT NM_FUNC, TO_CHAR(DT_NASC, 'DD') DIA
4 FROM FUNC
5 WHERE TO_NUMBER(TO_CHAR(DT_NASC, 'MM')) = MES
6 ORDER BY DIA;
7 RC1 C1%ROWTYPE;
8 BEGIN
9 :MSG := 'Os aniversariantes do mês são : '||CHR(10);
10 OPEN C1;
11 FETCH C1 INTO RC1;
12 WHILE C1%FOUND LOOP
13 :MSG := :MSG ||RPAD(RC1.NM_FUNC,13)||LPAD(RC1.DIA,2)||'; '||CHR(10);
14 FETCH C1 INTO RC1;
15 END LOOP;
16 END;
17 /
Entre o valor para mes: 3
antigo 2: MES NUMBER := '&MES';
novo 2: MES NUMBER := '3';
MSG
-------------------------------
Os aniversariantes do mês são :
JOANA 19;
ELINE 28;
SALVADOR 31;
3.25) Crie um bloco de PL/SQL que receba como parâmetro (de substituição) um grau de instrução e um código de
departamento e determine o cargo, salário e matrícula deste funcionário. Se existir mais de um, escolha o funcionário
mais novo. Se não existir nenhum, apresente mensagem correspondente.
Listagem-resposta 3.25A
SQL> DECLARE
2 CURSOR C1 IS SELECT CD_MAT, NR_CARGO, VL_SAL
3 FROM FUNC
4 WHERE CD_DEPTO = UPPER('&DEPTO')
5 AND NR_GIT = TO_NUMBER('&GIT')
6 ORDER BY DT_NASC DESC;
7 RC1 C1%ROWTYPE;
8 BEGIN
9 OPEN C1;
10 FETCH C1 INTO RC1;
11 IF C1%NOTFOUND THEN
12 :MSG := 'Não existem funcionários na situação informada';
13 ELSE
14 :MSG := 'MAT = '||RC1.CD_MAT||' SAL = '||RC1.VL_SAL||
15 ' CARGO = '||RC1.NR_CARGO;
16 END IF;
17 END;
18 /
Entre o valor para depto: d11
antigo 4: WHERE CD_DEPTO = UPPER('&DEPTO')
novo 4: WHERE CD_DEPTO = UPPER('d11')
Entre o valor para git: 18
antigo 5: AND NR_GIT = TO_NUMBER('&GIT')
novo 5: AND NR_GIT = TO_NUMBER('18')
MSG
---------------------------------
MAT = 220 SAL = 3282,4 CARGO = 55
Listagem-resposta 3.26A
SQL> DECLARE
2 X NUMBER(3) := '&X';
3 A EXCEPTION;
4 B EXCEPTION;
5 C EXCEPTION;
6 BEGIN -- INICIO BLOCO PRINCIPAL
7 BEGIN -- INICIO BLOCO INTERNO
8 IF X = 1 THEN
9 RAISE A;
10 ELSIF X = 2 THEN
11 RAISE B;
12 ELSIF X = 3 THEN
13 RAISE C;
14 END IF;
15 :VALOR := 100;
16 EXCEPTION
17 WHEN A THEN
18 :VALOR := 300;
19 END; -- FIM BLOCO INTERNO
20 EXCEPTION
21 WHEN B THEN
22 :VALOR := 400;
23 END; -- FIM BLOCO EXTERNO
24 /
Para cada um dos erros encontrados, o programa deverá ser interrompido com a mensagem adequada.
Obrigatoriamente, o tratamento deverá utilizar a área de Exception.
Listagem-resposta 3.27A
SQL> DECLARE
2 NOME VARCHAR2(12) := UPPER('&NOME');
3 SOBRENOME VARCHAR2(12) := UPPER('&SOBRENOME');
4 CODIGO VARCHAR2(03) := UPPER('&DEPTO');
5 GIT NUMBER(02) := '&GIT';
6 DATA DATE := TO_DATE('&DATA', 'DD/MM/YYYY');
7 CARGO NUMBER(02) := '&CARGO';
8 SEXO VARCHAR2(01) := UPPER('&SEXO');
9 DUMMY NUMBER := 0;
10 IDADE EXCEPTION;
11 INSTRU EXCEPTION;
12 BEGIN
13 BEGIN
14 SELECT CD_MAT INTO DUMMY FROM FUNC
15 WHERE NM_FUNC = NOME AND NM_SOBRENOME = SOBRENOME;
16 RAISE_APPLICATION_ERROR(-20001, 'Funcionário já existente');
17 EXCEPTION
18 WHEN NO_DATA_FOUND THEN
19 NULL;
20 END;
21 SELECT CD_GERENTE INTO DUMMY FROM DEPTO
22 WHERE CD_DEPTO = CODIGO;
23 IF (SYSDATE - DATA) / 365.25 >= 50 THEN
24 RAISE IDADE;
25 END IF;
26 IF GIT NOT BETWEEN 12 AND 18 THEN
27 RAISE INSTRU;
28 END IF;
29 IF CARGO NOT BETWEEN 55 AND 60 THEN
30 RAISE_APPLICATION_ERROR(-20005, 'Cargo inválido');
31 END IF;
32 IF SEXO NOT IN ('F', 'M') THEN
33 RAISE_APPLICATION_ERROR(-20006, 'Sexo diferente de F e M');
34 END IF;
35 — INCLUSÃO
36 SELECT MAX(CD_MAT) + 1 INTO DUMMY
37 FROM FUNC;
38 INSERT INTO FUNC(CD_MAT, NM_FUNC, NM_SOBRENOME, DT_NASC,
39 CD_DEPTO, NR_GIT, NR_CARGO, IN_SEXO)
40 VALUES (DUMMY, NOME, SOBRENOME, DATA,
41 CODIGO, GIT, CARGO, SEXO);
42 EXCEPTION
43 WHEN NO_DATA_FOUND THEN
44 RAISE_APPLICATION_ERROR(-20002, 'Departamento inexistente');
45 WHEN IDADE THEN
46 RAISE_APPLICATION_ERROR(-20003, 'Idade muito elevada');
47 WHEN INSTRU THEN
48 RAISE_APPLICATION_ERROR(-20004, 'Grau de instrução inválido');
49 END;
50 /
3.28) Para o programa apresentado na Listagem-resposta 3.28A, identifique e explique por que ocorreu o erro.
Listagem-resposta 3.28A
SQL> DECLARE
2 DUMMY NUMBER := '&NUMERO';
3 BEGIN
4 IF DUMMY > 5 THEN
5 :VALOR := 0;
6 END IF;
7 EXCEPTION
8 WHEN OTHERS THEN
9 RAISE_APPLICATION_ERROR(-20999, 'ERRO DE ATRIBUIÇÃO NA DECLARAÇÃO');
10 END;
11 /
Entre o valor para numero: A
antigo 2: DUMMY NUMBER := '&NUMERO';
novo 2: DUMMY NUMBER := 'A';
DECLARE
*
ERRO na linha 1:
ORA-06502: PL/SQL: error: erro de conversão de caractere em número numérico ou
de valor
ORA-06512: em line 2
O erro ocorre mesmo com a presença da área de tratamento de erro, porque erros adquiridos a tempo de declaração
são propagados diretamente para o bloco externo imediatamente superior àquele em que ocorreu o erro, não
sendo percebidos pela área de tratamento. No nosso caso, não existe bloco externo, e portanto a propagação
ocorre para o ambiente, derrubando o programa.
3.29) Qual a solução de contorno que permita que controlemos o tipo de erro do Exercício 3.26?
Listagem-resposta 3.29A
SQL> BEGIN
2 DECLARE
3 DUMMY NUMBER := '&NUMERO';
4 BEGIN
5 IF DUMMY > 5 THEN
6 :VALOR := 0;
7 END IF;
8 EXCEPTION
9 WHEN OTHERS THEN
10 RAISE_APPLICATION_ERROR(-20999, 'ERRO DE ATRIBUIÇÃO NA DECLARAÇÃO');
11 END;
12 EXCEPTION
13 WHEN OTHERS THEN
14 :MSG := SQLERRM(SQLCODE);
15 END;
16 /
Entre o valor para numero: A
antigo 3: DUMMY NUMBER := '&NUMERO';
novo 3: DUMMY NUMBER := 'A';
MSG
--------------------------------------------------------------------------------
ORA-06502: PL/SQL: error: erro de conversão de caractere em número numérico ou d
e valor
A solução de contorno é a criação de um bloco externo àquele em que estava ocorrendo o erro. Este bloco é capaz
de capturar as condições de erro ocorridas na declaração do bloco interno.
3.30) Crie um programa para cadastramento de funcionários. Somente informe dois parâmetros: Matrícula e Código
do departamento. O programa não deve abortar se a matrícula já existir (Dup_Val_On_Index) ou se o código do
departamento não existir na tabela Depto (use a diretiva Exception_Init para definir este controle).
Listagem-resposta 3.30A
SQL> DECLARE
2 MATRICULA NUMBER := '&MAT';
3 DEPTO VARCHAR2(03) := '&DEPTO';
4 R_DEPTO EXCEPTION;
5 PRAGMA EXCEPTION_INIT(R_DEPTO, -2291);
6 BEGIN
7 INSERT INTO FUNC(CD_MAT, CD_DEPTO)
8 VALUES (MATRICULA, DEPTO);
9 EXCEPTION
10 WHEN DUP_VAL_ON_INDEX THEN
11 :MSG := 'Matrícula já existente';
12 WHEN R_DEPTO THEN
13 :MSG := 'Relacionamento inexistente';
14 END;
15 /
Entre o valor para mat: 2
antigo 2: MATRICULA NUMBER := '&MAT';
novo 2: MATRICULA NUMBER := '2';
Entre o valor para depto: DDD
antigo 3: DEPTO VARCHAR2(03) := '&DEPTO';
novo 3: DEPTO VARCHAR2(03) := 'DDD';
Procedimento PL/SQL concluído com sucesso.
MSG
--------------------------
Relacionamento inexistente
3.31) Faça um programa que receba três números e os apresente em ordem ascendente. Para tal, estabeleça todas as
críticas necessárias para que o usuário forneça dados corretos.
Listagem-resposta 3.31A
SQL> BEGIN
2 DECLARE
3 V1 NUMBER := '&VALOR_1';
4 V2 NUMBER := '&VALOR_2';
5 V3 NUMBER := '&VALOR_3';
6 DUMMY NUMBER := 0;
7 TROCA BOOLEAN:= TRUE;
8 BEGIN
9 IF V1 = V2 AND V1 = V3 THEN
10 :MSG := 'Os três números são iguais';
11 ELSE
12 WHILE TROCA LOOP
13 TROCA := FALSE;
14 IF V1 > V2 THEN
15 DUMMY := V1;
16 V1 := V2;
17 V2 := DUMMY;
18 TROCA := TRUE;
19 END IF;
20 IF V2 > V3 THEN
21 DUMMY := V2;
22 V2 := V3;
23 V3 := DUMMY;
24 TROCA := TRUE;
25 END IF;
26 END LOOP;
27 END IF;
28 :MSG := 'Ordem ascendente : '||V1||'-'||V2||'-'||V3;
29 END;
30 EXCEPTION
31 WHEN VALUE_ERROR THEN
32 :MSG := 'Valor inválido na atribuição';
33 END;
34 /
Entre o valor para valor_1: 8
antigo 3: V1 NUMBER := '&VALOR_1';
novo 3: V1 NUMBER := '8';
Entre o valor para valor_2: 4
antigo 4: V2 NUMBER := '&VALOR_2';
novo 4: V2 NUMBER := '4';
Entre o valor para valor_3: 9
antigo 5: V3 NUMBER := '&VALOR_3';
novo 5: V3 NUMBER := '9';
MSG
------------------------
Ordem ascendente : 4-8-9
3.32) Quais os três tipos de coleções existentes em PL/SQL? Cite duas características das Index-By Tables.
A PL/SQL trabalha com os seguintes tipos de coleções: Nested Tables, Varrays e Index-By Tables. Como característica
comum entre as coleções de PL/SQL, diríamos que funcionam como arrays e devem ser indexadas por um valor inteiro.
Dentre as características das Index-By Tables temos:
♦ Index-By Tables são definidas usando-se a cláusula Index By Binary_Integer.
♦ Uma Index-By Table não inicializada está apenas vazia e não podemos comparar usando IS NULL.
♦ A tempo de execução, Index-By Tables tornam-se non-null automaticamente.
3.33) O que são registros em PL/SQL?
Em PL/SQL, registros são áreas estruturadas, ou seja, um conjunto de itens de dados contendo seus próprios nomes
e tipos, que estão relacionados através de um nome comum (nome do registro).
Uma das formas de criação de registros é através do atributo %Rowtype, que pode criar uma área estruturada
baseada nas colunas de uma tabela definida no banco de dados ou nas colunas selecionadas em um cursor.
3.34) Crie um bloco de PL/SQL que receba números (quantidade qualquer) e apresente-os em ordem ascendente. O
programa deve receber um único parâmetro alfanumérico contendo os números separados por vírgula (use coleção).
Listagem-resposta 3.34A
SQL> DECLARE
2 TYPE TAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 LISTA VARCHAR2(100) := LTRIM(RTRIM('&NUMEROS'))||',';
4 WORDEM TAB;
5 I NUMBER := 0;
6 POS NUMBER := 1;
7 BEGIN
8 POS := INSTR(LISTA, ',');
9 :MSG := 'A seqüência ordenada de números é: ';
10 IF POS = 0 THEN
11 GOTO FIM;
12 END IF;
13 WHILE POS > 0 LOOP
14 I := SUBSTR(LISTA, 1, POS - 1);
15 IF WORDEM.EXISTS(I) THEN
16 WORDEM(I) := WORDEM(I) + 1;
17 ELSE
18 WORDEM(I) := 1;
19 END IF;
20 LISTA := LTRIM(SUBSTR(LISTA, POS + 1));
21 POS := INSTR(LISTA, ',');
22 END LOOP;
23 I := WORDEM.FIRST;
24 WHILE TRUE LOOP
25 WHILE WORDEM(I) > 0 LOOP
26 :MSG := :MSG||I||' ';
27 WORDEM(I) := WORDEM(I) - 1;
28 END LOOP;
29 EXIT WHEN I = WORDEM.LAST;
30 I := WORDEM.NEXT(I);
31 END LOOP;
32 <<FIM>>
33 NULL;
34 END;
35 /
Entre o valor para numeros: 1, 3, 7, 2, 9, 3, 10, 4, 2, 1
antigo 3: LISTA VARCHAR2(100) := LTRIM(RTRIM('&NUMEROS'))||',';
novo 3: LISTA VARCHAR2(100) := LTRIM(RTRIM('1, 3, 7, 2, 9, 3, 10, 4, 2, 1'))||',';
Procedimento PL/SQL concluído com sucesso.
MSG
----------------------------------------------------------------
A seqüência ordenada de números é: 1 1 2 2 3 3 4 7 9 10
Nesta parte do exercício, separamos cada um dos números recebidos e os usamos como indexadores da tabela Index-
By. Isto somente pode ser feito com este tipo de coleção, pois podemos criar elementos não seqüenciais na tabela.
3.35) Leia a tabela de funcionários e preencha a seguinte tabela em memória: TabCargo – cujo layout é composto
do número do cargo e quantidade e código do departamento.
Listagem-resposta 3.35A
SQL> DECLARE
2 TYPE REG IS RECORD (DEPTO CHAR(03),
3 COD NUMBER,
4 QTD NUMBER);
5 TYPE TCARGO IS TABLE OF REG INDEX BY BINARY_INTEGER;
6 CARGO TCARGO;
7 CURSOR C1 IS SELECT NR_CARGO, CD_DEPTO
8 FROM FUNC
9 ORDER BY CD_DEPTO, NR_CARGO;
10 A_CARGO BOOLEAN;
11 I NUMBER;
12 BEGIN
13 :MSG := ''; -- TAMANHO DE 4000 BYTES
14 FOR R1 IN C1 LOOP
15 A_CARGO := FALSE;
16 FOR I IN 1..CARGO.COUNT() LOOP
17 IF CARGO(I).DEPTO = R1.CD_DEPTO AND
18 CARGO(I).COD = R1.NR_CARGO THEN
19 CARGO(I).QTD := CARGO(I).QTD + 1;
20 A_CARGO := TRUE;
21 EXIT;
22 END IF;
23 END LOOP;
24 IF NOT A_CARGO THEN
25 I := CARGO.COUNT() + 1;
26 CARGO(I).DEPTO := R1.CD_DEPTO;
27 CARGO(I).COD := R1.NR_CARGO;
28 CARGO(I).QTD := 1;
29 END IF;
30 END LOOP;
31 FOR I IN 1..CARGO.COUNT() LOOP
32 :MSG := :MSG||' DEPTO= '||CARGO(I).DEPTO||
33 ' CARGO= '||CARGO(I).COD||
34 ' QTD= '||CARGO(I).QTD||CHR(10);
35 END LOOP;
36 END;
37 /
Procedimento PL/SQL concluído com sucesso.
MSG
----------------------------
DEPTO= A00 CARGO= 58 QTD= 2
DEPTO= A00 CARGO= 66 QTD= 1
. . .
3.36) Faça um programa que calcule um elemento da seqüência de Fibonacci que será passado como parâmetro.
Listagem-resposta 3.36A
SQL> DECLARE
2 TYPE TFIBO IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 FIBO TFIBO;
4 QTD NUMBER := '&QTD';
5 BEGIN
6 FIBO(1) := 1;
7 FIBO(2) := 1;
8 IF QTD IS NULL OR
9 QTD > 100 OR QTD < 3 THEN
10 :MSG := 'Quantidade de elementos inválida';
11 ELSE
12 :MSG := '1-1';
13 FOR I IN 3..QTD LOOP
14 FIBO(I) := FIBO(I-1) + FIBO(I-2);
15 :MSG := :MSG ||'-'||FIBO(I);
16 END LOOP;
17 END IF;
18 END;
19 /
Entre o valor para qtd: 12
antigo 4: QTD NUMBER := '&QTD';
novo 4: QTD NUMBER := '12';
Procedimento PL/SQL concluído com sucesso.
MSG
------------------------------
1-1-2-3-5-8-13-21-34-55-89-144
3.37) Faça um bloco de PL/SQL que leia os n (recebido como parâmetro) funcionários com maior salário e apresente-
os em ordem de matrícula. Deve ser mostrado o nome, cargo e salário de cada funcionário.
Listagem-resposta 3.37A
SQL> DECLARE
2 N NUMBER := '&QTD_SALARIOS';
3 CURSOR C1 IS SELECT NM_FUNC, NR_CARGO, VL_SAL, CD_MAT
4 FROM FUNC
5 WHERE VL_SAL IS NOT NULL
6 ORDER BY VL_SAL DESC;
7 TYPE TAB IS TABLE OF C1%ROWTYPE INDEX BY BINARY_INTEGER;
8 TBFUNC TAB;
9 BEGIN
10 FOR R1 IN C1 LOOP
11 EXIT WHEN C1%ROWCOUNT > N;
12 TBFUNC(R1.CD_MAT) := R1;
13 END LOOP;
14 N := TBFUNC.FIRST;
15 :MSG := '';
16 WHILE N <= TBFUNC.LAST LOOP
17 :MSG := :MSG||'Matrícula = '||TBFUNC(N).CD_MAT||' Nome = '||TBFUNC(N).NM_FUNC||
18 ' Cargo = '||TBFUNC(N).NR_CARGO||' Salário = '||TBFUNC(N).VL_SAL||CHR(10);
19 N := TBFUNC.NEXT(N);
20 END LOOP;
21 END;
22 /
Entre o valor para qtd_salarios: 6
antigo 2: N NUMBER := '&QTD_SALARIOS';
novo 2: N NUMBER := '6';
Procedimento PL/SQL concluído com sucesso.
MSG
----------------------------------------------------------
Matrícula = 10 Nome = CRISTINA Cargo = 66 Salário = 5802,5
Matrícula = 20 Nome = MIGUEL Cargo = 61 Salário = 4537,5
Matrícula = 30 Nome = SANDRA Cargo = 60 Salário = 4207,5
Matrícula = 50 Nome = JOAO Cargo = 58 Salário = 4419,25
Matrícula = 70 Nome = EVA Cargo = 56 Salário = 3978,7
Matrícula = 110 Nome = VICENTE Cargo = 58 Salário = 5115
3.38) Suponha um tabuleiro de xadrez com oito linhas e oito colunas. Receba como parâmetro (linha e coluna) o
posicionamento de uma rainha no tabuleiro. Faça um programa que determine as outras possíveis posições em que a
outra rainha poderá ser colocada sabendo-se que, no xadrez, a rainha pode se deslocar tanto na reta quanto na diagonal.
Listagem-resposta 3.38A
SQL> VARIABLE MSG VARCHAR2(1000)
SQL> SET AUTOPRINT ON
SQL> DECLARE
2 TYPE ARX IS TABLE OF CHAR(1) INDEX BY BINARY_INTEGER;
3 TYPE ARY IS TABLE OF ARX INDEX BY BINARY_INTEGER;
4 TABULEIRO ARY;
5 POSX NUMBER := '&LINHA';
6 POSY NUMBER := '&COLUNA';
7 J NUMBER;
8 K NUMBER;
9 BEGIN
10 -- Retas
11 :MSG := 'As posições disponíveis são: ';
12 FOR I IN 1..8 LOOP
13 TABULEIRO(POSX)(I) := 'X';
14 END LOOP;
15 FOR I IN 1..8 LOOP
16 TABULEIRO(I)(POSY) := 'X';
17 END LOOP;
18 J := POSY - 1;
19 K := POSY + 1;
20 FOR I IN (POSX+1)..8 LOOP
21 IF J >= 1 THEN
22 TABULEIRO(I)(J) := 'X';
23 J := J -1;
24 END IF;
25 IF K <= 8 THEN
26 TABULEIRO(I)(K) := 'X';
27 K := K + 1;
28 END IF;
29 END LOOP;
30 J := POSY - 1;
31 K := POSY + 1;
32 FOR I IN REVERSE 1..(POSX-1) LOOP
33 IF J >= 1 THEN
34 TABULEIRO(I)(J) := 'X';
35 J := J -1;
36 END IF;
37 IF K <= 8 THEN
38 TABULEIRO(I)(K) := 'X';
39 K := K + 1;
40 END IF;
41 END LOOP;
42 FOR I IN 1..8 LOOP
43 FOR J IN 1..8 LOOP
44 IF NOT TABULEIRO(I).EXISTS(J) THEN
45 :MSG := :MSG ||'('||I||','||J||') ';
46 END IF;
47 END LOOP;
48 END LOOP;
49 END;
50 /
Entre o valor para linha: 3
Entre o valor para coluna: 4
Procedimento PL/SQL concluído com sucesso.
MSG
--------------------------------------------------------------------------------
As posições disponíveis são: (1,1) (1,3) (1,5) (1,7) (1,8) (2,1) (2,2) (2,6) (2,
7) (2,8) (4,1) (4,2) (4,6) (4,7) (4,8) (5,1) (5,3) (5,5) (5,7) (5,8) (6,2) (6,3)
(6,5) (6,6) (6,8) (7,1) (7,2) (7,3) (7,5) (7,6) (7,7) (8,1) (8,2) (8,3) (8,5) (
8,6) (8,7) (8,8)
Neste exercício não precisamos verificar a existência de cada uma das posições do array na direção X (tabuleiro.exists(
I )) porque preenchemos um elemento de cada uma das oito posições porque, quando executamos o primeiro
loop, para marcar as linhas retas, é criada uma linha para cada posição.
3.39) Crie um bloco de PL/SQL que receba como parâmetro uma série de matrículas separadas por vírgula em um
único parâmetro. Monte este número em um array e faça uma consulta ao banco de dados, obtendo o nome e
salário de todos os funcionários que existam na lista. Use ForAll e Bulk Collect.
Listagem-resposta 3.39A
SQL> DECLARE
2 MATS VARCHAR2(300) := '&MATRICULAS'||',';
3 TYPE TAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
4 TYPE TABCHAR IS TABLE OF VARCHAR2(50) INDEX BY BINARY_INTEGER;
5 TABMAT TAB;
6 SALARIOS TAB;
7 NOMES TABCHAR;
8 POS NUMBER;
9 I NUMBER := 1;
10 BEGIN
11 POS := INSTR(MATS, ',');
12 WHILE POS > 0 LOOP
13 TABMAT(I) := TO_NUMBER(SUBSTR(MATS,1,POS-1));
14 MATS := SUBSTR(MATS,POS+1);
15 POS := INSTR(MATS, ',');
16 I := I + 1;
17 END LOOP;
18 :MSG := '';
19 IF I > 1 THEN
20 FORALL J IN 1..TABMAT.LAST
21 UPDATE FUNC SET VL_SAL = VL_SAL
22 WHERE CD_MAT = TABMAT(J)
23 RETURNING NM_FUNC, VL_SAL BULK COLLECT INTO NOMES, SALARIOS;
24 COMMIT;
25 I := 1;
26 FOR J IN 1..TABMAT.LAST LOOP
27 IF SQL%BULK_ROWCOUNT(J) > 0 THEN
28 :MSG := :MSG||TABMAT(J)||'-'||NOMES(I)||'-'||SALARIOS(I)||CHR(10);
29 I := I + 1;
30 ELSE
31 :MSG := :MSG ||'UPDATE MAT='||TABMAT(J)||' NÃO REALIZADA'||CHR(10);
32 END IF;
33 END LOOP;
34 END IF;
35 END;
36 /
Entre o valor para matriculas: 100, 12, 150, 7, 180
antigo 2: MATS VARCHAR2(300) := '&MATRICULAS'||',';
novo 2: MATS VARCHAR2(300) := '100, 12, 150, 7, 180'||',';
Procedimento PL/SQL concluído com sucesso.
MSG
---------------------------
100-TEODORO-2876,5
UPDATE MAT=12 NÃO REALIZADA
150-BRUNO-2780,8
UPDATE MAT=7 NÃO REALIZADA
180-MARIA-2347,4
A principal diferença entre Procedures e Functions é que uma função obrigatoriamente retorna um valor ao programa
que a executou, enquanto um procedimento pode ou não retornar valor (em um parâmetro do tipo Out).
3.41) Crie uma função armazenada no banco de dados que retorne o nome do departamento, cujo código deve ser
passado como parâmetro. Caso o departamento não exista, a função deve retornar ‘Departamento Inexistente’.
Listagem-resposta 3.41A
SQL> CREATE OR REPLACE FUNCTION FDEPTO(COD IN VARCHAR2) RETURN VARCHAR2 IS
2 NOME VARCHAR2(100);
3 BEGIN
4 SELECT NM_DEPTO INTO NOME
5 FROM DEPTO
6 WHERE CD_DEPTO = COD;
7 RETURN NOME;
8 EXCEPTION
9 WHEN NO_DATA_FOUND THEN
10 RETURN 'Departamento Inexistente';
11 END;
12 /
Função criada.
FDEPTO('A00')
--------------------
DIRETORIA DA EMPRESA
3.42) Crie uma função ou procedure na base de dados que determine o departamento que possui menos funcionários.
Listagem-resposta 3.42A
SQL> CREATE OR REPLACE FUNCTION QDEPTO RETURN VARCHAR2 IS
2 CURSOR C1 IS SELECT CD_DEPTO, COUNT(*)
3 FROM FUNC F
4 GROUP BY CD_DEPTO
5 UNION
6 SELECT CD_DEPTO, 0 FROM DEPTO
7 WHERE NOT EXISTS (SELECT * FROM FUNC
8 WHERE CD_DEPTO = DEPTO.CD_DEPTO)
9 ORDER BY 2;
10 BEGIN
11 FOR R1 IN C1 LOOP
12 RETURN R1.CD_DEPTO;
13 END LOOP;
14 END;
15 /
Função criada.
3.43) Crie uma função ou procedure na base de dados que receba como parâmetro um código de departamento e
determine o ramal do gerente do departamento. Caso o departamento não tenha gerente, deverá ser escolhido o
ramal do funcionário com maior cargo deste departamento (se existir mais de um, obtenha o ramal do funcionário
mais velho e com maior cargo).
Listagem-resposta 3.43A
SQL> CREATE OR REPLACE
2 FUNCTION RAMAL (COD IN VARCHAR2) RETURN NUMBER IS
3 CURSOR C1 IS SELECT NR_RAMAL
4 FROM FUNC, DEPTO
5 WHERE FUNC.CD_MAT = DEPTO.CD_GERENTE
6 AND DEPTO.CD_DEPTO = COD;
7 CURSOR C2 IS SELECT NR_RAMAL
8 FROM FUNC
9 WHERE NR_CARGO = (SELECT MAX(NR_CARGO)
10 FROM FUNC
11 WHERE CD_DEPTO = COD)
12 AND CD_DEPTO = COD
13 ORDER BY DT_NASC;
14 BEGIN
15 FOR R1 IN C1 LOOP
16 RETURN R1.NR_RAMAL;
17 END LOOP;
18 FOR R2 IN C2 LOOP
19 RETURN R2.NR_RAMAL;
20 END LOOP;
21 RETURN 0;
22 END;
23 /
Função criada.
RAMAL('A00')
------------
4501
3.44) Crie uma função ou procedure na base de dados que receba como parâmetro um grau de instrução e um
código de departamento e determine o cargo e o salário correspondentes a estes parâmetros. Se existir mais de um,
escolha o do funcionário mais novo. Se não existir nenhum, retorne Null.
Listagem-resposta 3.44A
SQL> CREATE OR REPLACE
2 PROCEDURE SALCARGO (COD IN VARCHAR2, GIT IN NUMBER,
3 SAL OUT NOCOPY NUMBER, CARGO OUT NOCOPY NUMBER) IS
4 CURSOR C1 IS SELECT VL_SAL, NR_CARGO
5 FROM FUNC
6 WHERE CD_DEPTO = COD
7 AND NR_GIT = GIT
8 ORDER BY DT_NASC DESC NULLS LAST;
9 BEGIN
10 FOR R1 IN C1 LOOP
11 SAL := R1.VL_SAL;
12 CARGO := R1.NR_CARGO;
13 END LOOP;
14 END;
15 /
Procedimento criado.
SQL> PRINT
SAL
----------
5802,5
CARGO
----------
66
3.45) Crie um programa na base de dados que realize a admissão dos funcionários. Esse programa deverá receber
como parâmetro nome completo (nome e sobrenome), data de nascimento, sexo e grau de instrução.
Para a construção do programa, as seguintes regras devem ser estabelecidas:
♦ Usar a rotina do Exercício 3.42 para determinar o departamento.
♦ Usar a rotina do Exercício 3.43 para determinar o ramal.
♦ Usar a rotina do Exercício 3.44 para determinar o salário e o cargo.
♦ A data de admissão corresponde ao dia do cadastramento.
♦ A matrícula deverá ser gerada a partir da última cadastrada.
♦ Os parâmetros são opcionais (exceto nome) e devem ter valores defaults.
O programa deve ser testado com passagem nomeada dos parâmetros.
Listagem-resposta 3.45A
SQL> CREATE OR REPLACE
2 PROCEDURE CFUNC (NOME1 IN VARCHAR2,
3 NOME2 IN VARCHAR2,
4 DNASC IN DATE := TO_DATE('01011901', 'DDMMYYYY'),
5 SEXO IN VARCHAR2 := 'F',
6 GIT IN NUMBER := 12) IS
7 CDEPTO VARCHAR2(03);
8 CRAMAL NUMBER;
9 MAT NUMBER;
10 SAL NUMBER;
11 CARGO NUMBER;
12 BEGIN
13 IF NOME1 IS NULL OR NOME2 IS NULL THEN
14 RAISE_APPLICATION_ERROR(-20001, 'Nome é de preenchimento obrigatório');
15 END IF;
16 CDEPTO := QDEPTO;
17 CRAMAL := RAMAL(CDEPTO);
18 SALCARGO(CDEPTO, GIT, SAL, CARGO);
19 SELECT NVL(MAX(CD_MAT), 0) + 1 INTO MAT FROM FUNC;
20 INSERT INTO FUNC
21 (CD_MAT, NM_FUNC, NM_SOBRENOME, VL_SAL, NR_RAMAL,
22 CD_DEPTO, IN_SEXO, NR_CARGO, DT_NASC, DT_ADM, NR_GIT) VALUES
23 (MAT, NOME1, NOME2, SAL, CRAMAL,
24 CDEPTO, SEXO, CARGO, DNASC, SYSDATE, GIT);
25 END;
26 /
Procedimento criado.
3.46) Crie uma função que receba como parâmetro uma Index-By Table e retorne os dados da Index-By Table em
ordem crescente.
Listagem-resposta 3.46A
SQL> CREATE OR REPLACE PACKAGE PGLOBAL IS
2 TYPE TTAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 END;
4 /
Pacote criado.
SQL> DECLARE
2 LISTA PGLOBAL.TTAB;
3 TEXTO VARCHAR2(200) := '&LISTA'||',';
4 POS NUMBER := 0;
5 I NUMBER:= 0;
6 BEGIN
7 :MSG := '';
8 POS := INSTR(TEXTO, ',');
9 WHILE POS > 0 LOOP
10 I := I + 1;
11 LISTA(I) := SUBSTR(TEXTO, 1, POS - 1);
12 TEXTO := LTRIM(SUBSTR(TEXTO, POS + 1));
13 POS := INSTR(TEXTO, ',');
14 END LOOP;
15 PORDENA(LISTA);
16 FOR I IN 1..LISTA.COUNT() LOOP
17 :MSG := :MSG || ' ' || LISTA(I);
18 END LOOP;
19 END;
20 /
Entre o valor para lista: 5, 8, 10, 12, 13, 2, 5, 1, 6, 7, 9, 20
Procedimento PL/SQL concluído com sucesso.
MSG
---------------------------
1 2 5 5 6 7 8 9 10 12 13 20
Na Listagem-resposta 3.46A, estamos apresentando o programa de ordenação e um outro programa que se utiliza
da rotina de ordenação.
3.47) Faça uma rotina que receba como parâmetro um número de cargo e determine o nome do funcionário mais
velho com aquele cargo. Se não houver ninguém, o programa deve abortar com o erro Oracle correspondente.
Faça um programa que acione o programa anterior, e de acordo com seu resultado mostre o nome do funcionário
ou a mensagem “Nenhum funcionário para o cargo Informado”.
Listagem-resposta 3.47A
SQL> CREATE OR REPLACE
2 FUNCTION PCARGO(CARGO IN NUMBER) RETURN VARCHAR2 IS
3 CURSOR C1 IS SELECT NM_FUNC || ' ' || NM_SOBRENOME NOME
4 FROM FUNC
5 WHERE NR_CARGO = CARGO
6 ORDER BY DT_NASC DESC NULLS LAST;
7 BEGIN
8 FOR R1 IN C1 LOOP
9 RETURN R1.NOME;
10 END LOOP;
11 RAISE_APPLICATION_ERROR(-20001, 'Cargo Inválido');
12 END;
13 /
Função criada.
SQL> DECLARE
2 CARGO NUMBER := '&CARGO';
3 ECARGO EXCEPTION;
4 PRAGMA EXCEPTION_INIT(ECARGO, -20001);
5 BEGIN
6 :MSG := PCARGO(CARGO);
7 EXCEPTION
8 WHEN ECARGO THEN
9 :MSG := 'Nenhum funcionário para o cargo informado';
10 END;
11 /
Entre o valor para cargo: 99
Procedimento PL/SQL concluído com sucesso.
MSG
-----------------------------------------
Nenhum funcionário para o cargo informado
3.48) Crie um programa para gravar informações na tabela criada na Listagem-resposta 3.48A.
Listagem-resposta 3.48A
SQL> CREATE TABLE RESULTADO
2 (COD NUMBER,
3 QTD NUMBER);
Tabela criada.
COD QTD
---------- ----------
100 3
201 1
301 3
401 1
411 9
421 6
501 1
511 5
521 4
601 0
602 0
11 linhas selecionadas.
3.49) Crie uma função no banco de dados que calcule o n-ésimo elemento de uma série de Fibonacci. Utilize recursividade.
Listagem-resposta 3.49A
SQL> CREATE OR REPLACE
2 FUNCTION FIBO(I IN NUMBER) RETURN NUMBER IS
3 VALOR NUMBER;
4 BEGIN
5 IF I = 1 THEN
6 RETURN 1;
7 ELSIF I = 2 THEN
8 RETURN 1;
9 ELSE
10 VALOR := FIBO(I - 1) + FIBO(I - 2);
11 RETURN VALOR;
12 END IF;
13 END;
14 /
Função criada.
MSG
---------------------------
55
Listagem-resposta 3.50A
SQL> CREATE OR REPLACE
2 PROCEDURE TFORWARD (CARGO IN OUT NOCOPY NUMBER, OPCAO IN NUMBER := 9) IS
3 VLOOP NUMBER := 0;
4 VALOR NUMBER ;
5 FUNCTION F2(CARGO IN NUMBER) RETURN NUMBER;
CARGO
---------
60
CARGO
---------
4
3.51) Faça um programa que receba uma data no formato DDMMYYYY e verifique se é uma data válida. Havendo
erro, aborte com a mensagem adequada.
Faça um programa que acione o anterior e retorne a mensagem associada ao erro sem abortar.
Listagem-resposta 3.51A
SQL> CREATE OR REPLACE
2 FUNCTION CDATA(DATA IN VARCHAR2) RETURN BOOLEAN IS
3 VDATA DATE;
4 BEGIN
5 VDATA := TO_DATE(DATA, 'DDMMYYYY');
6 RETURN TRUE;
7 END;
8 /
Função criada.
SQL> DECLARE
2 DATA VARCHAR2(100) := '&DATA';
3 BEGIN
4 IF CDATA(DATA) THEN
5 :MSG := 'A DATA '|| DATA || ' É VÁLIDA';
6 END IF;
7 EXCEPTION
8 WHEN OTHERS THEN
9 :MSG := SQLCODE || ' # ' || SQLERRM(SQLCODE) || ' # '||
10 ' DATA '|| DATA || ' INVÁLIDA';
11 END;
12 /
Entre o valor para data: AAKLDGHAAKADH
Procedimento PL/SQL concluído com sucesso.
MSG
-------------------------------------------------------------------------------
-1858 # ORA-01858: foi localizado um caractere não-numérico onde se esperava um
numérico # DATA AAKLDGHAAKADH INVÁLIDA
3.52) Crie um pacote que tenha uma rotina que receba como parâmetro:
A) Um numérico e retorne um alfanumérico com o valor editado para o formato monetário brasileiro e símbolo
financeiro “R$”.
B) Um alfanumérico e retorne um alfanumérico com o texto apresentado de trás para a frente.
C) Uma data e retorne um alfanumérico com as seguintes características: dia da semana, dia no ano, mês por
extenso, mês em algarismos romanos, ano por extenso e ano ISO.
Use Overloading.
Listagem-resposta 3.52A
SQL> CREATE OR REPLACE PACKAGE ROTINAS IS
2 FUNCTION TROCA(VALOR IN NUMBER) RETURN VARCHAR2;
3 FUNCTION TROCA(TEXTO IN VARCHAR2) RETURN VARCHAR2;
4 FUNCTION TROCA(DATA IN DATE) RETURN VARCHAR2;
5 END ROTINAS;
6 /
Pacote criado.
SQL> BEGIN
2 :MSG := ROTINAS.TROCA(12459.88)||CHR(10);
3 :MSG := :MSG || ROTINAS.TROCA('ABCDEF')||CHR(10);
4 :MSG := :MSG || ROTINAS.TROCA(TO_DATE('01041989', 'DDMMYYYY'));
5 END;
6 /
Procedimento PL/SQL concluído com sucesso.
MSG
--------------------------------------------------------
R$12.459,88
FEDCBA
7 # 091 # ABRIL # IV # NINETEEN EIGHTY-NINE # 1989
Listagem-resposta 3.53A
SQL> CREATE OR REPLACE PACKAGE PROMOVE AUTHID CURRENT_USER IS
2 FUNCTION AVALIA (MAT IN NUMBER) RETURN VARCHAR2;
3 END PROMOVE;
4 /
Pacote criado.
Neste primeiro passo, criamos o pacote Promove e disponibilizamos apenas a rotina Avalia para uso dos usuários.
Definimos para todo o pacote que a autorização de execução seria a do usuário executor.
Para garantir que as leituras e atualizações se processariam nas tabelas do usuário Desenv, todas foram qualificadas
com o nome do usuário.
Listagem-resposta 3.53B
SQL> GRANT EXECUTE ON PROMOVE TO DAVI;
Operação de Grant bem-sucedida.
MSG
--------------------------------------------------
Funcionário não está em condições de ser promovido
Após a criação do pacote, precisamos autorizar seu uso para os usuários necessários. Uma vez que a atualização se
processará diretamente nos dados de Desenv, devemos autorizar também a atualização das duas tabelas envolvidas.
Listagem-resposta 3.54A
SQL> CREATE OR REPLACE PACKAGE CONV IS
2 FUNCTION NOME(VALOR IN VARCHAR2) RETURN VARCHAR2;
3 PRAGMA RESTRICT_REFERENCES(NOME, WNDS);
4 END;
5 /
Pacote criado.
33 linhas atualizadas.
3.55) Crie um pacote que declare uma variável Date, uma variável Varchar2(100) e uma variável Number.
Em uma mesma sessão do SQL*Plus:
A) Dê valor inicial para as três variáveis do pacote.
B) Execute as três funções do Exercício 3.52 passando como parâmetro as variáveis do pacote.
C) Apresente o valor das três variáveis.
Listagem-resposta 3.55A
SQL> CREATE OR REPLACE PACKAGE VALORES IS
2 DATA DATE;
3 TEXTO VARCHAR2(100);
4 NUMERO NUMBER;
5 END;
6 /
Pacote criado.
SQL> BEGIN
2 VALORES.DATA := TO_DATE('03011999', 'DDMMYYYY');
3 VALORES.TEXTO := 'LAZINHA';
4 VALORES.NUMERO := 887502.54;
5 END;
6 /
Procedimento PL/SQL concluído com sucesso.
SQL> BEGIN
2 :MSG := ROTINAS.TROCA(VALORES.DATA) ||CHR(10)||
3 ROTINAS.TROCA(VALORES.TEXTO) ||CHR(10)||
4 ROTINAS.TROCA(VALORES.NUMERO);
5 END;
6 /
Procedimento PL/SQL concluído com sucesso.
SQL> BEGIN
2 :MSG := VALORES.DATA ||CHR(10)||
3 VALORES.TEXTO ||CHR(10)||
4 VALORES.NUMERO;
5 END;
6 /
Procedimento PL/SQL concluído com sucesso.
MSG
-----------------------------------------
03/01/99
LAZINHA
887502,54
Listagem-resposta 3.56A
SQL> CREATE OR REPLACE PACKAGE DATAS IS
2 FUNCTION IDATA(DATAI IN DATE, DATAF IN DATE) RETURN NUMBER;
3 END;
4 /
Pacote criado.
38 46 60 IRACY
27 38 70 EVA
6 linhas selecionadas.
Na Listagem-resposta 3.56A criamos o pacote, juntamente com a rotina Idata, e executamos a rotina em um
comando Select. Observe que não precisamos usar a pragma Restrict_References.
Listagem-resposta 3.57A
SQL> CREATE OR REPLACE PACKAGE DEFINE IS
2 TYPE TABVC IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
3 TYPE VARDT IS TABLE OF DATE INDEX BY BINARY_INTEGER;
4 TYPE REG1 IS RECORD (DATA DATE,
5 CODIGO NUMBER,
6 TEXTO VARCHAR2(100));
7 TYPE TABREG IS TABLE OF REG1 INDEX BY BINARY_INTEGER;
8 TYPE REG2 IS RECORD (CODIGO NUMBER,
9 VALOR NUMBER);
10 TYPE VARREG IS TABLE OF REG2 INDEX BY BINARY_INTEGER;
11 TYPE TBFUNC IS TABLE OF FUNC%ROWTYPE INDEX BY BINARY_INTEGER;
12 TYPE TBDEPTO IS TABLE OF DEPTO%ROWTYPE INDEX BY BINARY_INTEGER;
13 CURSOR C1 (DEP IN VARCHAR2, CARGO IN NUMBER)
14 RETURN FUNC%ROWTYPE;
15 CURSOR C2 (GERENTE IN NUMBER)
16 RETURN DEPTO%ROWTYPE;
17 END;
18 /
Pacote criado.
3.58) Crie um programa que receba como parâmetro um código de departamento e um número de cargo e separe os
dados da tabela Func em três grupos para utilização como parâmetro por três outros programas da seguinte forma:
♦ O programa Rot1 deve receber uma lista de datas de admissão.
♦ O programa Rot2 deve receber uma lista de datas de nascimento, matrículas e nomes.
♦ O programa Rot3 deve receber uma lista de cargos e salários.
Utilize os tipos e cursores declarados no exercício anterior. Não é necessário criar os três programas.
Listagem-resposta 3.58A
SQL> CREATE OR REPLACE
2 PROCEDURE TESTE (PDEP IN VARCHAR2, PCARGO IN NUMBER) IS
3 VARDATA DEFINE.VARDT;
4 TABRECORD DEFINE.TABREG;
5 VARNUM DEFINE.VARREG;
6 I NUMBER := 0;
7 BEGIN
8 FOR R1 IN DEFINE.C1(PDEP, PCARGO) LOOP
9 I := I + 1;
10 VARDATA(I) := R1.DT_ADM;
11 TABRECORD(I).DATA := R1.DT_NASC;
12 TABRECORD(I).CODIGO := R1.CD_MAT;
13 TABRECORD(I).TEXTO := R1.NM_FUNC||' '||R1.NM_SOBRENOME;
14 VARNUM(I).CODIGO := R1.NR_CARGO;
15 VARNUM(I).VALOR := R1.VL_SAL;
16 END LOOP;
17 --ROT1(VARDATA);
18 --ROT2(TABRECORD);
19 --ROT3(VARNUM);
20 END;
21 /
Procedimento criado.
3.60) Crie um programa que receba como parâmetro um número de mês e emita uma carta parabenizando o
funcionário pela data do seu aniversário (use DBMS_OUTPUT). Não deve ser usada stored procedure.
Listagem-resposta 3.60A
SQL> SET SERVEROUT ON
SQL> SET VERIFY OFF
SQL> SET NEWPAGE 0
SQL> BREAK ON ROW SKIP PAGE
SQL> DEFINE MES = 3
SQL> SPOOL SAIDA.SQL
SQL> DECLARE
2 MES NUMBER := '&MES';
3 BEGIN
4 FOR R1 IN (SELECT NM_FUNC, DT_NASC FROM FUNC
5 WHERE TO_NUMBER(TO_CHAR(DT_NASC, 'MM')) = MES) LOOP
6 DBMS_OUTPUT.PUT_LINE('Sr(a). '||R1.NM_FUNC||
7 ' parabéns pelo seu aniversário dia '||
8 TO_CHAR(R1.DT_NASC, 'DD/MM') || '.');
9 DBMS_OUTPUT.PUT_LINE(CHR(10)||CHR(10));
10 DBMS_OUTPUT.PUT_LINE(' Muitas Felicidades !');
11 DBMS_OUTPUT.PUT_LINE(CHR(10)||CHR(10)||CHR(10));
12 END LOOP;
13 END;
14 /
Sr(a). JOANA parabéns pelo seu aniversário dia 19/03.
Muitas Felicidades !
Muitas Felicidades !
Muitas Felicidades !
3.61) Usando o pacote DBMS_OUTPUT, gere um arquivo contendo o nome, data de nascimento e salário dos
funcionários. Alinhe os dados por coluna.
Listagem-resposta 3.61A
SQL> DECLARE
2 CURSOR C1 IS SELECT NM_FUNC, NM_SOBRENOME, DT_NASC, VL_SAL
3 FROM FUNC;
4 BEGIN
5 FOR R1 IN C1 LOOP
6 DBMS_OUTPUT.PUT(RPAD(LTRIM(RTRIM(R1.NM_FUNC))||' '||
7 LTRIM(RTRIM(R1.NM_SOBRENOME)), 25));
8 DBMS_OUTPUT.PUT(TO_CHAR(R1.DT_NASC, 'DDMMYYYY')||' ');
9 DBMS_OUTPUT.PUT_LINE(LPAD(TO_CHAR(R1.VL_SAL, 'L999G999D99',
10 'NLS_CURRENCY=R$'), 12));
11 END LOOP;
12 END;
13 /
CRISTINA HENDERSON 14081953 R$5.802,50
MIGUEL TEIXEIRA 02021968 R$4.537,50
SANDRA KWAN 11051961 R$4.207,50
3.62) Faça uma rotina que usa a DBMS_OUTPUT para colocar no buffer o nome dos aniversariantes do mês (recebido
como parâmetro).
Listagem-resposta 3.62A
SQL> CREATE OR REPLACE
2 PROCEDURE ANI(MES IN NUMBER) IS
3 BEGIN
4 FOR R1 IN (SELECT NM_FUNC FROM FUNC
5 WHERE TO_NUMBER(TO_CHAR(DT_NASC, 'MM'))=MES) LOOP
6 DBMS_OUTPUT.PUT_LINE(LTRIM(RTRIM(R1.NM_FUNC)));
7 END LOOP;
8 END ANI;
9 /
Procedimento criado.
3.63) Faça um programa que leia a área de buffer do programa anterior e verifique se o funcionário cujo nome será
fornecido como parâmetro é aniversariante. Informe o resultado em uma variável Bind.
Listagem-resposta 3.63A
SQL> DECLARE
2 LINHAS DBMS_OUTPUT.CHARARR;
3 STATUS NUMBER := 0;
4 I NUMBER := 0;
5 NOME VARCHAR2(100) := UPPER('&NOME');
6 BEGIN
7 ANI(5);
8 :MSG := NOME || ' não faz aniversário';
9 WHILE STATUS = 0 LOOP
10 I := I + 1;
11 DBMS_OUTPUT.GET_LINE(LINHAS(I), STATUS);
12 END LOOP;
13 FOR J IN 1..I LOOP
14 IF NOME = LINHAS(J) THEN
15 :MSG := NOME || ' é aniversariante';
16 EXIT;
17 END IF;
18 END LOOP;
19 END;
20 /
Entre o valor para nome: DILSON
Procedimento PL/SQL concluído com sucesso.
MSG
-----------------------
DILSON é aniversariante
3.64) Faça um script que coloque no prompt do SQL*PLUS o nome do usuário e a linguagem em que está o banco
de dados atualmente. Garanta que este script seja executado todas as vezes em que o SQL*Plus for acionado (utilize
seus conhecimentos de SQL*Plus).
Listagem-resposta 3.64A
SQL> SET SERVEROUT ON
SQL> SPOOL PROMPT.SQL
SQL> DECLARE
2 TEXTO VARCHAR2(100);
3 BEGIN
4 SELECT LTRIM(RTRIM(USER))||'_'||USERENV('LANG')
5 INTO TEXTO FROM DUAL;
6 DBMS_OUTPUT.PUT_LINE('SET SQLPROMPT '||'”'||TEXTO||'> “');
7 END;
8 /
SET SQLPROMPT “DESENV_PTB> “
Procedimento PL/SQL concluído com sucesso.
Para que o script seja executado todas as vezes que o SQL*Plus for acionado gere-o com o nome de Login.SQL em
vez de Prompt.SQL.
3.65) Gere uma área de buffer com o seguinte layout: nome, sobrenome, data de nascimento (formato dd/mm/
yyyy), sexo e salário.
Os dados devem ser separados pelo símbolo #.
Caso uma determinada coluna não tenha valor (Null), deve ser substituído por “**” para colunas alfanuméricas e
-1 para colunas numéricas.
Listagem-resposta 3.65A
SQL> CREATE OR REPLACE PROCEDURE GRAVA IS
2 BEGIN
3 FOR R1 IN (SELECT NVL(NM_FUNC, '**') NM_FUNC,
4 NVL(NM_SOBRENOME, '**') NM_SOBRENOME,
5 NVL(TO_CHAR(DT_NASC, 'DD/MM/YYYY'), '**') DT_NASC,
6 NVL(IN_SEXO, '**') IN_SEXO,
7 NVL(LTRIM(TO_CHAR(VL_SAL, 'L999G999G999D99',
8 'NLS_CURRENCY=R$')), '-1') VL_SAL
9 FROM FUNC) LOOP
10 DBMS_OUTPUT.PUT(R1.NM_FUNC||'#'||R1.NM_SOBRENOME||'#');
11 DBMS_OUTPUT.PUT_LINE(R1.DT_NASC||'#'||R1.IN_SEXO||'#'||R1.VL_SAL);
12 END LOOP;
13 END;
14 /
Procedimento criado.
3.66) Faça um programa que leia o buffer gerado pelo programa anterior e crie novas linhas na tabela Func. O
número da matrícula deve ser gerado a partir do último armazenado em Func.
Listagem-resposta 3.66A
SQL> DECLARE
2 LINHA VARCHAR2(255);
3 TYPE TAB IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
4 STATUS NUMBER := 0;
5 POS NUMBER := 0;
6 MAT NUMBER;
7 TEXTO TAB;
8 BEGIN
9 SELECT NVL(MAX(CD_MAT),0) + 1 INTO MAT
10 FROM FUNC;
11 GRAVA;
12 LOOP
13 DBMS_OUTPUT.GET_LINE(LINHA,STATUS);
14 IF STATUS = 0 THEN
15 POS := INSTR(LINHA, '#');
16 WHILE POS > 0 LOOP
17 STATUS := STATUS + 1;
18 TEXTO(STATUS) := SUBSTR(LINHA,1,POS - 1);
19 LINHA := SUBSTR(LINHA, POS + 1);
20 POS := INSTR(LINHA, '#');
21 END LOOP;
22 STATUS := STATUS + 1;
23 TEXTO(STATUS) := LINHA;
24 ELSE
25 EXIT;
26 END IF;
27 FOR I IN 1..5 LOOP
28 IF TEXTO(I) = '**' OR TEXTO(I) = '-1' THEN
29 TEXTO(I) := NULL;
30 END IF;
31 END LOOP;
32 INSERT INTO FUNC(CD_MAT, NM_FUNC, NM_SOBRENOME, DT_NASC,
33 IN_SEXO, VL_SAL)
34 VALUES(MAT, TEXTO(1), TEXTO(2), TO_DATE(TEXTO(3), 'DD/MM/YYYY'),
35 TEXTO(4), TO_NUMBER(TEXTO(5), 'L999G999D99', 'NLS_CURRENCY=R$'));
36 MAT := MAT + 1;
37 END LOOP;
38 END;
39 /
3.67) Faça um programa que gere um arquivo contendo as seguintes colunas da tabela de funcionários: cd_mat,
nm_func, nm_sobrenome, dt_nasc, vl_sal.
Listagem-resposta 3.67A
SQL> DECLARE
2 ARQ UTL_FILE.FILE_TYPE;
3 BEGIN
4 ARQ := UTL_FILE.FOPEN('D:\TESTE', 'R67.TXT', 'A');
5 FOR R1 IN (SELECT CD_MAT,
6 NVL(NM_FUNC, '*') NM_FUNC,
7 NVL(NM_SOBRENOME, '*') NM_SOBRENOME,
8 NVL(VL_SAL, -1) VL_SAL,
9 NVL(TO_CHAR(DT_NASC, 'DD/MM/YYYY'), ' ') DT_NASC
10 FROM FUNC) LOOP
11 UTL_FILE.PUT(ARQ, LPAD(R1.CD_MAT, 5));
12 UTL_FILE.PUT(ARQ, RPAD(R1.NM_FUNC, 12));
13 UTL_FILE.PUT(ARQ, RPAD(R1.NM_SOBRENOME, 12));
14 UTL_FILE.PUT(ARQ, LPAD(R1.VL_SAL, 14));
15 UTL_FILE.PUT(ARQ, R1.DT_NASC);
16 UTL_FILE.NEW_LINE(ARQ, 1);
17 END LOOP;
18 UTL_FILE.FFLUSH(ARQ);
19 UTL_FILE.FCLOSE(ARQ);
20 END;
21 /
Procedimento PL/SQL concluído com sucesso.
Listagem-resposta 3.67B
60IRACY SOUZA 3547,507/07/1955
70EVA PEREIRA 3978,726/05/1963
90ELIANE HONOFRE 3272,515/05/1971
100TEODORO SIQUEIRA 2876,518/12/1966
110VICENTE LOURENCO 511505/11/1969
3.68) Faça um programa que leia um arquivo e realize a carga na tabela de funcionários, completando os dados de
acordo com as seguintes especificações: Data de admissão (será igual à data do cadastramento), Ramal (fixo igual a
1354), salário (fixo igual a 1.000,00) e cargo (fixo igual a 55).
Listagem-resposta 3.68A
SQL> DECLARE
2 ARQ UTL_FILE.FILE_TYPE;
3 RFUNC FUNC%ROWTYPE;
4 LINHA VARCHAR2(100);
5 MAT NUMBER;
6 BEGIN
7 ARQ := UTL_FILE.FOPEN('D:\TESTE', 'ENTRADA.SQL', 'R');
8 SELECT NVL(MAX(CD_MAT), 0) + 1 INTO MAT
9 FROM FUNC;
10 LOOP
11 UTL_FILE.GET_LINE(ARQ, LINHA);
12 RFUNC.NM_FUNC := UPPER(RTRIM(LTRIM(SUBSTR(LINHA,1,12))));
13 RFUNC.NM_SOBRENOME := UPPER(RTRIM(LTRIM(SUBSTR(LINHA,13,12))));
14 RFUNC.DT_NASC := TO_DATE(SUBSTR(LINHA,25,6), 'DDMMYY');
15 RFUNC.NR_GIT := SUBSTR(LINHA,33,2);
16 RFUNC.IN_SEXO := UPPER(SUBSTR(LINHA,35,1));
17 INSERT INTO FUNC
18 (CD_MAT, NM_FUNC, NM_SOBRENOME, DT_NASC, NR_GIT,
19 IN_SEXO, DT_ADM, NR_RAMAL, NR_CARGO, VL_SAL)
20 VALUES
21 (MAT, RFUNC.NM_FUNC, RFUNC.NM_SOBRENOME, RFUNC.DT_NASC,
22 RFUNC.NR_GIT, RFUNC.IN_SEXO, SYSDATE, 1354, 55, 1000);
23 MAT := MAT + 1;
24 END LOOP;
25 EXCEPTION
26 WHEN NO_DATA_FOUND THEN
27 UTL_FILE.FCLOSE(ARQ);
28 COMMIT;
29 END;
30 /
Procedimento PL/SQL concluído com sucesso.
3.69) Gere um arquivo a partir da tabela Func com as seguintes informações: nome, sobrenome, data de nascimento
(formato dd/mm/yyyy), sexo e salário.
Os dados devem ser separados pelo símbolo # (não deve haver alinhamento de colunas).
Caso uma determinada coluna esteja sem valor (Null), deve ser feita substituição por: “**” para as colunas
alfanuméricas e -1 para as colunas numéricas.
Use o pacote UTL_FILE para gerar o arquivo.
Listagem-resposta 3.69A
SQL> DECLARE
2 ARQ UTL_FILE.FILE_TYPE;
3 CURSOR C1 IS SELECT NVL(NM_FUNC, '**')
4 ||'#'||NVL(NM_SOBRENOME, '**')
5 ||'#'||NVL(IN_SEXO, '**')
6 ||'#'||NVL(TO_CHAR(DT_NASC, 'DDMMYYYY'), '**')
7 ||'#'||NVL(VL_SAL,'-1') TEXTO
8 FROM FUNC;
9 BEGIN
10 ARQ := UTL_FILE.FOPEN('D:\TESTE', 'R69.TXT', 'A');
11 FOR R1 IN C1 LOOP
12 UTL_FILE.PUT_LINE(ARQ, R1.TEXTO);
13 END LOOP;
14 UTL_FILE.FFLUSH(ARQ);
15 UTL_FILE.FCLOSE(ARQ);
16 END;
17 /
Procedimento PL/SQL concluído com sucesso.
3.70) Leia o arquivo gerado pelo exercício anterior e crie novas linhas na tabela Func. O número da matrícula deve
ser gerado com o uso de um Sequence de valor inicial 400.
Use o pacote UTL_FILE para ler o arquivo.
Listagem-resposta 3.70A
SQL> CREATE SEQUENCE SEQMAT START WITH 400;
Seqüência criada.
SQL> DECLARE
2 TYPE TAB IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
3 LINHA VARCHAR2(100);
4 ARQ UTL_FILE.FILE_TYPE;
5 I NUMBER := 0;
6 POS NUMBER := 0;
7 TF TAB;
8 BEGIN
9 ARQ := UTL_FILE.FOPEN('D:\TESTE', 'R69.TXT', 'R');
10 LOOP
11 UTL_FILE.GET_LINE(ARQ, LINHA);
12 POS := INSTR(LINHA, '#');
13 I := 0;
14 WHILE POS > 0 LOOP
15 I := I + 1;
16 TF(I) := SUBSTR(LINHA,1,POS - 1);
17 LINHA := SUBSTR(LINHA, POS + 1);
18 POS := INSTR(LINHA, '#');
19 END LOOP;
20 I := I + 1;
21 TF(I) := LINHA;
22 FOR J IN 1..5 LOOP
23 IF TF(I) = '**' OR TF(I) = '-1' THEN
24 TF(I) := NULL;
25 END IF;
26 END LOOP;
27 INSERT INTO FUNC(CD_MAT, NM_FUNC, NM_SOBRENOME, IN_SEXO, DT_NASC, VL_SAL)
28 VALUES(SEQMAT.NEXTVAL,TF(1), TF(2), TF(3), TO_DATE(TF(4), 'DD/MM/YYYY'),TF(5));
29 END LOOP;
30 EXCEPTION
31 WHEN NO_DATA_FOUND THEN
32 UTL_FILE.FCLOSE(ARQ);
33 COMMIT;
34 END;
35 /
Procedimento PL/SQL concluído com sucesso.
3.71) Faça uma rotina que envie mensagem para um Pipe público de nome “Publico”. Pode-se enviar dados
numéricos, alfanuméricos ou datas.
Listagem-resposta 3.71A
SQL> CREATE OR REPLACE PACKAGE PIPE IS
2 PROCEDURE ENVIA (TEXTO IN VARCHAR2);
3 PROCEDURE ENVIA (TEXTO IN NUMBER);
4 PROCEDURE ENVIA (TEXTO IN DATE);
5 END;
6 /
Pacote criado.
Foram criadas três rotinas Envia dentro do pacote PIPE: uma para enviar dados alfanuméricos, outra para envio de
dados numéricos e a última para datas.
3.72) Faça uma rotina que envie mensagem para um Pipe privativo de nome “Interno”. Pode-se enviar dados
numéricos, alfanuméricos ou datas.
Listagem-resposta 3.72A
SQL> CREATE OR REPLACE PACKAGE LPIPE IS
2 PROCEDURE CRIA_PIPE;
3 PROCEDURE ENVIA (TEXTO IN VARCHAR2);
4 END;
5 /
Pacote criado.
O pacote LPIPE é similar ao anterior, com a diferença da existência de uma rotina chamada Cria_Pipe que faz a criação
do Pipe Interno, de acesso exclusivo do usuário Desenv. Apresentamos apenas uma das rotinas Envia, neste caso.
3.73) Faça uma rotina que receba dados de um Pipe informado como parâmetro. Se não for informado o nome do
Pipe, faça a leitura do Pipe público.
Listagem-resposta 3.73A
SQL> CREATE OR REPLACE PROCEDURE RECEBE (PIPE IN VARCHAR2 := 'PUBLICO') IS
2 TEXTO VARCHAR2(100);
3 NUMERO NUMBER;
4 DATA DATE;
5 RETORNO PLS_INTEGER;
6 TIPO PLS_INTEGER := 0;
7 PRIVILEGIO EXCEPTION;
8 PRAGMA EXCEPTION_INIT(PRIVILEGIO, -23322);
9 BEGIN
10 LOOP
11 RETORNO := DBMS_PIPE.RECEIVE_MESSAGE(PIPE, 4);
12 IF RETORNO = 0 THEN
13 TIPO := DBMS_PIPE.NEXT_ITEM_TYPE;
14 WHILE TIPO <> 0 LOOP
15 IF TIPO = 6 THEN
16 DBMS_PIPE.UNPACK_MESSAGE(NUMERO);
17 DBMS_OUTPUT.PUT_LINE('NUMERO = '||NUMERO);
18 ELSIF TIPO = 9 THEN
19 DBMS_PIPE.UNPACK_MESSAGE(TEXTO);
20 DBMS_OUTPUT.PUT_LINE('TEXTO = '||TEXTO);
21 ELSIF TIPO = 12 THEN
22 DBMS_PIPE.UNPACK_MESSAGE(DATA);
23 DBMS_OUTPUT.PUT_LINE('DATA = '||TO_CHAR(DATA, 'DD/MM/YYYY'));
24 END IF;
25 TIPO := DBMS_PIPE.NEXT_ITEM_TYPE;
26 END LOOP;
27 ELSIF RETORNO = 1 THEN
28 EXIT;
29 ELSE
30 DBMS_OUTPUT.PUT_LINE('ERRO NA LEITURA DO PIPE '||PIPE||' = '||RETORNO);
31 EXIT;
32 END IF;
33 END LOOP;
34 EXCEPTION
35 WHEN PRIVILEGIO THEN
36 DBMS_OUTPUT.PUT_LINE('NÃO POSSUI PRIVILÉGIO PARA ACESSO AO PIPE '||PIPE);
37 END;
38 /
Procedimento criado.
Isso ocorre porque os programas armazenados na base executam no mesmo privilégio de domínio do userid criador
da rotina e do Pipe, que no nosso caso para ambas as situações é o usuário Desenv.
Se você quiser se aprofundar nos testes relativos a privilégios, crie um script para cada uma das etapas e não o
armazene na base de dados. Desta forma, a criação do Pipe será realizada pelo usuário que submeter o script e a
tentativa de envio (ou leitura) será realizada pelo usuário que submeter o script (se for usuário diferente daquele
que criou o Pipe, não conseguirá enviar/ler a mensagem).
3.75) Faça um programa que ordene as linhas da tabela Func por bloco e linha. Estabeleça uma quebra por bloco.
Listagem-resposta 3.75A
SQL> DECLARE
2 CURSOR C1 IS SELECT DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BLOCO,
3 DBMS_ROWID.ROWID_ROW_NUMBER(ROWID) LINHA,
4 CD_MAT, NM_FUNC, VL_SAL
5 FROM FUNC
6 ORDER BY BLOCO, LINHA;
7 BLOCO NUMBER := -1;
8 BEGIN
9 DBMS_OUTPUT.ENABLE(1000000);
10 FOR R1 IN C1 LOOP
11 IF R1.BLOCO <> BLOCO THEN
12 DBMS_OUTPUT.PUT_LINE(CHR(10));
13 DBMS_OUTPUT.PUT_LINE('BLOCO LINHA MATR NOME SALARIO');
14 DBMS_OUTPUT.PUT_LINE(CHR(10));
15 END IF;
16 BLOCO := R1.BLOCO;
17 DBMS_OUTPUT.PUT_LINE(TO_CHAR(R1.BLOCO, '00009')||
18 TO_CHAR(R1.LINHA, '999999')||
19 TO_CHAR(R1.CD_MAT, '00099')||' '||
20 RPAD(R1.NM_FUNC, 12)||LPAD(R1.VL_SAL, 10));
21 END LOOP;
22 END;
23 /
3.76) Suponhamos que regularmente recebêssemos para atualização o seguinte arquivo de layout:
Informação Coluna
Operação 1-1
Rowid (versão 7) 3-20
Nome 22-33
Sobrenome 35-46
Salário 48-59
Listagem-resposta 3.76A
SQL> DECLARE
2 ARQ UTL_FILE.FILE_TYPE;
3 ROW9 ROWID;
4 RF FUNC%ROWTYPE;
5 BUFFER VARCHAR2(100);
6 OPE VARCHAR2(1);
7 BEGIN
8 ARQ := UTL_FILE.FOPEN('D:\TESTE', 'ROW.SQL', 'R');
9 LOOP
10 UTL_FILE.GET_LINE(ARQ, BUFFER);
11 OPE := SUBSTR(BUFFER,1,1);
12 ROW9 := DBMS_ROWID.ROWID_TO_EXTENDED(SUBSTR(BUFFER,3,18),
13 'DESENV', 'FUNC', 1);
14 RF.NM_FUNC := LTRIM(RTRIM(SUBSTR(BUFFER,22,12)));
15 RF.NM_SOBRENOME := LTRIM(RTRIM(SUBSTR(BUFFER,35,12)));
16 RF.VL_SAL := TO_NUMBER(SUBSTR(BUFFER,48,12));
17 IF OPE = 'A' THEN
18 UPDATE FUNC
19 SET NM_FUNC = RF.NM_FUNC,
20 NM_SOBRENOME = RF.NM_SOBRENOME,
21 VL_SAL = RF.VL_SAL
22 WHERE ROWID = ROW9;
23 ELSIF OPE = 'E' THEN
24 DELETE FROM FUNC WHERE ROWID = ROW9;
25 END IF;
26 END LOOP;
27 EXCEPTION
28 WHEN NO_DATA_FOUND THEN
29 COMMIT;
30 UTL_FILE.FCLOSE(ARQ);
31 END;
32 /
Procedimento PL/SQL concluído com sucesso.
3.77) Gere uma massa de dados para atender ao exercício anterior. Obtenha os dados da própria tabela Func. Não
inclua na massa os gerentes de departamento e os responsáveis por projeto.
Na massa devem estar presentes, pelo menos, três alterações e duas exclusões.
Listagem-resposta 3.77A
SQL> DECLARE
2 CURSOR C1 IS SELECT 'A' OPER,
3 DBMS_ROWID.ROWID_TO_RESTRICTED(ROWID, 0) ROW7,
4 NM_FUNC, NM_SOBRENOME, VL_SAL
5 FROM FUNC
6 WHERE CD_MAT NOT IN (SELECT CD_GERENTE FROM DEPTO
7 WHERE CD_GERENTE IS NOT NULL)
8 AND CD_MAT NOT IN (SELECT DISTINCT CD_RESP FROM PROJ
9 WHERE CD_RESP IS NOT NULL);
10 BEGIN
11 FOR R1 IN C1 LOOP
12 DBMS_OUTPUT.PUT(R1.OPER);
13 DBMS_OUTPUT.PUT(R1.ROW7);
14 DBMS_OUTPUT.PUT(RPAD(R1.NM_FUNC,12));
15 DBMS_OUTPUT.PUT(RPAD(R1.NM_SOBRENOME,12));
16 DBMS_OUTPUT.PUT_LINE(LPAD(R1.VL_SAL,12));
17 END LOOP;
18 END;
19 /
A00000032.0009.0008SILVIO OLIVA 4000
A00000032.000B.0008HELENA NOVAES 3126,2
A00000032.000D.0008ELIZABET PINTO 2447,5
Para desenvolvimentos dos exercícios deste tópico crie as tabelas Tlob_E e Func_Lob. Preencha a tabela Func_Lob
a partir das tabelas Func e Depto. Use o script R03_00.SQL.
Id Number(03)
C_Blob Blob
S_Blob Number
C_BFile BFile
S_BFile Number
C_Clob Clob
S_Clob Number
SQL> COMMIT;
Validação completa.
3.78) Faça um bloco de PL/SQL que receba como parâmetro uma matrícula e um texto. Adicione o texto ao fim do
nome do funcionário. Use Dbms_Lob.Write (tabela Func_Lob).
Listagem-resposta 3.78A
SQL> CREATE OR REPLACE
2 PROCEDURE ANEXA(PMAT IN NUMBER, PTEXTO IN VARCHAR2) IS
3 CURSOR C1 IS SELECT NOME_FUNC, NOME_DEPTO FROM FUNC_LOB
4 WHERE MAT = PMAT FOR UPDATE;
5 BEGIN
6 FOR R1 IN C1 LOOP
7 DBMS_LOB.WRITE(R1.NOME_FUNC, LENGTH(PTEXTO),
8 DBMS_LOB.GETLENGTH(R1.NOME_FUNC) + 1, PTEXTO);
9 END LOOP;
10 END;
11 /
Procedimento criado.
NOME_FUNC
----------------------------------------------------------------
CRISTIANA HENDERSON TEXTO INCLUÍDO AO FIM DO NOME DO FUNCIONÁRIO
3.79) Faça um bloco de PL/SQL que apresente o nome do funcionário e o nome do departamento em que ele
trabalha. O programa recebe como parâmetro a matrícula do funcionário. Use Dbms_Lob.Read (tabela Func_lob).
Listagem-resposta 3.79A
SQL> CREATE OR REPLACE
2 PROCEDURE LISTA(PMAT IN NUMBER) IS
3 CURSOR C1 IS SELECT NOME_FUNC, NOME_DEPTO FROM FUNC_LOB
4 WHERE MAT = PMAT;
5 W_NM_DEPTO VARCHAR2(1000);
6 W_NM_FUNC VARCHAR2(1000);
7 TAM NUMBER := 1000;
8 BEGIN
9 FOR R1 IN C1 LOOP
10 DBMS_LOB.READ(R1.NOME_FUNC, TAM, 1, W_NM_FUNC);
11 TAM := 1000;
12 DBMS_LOB.READ(R1.NOME_DEPTO, TAM, 1, W_NM_DEPTO);
13 DBMS_OUTPUT.PUT_LINE('Nome do funcionário -> '|| W_NM_FUNC);
14 DBMS_OUTPUT.PUT_LINE('Nome do departamento -> '|| W_NM_DEPTO);
15 END LOOP;
16 END;
17 /
Procedimento criado.
3.80) Faça um bloco de PL/SQL que receba como parâmetro uma letra e uma matrícula. Verifique quantas vezes a
letra recebida existe em Nome_Depto. Use Dbms_Lob.Instr (tabela Func_Lob).
Listagem-resposta 3.80A
SQL> CREATE OR REPLACE
2 PROCEDURE LETRA(PMAT IN NUMBER, PLETRA IN VARCHAR2) IS
3 CURSOR C1 IS SELECT NOME_FUNC, NOME_DEPTO FROM FUNC_LOB
4 WHERE MAT = PMAT FOR UPDATE;
5 POS NUMBER := 1;
6 QTD NUMBER := 0;
7 BEGIN
8 FOR R1 IN C1 LOOP
9 POS := DBMS_LOB.INSTR(R1.NOME_DEPTO, PLETRA, 1);
10 WHILE POS > 0 LOOP
11 QTD := QTD + 1;
12 POS := DBMS_LOB.INSTR(R1.NOME_DEPTO, PLETRA, POS + 1);
13 END LOOP;
14 DBMS_OUTPUT.PUT_LINE('A QUANTIDADE DE LETRAS '||PLETRA||' É '||QTD);
15 END LOOP;
16 END;
17 /
Procedimento criado.
NOME_DEPTO
--------------------
DIRETORIA DA EMPRESA
3.81) Faça uma rotina que receba como parâmetro um ID e um nome de arquivo (o diretório em uso será Win-
dows). Carregue esse arquivo para a coluna Bfile e para a coluna Blob do ID especificado. Se este ID já existir efetue
uma alteração. Calcule o tamanho dos objetos incluídos ou recalcule para os alterados.
Listagem-resposta 3.81A
SQL> CREATE OR REPLACE
2 PROCEDURE CARGA_ARQ(ID IN NUMBER, ARQUIVO IN VARCHAR2) IS
3 CURSOR C1 IS SELECT C_BLOB, C_BFILE, S_BLOB,
4 S_BFILE, C_ID
5 FROM TLOB_E
6 WHERE C_ID = ID FOR UPDATE;
7 EXISTE BOOLEAN := FALSE;
8 C_BLOB BLOB;
9 BEGIN
10 FOR R1 IN C1 LOOP
11 EXISTE := TRUE;
12 R1.C_BFILE := BFILENAME('WINDOWS', ARQUIVO);
13 R1.S_BFILE := DBMS_LOB.GETLENGTH(R1.C_BFILE);
14 DBMS_LOB.FILEOPEN(R1.C_BFILE);
15 DBMS_LOB.LOADFROMFILE(R1.C_BLOB, R1.C_BFILE, R1.S_BFILE);
16 R1.S_BLOB := DBMS_LOB.GETLENGTH(R1.C_BLOB);
17 UPDATE TLOB_E
18 SET S_BLOB = R1.S_BLOB,
19 S_BFILE = R1.S_BFILE
20 WHERE C_ID = ID;
21 DBMS_LOB.FILECLOSE(R1.C_BFILE);
22 END LOOP;
23 IF NOT EXISTE THEN
24 INSERT INTO TLOB_E (C_BLOB, C_BFILE, S_BLOB, S_BFILE, C_ID)
25 VALUES (EMPTY_BLOB(), BFILENAME('WINDOWS',ARQUIVO), 0, 0, ID);
26 FOR R1 IN C1 LOOP
27 DBMS_LOB.FILEOPEN(R1.C_BFILE);
28 DBMS_LOB.LOADFROMFILE(R1.C_BLOB, R1.C_BFILE,
29 DBMS_LOB.GETLENGTH(R1.C_BFILE));
30 UPDATE TLOB_E
31 SET S_BLOB = DBMS_LOB.GETLENGTH(C_BLOB),
32 S_BFILE= DBMS_LOB.GETLENGTH(C_BFILE)
33 WHERE C_ID = ID;
34 DBMS_LOB.FILECLOSE(R1.C_BFILE);
35 END LOOP;
36 END IF;
37 END;
38 /
Procedimento criado.
3.82) Faça um programa que receba como parâmetro um texto e um ID e atualize o Clob do ID correspondente.
Não deve ser feita substituição, somente adição é permitida. Recalcule o tamanho do objeto.
Listagem-resposta 3.82A
SQL> CREATE OR REPLACE
2 PROCEDURE CARGA_TXT(ID IN NUMBER, TEXTO IN VARCHAR2) IS
3 CURSOR C1 IS SELECT C_CLOB, ROWID
4 FROM TLOB_E
5 WHERE C_ID = ID
6 FOR UPDATE;
7 R1 C1%ROWTYPE;
8 BEGIN
9 OPEN C1;
10 FETCH C1 INTO R1;
11 IF C1%FOUND THEN
12 IF R1.C_CLOB IS NULL THEN
13 UPDATE TLOB_E
14 SET C_CLOB = EMPTY_CLOB()
15 WHERE ROWID = R1.ROWID;
16 END IF;
17 CLOSE C1;
18 OPEN C1;
19 FETCH C1 INTO R1;
20 DBMS_LOB.WRITE(R1.C_CLOB, LENGTH(TEXTO),
21 DBMS_LOB.GETLENGTH(R1.C_CLOB) + 1, TEXTO);
22 UPDATE TLOB_E
23 SET S_CLOB = DBMS_LOB.GETLENGTH(R1.C_CLOB)
24 WHERE C_ID = ID;
25 ELSE
26 INSERT INTO TLOB_E(C_CLOB, S_CLOB, C_ID)
27 VALUES(TEXTO, LENGTH(TEXTO), ID);
28 END IF;
29 END;
30 /
Procedimento criado.
SQL> BEGIN
2 CARGA_TXT(1, 'PRIMEIRO TEXTO CARREGADO');
3 CARGA_TXT(2, 'SEGUNDO TEXTO INCLUÍDO NO ID 2');
4 CARGA_TXT(3, 'NOVO TEXTO PREENCHENDO C_CLOB PARA ID 3');
5 END;
6 /
Procedimento PL/SQL concluído com sucesso.
3.83) Faça um programa que pesquise um texto em um Clob ou pesquise um trecho binário em um Blob. Determine:
A) A quantidade de elementos encontrados.
B) Para os textos, os dez primeiros bytes após o texto e a posição inicial.
C) Para os binários, a posição encontrada.
Listagem-resposta 3.83A
SQL> CREATE OR REPLACE PACKAGE PROCURA IS
2 FUNCTION PRO_TEXTO(TEXTO IN VARCHAR2, LOB IN CLOB) RETURN VARCHAR2;
3 PRAGMA RESTRICT_REFERENCES(PRO_TEXTO, WNDS);
4 FUNCTION PRO_BLOB(BINARIO IN RAW, LOB IN BLOB) RETURN VARCHAR2;
5 PRAGMA RESTRICT_REFERENCES(PRO_BLOB, WNDS);
6 END PROCURA;
7 /
Pacote criado.
PROCURA.PRO_TEXTO('A',C_CLOB)
-----------------------------
ARREGADO—>17;22;
—>
ARA ID 3-—>32;34;
3.84) Faça um programa que copie o Clob de uma linha para outra da tabela Tlob_E. Os parâmetros são: ID da
origem, ID do destino e posição inicial da origem.
Listagem-resposta 3.84A
SQL> CREATE OR REPLACE
2 PROCEDURE COPIA(ID_ORIGEM IN NUMBER, ID_DESTINO IN NUMBER, INICIO IN NUMBER) IS
3 LOB_ORIGEM CLOB;
4 LOB_DESTINO CLOB;
5 QTD NUMBER := DBMS_LOB.LOBMAXSIZE;
6 BEGIN
7 SELECT C_CLOB INTO LOB_ORIGEM
8 FROM TLOB_E
9 WHERE C_ID = ID_ORIGEM
10 FOR UPDATE;
11 SELECT C_CLOB INTO LOB_DESTINO
12 FROM TLOB_E
13 WHERE C_ID = ID_DESTINO
14 FOR UPDATE;
15 DBMS_LOB.ERASE(LOB_DESTINO, QTD,INICIO);
16 DBMS_LOB.APPEND(LOB_DESTINO, LOB_ORIGEM);
17 UPDATE TLOB_E
18 SET S_CLOB = DBMS_LOB.GETLENGTH(C_CLOB)
19 WHERE C_ID = ID_DESTINO;
20 COMMIT;
21 END;
22 /
Procedimento criado.
3.85) Suponhamos que desejássemos salvar os fontes dos programas dentro do banco de dados. Os fontes podem
ser texto ou arquivos binários, com as extensões: Txt, Fmb (binário), Mmb (binário). Faça um programa que receba
como parâmetro o diretório, o nome do arquivo (sem a extensão) e seu tipo (corresponde à extensão do arquivo)
e carregue-o para a coluna Blob ou para a coluna Clob, dependendo do tipo do arquivo.
Utilize as tabelas apresentadas na Listagem-resposta 3.85A.
Listagem-resposta 3.85A
SQL> CREATE TABLE COFRE
2 (FONTE VARCHAR2(200) PRIMARY KEY,
3 FBIN BLOB,
4 FTEXTO CLOB);
Tabela criada.
Listagem-resposta 3.85B
SQL> CREATE OR REPLACE
2 PROCEDURE SALVA(DIR IN VARCHAR2,
3 ARQUIVO IN VARCHAR2,
4 TIPO IN VARCHAR2 := 'FMB') IS
5 CURSOR C1 IS SELECT * FROM COFRE
6 WHERE FONTE = ARQUIVO||'.'||TIPO;
7 ARQ BFILE;
8 R1 C1%ROWTYPE;
9 BEGIN
10 SELECT DUMMY_BFILE INTO ARQ FROM LOB_DUAL;
11 ARQ := BFILENAME(DIR, ARQUIVO||'.'||TIPO);
12 OPEN C1;
13 FETCH C1 INTO R1;
14 IF C1%NOTFOUND THEN
3.86) Obtenha todos os textos presentes na tabela Tlob, retire os brancos encontrados e concatene em um único
campo. Apresente o tamanho do texto resultante.
Listagem-resposta 3.86A
SQL> DECLARE
2 LOB_TEMP CLOB;
3 LOB_TOTAL CLOB;
4 POS NUMBER := 2000;
5 TEXTO VARCHAR2(2000);
6 CURSOR C1 IS SELECT C_CLOB1 FROM TLOB;
7 BEGIN
8 DBMS_LOB.CREATETEMPORARY(LOB_TEMP, TRUE, DBMS_LOB.SESSION);
9 DBMS_LOB.CREATETEMPORARY(LOB_TOTAL, TRUE, DBMS_LOB.SESSION);
10 FOR R1 IN C1 LOOP
11 IF R1.C_CLOB1 IS NOT NULL THEN
12 POS := DBMS_LOB.GETLENGTH(R1.C_CLOB1);
13 LOB_TEMP := R1.C_CLOB1;
14 WHILE POS > 2000 LOOP
15 TEXTO := DBMS_LOB.SUBSTR(LOB_TEMP, 2000, 1);
16 TEXTO := REPLACE(TEXTO,' ');
17 DBMS_LOB.WRITEAPPEND(LOB_TOTAL, LENGTH(TEXTO), TEXTO);
18 DBMS_LOB.COPY(LOB_TEMP, LOB_TEMP, POS - 2000,2000,1);
19 END LOOP;
20 TEXTO := DBMS_LOB.SUBSTR(LOB_TEMP, POS, 1);
21 TEXTO := REPLACE(TEXTO,' ');
22 DBMS_LOB.WRITEAPPEND(LOB_TOTAL, LENGTH(TEXTO), TEXTO);
23 END IF;
24 END LOOP;
25 POS := DBMS_LOB.GETLENGTH(LOB_TOTAL);
26 DBMS_OUTPUT.PUT_LINE('TAMANHO TOTAL É '||POS);
27 DBMS_LOB.FREETEMPORARY(LOB_TOTAL);
28 LOB_TEMP := LOB_TOTAL;
29 END;
30 /
TAMANHO TOTAL É 454
Procedimento PL/SQL concluído com sucesso.
Para que pudéssemos realizar as especificações, criamos dois Lobs temporários para manuseio dos dados. Um
chama-se Lob_Temp, que seria recortado para realizar a transferência dos pedaços da informação para uma variável
Varchar2. O outro Lob (chamado Lob_Total) é utilizado como acumulador para armazenamento dos pedaços de
informação já trabalhados.
Ao término do programa, os dois Lobs são liberados. Não ocorre atualização na informação original da tabela.
3.87) Faça uma rotina que, aleatoriamente, escolha 3 funcionários para premiação de Natal da empresa.
Listagem-resposta 3.87A
SQL> DECLARE
2 NUMP NUMBER;
3 MAT NUMBER;
4 CALC NUMBER;
5 TYPE TPREM IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
6 PREMIO TPREM;
7 BEGIN
8 SELECT MAX(CD_MAT)+1 INTO MAT FROM FUNC;
9 CALC := EXTRACT(MINUTE FROM CURRENT_TIMESTAMP) +
10 EXTRACT(SECOND FROM CURRENT_TIMESTAMP);
11 DBMS_RANDOM.INITIALIZE(CALC);
12 FOR I IN 1..MAT LOOP
13 NUMP := MOD(ABS(DBMS_RANDOM.RANDOM), MAT);
14 SELECT CUME_DIST(NUMP) WITHIN GROUP (ORDER BY CD_MAT ASC) INTO CALC
15 FROM FUNC WHERE CD_MAT BETWEEN (NUMP - 100) AND (NUMP + 100);
16 SELECT PERCENTILE_DISC(CALC) WITHIN GROUP (ORDER BY CD_MAT) INTO CALC
17 FROM FUNC
18 WHERE CD_MAT BETWEEN (NUMP - 100) AND (NUMP + 100);
19 PREMIO(NVL(PREMIO.LAST,0) + 1) := CALC;
20 FOR I IN 1..(PREMIO.LAST - 1) LOOP
21 IF PREMIO(I) = CALC THEN
22 PREMIO.DELETE(PREMIO.LAST);
23 END IF;
24 END LOOP;
25 IF PREMIO.LAST = 3 THEN
26 EXIT;
27 END IF;
28 END LOOP;
29 :MSG := 'OS FUNCIONÁRIOS SORTEADOS SÃO : ';
30 FOR I IN 1..PREMIO.LAST LOOP
31 :MSG := :MSG ||PREMIO(I)||' ';
32 END LOOP;
33 END;
34 /
Procedimento PL/SQL concluído com sucesso.
MSG
---------------------------------------------
OS FUNCIONÁRIOS SORTEADOS SÃO : 310 426 320
3.88) Sabendo-se que uma roleta contém 25 números vermelhos (ímpares) e 25 números pretos (pares). Determine
o número ganhador e se ele é vermelho ou preto.
Listagem-resposta 3.88A
SQL> DECLARE
2 NUMP NUMBER;
3 CALC NUMBER;
4 BEGIN
5 CALC := EXTRACT(MINUTE FROM CURRENT_TIMESTAMP) +
6 EXTRACT(SECOND FROM CURRENT_TIMESTAMP);
7 DBMS_RANDOM.INITIALIZE(CALC);
8 NUMP := MOD(ABS(DBMS_RANDOM.RANDOM), 51);
9 IF MOD(NUMP,2) = 0 THEN
10 :MSG := 'O ganhador é '||NUMP||' preto';
11 ELSE
12 :MSG := 'O ganhador é '||NUMP||' vermelho';
13 END IF;
14 END;
15 /
Procedimento PL/SQL concluído com sucesso.
MSG
---------------------
O ganhador é 46 preto
3.89) Faça uma rotina que coloque no SQL*Prompt, a cada vez que o usuário quiser ou quando este abrir o SQL*Plus
o último SCN.
Listagem-resposta 3.89A
SQL> SET SERVEROUT ON
SQL> SPOOL SCN.SQL
SQL> DECLARE
2 TEXTO VARCHAR2(100);
3 WSCN NUMBER;
4 BEGIN
5 WSCN := DBMS_FLASHBACK.Get_System_Change_Number;
Se você desejar que este valor seja apresentado imediatamente após o usuário abrir o SQL*Plus, inclua a chamada
a este programa no arquivo GLOGIN.SQL. Isto afetará todos os usuários simultaneamente.
3.90) Faça uma rotina que a partir de um SCN recebido como parâmetro gere um arquivo com as diferenças
encontradas, na tabela de Funcionários, entre a versão na data do SCN e a atual.
Listagem-resposta 3.90A
SCN 736605> DELETE FROM FUNC WHERE CD_MAT = 403;
1 linha deletada.
SCN 736605> INSERT INTO FUNC (CD_MAT, NM_FUNC, VL_SAL) VALUES (5, 'Jorgete', 3000);
1 linha criada.
SCN 736605> UPDATE FUNC SET VL_SAL = 4000 WHERE CD_MAT = 120;
1 linha atualizada.
45 /
Entre o valor para pscn: 736605
O funcionário Jorgete matrícula 5 foi incluído
O funcionário SILVIO matrícula 120 sofreu modificações no salário: valor antigo
= 3217,5 valor atual = 4000
O funcionário JOAO matrícula 403 foi removido
3.91) Crie uma stored procedure que faça a atualização dos salários dos funcionários de acordo com os parâmetros:
cargo e percentual.
Se o funcionário for líder de projeto (cd_resp da tabela Proj), deve ser feito um acréscimo de 3% ao percentual
fornecido. Se o funcionário for gerente de departamento (cd_gerente da tabela Depto), deve ser feita uma adição
de 4% ao percentual acumulado.
Listagem-resposta 3.91A
SQL> CREATE OR REPLACE
2 PROCEDURE ATUALIZA(CARGO IN NUMBER, PERC IN NUMBER) IS
3 PCT NUMBER;
4 CURSOR C1 IS SELECT CD_MAT, VL_SAL, CD_GERENTE
5 FROM FUNC, DEPTO
6 WHERE NR_CARGO = CARGO
7 AND FUNC.CD_DEPTO = DEPTO.CD_DEPTO(+)
8 AND CD_MAT = CD_GERENTE(+)
9 FOR UPDATE OF VL_SAL;
10 RESP NUMBER;
11 BEGIN
12 FOR R1 IN C1 LOOP
13 PCT := PERC;
14 BEGIN
15 SELECT DISTINCT CD_RESP INTO RESP
16 FROM PROJ
17 WHERE CD_RESP = R1.CD_MAT;
18 PCT := PCT + 3;
19 EXCEPTION
20 WHEN NO_DATA_FOUND THEN
21 NULL;
22 END;
23 IF R1.CD_GERENTE IS NOT NULL THEN
24 PCT := PCT + 4;
25 END IF;
26 UPDATE FUNC
27 SET VL_SAL = VL_SAL + (VL_SAL * PCT)/100
28 WHERE CURRENT OF C1;
29 END LOOP;
30 END;
31 /
Procedimento criado.
Após a criação da rotina, consulte a tabela User_Source. Qual o nível de visibilidade do código?
Listagem-resposta 3.91B
SQL> SET LINESIZE 100
SQL> COL TEXT FOR A72
SQL> SELECT LINE, TEXT FROM USER_SOURCE
2 WHERE NAME = 'ATUALIZA'
3 AND LINE <= 5;
LINE TEXT
---------- -------------------------------------------------------
1 PROCEDURE ATUALIZA(CARGO IN NUMBER, PERC IN NUMBER) IS
2 PCT NUMBER;
3 CURSOR C1 IS SELECT CD_MAT, VL_SAL, CD_GERENTE
4 FROM FUNC, DEPTO
5 WHERE NR_CARGO = CARGO
Autorize o uso desta rotina por outro usuário do seu banco, por exemplo, Scott (password Tiger). Estabeleça conexão
como Scott e consulte a tabela All_Source. Qual o nível de visibilidade do código?
Listagem-resposta 3.91C
SQL> GRANT EXECUTE ON ATUALIZA TO SCOTT;
LINE TEXT
---------- -------------------------------------------------------
1 PROCEDURE ATUALIZA(CARGO IN NUMBER, PERC IN NUMBER) IS
2 PCT NUMBER;
3 CURSOR C1 IS SELECT CD_MAT, VL_SAL, CD_GERENTE
4 FROM FUNC, DEPTO
5 WHERE NR_CARGO = CARGO
Figura-resposta 3.91A
Listagem-resposta 3.91D
SQL> CONNECT DESENV/DESENV
Conectado.
SQL> @atualiza.plb
Procedimento criado.
Listagem-resposta 3.91E
SQL> SELECT LINE, TEXT FROM USER_SOURCE
2 WHERE NAME = 'ATUALIZA'
3 AND LINE <= 5;
LINE TEXT
---------- --------------------------
1 PROCEDURE ATUALIZA wrapped
0
abcd
abcd
abcd
abcd
Listagem-resposta 3.92A
SQL> CREATE OR REPLACE PACKAGE CODIGO IS
2 BLOQUEIO NUMBER;
3 PROCEDURE ATUALIZA(CARGO IN NUMBER, PERC IN NUMBER);
4 END;
5 /
Pacote criado.
Após a criação do pacote, consulte a tabela User_Source. Qual o nível de visibilidade do código?
Listagem-resposta 3.92B
SQL> SELECT LINE, TEXT FROM USER_SOURCE
2 WHERE NAME = 'CODIGO'
3 AND LINE <= 5
4 /
LINE TEXT
---------- ---------------------------------------------------------
1 PACKAGE CODIGO IS
2 BLOQUEIO NUMBER;
3 PROCEDURE ATUALIZA(CARGO IN NUMBER, PERC IN NUMBER);
4 END;
1 PACKAGE BODY CODIGO IS
2 PROCEDURE ATUALIZA(CARGO IN NUMBER, PERC IN NUMBER) IS
3 PCT NUMBER;
4 CURSOR C1 IS SELECT CD_MAT, VL_SAL, CD_GERENTE
5 FROM FUNC, DEPTO
9 linhas selecionadas.
Autorize o uso deste pacote por outro usuário do seu banco, por exemplo, Scott (password Tiger). Estabeleça
conexão como Scott e consulte a tabela All_Source. Qual o nível de visibilidade do código?
Listagem-resposta 3.92C
SQL> GRANT EXECUTE ON CODIGO TO SCOTT;
Operação de Grant bem-sucedida.
LINE TEXT
---------- ------------------------------------------------------
1 PACKAGE CODIGO IS
2 BLOQUEIO NUMBER;
3 PROCEDURE ATUALIZA(CARGO IN NUMBER, PERC IN NUMBER);
4 END;
Converta o fonte deste pacote usando o aplicativo Wrapper. Crie novamente a rotina no usuário Desenv.
Listagem-resposta 3.92D
SQL> CONNECT DESENV/DESENV
Conectado.
SQL> @CODIGO.PLB
Pacote criado.
Listagem-resposta 3.92E
SQL> SELECT LINE, TEXT FROM USER_SOURCE
2 WHERE NAME = 'CODIGO'
3 AND LINE <= 5
4 /
LINE TEXT
---------- ----------------------
1 PACKAGE CODIGO wrapped
0
abcd
abcd
abcd
abcd
abcd
abcd
LINE TEXT
---------- ----------------------
1 PACKAGE CODIGO wrapped
0
abcd
abcd
abcd
abcd
abcd
abcd
Quando desejamos apenas que o usuário que venha a executar a rotina não tenha visibilidade do código, podemos
trabalhar com pacotes, que, além de favorecerem à organização, ainda impedem que os demais usuários autorizados
a executar o pacote tenham acesso ao código das rotinas pertencentes ao pacote.
A rotina Wrapper, porém, pode ser extremamente útil quando enviamos código a outras instalações e não desejamos
correr o risco de ter o código modificado ou até mesmo lido.
3.93) Faça um programa que receba como parâmetro uma opção e um número. Se a opção for “Q” retorne o
quadrado do número e se a opção for “D” retorne o dobro do número. Utilize a classe Util.class externa para a
montagem deste exercício.
Listagem-resposta 3.93A
SQL> CREATE DIRECTORY JAVADIR AS 'D:\TESTE';
Diretório criado.
MSG
------------------------------------------
O quadrado do número 3 é 9
SQL> /
Entre o valor para opcao: D
Entre o valor para num: 4
Procedimento PL/SQL concluído com sucesso.
MSG
------------------------------------------
O dobro do número 4 é 8
Se você tiver criado a Java Class durante os exemplos não precisa criá-la agora novamente.
3.94) Faça um programa que receba como parâmetro o tipo de informação a ser apresentada:
A) Nome e sobrenome.
B) Matrícula, cargo e salário.
C) Nome, grau de instrução e data de nascimento.
Use uma única variável cursor e DBMS_OUTPUT para mostrar os resultados.
Listagem-resposta 3.94A
SQL> CREATE OR REPLACE PROCEDURE DISPLAY (OPCAO IN VARCHAR2) IS
2 TYPE VCURSOR IS REF CURSOR;
3 CLER VCURSOR;
4 DADOS VARCHAR2(100);
5 BEGIN
6 DBMS_OUTPUT.ENABLE(1000000);
7 IF UPPER(OPCAO) NOT IN ('A', 'B', 'C') OR
8 OPCAO IS NULL THEN
9 RAISE_APPLICATION_ERROR(-20001, 'OPÇÃO INVÁLIDA');
3.95) Faça três programas, cada um deles deverá receber uma variável cursor e abri-la para as situações apresentadas
no Exercício 3.94.
Listagem-resposta 3.95A
SQL> CREATE OR REPLACE
2 PROCEDURE DNOME(CLER IN OUT SYS_REFCURSOR) IS
3 BEGIN
4 OPEN CLER FOR SELECT NM_FUNC||' '||NM_SOBRENOME FROM FUNC;
5 END;
6 /
Procedimento criado.
3.96) Faça um programa que declare uma variável cursor e, de acordo com o parâmetro recebido, acione cada um
dos programas do Exercício 3.95 e mostre as informações selecionadas.
Listagem-resposta 3.96A
SQL> CREATE OR REPLACE PROCEDURE PROGS(OPCAO IN VARCHAR2) IS
2 CLER SYS_REFCURSOR;
3 DADOS VARCHAR2(100);
4 BEGIN
5 DBMS_OUTPUT.ENABLE(1000000);
6 IF UPPER(OPCAO) NOT IN ('A', 'B', 'C') OR
7 OPCAO IS NULL THEN
8 RAISE_APPLICATION_ERROR(-20001, 'OPÇÃO INVÁLIDA');
9 ELSIF OPCAO = 'A' THEN
10 DNOME(CLER);
11 LOOP
12 FETCH CLER INTO DADOS;
13 EXIT WHEN CLER%NOTFOUND;
14 DBMS_OUTPUT.PUT_LINE(DADOS);
15 END LOOP;
16 ELSIF OPCAO = 'B' THEN
17 DMAT(CLER);
18 LOOP
19 FETCH CLER INTO DADOS;
20 EXIT WHEN CLER%NOTFOUND;
21 DBMS_OUTPUT.PUT_LINE(DADOS);
22 END LOOP;
23 ELSE
24 DGIT(CLER);
25 LOOP
26 FETCH CLER INTO DADOS;
27 EXIT WHEN CLER%NOTFOUND;
28 DBMS_OUTPUT.PUT_LINE(DADOS);
29 END LOOP;
30 END IF;
31 END;
32 /
Procedimento criado.
3.97) Faça um programa que receba como parâmetro o nome da tabela, as colunas a serem criadas e a indicação de
permanência ou não. Faça a criação do objeto no schema do usuário.
Listagem-resposta 3.97
SQL> CREATE OR REPLACE PROCEDURE CRIA_TAB (NOME IN VARCHAR2, COLUNAS IN VARCHAR2,
2 PERMANENTE IN BOOLEAN:= TRUE) IS
3 TEXTO VARCHAR2(2000);
4 BEGIN
5 IF NOT PERMANENTE THEN
6 TEXTO := 'CREATE GLOBAL TEMPORARY TABLE ';
7 ELSE
8 TEXTO := 'CREATE TABLE ';
9 END IF;
10 TEXTO := TEXTO || NOME ||'('||COLUNAS||')';
11 IF PERMANENTE THEN
12 TEXTO := TEXTO ||' ON COMMIT PRESERVE ROWS';
13 END IF;
14 EXECUTE IMMEDIATE TEXTO;
15 END;
16 /
Procedimento criado.
No exercício 3.97, criamos um procedimento bastante simples. Você poderá sofisticá-lo incluindo críticas, por exemplo.
Caso você receba algum erro de privilégio na execução deste comando, estabeleça conexão como SYS (password
default é CHANGE_ON_INSTALL, se você não alterou) e execute o comando GRANT ALL PRIVILEGES TO DESENV.
3.98) Faça um programa que receba como parâmetro o nome das colunas a serem lidas da tabela Func (podem ser
informadas até três colunas separadas por vírgula). Apresente os dados lidos.
Listagem-resposta 3.98A
SQL> CREATE OR REPLACE PROCEDURE LER_FUNC(COLUNAS IN VARCHAR2) IS
2 TEXTO VARCHAR2(2000);
3 TYPE VC1 IS REF CURSOR;
4 A VARCHAR2(100);
5 B VARCHAR2(100);
6 C VARCHAR2(100);
7 C1 VC1;
8 BEGIN
9 TEXTO := 'SELECT '||COLUNAS||' FROM FUNC';
10 OPEN C1 FOR TEXTO;
11 LOOP
12 FETCH C1 INTO A, B, C;
13 EXIT WHEN C1%NOTFOUND;
14 DBMS_OUTPUT.PUT_LINE(A||'-'||B||'-'||C);
15 END LOOP;
16 END;
17 /
Procedimento criado.
Este programa também é bastante simplificado, porque a tabela Func não possui dados complexos; desta forma, a
conversão para varchar2 é sempre possível. Você poderá usar sua imaginação e criar aplicativos bem mais interessantes.
3.99) Faça um trigger para controlar as modificações feitas nos salários dos funcionários.
Para tal crie uma tabela de log com o seguinte layout: operação (I, E ou A), valor anterior, valor atual, matrícula,
timestamp (data + hora).
Listagem-resposta 3.99A
SQL> CREATE TABLE TLOG
2 (OPERACAO VARCHAR2(1),
3 SAL_ANT NUMBER,
4 SAL_ATU NUMBER,
5 MAT NUMBER,
6 TIMESTAMP DATE,
7 PRIMARY KEY (MAT, OPERACAO, TIMESTAMP));
Tabela criada.
Se for feita uma inclusão, apenas o valor atual deve ser preenchido. Para alteração, ambos os valores devem ser
preenchidos; para exclusão, apenas o valor anterior deve ser preenchido.
Listagem-resposta 3.99B
SQL> CREATE OR REPLACE TRIGGER SALARIO
2 AFTER INSERT OR DELETE OR UPDATE OF VL_SAL ON FUNC
3 FOR EACH ROW
4 DECLARE
5 OPER VARCHAR2(1);
6 MAT NUMBER;
7 BEGIN
8 IF INSERTING THEN
9 OPER := 'I';
10 MAT := :NEW.CD_MAT;
11 ELSIF UPDATING THEN
12 OPER := 'A';
13 MAT := :NEW.CD_MAT;
14 ELSE
15 OPER := 'E';
16 MAT := :OLD.CD_MAT;
17 END IF;
18 INSERT INTO TLOG (OPERACAO, SAL_ANT, SAL_ATU, MAT, TIMESTAMP)
19 VALUES (OPER, :OLD.VL_SAL, :NEW.VL_SAL, MAT, SYSDATE);
20 END;
21 /
Gatilho criado.
Listagem-resposta 3.100A
SQL> CREATE OR REPLACE TRIGGER MODIFICA
2 BEFORE INSERT OR UPDATE OF VL_SAL, CD_DEPTO, DT_ADM, NM_FUNC, NR_CARGO, NM_SOBRENOME
3 ON FUNC
4 FOR EACH ROW
5 DECLARE
6 CURSOR C1 IS SELECT CD_DEPTO, 0 FROM DEPTO
7 WHERE NOT EXISTS (SELECT 0 FROM FUNC
8 WHERE FUNC.CD_DEPTO = DEPTO.CD_DEPTO)
9 UNION
10 SELECT CD_DEPTO, COUNT(*) FROM FUNC
11 GROUP BY CD_DEPTO
12 ORDER BY 2;
13 R1 C1%ROWTYPE;
14 BEGIN
15 IF :NEW.CD_MAT IS NULL THEN
16 SELECT SEQMAT.NEXTVAL INTO :NEW.CD_MAT
17 FROM DUAL;
18 END IF;
19 IF :NEW.VL_SAL IS NULL THEN
20 :NEW.VL_SAL := GREATEST((:NEW.NR_CARGO - 40), 0) * 300 + 1000;
21 END IF;
22 IF :NEW.CD_DEPTO IS NULL THEN
23 OPEN C1;
24 FETCH C1 INTO R1;
25 :NEW.CD_DEPTO := R1.CD_DEPTO;
26 END IF;
27 IF INSERTING THEN
28 :NEW.DT_ADM := SYSDATE;
29 END IF;
30 :NEW.NM_FUNC := UPPER(:NEW.NM_FUNC);
31 :NEW.NM_SOBRENOME:= UPPER(:NEW.NM_SOBRENOME);
32 END;
33 /
Gatilho criado.
3.101) Crie um trigger que critique a inclusão ou alteração de dados na tabela Func:
♦ Ramal deve ter quatro posições.
♦ Salário deve ser maior que 500,00 e não pode ser diminuído.
♦ A data de nascimento deve ser maior que 1950.
Listagem-resposta 3.101A
SQL> CREATE OR REPLACE TRIGGER CRITICA
2 BEFORE INSERT OR UPDATE OF NR_RAMAL, VL_SAL, DT_NASC
3 ON FUNC
4 FOR EACH ROW
5 BEGIN
6 IF LENGTH(LTRIM(RTRIM(:NEW.NR_RAMAL))) <> 4 THEN
7 RAISE_APPLICATION_ERROR(-20001, 'RAMAL INVÁLIDO');
8 END IF;
9 IF UPDATING AND
10 :NEW.VL_SAL < :OLD.VL_SAL THEN
11 RAISE_APPLICATION_ERROR(-20002, 'SALÁRIO NÃO PODE SER DIMINUÍDO');
12 END IF;
13 IF :NEW.DT_NASC <= TO_DATE('311219492359', 'DDMMYYYYHH24MI') + 59/86400 THEN
14 RAISE_APPLICATION_ERROR(-20003, 'DATA DE NASCIMENTO INVÁLIDA');
15 END IF;
16 :NEW.NM_FUNC := UPPER(:NEW.NM_FUNC);
17 :NEW.NM_SOBRENOME:= UPPER(:NEW.NM_SOBRENOME);
18 END;
19 /
Gatilho criado.
3.102) Faça um trigger que, para cada salário incluído, alterado ou excluído em Funcionário, atualize os valores de
salários do departamento da tabela Depto_Acum, cujo layout é:
cd_depto char(03)
vl_média number
vl_max number
vl_min number
vl_total number
Listagem-resposta 3.102A
SQL> CREATE TABLE DEPTO_ACUM
2 (CD_DEPTO CHAR(03) PRIMARY KEY,
3 VL_MEDIA NUMBER,
4 VL_MAX NUMBER,
5 VL_MIN NUMBER,
6 VL_TOTAL NUMBER);
Tabela criada.
Listagem-resposta 3.102B
SQL> CREATE OR REPLACE TRIGGER ACUMULA
2 AFTER INSERT OR DELETE OR UPDATE OF VL_SAL
3 ON FUNC
4 FOR EACH ROW
5 BEGIN
6 DELETE FROM DEPTO_ACUM
7 WHERE CD_DEPTO IN (:NEW.CD_DEPTO, :OLD.CD_DEPTO);
8 EXCEPTION
9 WHEN NO_DATA_FOUND THEN
10 NULL;
11 END;
12 /
Gatilho criado.
Foram criados dois triggers, o primeiro de linha, que será acionada a cada linha excluída ou modificada. Quando
isso ocorrer, o trigger fará a exclusão das linhas relativas ao departamento afetado da tabela Depto_Acum.
Quando o comando acabar (trigger de comando), será feito o cálculo para todos os departamentos que existam em
Funcionário e que não existam mais em Depto_Acum.
Listagem-resposta 3.102C
SQL> CREATE OR REPLACE TRIGGER CALCULA_ACUM
2 AFTER INSERT OR DELETE OR UPDATE OF VL_SAL
3 ON FUNC
4 BEGIN
5 FOR R1 IN (SELECT AVG(VL_SAL) AAVG, MAX(VL_SAL) AMAX,
6 MIN(VL_SAL) AMIN, SUM(VL_SAL) ASUM, CD_DEPTO
7 FROM FUNC
8 WHERE NOT EXISTS (SELECT CD_DEPTO FROM DEPTO_ACUM
9 WHERE CD_DEPTO = FUNC.CD_DEPTO)
10 GROUP BY CD_DEPTO) LOOP
11 INSERT INTO DEPTO_ACUM
12 VALUES (R1.CD_DEPTO, R1.AAVG, R1.AMAX, R1.AMIN, R1.ASUM);
13 END LOOP;
14 END;
15 /
Gatilho criado.
Esta forma de trabalhar impede a leitura da tabela Func durante o processo de atualização, o que causaria o erro
ORA-04091: a tabela DESENV.FUNC é mutante.
3.103) Faça um programa que inclua linhas na tabela Func, recebendo como parâmetro matrícula, nome e
departamento do funcionário. Execute este programa em um comando Select.
Listagem-resposta 3.103
SQL> CREATE OR REPLACE
2 FUNCTION INCLUI(MAT IN NUMBER, NOME IN VARCHAR2, DEP IN VARCHAR2)
3 RETURN VARCHAR2 IS
4 PRAGMA AUTONOMOUS_TRANSACTION;
5 BEGIN
6 INSERT INTO FUNC (CD_MAT, NM_FUNC, CD_DEPTO)
7 VALUES (MAT, NOME, DEP);
8 COMMIT;
9 RETURN 'INCLUSÃO REALIZADA COM SUCESSO';
10 EXCEPTION
11 WHEN OTHERS THEN
12 RETURN SQLERRM;
13 END;
14 /
Função criada.
INCLUI(MAX(CD_MAT)+1,'NOVO','A00')
------------------------------
INCLUSÃO REALIZADA COM SUCESSO
Listagem-resposta 3.104A
SQL> CREATE OR REPLACE PROCEDURE GERAPRJ IS
2 PPROJ CHAR(06);
3 PATIV NUMBER(3);
4 CURSOR C1 IS SELECT P.CD_PROJ, P.NM_PROJ, A.CD_ATIV,
5 A.NM_SIGLA, PJ.DT_INI, PJ.DT_FIM
6 FROM PROJ P, ATIV A, PRJATV PJ
7 WHERE PJ.CD_PROJ = P.CD_PROJ
8 AND PJ.CD_ATIV = A.CD_ATIV
9 AND ((PJ.CD_PROJ = PPROJ AND PJ.CD_ATIV > PATIV)
10 OR (PJ.CD_PROJ > PPROJ))
11 ORDER BY 1, 3;
12 ARQ UTL_FILE.FILE_TYPE;
13 VEZ NUMBER := 0;
14 BUFFER VARCHAR2(200);
15 BEGIN
16 BEGIN
17 ARQ := UTL_FILE.FOPEN('D:\TESTE', 'R104.TXT', 'R');
18 LOOP
19 UTL_FILE.GET_LINE(ARQ, BUFFER);
20 END LOOP;
21 EXCEPTION
22 WHEN NO_DATA_FOUND THEN
23 VEZ := INSTR(BUFFER,'#', 1);
24 PPROJ := SUBSTR(BUFFER,1,VEZ-1);
25 PATIV := TO_NUMBER(SUBSTR(BUFFER,VEZ+1,INSTR(BUFFER,'#',1,2) - VEZ - 1));
26 VEZ := 0;
27 WHEN UTL_FILE.INVALID_OPERATION THEN
28 PPROJ := ' ';
29 PATIV := 0;
30 END;
31 UTL_FILE.FCLOSE(ARQ);
32 ARQ := UTL_FILE.FOPEN('D:\TESTE', 'R014.TXT', 'A');
33 FOR R1 IN C1 LOOP
34 UTL_FILE.PUT(ARQ, R1.CD_PROJ||'#'||R1.CD_ATIV||'#');
35 UTL_FILE.PUT(ARQ, R1.NM_PROJ||'#'||R1.NM_SIGLA||'#');
36 UTL_FILE.PUT(ARQ, TO_CHAR(R1.DT_INI, 'DDMMYYYY')||'#');
37 UTL_FILE.PUT_LINE(ARQ, TO_CHAR(R1.DT_FIM, 'DDMMYYYY'));
38 VEZ := VEZ + 1;
39 IF VEZ = 8 THEN
40 VEZ := 0;
41 UTL_FILE.FFLUSH(ARQ);
42 END IF;
43 END LOOP;
44 UTL_FILE.FFLUSH(ARQ);
45 UTL_FILE.FCLOSE(ARQ);
46 EXCEPTION
47 WHEN OTHERS THEN
48 UTL_FILE.FFLUSH(ARQ);
49 UTL_FILE.FCLOSE(ARQ);
50 DBMS_OUTPUT.PUT_LINE(SQLERRM(SQLCODE));
51 END;
52 /
Procedimento criado.
3.105) Faça um programa que receba como parâmetro um percentual de aumento para todos os funcionários.
Deve ser garantido o reinício do programa em caso de falha e a cada oito atualizações.
Listagem-resposta 3.105A
SQL> CREATE OR REPLACE
2 PROCEDURE ATUFUNC(PERC IN NUMBER) IS
3 MAT NUMBER;
4 CURSOR C1 IS SELECT CD_MAT FROM FUNC
5 WHERE CD_MAT > MAT;
6 BUFFER VARCHAR2(20);
7 CURSOR LOCK_FUNC IS SELECT CD_MAT, VL_SAL FROM FUNC
8 WHERE CD_MAT = MAT FOR UPDATE;
9 VEZ NUMBER := 0;
10 RL LOCK_FUNC%ROWTYPE;
11 BEGIN
12 BEGIN
13 SELECT TX_RESTART INTO BUFFER
14 FROM RESTART
15 WHERE ID_PROGRAMA = 'ATUFUNC';
16 MAT := TO_NUMBER(BUFFER);
17 EXCEPTION
18 WHEN NO_DATA_FOUND THEN
19 INSERT INTO RESTART (ID_PROGRAMA, DT_TIMESTAMP, TX_RESTART)
20 VALUES ('ATUFUNC', SYSDATE, '0');
21 MAT := 0;
22 END;
23 FOR R1 IN C1 LOOP
24 MAT := R1.CD_MAT;
25 OPEN LOCK_FUNC;
26 FETCH LOCK_FUNC INTO RL;
27 VEZ := VEZ + 1;
28 UPDATE FUNC
29 SET VL_SAL = VL_SAL + (VL_SAL * PERC / 100)
30 WHERE CURRENT OF LOCK_FUNC;
31 CLOSE LOCK_FUNC;
32 IF VEZ = 8 THEN
33 UPDATE RESTART
34 SET TX_RESTART = MAT
35 WHERE ID_PROGRAMA = 'ATUFUNC';
36 COMMIT;
37 VEZ := 0;
38 END IF;
39 END LOOP;
40 DELETE FROM RESTART
41 WHERE ID_PROGRAMA = 'ATUFUNC';
42 COMMIT;
43 END;
44 /
Procedimento criado.
Listagem-resposta 3.106A
SQL> CREATE TABLE TBMOV
2 (CD_MOV NUMBER(06)
3 ,DT_MOV DATE
4 ,CD_MAT NUMBER(5)
5 ,NM_FUNC VARCHAR2(30)
6 ,DT_NASC DATE
7 ,VL_SAL NUMBER(10,2)
8 ,NR_CARGO NUMBER(2)
9 ,NR_GIT NUMBER(2)
10 ,CD_DEPTO VARCHAR2(3)
11 ,CD_STATUS VARCHAR2(1));
Tabela criada.
A inclusão de linhas nesta tabela pode ser feita a qualquer momento durante o dia pelos programas de carga.
Imediatamente após sua inclusão, o status de cada registro é “C”.
Faça um programa que realize a atualização da base de dados baseado nos dados do movimento.
A atualização dos dados na tabela Func deve efetuar uma crítica e gerar uma tabela de erros contendo o Rowid da
linha e a mensagem de erro. Caso o registro contenha erros, o status deve ser alterado para “E”. Caso seja feita a
atualização de Func, mude o status para “A”.
Críticas:
♦ Cargo deve variar de 42 a 60.
♦ Departamento deve existir na tabela Depto.
♦ Data de nascimento deve ser maior que 1950.
♦ Salário deve ser maior ou igual ao dos demais funcionários com o mesmo cargo do mesmo departamento.
O programa deve atualizar um funcionário de cada vez sem bloquear as demais linhas do movimento. Caso a linha
requisitada esteja bloqueada, passe para a próxima linha. O programa somente poderá encerrar se todas as linhas
do movimento (não bloqueadas) estiverem com status diferente de “C”.
Listagem-resposta 3.106B
SQL> CREATE OR REPLACE PROCEDURE CARGAMOV IS
2 CURSOR C1 IS SELECT CD_MAT, ROWID EROW FROM TBMOV
3 WHERE CD_STATUS = 'C';
4 CURSOR C2(MAT IN NUMBER)
5 IS SELECT * FROM FUNC
6 WHERE CD_MAT = MAT FOR UPDATE;
7 REND ROWID;
8 RL TBMOV%ROWTYPE;
9 AUX NUMBER;
10 ERRO BOOLEAN;
11 BLOQUEIO EXCEPTION;
12 PRAGMA EXCEPTION_INIT(BLOQUEIO, -54);
13 BEGIN
14 FOR R1 IN C1 LOOP
15 ERRO := FALSE;
16 FOR R2 IN C2(R1.CD_MAT) LOOP
17 BEGIN
18 SELECT * INTO RL FROM TBMOV WHERE ROWID = R1.EROW
19 FOR UPDATE OF CD_STATUS NOWAIT;
20 IF RL.NR_CARGO BETWEEN 42 AND 60 THEN
21 ERRO := TRUE;
22 INSERT INTO ERROS VALUES
23 (R1.EROW, SEQERR.NEXTVAL,'CARGO INVÁLIDO —>'||RL.NR_CARGO);
24 END IF;
25 BEGIN
26 SELECT 1 INTO AUX FROM DEPTO
27 WHERE CD_DEPTO = RL.CD_DEPTO;
28 EXCEPTION
29 WHEN NO_DATA_FOUND THEN
30 ERRO := TRUE;
31 INSERT INTO ERROS VALUES
32 (R1.EROW, SEQERR.NEXTVAL,'DEPARTAMENTO INVÁLIDO —>'||RL.CD_DEPTO);
33 END;
34 IF RL.DT_NASC < TO_DATE('01011950', 'DDMMYYYY') THEN
35 ERRO := TRUE;
36 INSERT INTO ERROS VALUES
37 (R1.EROW, SEQERR.NEXTVAL,'NASCIMENTO INVÁLIDA —>'||TO_CHAR(RL.DT_NASC, 'DD/MM/YYY
38 END IF;
39 BEGIN
40 IF RL.NR_CARGO IS NOT NULL AND
41 RL.CD_DEPTO IS NOT NULL THEN
42 SELECT NVL(MIN(VL_SAL), 0) INTO AUX
43 FROM FUNC
44 WHERE NR_CARGO = RL.NR_CARGO
45 AND CD_DEPTO = RL.CD_DEPTO;
46 ELSIF RL.NR_CARGO IS NOT NULL THEN
47 SELECT NVL(MIN(VL_SAL), 0) INTO AUX
48 FROM FUNC
49 WHERE NR_CARGO = RL.NR_CARGO
50 AND CD_DEPTO = R2.CD_DEPTO;
51 ELSIF RL.CD_DEPTO IS NOT NULL THEN
52 SELECT NVL(MIN(VL_SAL), 0) INTO AUX
53 FROM FUNC
54 WHERE NR_CARGO = R2.NR_CARGO
55 AND CD_DEPTO = RL.CD_DEPTO;
56 ELSE
57 SELECT NVL(MIN(VL_SAL), 0) INTO AUX
58 FROM FUNC
59 WHERE NR_CARGO = R2.NR_CARGO
60 AND CD_DEPTO = R2.CD_DEPTO;
61 END IF;
62 IF RL.VL_SAL IS NOT NULL AND
63 RL.VL_SAL < AUX THEN
64 ERRO := TRUE;
65 INSERT INTO ERROS
66 VALUES (R1.EROW, SEQERR.NEXTVAL, 'SALÁRIO INVÁLIDO —>'||RL.VL_SAL);
67 END IF;
68 EXCEPTION
69 WHEN NO_DATA_FOUND THEN
70 NULL;
71 END;
72 IF ERRO THEN
73 UPDATE TBMOV
74 SET CD_STATUS = 'E'
75 WHERE ROWID = R1.EROW;
76 ELSE
77 UPDATE TBMOV
78 SET CD_STATUS = 'A'
79 WHERE ROWID = R1.EROW;
80 END IF;
81 UPDATE FUNC
82 SET NM_FUNC = NVL(RL.NM_FUNC, NM_FUNC),
83 DT_NASC = NVL(RL.DT_NASC, DT_NASC),
84 VL_SAL = NVL(RL.VL_SAL, VL_SAL),
85 NR_CARGO = NVL(RL.NR_CARGO, NR_CARGO),
86 NR_GIT = NVL(RL.NR_GIT, NR_GIT),
87 CD_DEPTO = NVL(RL.CD_DEPTO, CD_DEPTO)
88 WHERE CURRENT OF C2;
89 COMMIT;
90 EXCEPTION
91 WHEN BLOQUEIO THEN
92 NULL;
93 END;
94 END LOOP;
95 END LOOP;
96 END;
97 /
Procedimento criado.
Capítulo 4
OBJETOS E COLEÇÕES
Este capítulo é dedicado exclusivamente ao estudo de objetos e, em seguida, de coleções no banco de dados.
Consideramos que objetos são um tema que merece uma análise mais vagarosa e segura, principalmente porque a
Oracle, nesta versão 9i, implementou características que aproximam mais os objetos no banco de dados daqueles
presentes em linguagens orientadas a objetos.
Eventualmente usaremos exemplos em Java para comparar o uso de objetos no banco de dados e em uma linguagem
de programação.
Para que o estudo seja proveitoso, é indispensável que o leitor já tenha concluído o estudo dos Capítulos 2 e 3.
INTRODUÇÃO
A indústria da informática, desde seu início, recria no computador cópias bidimensionais do mundo em que
vivemos. Começamos com arquivos, registros, relacionamentos e chegamos aos objetos de hoje.
O objetivo continua o mesmo até hoje: representar da maneira mais fiel possível o mundo que nos cerca. Nossa
tarefa, neste capítulo, é conceituar e entender esta nova nomenclatura: objeto e classe.
OBJETOS
Nós vivemos em um mundo cercado de objetos. Cada um destes objetos é único no mundo.
Cada ser humano possui em seu corpo marcas que o identificam inequivocamente em relação a todos os outros
seres humanos no mundo. Não existem dois iguais.
Assim é o nosso mundo, os animais, vegetais, minerais e o ser humano são diferentes, únicos, apesar de compostos
da mesma matéria básica.
Exemplifiquemos com uma árvore. Certamente, você conhece muitas árvores, mas pense em uma árvore específica.
Você não encontrará, no mundo, nenhuma outra árvore, exatamente igual a esta em que você está pensando, pois
ela é única. O que isto quer dizer, exatamente?
Se ela é única e sabemos que dois corpos materiais não ocupam o mesmo lugar no espaço, significa que não existe
outra árvore com o mesmo número de galhos, a mesma forma, o mesmo número de folhas, as mesmas cores, etc.
e, ainda, no mesmo lugar que esta. Podemos dizer, que ela é, inequivocamente, única.
Continuemos nossa abstração. Anteriormente dissemos que uma árvore possui galhos, folhas, tronco, etc. Ob-
serve, então, que quando usamos a palavra árvore, sabemos, a princípio, do que se trata, pois esta palavra reúne
um significado, ou seja, um conjunto de características comuns a diversos elementos. Estas características identificam
este elemento no mundo real.
Transportemos, agora, estes conceitos para o computador.
PRIMEIRAS CONCLUSÕES
Nossa intenção é caracterizar “objeto” de tal forma que possamos representá-lo em nosso mundo bidimensional.
Como principal característica de um objeto temos que ele é único, não existem dois iguais no mundo. Sabemos,
também, que ele possui características que identificam um conjunto de objetos de mesma “categoria”. Formalmente
diremos que um objeto é único e possui atributos.
AÇÕES
No mundo real uma grande parcela destes “objetos” está viva e realiza movimentos ou ações. Por exemplo, as
árvores (que estamos usando como exemplo) crescem, dão frutos, sementes que permitem sua reprodução, seus
galhos balançam ao vento, perdem as folhas, etc.
Desta forma, queremos que nosso objeto (no computador) também realize ações intrínsecas a ele. Nossa meta para
representação de objeto, no computador, passa a ser:
a) Um objeto tem de ser único.
b) Um objeto deve possuir atributos que o caracterizam.
c) Um objeto deve ser capaz de realizar ações.
FORMALIZANDO OS CONCEITOS
Quando dizemos que um objeto possui atributos, estamos querendo dizer que ele armazena informações que o
caracterizam; portanto, uma parte deste objeto é composta de dados.
Quando dizemos que um objeto pode realizar ações, estamos querendo dizer que ele realiza procedimentos, e,
portanto, uma parte deste objeto é composta de rotinas (procedimentos, funções, etc.) que realizam ações.
Chamaremos estas ações de métodos.
Como conclusão temos que um objeto é “algo” que, de alguma forma, junta dados (atributos) e códigos (métodos)
em um elemento único.
CONCLUSÃO
Podemos, formalmente, dizer que um objeto “encapsula” dados e código (atributos e métodos).
CLASSES
Vimos, anteriormente, que aquela árvore específica que conhecemos e que sabemos que é única é um Objeto.
Porém, dissemos também que, quando utilizamos a palavra ÁRVORE, indicamos um tipo de OBJETO, ou seja,
todas as árvores possuem características comuns.
Estas características podem ser listadas e conhecidas. Seus valores podem ser diferentes de um objeto para outro,
porém a lista de características é igual.
Por exemplo, dissemos que as árvores possuem folhas (o número varia de árvore para árvore), galhos (a quantidade
também depende do objeto), altura (este comprimento depende da árvore) e assim por diante.
Uma classe, portanto, nada mais é do que o conjunto de atributos e métodos que caracterizam um objeto. Podemos
dizer que é um MOLDE ou um LAYOUT do objeto.
Quando uma fábrica de automóveis cria um carro, os esboços, desenhos, etc. são a classe e o carro (de cada um) é o objeto.
CONCLUSÃO
Podemos ter diversos objetos com as mesmas características, objetos de uma mesma classe, porém diferentes entre si,
pois os valores de seus atributos são diferentes.
CLASSE
Dissemos, anteriormente, que, se reunirmos a lista de características e ações de um determinado objeto,
conseguiremos classificar e identificar que tipo de objeto é aquele, ou seja, identificamos a classe ou tipo de objeto.
Formalmente, em Java, esta lista de características é chamada de Classe. No banco de dados esta lista de características
é um Tipo. Observe o exemplo da Listagem 4.01.
Um tipo objeto contém três informações: nome, atributo(s) e método(s). Os atributos constituem-se de variáveis que
definem a estrutura de dados do objeto. Métodos são subprogramas que definem operações sobre os dados do objeto.
Neste primeiro exemplo criamos um tipo objeto sem nenhum método formal associado a ele.
Dissemos, anteriormente, que a classe ou tipo de objeto corresponde a um molde e não ao objeto em si. No banco
de dados este conceito está perfeitamente adequado, isto é, não podemos incluir dados em um tipo de objeto.
Quando tratamos deste assunto em um programa, a criação e armazenamento do objeto com as características
definidas pelo tipo OT_END é feita em memória, o que é extremamente volátil. Em um banco de dados, no
entanto, queremos e precisamos armazenar os objetos. Sendo assim, precisamos de um “repositório” para
armazenamento de objetos.
OBJECT TABLE
Para resolver esta necessidade, a Oracle criou um novo tipo de tabela no banco de dados. Uma Object Table é uma
tabela para armazenamento das instâncias de uma determinada classe.
Uma instância de uma classe é o resultado da construção de um elemento com características definidas pela classe,
ou seja, da construção de um objeto.
Uma Object Table é uma tabela para armazenamento de objetos. Na Listagem 4.02 criaremos uma Object Table
para armazenamento de objetos do tipo OT_END.
Com a criação de um local para armazenamento de objetos, nosso próximo objetivo é criar os objetos e armazená-los.
MÉTODO CONSTRUTOR
Neste momento, nos deparamos com um segundo problema: como construir um objeto?
Quando tratamos de dados escalares, não existem problemas quanto ao armazenamento da informação;
simplesmente fazemos uma atribuição (em qualquer linguagem) à variável ou elemento em questão, porém, como
faremos com um elemento “complexo”, como é o caso de OT_END? Não podemos, simplesmente, dar um valor
diretamente a ele, pois que ele é composto de diversos atributos.
Quando trabalhamos com uma linguagem orientada a objeto, como é o caso da Java, este problema é resolvido
pela linguagem com a criação de uma rotina especial para a construção de objetos de uma determinada classe.
Chamamos esta rotina de Método Construtor.
Estudamos, anteriormente, que os objetos possuem atributos e métodos. Quando definimos um tipo de objeto
podemos anexar os métodos que compõem este tipo. O método construtor é um método especial que é capaz de
construir o objeto.
Quando criamos um tipo de objeto, implicitamente estamos criando simultaneamente um método capaz de construir
objetos deste tipo. Esta ação tanto é feita nas linguagens OO quanto no banco de dados.
Para que a linguagem ou o banco de dados identifique um dos métodos da classe como construtor, existem duas regras:
♦ O nome do método construtor deve ser, exatamente, igual ao nome da classe.
♦ Pode haver mais de um método construtor para a mesma classe.
A partir destas regras, já sabemos o nome do método construtor. Veremos, com os exemplos a seguir, como construir,
destruir, consultar ou modificar objetos em um banco de dados Oracle.
INCLUSÃO
No exemplo da Listagem 4.03, estamos usando a linguagem SQL para incluir um objeto em nossa Object Table.
Observe, no exemplo, que acionamos o método construtor OT_END (mesmo nome do objeto) a fim de construir
o objeto. Para este método informamos os valores referentes a todos os componentes individuais do objeto.
Apesar de esta forma ser mais compatível com toda a teoria vista até agora, o Oracle, implicitamente, aciona o
método construtor, quando executamos um comando INSERT.
CONSULTA
No primeiro exemplo da Listagem 4.04, vemos os dados do objeto armazenado no banco de dados.
No segundo exemplo usamos a função Value para que fosse retornada a instância do tipo de objeto OT_END, que
estivesse armazenado na tabela TB_END.
Observe que, neste caso, o nome do tipo de objeto foi apresentado juntamente com os dados do objeto.
NM_BAIRRO NM_CIDADE
----------- --------------
Bairro Cidade
Novo Bairro Rio de Janeiro
Centro
Neste exemplo, da Listagem 4.05, executamos um comando SELECT que obtinha apenas informações sobre os
atributos NM_BAIRRO e NM_CIDADE de todos os objetos armazenados na tabela TB_END.
ALTERAÇÃO E EXCLUSÃO
No exemplo da Listagem 4.06 estamos atualizando uma coluna de um objeto armazenado no banco de dados.
EM PL/SQL
No exemplo da Listagem 4.07, fizemos um programa, que recebe como parâmetro os elementos do tipo objeto OT_END.
SQL> /
Entre o valor para opcao: A
Entre o valor para rua: Rua da Imperatriz
Entre o valor para bairro: Centro
Entre o valor para cidade: Petrópolis
Entre o valor para estado: RJ
Entre o valor para num: 325
Entre o valor para cep: 25876320
Procedimento PL/SQL concluído com sucesso.
Observe, no exemplo da Listagem 4.07, que definimos uma variável a partir do tipo OT_END definido no banco de
dados. Já podemos notar, de imediato, uma diferença no manuseio desta variável. Fomos obrigados a construir o
objeto (mesmo vazio) antes de usá-lo. Para tal, usamos o método construtor OT_END que recebia diversos (6)
parâmetros, aos quais atribuímos NULL, construindo um objeto vazio. Comente a atribuição da linha 2 e repita o
exemplo para verificar o erro recebido.
No caso da opção ‘I’, atribuímos os parâmetros recebidos no programa aos atributos correspondentes do objeto
instanciado pela variável OEND. No comando INSERT usamos diretamente a instância, uma vez que o objeto foi
construído e preenchido anteriormente.
SQL> /
Entre o valor para opcao: A
Entre o valor para rua: Rua Barão de Mesquita
Entre o valor para bairro: Tijuca
Entre o valor para cidade: Rio de Janeiro
Entre o valor para estado: RJ
Entre o valor para num: 438
Entre o valor para cep: 25000001
Procedimento PL/SQL concluído com sucesso.
Neste segundo exemplo a atualização do objeto desejado na Object Table foi feita através da instância OEND.
Como primeiro passo obtivemos do banco de dados, usando a função Value, o objeto desejado e o armazenamos
na instância OEND. Como segundo passo modificamos os valores relativos aos atributos que recebemos como
parâmetro e, finalmente, como terceiro passo atualizamos o objeto correspondente na tabela TB_END.
MÉTODOS
Um método, como sabemos, é um código associado (ou “encapsulado”) ao objeto. Sua principal característica é ter
acesso ilimitado aos dados do objeto ao qual está ligado.
Quando criamos um tipo de objeto, podemos associar a este tipo rotinas de PL/SQL, as quais têm acesso a todos os
atributos do tipo diretamente. Essas rotinas são referenciadas como se fossem atributos do tipo e são chamadas de
Métodos. Desta forma, o Oracle contempla o conceito de método apresentado acima.
A criação das rotinas obedece a duas etapas; a primeira se refere à parte de especificação da rotina, que ocorre juntamente
com a criação do tipo de objeto, onde definiremos o nome da rotina, os parâmetros e o tipo de retorno (no caso de função).
Da mesma forma que ocorre com package, a parte de especificação é visível pelas aplicações e é a única parte
necessária para que uma referência ao método seja compilada.
Após a definição da especificação, passamos à definição do corpo da rotina. Para tal, criaremos um Type Body (da
mesma forma que Package Body) associado ao tipo definido. Desta forma, todas as rotinas associadas àquele tipo
serão definidas no corpo do tipo.
MEMBER
Quando criamos um método do tipo Member, sua utilização deverá ser explícita pelas aplicações ou nos comandos de SQL.
Pode especificar uma procedure ou função associada com o objeto. Esta rotina pode ser referenciada da mesma
forma que um atributo do objeto.
Observe no exemplo da Listagem 4.09 que adicionamos uma função ao tipo de objeto OT_END e indicamos que se
tratava de uma função MEMBER. Isto significa que é um método comum e que tem acesso a todos os atributos do
objeto específico associado. No corpo da rotina usamos o qualificador SELF para indicar que se tratava de um
atributo do próprio objeto, do objeto corrente. Isto não é obrigatório neste momento pois a rotina tem acesso a
apenas um objeto de cada vez, porém deixa o código mais elegante.
A palavra-chave INVALIDADE indica que todos os objetos dependentes serão tornados inválidos sem qualquer verificação.
No comando SELECT seguinte já usamos a função como se fosse mais um atributo do objeto. Observe, no entanto,
que a sintaxe possui algumas particularidades. Para fazermos referência a um método devemos qualificá-lo com o
objeto, pois se trata de uma rotina do objeto. Com este objetivo apelidamos a Object Table de “C”, que representará
o objeto armazenado internamente na tabela. Desta forma, quando usamos C.ETIQUETA( ), estamos, na verdade,
indicando que desejamos que o método ETIQUETA do tipo de objeto C seja acionado para cada um dos objetos
presentes na tabela TB_END.
Notamos, ainda, uma outra diferença no acionamento do método: o uso dos parênteses. Os parênteses devem ser
usados por nós mesmo que o método não receba parâmetros (o que é perfeitamente possível). Eles diferenciam um
método de uma função qualquer criada por nós no banco de dados.
MAP MEMBER
É uma função que retorna uma informação escalar (number, varchar2, char, etc.) com a finalidade de determinar
a posição relativa do objeto particular no conjunto.
Este tipo de método tem a finalidade de resolver um problema com o qual nos depararemos mais cedo ou mais
tarde no uso de objetos. Como ordenar o resultado baseado em um objeto?
No primeiro exemplo da Listagem 4.10, recebemos um erro porque solicitamos uma ordenação pelo objeto
armazenado em TB_END e representado por C. Um objeto é um tipo complexo e o banco de dados somente
consegue determinar se um objeto é igual ou diferente de outro. Para determinar se ele é maior ou menor, precisará
de uma “ajudinha extra”. Esta ajuda é dada sob a forma de método. Para cada objeto que viermos a criar podemos
adicionar uma função Map ou uma função Order (apenas uma delas), a qual será usada para determinar, entre dois
objetos, qual o maior.
Um método Map é um método especial, pois é acionado diretamente pelo Oracle quando fazemos uma ação que
necessite da ordenação do objeto.
Quando isto é necessário, ele aciona o método Map (ou Order) existente para aquele objeto.
Após criarmos o método Map, não houve maiores dificuldades para o Oracle realizar o SELECT que havíamos
tentado anteriormente. Neste exemplo foi solicitada a ordenação pelo objeto e não por um atributo específico. A
rotina ORDEM foi usada, pelo Oracle, para realizar esta tarefa.
RESTRIÇÃO
Como restrição, temos que um objeto só pode conter uma função Map. Podemos definir um método do tipo Map
ou um método do tipo Order para um determinado objeto, mas não ambos.
Se não definirmos nenhum dos dois, o Oracle terá capacidade de efetuar apenas comparações de igualdade (ou
desigualdade) entre os objetos deste tipo. Não conseguirá determinar o maior ou menor.
ORDER MEMBER
Especifica uma função que recebe como parâmetro um outro objeto deste mesmo tipo.
A PL/SQL usa a ordenação para avaliar expressões boleanas do tipo > (maior) e < (menor) e para realizar comparações
implícitas tais como Distinct, Group By e cláusulas Order By. O método Map retorna a posição relativa de um
objeto em relação ao grupo.
Outra forma de estabelecer ordem é a utilização de um método do tipo Order que, diferentemente do método
Map, deve receber como parâmetro outro objeto do mesmo tipo do objeto no qual o método está sendo criado a
fim de que internamente na rotina estabeleça as condições de comparação e retorne a indicação de qual dos dois
objetos (aquele recebido como parâmetro ou o próprio objeto) é maior (menor ou igual).
Esta função deve retornar um inteiro com um dos valores: negativo, zero ou positivo. Esses valores indicam
respectivamente que o argumento implícito Self é menor, igual ou maior que o argumento explícito. Já sabemos que
o argumento Self não é passado explicitamente; refere-se ao próprio objeto atual, ao qual o método tem acesso direto.
Observe que já podemos perceber uma diferença entre esta função e a Map. Ela recebe como parâmetro um objeto
do tipo OT_END, do mesmo tipo do tipo objeto que está sendo alterado (ou criado).
O resultado desta função dirá se o objeto interno (referenciado como SELF) é maior (retorno 1), menor (retorno -1) ou
igual (retorno 0) a este objeto explicitamente passado como parâmetro.
A utilização da qualificação não é obrigatória para o objeto SELF (é o default); no entanto, é conveniente para
maior clareza do código.
Esta rotina compara o estado e o CEP do parâmetro com o estado e o CEP do objeto atual e determina se são iguais (retorna
0), se o objeto atual tem estado ou CEP maior (retorna 1) ou se o objeto atual tem estado ou CEP menor (retorna -1).
Encerramos este tópico neste ponto, pois já podemos realizar testes de uso de objetos. A criação e alteração de
objetos cabem ao DBA e não serão aprofundadas neste material.
EXERCÍCIOS
4.01) Deseja-se listar o conteúdo da tabela tb_tfunc. O resultado deve vir ordenado pelo endereço. Repita a construção
utilizando a função Value.
4.02) Inclua uma nova linha na tabela Tb_tcargo utilizando o método construtor Tcargo.
4.03) Inclua um novo funcionário em Tb_Tfunc. Não forneça valor para as colunas cd_cargo, nr_telefone e cd_estado.
4.04) Utilize o método Mcargo para obter informações sobre o objeto Tcargo. Liste simultaneamente o código do cargo.
4.05) Crie um programa em PL/SQL que receba como parâmetro o código do funcionário e seu endereço para
alteração. Estado não deve ser modificado.
4.06) Usando a rotina do exercício anterior, atualize o CEP do funcionário de matrícula 200 para o valor 20789500.
Após a atualização verifique o resultado.
Se você consultar a Sintaxe 4.01 relativa a criação de tipo, verá que não temos as especificações relativas a con-
straints. Veja o exemplo da Listagem 4.13 a seguir.
Isto ocorre porque um tipo de objeto, como já sabemos, corresponde a um Molde; ao tempo de implementação é
que estabelecemos as regras de integridade para aquela implementação.
6 NR_RUA NUMBER(8),
7 NR_CEP NUMBER(8))
8 /
Tipo criado.
Neste exemplo da Listagem 4.14 implementamos o tipo OT_END em duas tabelas diferentes. Em cada uma das
implementações estabelecemos restrições compatíveis com o objeto a ser armazenado.
RELACIONAMENTOS
Num modelo Relacional, os relacionamentos são restrições que participam das regras de negócio estabelecidas no
banco de dados.
Num modelo Objeto-Relacional, utilizamos uma Ref (referência) para estabelecer uma ligação com um objeto
específico, ou mais formalmente, com uma instância específica de um tipo de objeto.
REF
A expressão Ref difere de um relacionamento estabelecido num modelo Relacional. Ela, por si só, não estabelece
uma restrição de integridade, não há impedimento à remoção de uma instância que esteja sendo referenciada por
outra. A expressão Ref corresponde a um ponteiro, objetiva acesso mais rápido e não regra de integridade.
Antes de iniciarmos os testes vamos analisar o que foi criado. Inicialmente criamos o tipo de objeto OT_CLI01,
uma tabela para armazenamento dos objetos deste tipo, com as restrições que consideramos necessárias.
Em seguida criamos o tipo de objeto OT_DEP01 contendo um atributo RF_TITULAR cujo tipo é REF; isto significa
que este atributo estará fazendo uma referência e não armazenando dados escalares. Esta referência poderá ser feita
para objetos do tipo OT_CLI01 que estejam armazenados em qualquer tabela.
Quando implementamos a tabela TB_DEP01 para armazenamento de objetos do tipo OT_DEP01 limitamos a
referência da coluna (agora já pode ser chamada de coluna) RF_TITULAR a objetos armazenados na tabela TB_CLI01.
Para que pudéssemos incluir as referências ao objeto armazenado em TB_CLI01, precisamos realizar uma consulta para
obter o OID (object identifier) do objeto desejado. O OID é uma informação acrescida pela Oracle a todos os objetos,
que garantirá que os mesmos seja únicos (veremos o conteúdo desta informação no próximo exemplo). Observe, ainda,
que para obtermos a indicação do objeto usamos, novamente, a função REF do objeto apelidado de C.
NM_DEPENDENTE
-------------
RF_TITULAR
---------------------------------------------------------------------------
PRIMEIRO DEPENDENTE
0000220208B9D5D2D5F9744CEE99A7B44EA02F91119C912069FE034759B80A892A4DB96F23
SEGUNDO DEPENDENTE
000022020865D366CF6F154EA4B535F300D82B9A809C912069FE034759B80A892A4DB96F23
No primeiro comando SELECT obtivemos o conteúdo da coluna RF_TITULAR. Este número é o OID gerado pelo
Oracle e que torna cada objeto único, como determina a parte conceitual. Se ele identifica um objeto específico,
podemos obter informações deste objeto usando esta referência.
No segundo SELECT usamos a coluna RF_TITULAR (ou o atributo do objeto OT_DEP01 armazenado na tabela
TB_DEP01) para obter informações diretamente dos objetos a que ela faz referência. Observe que apelidamos
nosso objeto de T e solicitamos que fosse obtido o número do cartão através da referência RF_TITULAR do objeto
T que houvermos selecionado.
DANGLING
Nosso próximo passo é determinar o que acontece se removermos um objeto referenciado.
Como primeiro passo do exemplo removemos um objeto qualquer da tabela TB_CLI01. Não houve qualquer tipo
de restrição ou aviso referente a esta remoção.
Quando repetimos o comando SELECT pudemos observar que as informações referentes aos dados do titular do
cartão 501 não foram trazidos, porém o dependente continuou existindo.
Com isso vemos que a cláusula REF não estabelece uma restrição de integridade, ela, simplesmente, contém uma
referência a um determinado objeto, em relação ao qual podemos obter informações.
Para sabermos se uma referência ainda é válida ou não, usamos a expressão IS DANGLING (é inválida) ou IS NOT
DANGLING (é válida). Foi isso que fizemos nos dois penúltimos comandos SELECT. No primeiro obtivemos aqueles
objetos cuja referência estava inválida e no segundo aqueles objetos cuja referência estava válida. No último
comando SELECT verificamos que DANGLING é diferente de NULL. A referência está preenchida, porém não
indica um objeto existente na tabela TB_CLI01.
Neste exemplo já criamos os tipos, as tabelas e as linhas simultaneamente. Devemos, apenas, observar as diferenças
na criação da tabela TB_DEP02. Quando estabelecemos as restrições para a coluna RF_TITULAR determinamos
duas cláusulas: with rowid e references.
A cláusula With Rowid tem a finalidade de importar, do objeto associado, não apenas o OID, mas também a
identificação física da linha. Isto dará, certamente, muito mais velocidade de acesso quando desejarmos obter
informações do objeto referenciado, uma vez que contamos com o endereço da linha para acesso direto.
A cláusula References (já nossa conhecida na etapa relacional) garante a integridade referencial, ou seja, não
poderemos remover elementos de cliente se houver dependentes relacionados. Poderíamos ter determinado que
na remoção de cliente os dependentes fossem removidos simultaneamente ou, ainda, que na remoção de cliente o
relacionamento dos dependentes fosse anulado (Set Null).
SEGUNDO DEPENDENTE
000022020898575F1FCBCB43CC83725968FDD28F3EF187CE6A86E047FC80CDF4514E89CC17
Nesta listagem observamos que a inclusão do Rowid junto com o REF não produziu nenhum efeito visível, a mudança
será apenas de performance. A inclusão da cláusula References impediu a remoção do objeto “pai” do relacionamento.
Desta forma temos as seguintes opções:
♦ Coluna REF contendo a cláusula References – simultaneamente endereça e restringe.
♦ Coluna REF sem a cláusula References – apenas endereça.
♦ Coluna não REF contendo a cláusula References – apenas restringe.
Listagem 4.21 – Deferrable e References sem REF
SQL> DROP TABLE TB_DEP02;
Tabela eliminada.
Neste exemplo incluimos uma tabela relacional (Pessoas) para que possamos observar que há intercâmbio entre o
ambiente relacional e o ambiente objeto (por este motivo dizemos que o banco de dados é Objeto-Relacional).
Nossa nova tabela TB_CLI02 passou a fazer uma restrição de integridade também com a tabela relacional Pessoas.
Toda vez que incluímos uma restrição temos a opção de determinar se a verificação será feita de imediato ou
somente no momento do Commit e se esta situação pode ser alterada.
Na cláusula References temos como opção o uso da expressão ON DELETE CASCADE, que indica que se removermos o
“pai” da relação os filhos também devem ser removidos, ou da expressão ON DELETE SET NULL, que indica que se
removermos o “pai” da relação os filhos não devem ser removidos, porém o relacionamento deve ser anulado. Quando
não usamos a expressão ON DELETE, indicamos que não desejamos que seja removido nenhum “pai” com filhos.
Neste exemplo da Listagem 4.22, criamos uma rotina para cadastramento de dependente. Nela já embutimos a
criação da linha na tabela relacional Pessoas. Observe que criamos uma variável (TIT_REF) do tipo REF para o
objeto OT_CLI02, para que pudéssemos obter o endereço (a referência) da instância do tipo de objeto. Usamos um
comando SELECT para obter esta informação e a passamos para o comando INSERT em um segundo passo.
DEREF
Suponhamos agora que desejássemos obter um relatório contendo, para cada dependente, o nome e identificador
do titular.
Neste exemplo, desejávamos obter o nome do titular associado a cada dependente. Em vez de utilizarmos diretamente
a referência presente no objeto Dependente, decidimos trazer o objeto (e não seus atributos) para o programa PL e
lá realizar a manipulação desejada.
Como primeiro passo definimos uma variável para receber objetos do tipo OT_CLI02 e outra para receber objetos
do tipo OT_DEP02. No comando SELECT associado ao cursor obtivemos o objeto apelidado de C e armazenado na
tabela TB_DEP02.
A cada objeto lido, obtinhamos em memória o nome do dependente, o número do cartão e a referência ao cliente.
De posse da referência desejávamos obter as informações relativas ao cliente correspondente. Para tal devemos
usar a função DEREF (contrário da REF) que, porém, não pode ser usada diretamente em PL/SQL.
Em função desta restrição, tivemos necessidade de efetuar um Select na tabela Dual para que a referência contida
no atributo RF_TITULAR pudesse ser usada e obtido o objeto Cliente correspondente. Usamos neste comando
Select a cláusula Dangling para que a leitura somente fosse efetuada se a referência fosse válida.
O exemplo apresentado a seguir objetiva o mesmo resultado, porém utilizamos navegação através da referência
em SQL para obter os dados relativos ao cliente. Veja como o resultado é mais simples.
EXERCÍCIOS
4.07) Selecione com um único comando o nome do funcionário e o nome de seu cargo. Não utilize join.
4.08) Atualiza a tabela de funcionários associando o cargo 3 (professor) ao funcionário de matrícula 400.
4.09) Inclua uma nova linha em funcionário informando, simultaneamente, valor para cargo e estado.
4.10) Verifique se existe algum cliente sem definição de empresa ou com especificação de empresa inválida.
4.11) Inclua uma nova linha na tabela TB_TEMPRESA sem informar valor para as colunas nm_empresa e nr_telefone.
O que acontece? Por quê? Em que local a restrição é definida?
4.12) Obtenha informações relativas a cargo e estado, quando possível. Use DEREF.
INTRODUÇÃO
Uma das mais importantes características da orientação a objeto é a possibilidade de reuso de código.
COMPOSIÇÃO
A composição consiste na criação de objetos de classes existentes dentro de uma nova classe. Desta forma a nova
classe é composta de classes existentes. Estaremos simplesmente reutilizando a funcionalidade do código.
3 BEGIN
4 RETURN MOD(SELF.NR_CARTAO,11) + MOD(SELF.NR_CARTAO,10) +
5 MOD(SELF.NR_CARTAO,9) + MOD(SELF.NR_CARTAO,8) +
6 MOD(SELF.NR_CARTAO,7) + MOD(SELF.NR_CARTAO,6) +
7 MOD(SELF.NR_CARTAO,5) + MOD(SELF.NR_CARTAO,4) +
8 MOD(SELF.NR_CARTAO,3);
9 END;
10 MAP MEMBER FUNCTION ORDCLI RETURN NUMBER IS
11 BEGIN
12 RETURN (NR_CARTAO * 100) + NR_DV;
13 END;
14 END;
15 /
Tipo de corpo criado.
Para a montagem dos testes criamos um tipo OT_END03 contendo duas funções (uma membro e outra map), o tipo
OT_TEL03 também contendo duas funções (uma membro e outra map) e, finalmente o tipo OT_CLI03 que usa como
atributo os dois tipos anteriores. Esta sintaxe representa a composição, que é uma das formas de reuso de código.
Nosso último passo foi criar a tabela para armazenamento de objetos do tipo OT_CLI03. Observe que não criamos
tabelas para armazenamento individual dos tipos OT_END03 e OT_TEL03. Estes tipos foram criados apenas para
serem usados como composição. Eles podem ser usados em composições de outros tipos.
O reuso através da composição permite que criemos tipos simples e que estes sejam usados para a montagem de
tipos complexos. Veremos, a seguir, as operações básicas com esta tabela contendo tipos como colunas.
METHOD
--------------------------------------
MEMBER FUNCTION CALCDV RETURNS NUMBER
METHOD
------------------------------------------
MAP MEMBER FUNCTION ORDCLI RETURNS NUMBER
Quando solicitamos a descrição do tipo no SQL*Plus podemos verificar os tipos definidos para os atributos
NM_ENDERECO e NR-TELEFONE (obtidos de outros tipos). Simultaneamente verificamos que a solicitação de
descrição de um tipo mostra os métodos associados ao tipo solicitado. Repita esta operação para os tipos OT_END03
e OT_TEL03 e verifique os resultados.
No exemplo da Listagem 4.27 incluímos duas linhas na tabela TB_CLI03. Para atribuirmos valor às colunas
NR_TELEFONE e NM_ENDERECO tivemos de acionar os métodos contrutores correspondentes dos tipos de objeto
OT_END03 e OT_TEL03, como já fizemos anteriormente. Neste caso, o uso dos construtores torna-se indispensável
para o preenchimento das colunas.
Após a inclusão acionamos o método CALCDV para calcular o DV de cada um dos cartões incluídos. Observe que
como usamos um método do objeto, apesar de não passarmos nenhum parâmetro, os valores calculados para DV
de cada um dos cartões foram diferentes, porque o parâmetro SELF (contendo toda a descrição do objeto selecionado)
é passado implicitamente para a função.
O primeiro comando SELECT apresentado no exemplo mostra, claramente, que a coluna NM_ENDERECO é uma
coluna composta e o mesmo ocorre para NR_TELEFONE.
No segundo SELECT, escolhemos as informações que desejávamos visualizar qualificando os atributos dos objetos
internos com o nome da coluna e o apelido do objeto. Ordenamos o resultado por uma coluna complexa
NM_ENDERECO e usamos o método TELEFONE normalmente como se fizesse parte da descrição do objeto.
HERANÇA
A palavra herança, por si só, já nos dá uma idéia do que significa este conceito. Sua conceituação é simples e
facilmente compreenderemos seu uso.
CONCEITUANDO HERANÇA
É o mecanismo de reutilização de atributos e operações definidos em classes (ou tipos de objetos) gerais por classes
(ou tipos de objetos) mais específicas.
O tipo de objeto mais genérico é chamado de SUPERTIPO (também conhecido como tipo pai ou tipo base) e o tipo
de objeto mais especializado é chamado de SUBTIPO (tipo filho ou tipo derivado).
A herança fornece um meio para se construir componentes reutilizáveis. Permite especificar atributos e operações
comuns a várias classes com características semelhantes. Observemos o exemplo a seguir:
O subtipo AUTOMÓVEL possui os mesmos atributos e métodos do tipo VEÍCULO TERRESTRE, porém como possui
métodos com os mesmos nomes do Supertipo, ela dá uma implementação diferenciada a estes métodos. Esta ação
de redefinição é aplicável tanto a métodos quanto a atributos. Vejamos, agora, os exemplos no Oracle.
Neste primeiro passo criamos os tipos, exatamente como mostramos na Figura 4.01. O tipo ANIMAL é um supertipo.
Suas características foram herdadas pelos três subtipos criados (AVE, MAMÍFERO e PEIXE).
Quando criamos as tabelas para os tipos criados poderemos instanciar os objetos. Para sabermos o layout dos
objetos que iremos incluir usamos o comando de SQL*Plus DESC para algumas tabelas e para o tipo AVE. No caso
do tipo AVE o comando DESC especificou o supertipo e a indicação de NOT FINAL.
Em todos os casos já podemos visualizar o significado de herança: os atributos criados apenas em ANIMAL foram
herdados por todos os tipos. Se tivéssemos métodos, o mesmo aconteceria com os métodos.
No exemplo da Listagem 4.30 conseguimos incluir informações nas tabelas TB_AVE, TB_PEIXE e até mesmo na
TB_ANIMAL. A criação de um objeto na tabela TB_MAMIFERO deu erro porque o tipo no qual a tabela foi baseado
não é instanciável, como definimos anteriormente. Para o tipo de objeto ANIMAL é que deveríamos ter feito esta
restrição uma vez que, na verdade, estávamos detalhando as informações nos subtipos.
Tipo criado.
No exemplo da Listagem 4.31 criamos um tipo objeto VTERRESTRE contendo duas funções membro (partida e
parada). Quando criamos os subtipos a partir do supertipo, substituímos as funções definidas no supertipo por
funções próprias e particulares ao subtipo. Para o subtipo CAMINHAO criamos mais uma função específica chamada
ESTATICA. Criamos, adicionalmente, o corpo das funções para que possamos usá-los a seguir.
1 linha criada.
A.PARADA()
-------------------------------------------
PARADA DE AUTOMOVEL - PORTAS = 5
PARADA DE AUTOMOVEL - PORTAS = 5
Neste exemplo utilizamos os métodos para testar herança. No resultado podemos verificar que o valor correspondente
de cada rotina Partida ou Parada foi específico ao seu tipo. Por exemplo enquanto a rotina Partida selecionada do
objeto residente na tabela TB_CAMINHAO apresentava o texto “partida de caminhao” a mesma rotina, selecionada
do objeto residente na tabela TB_VTERRESTRE, apresentava o texto “partida de vterrestre”.
A rotina ESTATICA, por ser do tipo Static, não tem acesso ao objeto instanciado para o tipo de objeto ao qual ela está
criada; por este motivo é comum a criação de funções ou procedures estáticas que recebam parâmetros. Quando
acionamos a rotina não usamos uma referência ao objeto apelidado por A e sim ao nome do próprio tipo de objeto.
OVERRIDING
As expressões OVERRIDING ou NOT OVERRIDING indicam se um método definido no supertipo está sendo
substituído no subtipo. Estas expressões devem ser usadas no subtipo. Para que o Oracle saiba a que método
estamos substituindo devemos colocar os métodos com o mesmo nome. O default é NOT OVERRIDING. Desta
forma se viermos a especificar um método no subtipo com o mesmo nome de um método no supertipo sem a
especificação OVERRIDING receberemos erro.
STATIC
Esta expressão indica que a função não receberá o parâmetro implícito SELF. Isto significa que a função está
associada ao tipo de objeto e não ao objeto em si. Para acioná-la devemos utilizar como qualificador o nome do
tipo de objeto (veja o exemplo da Listagem 4.32). Como este método não tem acesso direto aos dados do objeto,
normalmente criamos parâmetros para compensar esta situação.
UPCASTING
Dentro da orientação a objeto, quando criamos uma hierarquia do tipo superclasse – subclasse, podemos utilizar
um subclasse onde seja permitido uma superclasse uma vez que a subclasse contém todas as cacterísticas da
superclasse e “mais alguma coisa”. Este conceito se chama Upcasting.
Esta forma de uso de objeto é usada implicitamente pelo Oracle. Veja o exemplo da Listagem 4.33.
Nos dois exemplos apresentados incluímos um objeto do tipo CAMINHAO em uma tabela que armazena objetos
do tipo VTERRESTRE. Sabemos, pela criação anterior, que CAMINHAO é um subtipo (mais detalhado) de
VTERRESTRE (supertipo).
TREAT
A função Treat realiza a operação anterior de forma explícita. Indicamos para que tipo de objeto desejamos que a
informação seja considerada. Este uso somente será válido se as expressões e/ou os objetos envolvidos pertencerem
à mesma hierarquia. Caso contrário a função retornará NULL. Veja os exemplos da Listagem 4.34.
TREAT(VALUE(A)ASAUTOMOVEL).PARTIDA()
-------------------------------------------
Qundo incluímos, explicitamente, ou implicitamente objetos mais específicos em uma tabela que armazena objetos
mais genéricos, estes objetos levam consigo a indicação de seus tipos. Observe que no primeiro SELECT apresentado,
na tabela TB_VTERRESTRE, encontramos 3 automóveis, 1 caminhão e 1 veículo terrestre (indeterminado).
Quando usamos a função Treat e solicitamos apenas os objetos considerados AUTOMOVEL, as duas primeiras
linhas retornam NULL. Quando solicitamos apenas os objetos considerados CAMINHAO, apenas a segunda linha
aparece preenchida.
No primeiro comando SELECT obtivemos da tabela TB_VTERRESTRE aqueles objetos do tipo AUTOMOVEL ou
CAMINHAO. No segundo comando SELECT solicitamos que apenas os objetos do tipo VTERRESTRE fossem listados.
Observe que no terceiro exemplo, quando retiramos a palavra ONLY da cláusula WHERE, os objetos do tipo
AUTOMOVEL e CAMINHAO também foram listados uma vez que eles também são VTERRESTRE por herança.
POLIMORFISMO
Polimorfismo é a capacidade de o software construir, ao tempo de execução, o objeto adequado e, conseqüentemente,
acionar o método associado com o tipo de objeto derivado específico do objeto.
Isto permite a criação de programas extensíveis, que podem crescer não apenas durante a criação original do
projeto, mas ao longo do tempo quando novas características forem adicionadas.
Nos exercícios deste capítulo estaremos fazendo exemplos passo-a-passo para a utilização desta capacidade.
EXERCÍCIOS
4.13) Criar um tipo de objeto NAVE contendo:
♦ três atributos – tempo de vôo, quantidade mínima de metros da pista de aterrissagem e tempo para levantar vôo.
♦ três métodos – VOAR (que apresenta uma mensagem sobre o tempo de vôo), ATERRISSAR (que apresenta uma
mensagem sobre o tamanho da pista) e ALÇAR (que indique o tempo para levantar vôo).
O tipo de objeto Nave deve ser considerado um tipo concreto, isto é, pode ser instanciado. No entanto ele será
herdado por outros tipos.
4.14) Criar um tipo de objeto PASSARO derivado de NAVE que contenha os métodos VOAR (que indique o tempo
máximo de vôo do pássaro) e ALÇAR (que indique a envergadura do pássaro).
O tipo de objeto Passaro deve ser considerado concreto, isto é, pode ser instanciado. No entanto ele não mais
poderá ser herdado por outros tipos.
4.15) Criar um tipo de objeto BALAO derivado de NAVE que contenha os métodos ATERRISSAR (que apresente a
latitude do balão) e VOAR (que apresente o tempo estimado para o balão atingir uma altura de 50M).
O tipo de objeto Balao deve ser considerado concreto, isto é, pode ser instanciado. No entanto ele não mais poderá
ser herdado por outros tipos.
4.16) Criar uma aplicação que receba como parâmetro um tipo de objeto Nave e que execute os métodos ATERRISSAR,
VOAR e ALÇAR. Acione a rotina passando como parâmetro um objeto do tipo Nave, Passaro e Balao. Qual o
resultado obtido e por quê?
4.17) Crie uma rotina que, aleatoriamente, armazene em um array objetos do tipo Nave, Balao ou Passaro. A
quantidade de elementos do array será passada como parâmetro. Ao término do preenchimento do array execute
e apresente as mensagens enviadas pelos métodos associados ao objeto construído.
4.18) Crie uma tabela para armazenamento de Naves. Faça uma rotina para, aleatoriamente, incluir objetos do tipo
Nave, Passaro ou Balao. Use a função Treat para facilitar o armazenamento.
4.19) Execute a rotina criada no exercício anterior e inclua 10 objetos na tabela TB_NAME. Em seguida prepare um
comando de SQL que liste apenas os objetos do tipo definido como parâmetro pelo usuário.
Nos exemplos a seguir voltamos a usar as tabelas tb_cli01 e tb_dep01. Para reconstruí-las utilize os scripts 15 e 16
deste capítulo das Listagenn 4.15 e 4,16.
DEREF
Esta função retorna o objeto referenciado pelo argumento <referência>.
Na Listagem 4.36, quando usamos a função Deref para a coluna RF_TITULAR da tabela TB_DEP01, foi apresentado
o objeto referenciado, no caso o cliente titular daquele dependente.
REF
A função Ref recebe como argumento a linha de uma object table ou object view. Este valor de argumento corresponde
ao alias da tabela.
O valor retornado é uma referência à instância do objeto indicado pelo argumento.
REF(C)
--------------------------------------------------------------------------------------
0000280209E435DF64234D4E2DAA9F6DF049B621BDD8980BE5F7B5486EA51EEA841695091B020005020000
000028020917F60FB77FB844CA9220544C6D55A7C0D8980BE5F7B5486EA51EEA841695091B020005020001
Na Listagem 4.37, uma referência é construída para cada linha selecionada da Object Table TB_CLI01. O argumento para
a função, neste caso, foi o alias da tabela, pois desejávamos que a referência fosse construída para cada objeto selecionado.
REFTOHEX
Esta função converte o argumento <referência> para o hexadecimal equivalente.
NR_CARTAO RF_TITULAR
---------- --------------------------------------------------------------------------
501 0000220208E435DF64234D4E2DAA9F6DF049B621BDD8980BE5F7B5486EA51EEA841695091B
502 000022020817F60FB77FB844CA9220544C6D55A7C0D8980BE5F7B5486EA51EEA841695091B
A Listagem 4.38 apresenta o resultado em hexadecimal do argumento RF_TITULAR. Esta função é chamada implicitamente
quando solicitamos a listagem de uma coluna REF, pois a informação apresentada no SQL*Plus deve ser legível.
VALUE
A função Value recebe como argumento a linha de uma object table ou object view. Este valor de argumento corresponde
ao alias da tabela. O valor retornado é uma instância do objeto, ou seja, os dados correspondentes a esta instância.
No exemplo da Listagem 4.39, obtivemos a mesma informação de duas formas diferentes. Na primeira solicitamos o
valor do objeto e na segunda a row da tabela. Observe que, na primeira forma, a resposta inclui o nome do objeto com
o conteúdo da instância selecionada. Na segunda, recebemos apenas os valores dos atributos dos objetos selecionados.
MAKE_REF
Esta função monta uma referência (REF), baseada nas chaves informadas, para uma row de uma object view ou de
uma object table cujo OID é baseado na primary key. Estas chaves devem identificar inequivocamente a linha
relacionada. Seu uso será visto a seguir no tópico relativo a views.
Na Listagem 4.40, criamos a view Vdep com o layout do objeto OT_DEP01. Este objeto possui os atributos escalares
NR_CARTAO e NM_DEPENDENTE, os quais foram selecionados diretamente da tabela relacional DEPENDENTE. A
referência (RF_TITULAR) na tabela relacional corresponde ao relacionamento NR_CARTAO_TIT. Desta forma,
utilizamos a função Make_Ref para criar uma referência à linha da view VCLI associada à chave contida em
NR_CARTAO_TIT. Na view VCLI, o número do cartão foi utilizado para identificação única do objeto “With Object
Identifier (nr_cartao)”. Retorne a este exemplo após o estudo sobre Object Views.
OBJECT VIEWS
As Object Views tem a finalidade de simular a notação objeto tendo como origem tabelas ou views relacionais. A
definição destas views permite a criação de um ambiente de transição entre as tabelas relacionais e as Object Tables.
As aplicações já escritas continuam vendo o ambiente apenas como relacional. As novas aplicações já podem
considerar a existência de objetos utilizando, no entanto, o mesmo conjunto de tabelas. Quando todas as aplicações
tiverem sido convertidas basta que façamos a remoção das views e a carga das informações armazenadas nas
tabelas-objeto. Desta forma, fica transparente para as novas aplicações a que ambiente estamos fazendo acesso.
Para estudarmos a funcionalidade desta característica criaremos as tabelas relacionais, as preencheremos e, em
seguida, criaremos as views.
Na Listagem 4.41, estamos criando uma tabela relacional chamada CLIENTE contendo as mesmas informações das
tabelas Cliente criadas até agora: nome, número do cartão e número de telefone.
Na Listagem 4.42, foram incluídas três linhas na tabela relacional CLIENTE e quatro linhas na tabela relacional DEPENDENTE.
Para prepararmos a visualização das tabelas relacionais como objetos, usaremos os tipos OT_END01 e OT_CLI01 já
estudados anteriormente.
♦ View VDEP – Nesta view, a única dificuldade era estabelecer a referência ao objeto correspondente. Utilizamos
a função Make_Ref (já apresentada anteriormente) para estabelecer a referência dinâmica da view VCLI relativa
ao cartão Nr_Cartão_Tit.
Em ambos os casos, a criação da view necessitou da expressão “With Object Identifier” a fim de determinar qual o
atributo ou conjunto de atributos que devem ser usados para identificar univocamente a row da view.
NM_DEPENDENTE RF_TITULAR.NM_CLIENTE
-------------------- ---------------------
João Primeiro cliente
Pedro Segundo cliente
Maurício Segundo cliente
Fátima Primeiro cliente
Na Listagem 4.45, fazemos uma consulta total à view VCLI e obtemos um resultado similar à consulta a uma tabela
Objeto. No segundo comando SELECT utilizamos a referência RF_TITULAR para atingir uma informação do “objeto”
correspondente. Observe que em ambos os casos usamos sintaxes associadas a objeto e o comportamento do View
é similar a uma Object Table.
Nosso próximo passo serão as operações de atualização.
Na Listagem 4.46 criamos um trigger para a view VDEP, que faz uma referência ao objeto cliente.
A função Deref utilizada no exemplo fará a obtenção do objeto endereçado pela view. De posse deste objeto,
podemos obter o número do cartão para estabelecer o relacionamento.
No próximo exemplo, a cada inclusão em VCLI são adicionadas linhas em CLIENTE.
1 linha criada.
Executamos os comandos INSERT sobre as views-objeto e veremos a seguir o que aconteceu nas tabelas relacionais.
Na Listagem 4.48, vemos o resultado das inclusões realizadas anteriormente e podemos conferir que as linhas
incluídas através da view VDEP foram associadas ao cartão titular desejado.
EXERCÍCIOS
4.20) Monte uma listagem que apresente o funcionário, seu endereço (utilize navegação via Ref) e seu cargo
(utilize a função Deref).
4.21) A partir da tabela relacional Func, crie uma Object View que simule a tabela TB_FUNC. Não inclua telefone
nesta simulação.
4.22) Crie uma trigger associada à view do exercício anterior e que realize as operações de inclusão ou exclusão nas
tabelas correspondentes.
4.23) Faça uma rotina para inclusão de linhas na tabela TB_TFUNC.
TÉCNICA
♦ Exemplificação passo-a-passo e exercícios de fixação.
Estes tipos também podem ser coleções (Varrays, Nested Tables). Podemos criar uma coleção de escalares ou uma
coleção de objetos, isto é, um tipo coleção utiliza a definição de um tipo objeto como elemento da coleção ou um
tipo predefinido no Oracle (varchar2, date, etc.).
Por outro lado, um tipo pode ser derivado de outro: um Varray pode ser composto de uma lista de objetos ou um
objeto pode conter um ou mais Varrays (como atributos), e assim por diante.
Vimos, anteriormente, que cada tipo de objeto definido pelo usuário possui um método construtor capaz de
construir o objeto correspondente. Esta mesma técnica será usada com coleções. Quando criamos uma coleção, é
criada, implicitamente, associada a ela, uma forma de construir os elementos da coleção. É o que veremos passo a
passo a partir de agora.
VARRAY TYPE
Um varray é uma coleção ordenada e limitada de elementos de mesmo tipo. Um Varray deve ter um nome (o
Oracle não suporta varrays anônimos). Todos os varrays são de comprimento variável (com um tamanho limite
inteiro); a alocação da informação ocorre à medida que preenchemos a coleção.
O tipo de dado de um Varray pode ser: um escalar (varchar2, number, date, raw, char, etc.), uma referência a um
objeto (Ref) ou um outro tipo objeto (contendo outro varray).
Como restrição temos que o tipo de dado de um varray não pode ser: um LOB ou um objeto do tipo XMLTYPE no banco de dados (em PL/SQL este
uso é permitido) porque o Oracle armazena os dados de um XMLTYPE como CLOB.
O Varray pode ser armazenado na linha da tabela ou podemos determinar que seja armazenado externamente.
Após a criação do tipo, podemos utilizá-lo tanto em PL/SQL, como variável, quanto no banco de dados como
atributo de um objeto ou coluna de uma tabela relacional (como no exemplo da Listagem 4.50).
Observe que para incluirmos elementos no varray utilizamos o nome do tipo, como se fosse uma função que
recebe parâmetro. Na verdade, estamos invocando o método construtor (constructor method) definido
implicitamente para cada tipo.
Para o último cliente incluído não informamos telefone. Neste caso, o método construtor é invocado sem parâmetros,
porém apresentando o abre e fecha parênteses, como vimos anteriormente no estudo de objetos.
Neste exemplo, efetuamos a alteração de uma linha, inclusive modificando um número de telefone. Observe que
o Varray é tratado como uma coluna única. Não temos mecanismo para indexar seus valores individualmente em
nível de SQL; isto será feito em PL/SQL.
Neste exemplo, efetuamos uma consulta sobre a tabela CLI04 contendo um array de telefones. Observe que a lista
apresentada mostra o tipo da coluna com os valores internamente.
No exemplo da Listagem 4.54 montamos um rotina para realizar a inclusão na tabela CLI04 a partir de dados
fornecidos pelo usuário.
Para a utilização de uma nova posição no Varray Vr_Telefone, tivemos de primeiramente estender o array (usamos
a procedure Extend para realizar esta operação). Em seguida, fizemos a atribuição indexada para o Varray.
27 END IF;
28 IF PTEL5 IS NOT NULL THEN
29 WTEL.EXTEND;
30 I := I + 1;
31 WTEL(I) := PTEL5;
32 END IF;
33 INSERT INTO CLI04
34 VALUES (PNUM, PNOME, WTEL);
35 END;
36 /
Procedimento criado.
No exemplo da Listagem 4.54 temos alguns pontos a observar. Primeiramente declaramos o VARRAY a partir do
tipo definido diretamente no banco de dados. Nesta declaração devemos alocar o VARRAY. Por este motivo usamos
o método construtor, sem parâmetros para a construção da área do array, vazia. A cada elemento a ser incluído no
array, precisamos usar o método EXTEND para alocar a área da posição para que possamos preenchê-la. Estas são
as diferenças básicas entre o uso de VARRAY (o mesmo se aplica a NESTED TABLES) e INDEX-BY TABLES.
O Oracle Server armazena os dados das Nested Tables fora das linhas da tabela-pai, usando uma propriedade (store
table) que ficará associada com a coluna da Nested Table. A linha-pai, na verdade, contém um identificador único
associado com a instância correspondente da Nested Table.
O tipo de dado de uma Nested Table pode ser: um escalar (varchar2, number, date, raw, char, blob, clob, etc.), uma
referência a um objeto (Ref), um tipo objeto.
Quando o tipo de dado é um objeto, a nested table descreve uma tabela cujas colunas correspondem a atributos do
tipo objeto.
Quando seu tipo é escalar, a nested table descreve uma tabela com uma única coluna, de tipo escalar, chamada
“column_value” (nome padrão predefinido).
Como restrição temos que o tipo de dado de uma Nested Table não pode ser NCLOB, mas pode ser BLOB ou CLOB.
Repetimos o exemplo do Varray para examinarmos as diferenças de utilização entre um e outro. A primeira diferença já
observamos na definição, em que não mencionamos o limite. Uma coleção do tipo Nested Table não tem limite predefinido.
Na Listagem 4.56, estabelecemos a Nested Table como uma coluna da tabela relacional CLI05 e definimos que seu
armazenamento será realizado na tabela física Tab_Nr_Tel.
Apesar de a tabela Tab_Nr_Tel não poder ser referenciada pela DML diretamente, alguns comandos de DDL podem ser
feitos para ela, tais como: adição de restrições, índices e modificações de especificações de armazenamento, dentre outros.
A inclusão pode ser feita junto com a inclusão da linha, como ocorreu para o cartão 100 e 200. Para o cartão 300,
inicialmente, utilizamos o método default da Nested Table para indicar uma linha vazia para o telefone; no próximo
exemplo faremos a inclusão de dados apenas na Nested Table.
Os comandos Insert da Listagem 4.58 incluem dados apenas na Nested Table e não na tabela CLI05.
A expressão TABLE obtém uma referência à Nested Table subordinada à linha da tabela Cliente_03 indicada pela
cláusula Where. A cláusula Where identifica qual a linha da tabela cliente que contém a Nested Table na qual
desejamos efetuar a inclusão.
Desta forma, a inclusão se processa apenas na tabela embutida Nr_Tel do cartão 300 e depois do cartão 200.
A utilização da expressão TABLE indica o retorno de uma Nested Table. Se mais de uma tabela embutida for
retornada, ocorrerá um erro.
O comando de alteração inicialmente identifica a Nested Table com a expressão TABLE, da mesma forma que
fizemos na inclusão, obtendo uma Nested Table relativa à linha com cartão 100 da tabela CLI05.
Identificada a tabela, o segundo passo é identificar a linha desta tabela embutida que desejamos modificar. Como
nossa tabela, neste primeiro exemplo, é composta de uma única coluna denominada Column_Value, utilizamos
esta coluna (na cláusula Where) para determinar, exatamente, a linha que desejávamos modificar. Esta coluna
pode ser utilizada tanto na cláusula Where quanto na cláusula Set.
No comando Select da Listagem 4.60, facilmente obtivemos todas as linhas da tabela embutida Nr_Tel, de forma
similar ao que aconteceu com o Varray.
CURSOR STATEMENT : 3
COLUMN_VA
---------
2345167
2546789
CURSOR STATEMENT : 3
COLUMN_VA
---------
2879076
CURSOR STATEMENT : 3
não há linhas selecionadas
Já no comando Select da Listagem 4.61, imaginamos que somente os números de telefone começados com 2
interessavam ao resultado. Desta forma, precisamos realizar uma restrição sobre os dados trazidos da tabela embutida.
Para realizar esta operação, utilizamos a expressão Cursor que gera uma lista contendo as linhas de Nr_Tel que
satisfazem à condição estabelecida. Não necessitamos utilizar este recurso no primeiro comando Select (Listagem
4.60), porque todas as linhas de Nr_Tel foram selecionadas.
A palavra Table utilizada no subselect tem a finalidade de indicar que estamos consultando informações de uma
Nested Table.
♦ A criação de índices em colunas de uma Nested Table pode ser necessária. Este recurso não está disponibilizado
para Varrays.
♦ A ordem de cadastramento das linhas não é importante, e caso haja alguma necessidade de ordem podemos
provê-la através de um índice em uma coluna da tabela embutida.
♦ Não temos idéia da quantidade de linhas da tabela embutida, ou não há limite, na prática. A definição de um
Varray necessita de um limite definido que seja real para que possamos lucrar no armazenamento.
USANDO CAST
A função Cast tem a finalidade de permitir a transformação de uma coleção em outra (Varrays em Nested Tables e
vice-versa).
Neste exemplo da Listagem 4.62 criamos um tipo de objeto OTEND01 com os atributos NM_RUA, CD_ESTADO e
NR_RUA. Em seguida criamos um VARRAY e uma NESTED TABLE baseados neste tipo de objeto (e não mais em
escalares, como fizemos anteriormente).
Na criação da tabela, utilizamos o Varray como atributo do objeto OTCLI06 e, posteriormente, da tabela CLI06.
A inclusão de linhas não trouxe grandes novidades. Incluímos mais de um elemento no Varray, mesmo sendo derivado
de um objeto. Precisamos apenas utilizar o método construtor tanto do Varray quanto do objeto incluído nele.
NR_CARTAO NM_CLIENTE
---------- ----------
NM_ENDERECO(NM_RUA, CD_ESTADO, NR_RUA)
---------------------------------------------------------------------
100 CLIENTE DE TESTE 01
VREND01(OTEND01('RUA R1', 'RJ', 123), OTEND01('RUA R2', 'RJ', 456))
NR_CARTAO NM_CLIENTE
---------- ----------
CAST(NM_ENDERECOASNTEND01)(NM_RUA, CD_ESTADO, NR_RUA)
---------------------------------------------------------------------
100 CLIENTE DE TESTE 01
NTEND01(OTEND01('RUA R1', 'RJ', 123), OTEND01('RUA R2', 'RJ', 456))
Neste exemplo utilizamos a função Cast e transformamos as informações do Varray em informações de uma
Nested Table. Aparentemente o resultado é o mesmo, com a diferença apenas no método construtor, que neste
segundo exemplo mostra o método da Nested Table e não do Varray.
NM_RUA CD NR_RUA
----------- -------------- ------
RUA R1 RJ 123
RUA R2 RJ 456
A diferença está no fato de podermos obter linhas selecionadas de uma Nested Table e não termos esta possibilidade
em um Varray.
Quando usamos a expressão Cast, podemos tratar o Varray como uma Nested Table e utilizar as opções disponíveis.
Ocorre alguma degradação na pesquisa por termos de, inicialmente, transformar o Varray na Nested Table, porém,
em diversas situações, isto pode ser extremamente útil.
Na Listagem 4.67, no subselect, a operação mais interna é transformar um determinado Varray (referente ao cartão
100) em uma Nested Table. Com a indicação de que o resultado do subselect retornaria a referência a uma tabela
(TABLE), pudemos, no Select de nível mais externo, estabelecer restrições sobre as linhas lidas da tabela em referência.
Só foram lidas linhas em que o código do estado fosse RJ.
SQL> INSERT INTO REND01 VALUES ('RUA 1', 'RJ', 123, 100);
1 linha criada.
SQL> INSERT INTO REND01 VALUES ('RUA 2', NULL, 456, 200);
1 linha criada.
SQL> INSERT INTO REND01 VALUES ('RUA 3', 'RS', NULL, 300);
1 linha criada.
Na Listagem 4.68, estamos criando tabelas relacionais com a mesma informação relativa à tabela Nested ou ao Varray.
NR_CARTAO NM_CLIENTE
---------- ----------
CAST(NM_RUA, CD_ESTADO, NR_RUA)
-------------------------------------
100 CLIENTE DE TESTE 01
NTEND01(OTEND01('RUA 1', 'RJ', 123))
Na Listagem 4.69, executamos um comando Select relacionando uma tabela relacional e uma tabela objeto.
O layout da tabela relacional foi adaptado ao layout da coleção NTEND01. Isto é possível graças à expressão Cast
utilizada junto com Multiset. Multiset indica que o subselect retornará mais de uma linha.
Os dados retornados possuem a mesma definição e são selecionados na mesma ordem do objeto OTEND01 (Nested
Table NTEND01). A sintaxe “as NTEND01” indica à qual tipo de coleção o resultado se compara. A expressão Cast
faz, então, a adaptação.
Isto permite que utilizemos tabelas relacionais, porém já com a sintaxe objeto-relacional. Pode ser útil em Object
Views, já estudadas anteriormente.
EXERCÍCIOS
4.24) Incluir o telefone 938274039, ddd 31, celular, para o funcionário de matrícula 400. Inclua também o telefone
28495098, ddd 11, não celular, para o funcionário de matrícula 600.
4.25) Deseja-se um arquivo contendo: nome do funcionário, telefone completo, nascimento, nome do cargo,
salário e grau de instrução. O arquivo deve receber os dados ordenados por nome do cargo e nome do funcionário.
4.26) Faça uma rotina que realize inclusão de novos endereços para cliente.
4.27) Faça uma rotina que apresente, para cada cliente, a lista de endereços cadastrados.
4.28) Altere a Object View criada no exercício 4.21 para incluir a leitura da tabela TEL_FUNC de tal forma que cada
funcionário possa ter mais de um telefone.
4.29) Modifique o trigger associado à view para que comporte a atualização da tabela TEL_FUNC.
4.30) Inclua um novo funcionário contendo 3 telefones. Verifique o resultado.
MODELO OBJETO
O modelo apresentado na Figura 4.03 apresenta os tipos de objeto que usaremos nos exercícios deste capítulo.
No diagrama o tipo de objeto Tpessoa é herdado por dois tipos: Tfunc e Tcliente. Tfunc tem uma associação com
Tcargo, enquanto que Tcliente tem uma associação com Tempresa. Ttel é uma agregação presente em Tcliente,
Tempresa e Tfunc. Já Tend é uma agregação para Tcliente e Tfunc. Tend ainda tem uma associação com Testado.
O único tipo de objeto que não possui método é Tempresa. Todos os outros possuem.
O tipo de objeto Tpessoa é abstrato, ou seja, foi definido como Not Instantiable. Ele tem a finalidade de determinar
um padrão para os tipos Tcliente e Tfunc. Em cada um dos tipos de objeto (exceto Tempresa) foi criado um método
do tipo Map para garantir que poderemos estabelecer ordenação pelo atributo correspondente.
As coleções não foram apresentadas no diagrama. Para que cada cliente pudesse informar diversos telefones, os
objetos do tipo Ttel foram organizados em um varray de nome Tvtel (isto ocorre para Tcliente e Tfunc, mas não
ocorre para Tempresa). Um cliente pode informar diversos endereços. Para tal os objetos do tipo Tend foram
organizados em uma Nested Table de nome Tnend. Isto não ocorre para Tfunc, que só possui um endereço.
Nesse primeiro script, todas as tabelas são removidas, o que permite que reexecutemos as mesmas operações
diversas vezes e façamos a implementação do modelo novamente; portanto, não se espante se na primeira vez que
você executá-lo cada um dos comandos DROP apresente a mensagem de erro ERRO na linha 1: ORA-00942: a
tabela ou view não existe.
Neste script criamos os tipos de objeto e aqueles tipos referentes a coleções. Observe que criamos um supertipo
TPESSOA com a especificação NOT INSTANTIABLE; isto significa que não poderemos instanciar objetos para este
tipo. Podemos dizer que se trata de um tipo de objeto abstrato. Todos os métodos associados a este tipo também
receberam a especificação NOT INSTANTIABLE. Neste caso, o objetivo foi estabelecer um padrão de rotina. A
rotina não foi implementada no nível TPESSOA; no entanto seu nome, parâmetros e tipo de retorno foram
especificados neste nível e deverão ser respeitados pelos subtipos associados.
Neste script criamos as tabelas associadas ao modelo para os tipos previamente definidos.
Neste script definimos os métodos para cada um dos tipos. Apesar da diversidade de métodos, a lógica individual
de cada um é bem simples.
Com este script incluímos algumas poucas linhas nas tabelas criadas. Ao longo dos exercícios incluiremos mais
algumas linhas. Iniciemos, portanto, os exercícios.
Listagem-resposta 4.01A
SQL> COL NM_PESSOA FOR A25
SQL> SELECT NM_PESSOA, CD_PESSOA, NM_ENDERECO FROM TB_TFUNC
2 ORDER BY 3;
NM_PESSOA CD_PESSOA
--------------------------------------------------------------------
NM_ENDERECO(NM_RUA, NM_BAIRRO, NM_CIDADE, CD_ESTADO, NR_RUA, NR_CEP)
--------------------------------------------------------------------------------
Daniel Marques 100
TEND('Av Niemyer', 'Leblon', 'Rio de Janeiro', 0000220208708EE7F500A74950A8161B1
953E759802DB4EF2BD141485BB762A457C0DFD6C8, 12, 20854900)
Como a tabela possui diversas colunas listamos apenas três delas e solicitamos ordenação pela coluna nm_endereço,
como se ela fosse uma coluna escalar. Verifique a função Map associada a Tend e observe que a ordenação se dará
pelo número do CEP.
Listagem-resposta 4.01B
SQL> SELECT VALUE(C) FROM TB_TFUNC C
2 ORDER BY 1;
TFUNC('Davi Barbosa', 300, 'F ', TVTEL(TTEL(21, 22985467, 'N'), TTEL(21, 9127845
, 'S')), '30/03/82', '01/05/01', 3000, 000022020827F30CAB40444F26A5126DCA2DFE1FA
6738452E4B14D4EA691241F3F54126040, TEND('Av das Américas', 'Barra da Tijuca', 'R
io de Janeiro', 0000220208708EE7F500A74950A8161B1953E759802DB4EF2BD141485BB762A4
57C0DFD6C8, 23987, 20954900), 55)
TFUNC('Gabriel Azevedo', 200, 'F ', TVTEL(TTEL(21, 22478912, 'N'), TTEL(21, 9098
5430, 'S')), '07/10/78', '01/12/00', 3500, 000022020872C52048B9BB453D9202BC42EAD
6B92F738452E4B14D4EA691241F3F54126040, TEND('Av das Américas', 'Barra da Tijuca'
, 'Rio de Janeiro', 0000220208708EE7F500A74950A8161B1953E759802DB4EF2BD141485BB7
62A457C0DFD6C8, 11233, 20954900), 55)
Nesta segunda forma de leitura dos dados usamos a função Value e solicitamos a ordenação pelo próprio objeto
Tfunc. No corpo do pacote Tfunc encontramos a função Ordena que é do tipo Map. Verifique a rotina para saber
como foi feita esta ordenação.
4.02) Inclua uma nova linha na tabela Tb_tcargo utilizando o método construtor Tcargo.
Listagem-resposta 4.02A
SQL> INSERT INTO TB_TCARGO VALUES (TCARGO('Professor', 3));
1 linha criada.
4.03) Inclua um novo funcionário em Tb_Tfunc. Não forneça valor para as colunas cd_cargo, nr_telefone e cd_estado.
Listagem-resposta 4.03A
SQL> INSERT INTO TB_TFUNC
2 (NM_PESSOA, CD_PESSOA, IN_TIPO_PESSOA, DT_NASC, DT_ADM,
3 VL_SAL, NM_ENDERECO, NR_GIT) VALUES
4 ('João Pedro', 400, 'PF', TO_DATE('12041989', 'DDMMYYYY'), SYSDATE, 2000,
5 TEND('Rua Pereira Nunes', 'Tijuca', 'Rio de Janeiro', null, 144, 20123650), 45);
1 linha criada.
4.04) Utilize o método Mcargo para obter informações sobre o objeto Tcargo. Liste simultaneamente o código do cargo.
Listagem-resposta 4.04A
SQL> SELECT C.MCARGO(), CD_CARGO FROM TB_TCARGO C;
4.05) Crie um programa em PL/SQL que receba como parâmetro o código do funcionário e seu endereço para
alteração. Estado não deve ser modificado.
Listagem-resposta 4.05A
SQL> CREATE OR REPLACE PROCEDURE ALTFUNC (PCOD IN NUMBER, PRUA IN VARCHAR2 := NULL,
2 PBAIRRO IN VARCHAR2 := NULL, PCIDADE IN VARCHAR2 := NULL,
3 PNR IN NUMBER := NULL, PCEP IN NUMBER := NULL) IS
4 WEND TEND;
5 WROW ROWID;
6 BEGIN
7 SELECT E.NM_ENDERECO, ROWID INTO WEND, WROW
8 FROM TB_TFUNC E
9 WHERE CD_PESSOA = PCOD
10 FOR UPDATE;
11 WEND.NM_RUA := NVL(PRUA, WEND.NM_RUA);
12 WEND.NM_BAIRRO := NVL(PBAIRRO, WEND.NM_BAIRRO);
13 WEND.NM_CIDADE := NVL(PCIDADE, WEND.NM_CIDADE);
14 WEND.NR_RUA := NVL(PNR, WEND.NR_RUA);
15 WEND.NR_CEP := NVL(PCEP, WEND.NR_CEP);
16 UPDATE TB_TFUNC F
17 SET F.NM_ENDERECO = WEND
18 WHERE ROWID = WROW;
19 COMMIT;
20 END;
21 /
Procedimento criado.
4.06) Usando a rotina do exercício anterior, atualize o CEP do funcionário de matrícula 200 para o valor 20789500.
Após a atualização verifique o resultado.
Listagem-resposta 4.06A
SQL> EXECUTE ALTFUNC(200, PCEP => 20789500);
Procedimento PL/SQL concluído com sucesso.
4.07) Selecione com um único comando o nome do funcionário e o nome de seu cargo. Não utilize join.
Listagem-resposta 4.07A
SQL> COL NM_PESSOA FOR A30
SQL> COL CARGO FOR A20
SQL> SELECT F.NM_PESSOA, F.CD_CARGO.NM_CARGO CARGO FROM TB_TFUNC F;
4.08) Atualize a tabela de funcionários associando o cargo 3 (professor) ao funcionário de matrícula 400.
Listagem-resposta 4.08A
SQL> UPDATE TB_TFUNC F
2 SET F.CD_CARGO = (SELECT REF(C) FROM TB_TCARGO C
3 WHERE CD_CARGO = 3)
4 WHERE F.CD_PESSOA = 400;
4.09) Inclua uma nova linha em funcionário informando, simultaneamente, valor para cargo e estado.
Listagem-resposta 4.09A
SQL> INSERT INTO TB_TFUNC F VALUES
2 ('Alfredo Lima', 600, 'PJ', NULL, TO_DATE('07031983'),
3 SYSDATE, 800, (SELECT REF(C) FROM TB_TCARGO C WHERE CD_CARGO = 2),
4 TEND('Rua Ipiranga', 'Centro', 'Petrópolis',
5 (SELECT REF(E) FROM TB_TESTADO E WHERE CD_ESTADO = 'RJ'),
6 42, 25985020), 55);
1 linha criada.
4.10) Verifique se existe algum cliente sem definição de empresa ou com especificação de empresa inválida.
Listagem-resposta 4.10A
SQL> SELECT CD_PESSOA, NM_PESSOA, 'SEM EMPRESA'
2 FROM TB_TCLIENTE
3 WHERE CD_EMP IS NULL
4 OR CD_EMP IS DANGLING;
4.11) Inclua uma nova linha na tabela TB_TEMPRESA sem informar valor para as colunas nm_empresa e nr_telefone.
O que acontece? Por quê? Em que local a restrição é definida?
Listagem-resposta 4.11A
SQL> INSERT INTO TB_TEMPRESA (CD_EMPRESA) VALUES (4);
INSERT INTO TB_TEMPRESA (CD_EMPRESA) VALUES (4)
*
ERRO na linha 1:
ORA-01400: não é possível inserir NULL em (“DESENV”.”TB_TEMPRESA”.”NM_EMPRESA”)
Ocorre um erro (mostrado na resposta 4.11A) porque o atributo NM_EMPRESA é de preenchimento obrigatório. As
restrições são definidas quando o objeto é implementado em uma tabela.
4.12) Obtenha informações relativas a cargo e estado, quando possível. Use DEREF.
Listagem-resposta 4.12A
SQL> SELECT F.NM_PESSOA, DEREF(F.CD_CARGO) CARGO,
2 F.NM_ENDERECO.CD_ESTADO ESTADO
3 FROM TB_TFUNC F
4 WHERE F.CD_CARGO IS NOT NULL
5 AND F.CD_CARGO IS NOT DANGLING
6 AND F.NM_ENDERECO.CD_ESTADO IS NOT NULL
7 AND F.NM_ENDERECO.CD_ESTADO IS NOT DANGLING;
Listagem-resposta 4.13A
SQL> CREATE OR REPLACE TYPE NAVE AS OBJECT
2 (VOO NUMBER,
3 PISTA NUMBER,
4 TEMPO NUMBER,
5 MEMBER FUNCTION VOAR RETURN VARCHAR2,
4.14) Criar um tipo de objeto PASSARO derivado de NAVE que contenha os métodos VOAR (que indique o tempo
máximo de vôo do pássaro) e ALÇAR (que indique a envergadura do pássaro).
O tipo de objeto Passaro deve ser considerado concreto, isto é, pode ser instanciado. No entanto ele não mais
poderá ser herdado por outros tipos.
Listagem-resposta 4.14A
SQL> CREATE OR REPLACE TYPE PASSARO UNDER NAVE
2 (ENVERGADURA NUMBER,
3 OVERRIDING MEMBER FUNCTION VOAR RETURN VARCHAR2,
4 OVERRIDING MEMBER FUNCTION ALÇAR RETURN VARCHAR2
5 );
6 /
Tipo criado.
METHOD
------
MEMBER FUNCTION VOAR RETURNS VARCHAR2
METHOD
------
MEMBER FUNCTION ATERRISSAR RETURNS VARCHAR2
METHOD
------
MEMBER FUNCTION ALÇAR RETURNS VARCHAR2
Neste exercício criamos o tipo Passaro que contém 4 atributos, três dos quais herdados de Nave e um próprio. Os
métodos Voar e Alçar foram substituídos neste subtipo, porém o método Aterrissar foi herdado de Nave.
Uma vez que FINAL é o default, não precisamos fazer nenhuma outra especificação para indicar que ele não
poderá ser herdado por outros tipos.
4.15) Criar um tipo de objeto BALAO derivado de NAVE que contenha os métodos ATERRISSAR (que apresente a
latitude do balão) e VOAR (que apresente o tempo estimado para o balão atingir uma altura de 50M).
O tipo de objeto Balao deve ser considerado concreto, isto é, pode ser instanciado. No entanto ele não mais poderá
ser herdado por outros tipos.
Listagem-resposta 4.15A
SQL> CREATE OR REPLACE TYPE BALAO UNDER NAVE
2 (LATITUDE NUMBER,
3 OVERRIDING MEMBER FUNCTION VOAR RETURN VARCHAR2,
4 OVERRIDING MEMBER FUNCTION ATERRISSAR RETURN VARCHAR2
5 );
6 /
Tipo criado.
METHOD
------
MEMBER FUNCTION VOAR RETURNS VARCHAR2
METHOD
------
MEMBER FUNCTION ATERRISSAR RETURNS VARCHAR2
METHOD
------
MEMBER FUNCTION ALÇAR RETURNS VARCHAR2
Observe que Balao também é derivado de Nave; no entanto seus atributos são diferentes dos de Passaro pois ele
acrescentou o atributo LATITUDE àqueles herdados de Nave. As funções Voar e Aterrissar foram substituídas por
funções próprias, enquanto que Alçar corresponde à mesma função implementada em Nave.
4.16) Criar uma aplicação que receba como parâmetro um tipo de objeto Nave e que execute os métodos ATERRISSAR,
VOAR e ALÇAR. Acione a rotina passando como parâmetro um objeto do tipo Nave, Passaro e Balao. Qual o
resultado obtido e por quê?
Listagem-resposta 4.16A
SQL> CREATE OR REPLACE FUNCTION POLIMORFISMO(POBJETO IN NAVE) RETURN VARCHAR2 IS
2 RETORNO VARCHAR2(1000);
3 BEGIN
4 RETORNO := POBJETO.VOAR||CHR(10)||
5 POBJETO.ATERRISSAR||CHR(10)||
6 POBJETO.ALÇAR||CHR(10);
7 RETURN RETORNO;
8 END;
9 /
Função criada.
A função criada espera receber como parâmetro um objeto do tipo Nave. Desta forma a expectativa é que as rotinas
a serem executadas sejam aquelas relativas a Nave.
Listagem-resposta 4.16B
SQL> SELECT 'NAVE', POLIMORFISMO(NAVE(1,2,3)) POLIMORFISMO FROM DUAL
2 UNION
3 SELECT 'PASSARO', POLIMORFISMO(PASSARO(4, 5, 6, 7)) FROM DUAL
4 UNION
5 SELECT 'BALAO', POLIMORFISMO(BALAO(8, 9, 10, 11)) FROM DUAL
6 ORDER BY 1;
'NAVE'
------
POLIMORFISMO
------------
BALAO
O tempo para o balão atingir 50M é de 8 horas
A latitude atual é 11 graus
O tempo previsto para o avião alçar vôo é de 10 minutos
NAVE
O tempo previsto de vôo é de 1 horas
O tamanho mínimo para a pista de aterrissagem é de 2 metros
O tempo previsto para o avião alçar vôo é de 3 minutos
PASSARO
O tempo máximo de voo do pássaro é de 4 horas
O tamanho mínimo para a pista de aterrissagem é de 5 metros
A envergadura do pássaro é de 7 metros
Observe que, quando passamos como parâmetro um objeto do tipo Balão, o software percebeu que o objeto
pertencia à hierarquia de Nave, porém não era Nave e sim Balão e executou o método relativo a Balão e não a Nave.
Esta característica se chama Polimorfismo.
4.17) Crie uma rotina que, aleatoriamente, armazene em um array objetos do tipo Nave, Balao ou Passaro. A
quantidade de elementos do array será passado como parâmetro. Ao término do preenchimento do array execute
e apresente as mensagens enviadas pelos métodos associados ao objeto construído.
Listagem-resposta 4.17A
SQL> CREATE OR REPLACE PROCEDURE POLIMORFISMO2(PQTD IN NUMBER) IS
2 TYPE TAB IS TABLE OF NAVE INDEX BY BINARY_INTEGER;
3 LINHA TAB;
4 VRANDOM NUMBER;
5 RETORNO VARCHAR2(1000);
6 BEGIN
7 DBMS_RANDOM.INITIALIZE(TO_NUMBER(TO_CHAR(SYSDATE,'SSMIHH24DD')));
8 FOR I IN 1..PQTD LOOP
9 VRANDOM := MOD(DBMS_RANDOM.RANDOM, 3);
10 CASE VRANDOM WHEN 0 THEN LINHA(I) := NAVE(1, 2, 3);
11 WHEN 1 THEN LINHA(I) := PASSARO(4, 5, 6, 7);
12 ELSE LINHA(I) := BALAO(8, 9, 10, 11);
13 END CASE;
14 END LOOP;
15 FOR I IN 1..PQTD LOOP
16 RETORNO := LINHA(I).VOAR||CHR(10)||
17 LINHA(I).ATERRISSAR||CHR(10)||
18 LINHA(I).ALÇAR||CHR(10);
19 DBMS_OUTPUT.PUT_LINE(RETORNO);
20 END LOOP;
21 END;
22 /
Procedimento criado.
No procedimento criado o array é definido baseado no objeto Nave; no entanto, quando construímos o objeto a
ser armazenado neste array utilizamos Nave, Passaro e Balao, de acordo com o retorno da função Random. Quando
encerramos a construção voltamos a ler todo o array e passamos a executar os métodos Voar, Aterrissar e Alçar do
objeto construído.
Listagem-resposta 4.17B
SQL> SET LINESIZE 300
SQL> SET SERVEROUT ON
SQL> EXECUTE POLIMORFISMO2(4);
O tempo previsto de vôo é de 1 horas
O tamanho mínimo para a pista de aterrissagem é de 2 metros
O tempo previsto para o avião alçar vôo é de 3 minutos
Pelo resultado observamos que nesta execução foram construídos dois objetos do tipo Balao e dois objetos do tipo
Passaro. A característica de Polimorfismo é observada mais uma vez pois ao tempo de execução construímos,
aleatoriamente, os objetos e o software foi capaz de construí-los, identificá-los e executar o método adequado ao
objeto correspondente.
4.18) Crie uma tabela para armazenamento de Naves. Faça uma rotina para, aleatoriamente, incluir objetos do tipo
Nave, Passaro ou Balao. Use a função Treat para facilitar o armazenamento.
Listagem-resposta 4.18A
SQL> CREATE TABLE TB_NAVE OF NAVE;
Tabela criada.
Observe que ao tempo de execução preenchemos as linhas da tabela com objetos contendo características diferentes,
porém somente os atributos comuns serão incluídos na tabela TB_NAVE.
4.19) Execute a rotina criada no exercício anterior e inclua 10 objetos na tabela TB_NAVE. Em seguida prepare um
comando de SQL que liste apenas os objetos do tipo definido como parâmetro pelo usuário.
Listagem-resposta 4.19A
SQL> EXECUTE INAVE(10);
Procedimento PL/SQL concluído com sucesso.
Observe que, mesmo que algumas características do objeto sejam perdidas, pelo fato de estar sendo armazenada
em uma tabela do supertipo, a identificação do tipo de objeto não é perdida, o que permite que o método adequado
seja executado, como apresentado na Listagem-resposta 4.19B.
Listagem-resposta 4.19B
SQL> select n.voar() from tb_nave n;
N.VOAR()
---------------------------------------------
O tempo para o balão atingir 50M é de 8 horas
O tempo para o balão atingir 50M é de 8 horas
O tempo máximo de voo do pássaro é de 4 horas
O tempo para o balão atingir 50M é de 8 horas
O tempo máximo de voo do pássaro é de 4 horas
O tempo para o balão atingir 50M é de 8 horas
O tempo para o balão atingir 50M é de 8 horas
O tempo para o balão atingir 50M é de 8 horas
O tempo para o balão atingir 50M é de 8 horas
O tempo para o balão atingir 50M é de 8 horas
10 linhas selecionadas.
4.20) Monte uma listagem que apresente o funcionário, seu endereço (utilize navegação via Ref) e seu cargo
(utilize a função Deref).
Listagem-resposta 4.20A
SQL> SET LINESIZE 100
SQL> COL NOME FOR A18
SQL> COL RUA FOR A18
SQL> COL BAIRRO FOR A18
SQL> COL CIDADE FOR A18
SQL> COL ESTADO FOR A18
SQL> COL CARGO FOR A40
SQL> SET NUMWIDTH 8
SQL> SET PAGESIZE 200
SQL> SELECT CD_PESSOA COD, NM_PESSOA NOME, E.NM_ENDERECO.NM_RUA RUA,
2 E.NM_ENDERECO.NM_BAIRRO BAIRRO, E.NM_ENDERECO.NM_CIDADE CIDADE,
3 E.NM_ENDERECO.CD_ESTADO.NM_ESTADO ESTADO, E.NM_ENDERECO.NR_CEP CEP,
4 DEREF(E.CD_CARGO) CARGO
5 FROM TB_TFUNC E;
4.21) A partir da tabela relacional Func, crie uma Object View que simule a tabela TB_FUNC. Não inclua telefone
nesta simulação.
Listagem-resposta 4.21A
SQL> CREATE TABLE TB_CARGO
2 (CD_CARGO NUMBER,
3 NM_CARGO VARCHAR2(100),
4 PRIMARY KEY (CD_CARGO));
Tabela criada.
Para reproduzir o ambiente objeto, algumas informações devem ser acrescidas no ambiente relacional. Nossa
primeira etapa deste exercício, se refere a este acréscimo: criação de uma tabela de cargos (independente), criação
de uma tabela de endereços (dependente de Func, com relacionamento 1 para 1) e criação de uma tabela de
telefones (dependente de Func, com relacionamento 1 para n). A tabela TEL_FUNC não será usada neste momento.
Listagem-resposta 4.21B
SQL> INSERT INTO TEL_FUNC
2 SELECT CD_MAT, 21, '2223'||LPAD(NR_RAMAL, 4, '0'), 'N'
3 FROM FUNC;
Como segundo passo, fizemos o preenchimento dos dados destas tabelas a partir dos dados de Func, quando
possível. A tabela TB_END está vazia pois estes dados não existiam, originariamente, em Func.
Listagem-resposta 4.21C
SQL> CREATE OR REPLACE VIEW VCARGO OF TCARGO
2 WITH OBJECT IDENTIFIER (CD_CARGO)
3 AS SELECT NM_CARGO, CD_CARGO
4 FROM TB_CARGO
5 /
View criada.
Neste passo criamos a view para simulação da referência a cargo. A criação de uma view deste tipo só é necessária
se tivermos usado referência (REF), como é o caso com cargo. A simulação única de um objeto é feita diretamente
na view final. Veja a Listagem-resposta 4.21D.
Listagem-resposta 4.21D
SQL> CREATE OR REPLACE VIEW VFUNC OF TFUNC
2 WITH OBJECT IDENTIFIER (CD_PESSOA) AS
3 SELECT NM_FUNC||' '||NM_SOBRENOME NM_PESSOA, FUNC.CD_MAT CD_PESSOA,
4 'PF' IN_TIPO_PESSOA,
5 TVTEL(TTEL(21, TO_NUMBER('2223'||LPAD(NR_RAMAL, 4, '0')), 'N')) NR_TELEFONE,
6 DT_NASC, DT_ADM, VL_SAL, MAKE_REF(VCARGO, NR_CARGO) CD_CARGO,
7 TEND(NM_RUA, NM_BAIRRO, NM_CIDADE,
8 (SELECT REF(T) FROM TB_TESTADO T WHERE T.CD_ESTADO = END_FUNC.CD_ESTADO),
9 NR_RUA, NR_CEP) NM_ENDERECO, NR_GIT
10 FROM FUNC, END_FUNC
Como última etapa construímos a view e verificamos o resultado. Observe que a descrição da view ficou igual à
descrição do objeto TFUNC (excetuando-se os métodos).
A construção da view possui três pontos que merecem a nossa atenção:
♦ a construção do varry TVTEL. Uma vez que o estudo de coleções ocorrerá no próximo tópico, simplesmente
acionamos o método construtor do varry e o método construtor do tipo de objeto armazenado no varry e
usamos constantes e o número do ramal do funcionário para compor o resultado.
♦ o cargo presente em TFUNC correspondia a uma referência ao objeto TCARGO. Desta forma criamos uma view
VCARGO, que simula a construção de um objeto com OID definido por cd_cargo, sobre a tabela Tb_cargo. Na
view usamos a função make_ref para construir a referência ao elemento correspondente na view VCARGO. O
acesso a esta view é feito através da coluna nr_cargo da tabela Func.
♦ a referência a estado presente na descrição de endereço deveria ser simulada também, porém não criamos uma
tabela relacional para isto. Incluímos, então, um comando SELECT (na posição desejada) que obtivesse a referência
(REF) da linha com o código de estado igual ao valor escalar presente na tabela END_FUNC.
Como a tabela END_FUNC estava vazia foi necessário um Outer Join na cláusula Where da view. O comando Insert
e o Select posteriores tiveram apenas o objetivo de teste.
4.22) Crie uma trigger associada à view do exercício anterior e que realize as operações de inclusão ou exclusão nas
tabelas correspondentes.
Listagem-resposta 4.22A
SQL> CREATE OR REPLACE TRIGGER TG_VFUNC
2 INSTEAD OF INSERT OR DELETE ON VFUNC
3 DECLARE
4 OESTADO TESTADO;
5 OEND TEND;
6 OTEL TTEL;
7 OCARGO TCARGO;
8 RFUNC FUNC%ROWTYPE;
9 POS NUMBER;
10 REND END_FUNC%ROWTYPE;
11 BEGIN
12 IF INSERTING THEN
13 OEND := :NEW.NM_ENDERECO;
14 OTEL := :NEW.NR_TELEFONE(1);
15 BEGIN
16 SELECT DEREF(:NEW.CD_CARGO) INTO OCARGO
17 FROM DUAL;
18 RFUNC.NR_CARGO := OCARGO.CD_CARGO;
19 EXCEPTION
20 WHEN NO_DATA_FOUND THEN
21 RFUNC.NR_CARGO := NULL;
22 END;
23 BEGIN
24 SELECT DEREF(OEND.CD_ESTADO) INTO OESTADO
25 FROM DUAL;
26 REND.CD_ESTADO := OESTADO.CD_ESTADO;
27 EXCEPTION
28 WHEN NO_DATA_FOUND THEN
29 REND.CD_ESTADO := NULL;
30 END;
31 POS := INSTR(:NEW.NM_PESSOA, ' ');
32 INSERT INTO FUNC(CD_MAT, NM_FUNC, NM_SOBRENOME, NR_RAMAL, DT_NASC,
33 DT_ADM, VL_SAL, NR_CARGO, NR_GIT)
34 VALUES (:NEW.CD_PESSOA,SUBSTR(:NEW.NM_PESSOA, 1,(POS -1)),
35 SUBSTR(:NEW.NM_PESSOA,(POS +1)), SUBSTR(OTEL.NR_TEL, -4),
36 :NEW.DT_NASC, :NEW.DT_ADM, :NEW.VL_SAL, RFUNC.NR_CARGO, :NEW.NR_GIT);
37 INSERT INTO END_FUNC (CD_MAT, NM_RUA, NM_BAIRRO, NM_CIDADE,
38 CD_ESTADO, NR_RUA, NR_CEP)
39 VALUES (:NEW.CD_PESSOA, OEND.NM_RUA, OEND.NM_BAIRRO, OEND.NM_CIDADE,
40 REND.CD_ESTADO, OEND.NR_RUA, OEND.NR_CEP);
41 ELSE
42 DELETE FROM END_FUNC WHERE CD_MAT = :OLD.CD_PESSOA;
43 DELETE FROM FUNC WHERE CD_MAT = :OLD.CD_PESSOA;
44 END IF;
45 END;
46 /
Gatilho criado.
No trigger do exercício 4.22 tínhamos como problema a ser resolvido a obtenção do nr_ramal, cd_estado e nr_cargo.
Declaramos, então, variáveis do tipo de objeto correspondente para que pudéssemos realizar os acessos necessários.
Para telefone, como estamos supondo apenas uma ocorrência, obtivemos a primeira posição do array e associamos
a um objeto do tipo TTEL. Para obter os valores escalares relativos às referências de estado e cargo, fizemos uma
decomposição da referência para área do tipo de objeto correspondente.
Listagem-resposta 4.22B
SQL> INSERT INTO VFUNC VALUES
2 ('TESTE TRIGGER', 9999, 'PF',
3 TVTEL(TTEL(21, 22879181, 'N')), TO_DATE('01012001', 'DDMMYYYY'),
4 TO_DATE('01102001', 'DDMMYYYY'), 500,
5 (SELECT REF(C) FROM VCARGO C WHERE CD_CARGO = 60),
6 TEND('RUA 1', 'BAIRRO 1', 'CIDADE 1',
7 (SELECT REF(E) FROM TB_TESTADO E WHERE CD_ESTADO = 'RJ'),
8 2, 23098765), 55);
1 linha criada.
O comando Insert foi feito sobre a view. Os dois comandos SELECT nas tabelas relacionais completam o teste.
4.23) Faça uma rotina para inclusão de linhas na tabela TB_TFUNC.
Listagem-resposta 4.23A
SQL> CREATE OR REPLACE
2 PROCEDURE IFUNC(PCOD IN NUMBER, PNOME IN VARCHAR2,
3 PDDD IN NUMBER := NULL, PTEL IN NUMBER := NULL,
4 PCEL IN VARCHAR2 := NULL, PNASC IN VARCHAR2 := NULL,
5 PSAL IN NUMBER := NULL, PCARGO IN NUMBER := NULL,
6 PNMRUA IN VARCHAR2 := NULL, PBAIRRO IN VARCHAR2 := NULL,
4.24) Incluir o telefone 938274039, ddd 31, celular, para o funcionário de matrícula 400. Inclua também o telefone
28495098, ddd 11, não celular, para o funcionário de matrícula 600.
Listagem-resposta 4.24A
SQL> DECLARE
2 OVTEL TVTEL;
3 OTEL TTEL;
4 ULTIMO NUMBER;
5 BEGIN
6 SELECT NR_TELEFONE INTO OVTEL
7 FROM TB_TFUNC
8 WHERE CD_PESSOA = &mat;
9 IF OVTEL IS NOT NULL THEN
10 OVTEL.EXTEND;
11 ELSE
12 OVTEL := TVTEL(TTEL(NULL, NULL, NULL));
13 END IF;
14 ULTIMO := OVTEL.LAST;
15 OVTEL(ULTIMO) := TTEL(&ddd, &tel, UPPER('&cel'));
16 END;
17 /
Entre o valor para mat: 600
Entre o valor para ddd: 11
Entre o valor para tel: 28495098
Entre o valor para cel: n
Procedimento PL/SQL concluído com sucesso.
4.25) Deseja-se um arquivo contendo: nome do funcionário, telefone completo, nascimento, nome do cargo,
salário e grau de instrução. O arquivo deve receber os dados ordenados por nome do cargo e nome do funcionário.
Listagem-resposta 4.25A
SQL> DECLARE
2 ARQ UTL_FILE.FILE_TYPE;
3 CTRL NUMBER;
4 BUFFER VARCHAR2(1000);
5 OTEL TTEL;
6 OCARGO TCARGO;
7 OVTEL TVTEL;
8 CURSOR C1 IS SELECT * FROM TB_TFUNC;
9 BEGIN
10 ARQ := UTL_FILE.FOPEN('D:\TESTE', 'LAB4_25.SQL', 'W');
11 FOR R1 IN C1 LOOP
12 BUFFER := RPAD(R1.NM_PESSOA, 20, ' ')||' ';
13 IF R1.NR_TELEFONE IS NULL THEN
14 BUFFER := BUFFER||LPAD(' ', 32);
15 ELSE
16 CTRL := R1.NR_TELEFONE.LAST;
17 FOR I IN 1..LEAST(CTRL,2) LOOP
18 OTEL := R1.NR_TELEFONE(I);
19 BUFFER := BUFFER||RPAD(OTEL.MTEL(), 15)||' ';
20 END LOOP;
21 IF CTRL < 2 THEN
22 BUFFER := BUFFER||RPAD(' ', 16);
23 END IF;
24 END IF;
25 BUFFER := BUFFER||TO_CHAR(R1.DT_NASC, 'DD/MM/YYYY')||' ';
26 IF R1.CD_CARGO IS NOT NULL THEN
27 SELECT DEREF(R1.CD_CARGO) INTO OCARGO FROM DUAL;
28 BUFFER := BUFFER||RPAD(OCARGO.NM_CARGO, 20, ' ')||' ';
29 ELSE
30 BUFFER := BUFFER||RPAD(' ', 21, ' ');
31 END IF;
32 BUFFER := BUFFER||LPAD(LTRIM(TO_CHAR(R1.VL_SAL, 'L999G999G990D00')),16, ' ')||' ';
33 BUFFER := BUFFER||LPAD(R1.NR_GIT, 2, ' ');
34 UTL_FILE.PUT_LINE(ARQ, BUFFER);
35 END LOOP;
36 UTL_FILE.FCLOSE_ALL;
37 END;
38 /
Procedimento PL/SQL concluído com sucesso.
Observe que utilizamos o método Mtel do tipo de objeto Otel para montar o telefone.
4.26) Faça uma rotina que realize inclusão de novos endereços para cliente.
Listagem-resposta 4.26A
SQL> CREATE OR REPLACE
2 PROCEDURE IECLI (PCOD IN NUMBER, PNMRUA IN VARCHAR2,
3 PBAIRRO IN VARCHAR2 := NULL, PCITY IN VARCHAR2 := NULL,
4 PCDUF IN VARCHAR2 := NULL, PNRRUA IN NUMBER := NULL,
5 PCEP IN NUMBER := NULL) IS
6 OEND TEND := TEND(NULL, NULL, NULL, NULL, NULL, NULL);
7 OCLI TCLIENTE;
8 BEGIN
9 IF PCDUF IS NOT NULL THEN
10 BEGIN
11 SELECT REF(S) INTO OEND.CD_ESTADO
12 FROM TB_TESTADO S WHERE CD_ESTADO = PCDUF;
13 EXCEPTION
14 WHEN NO_DATA_FOUND THEN
15 OEND.CD_ESTADO := NULL;
16 END;
17 END IF;
18 OEND := TEND(PNMRUA, PBAIRRO, PCITY, OEND.CD_ESTADO, PNRRUA, PCEP);
19 SELECT VALUE(C) INTO OCLI FROM TB_TCLIENTE C WHERE CD_PESSOA = PCOD FOR UPDATE;
20 IF OCLI.NM_ENDERECO IS NULL THEN
21 OCLI.NM_ENDERECO := TNEND(OEND);
22 ELSE
23 OCLI.NM_ENDERECO.EXTEND;
24 OCLI.NM_ENDERECO(OCLI.NM_ENDERECO.LAST) := OEND;
25 END IF;
26 UPDATE TB_TCLIENTE C
SQL> EXECUTE IECLI (1, 'Av. Rio Branco', 'Centro', 'Rio de Janeiro', 'RJ', 1, 20921900);
Procedimento PL/SQL concluído com sucesso.
4.27) Faça uma rotina que apresente para cada cliente a lista de endereços cadastrados.
Listagem-resposta 4.27A
SQL> CREATE OR REPLACE PROCEDURE CECLI IS
2 OEND TEND;
3 UF TESTADO;
4 NMUF VARCHAR2(100);
5 BEGIN
6 FOR R1 IN (SELECT * FROM TB_TCLIENTE) LOOP
7 DBMS_OUTPUT.PUT_LINE('Cliente: '||LPAD(R1.CD_PESSOA, 4)||' - '||
8 RPAD(R1.NM_PESSOA, 20));
9 DBMS_OUTPUT.PUT_LINE('Endereços:');
10 FOR I IN 1..R1.NM_ENDERECO.LAST LOOP
11 OEND := R1.NM_ENDERECO(I);
12 IF OEND.CD_ESTADO IS NOT NULL THEN
13 SELECT DEREF(OEND.CD_ESTADO) INTO UF FROM DUAL;
14 NMUF := UF.NM_ESTADO;
15 ELSE
16 NMUF := ' ';
17 END IF;
18 DBMS_OUTPUT.PUT_LINE(RPAD(OEND.NM_RUA, 20)||' '||RPAD(OEND.NM_BAIRRO, 20)||' '||
19 RPAD(OEND.NM_CIDADE, 20)||' '||RPAD(NMUF, 20)||' '||
20 LPAD(OEND.NR_RUA,7)||' '||LPAD(OEND.NR_CEP, 8, ' '));
21 END LOOP;
22 DBMS_OUTPUT.PUT_LINE('---------------');
23 END LOOP;
24 END;
25 /
Procedimento criado.
4.28) Altere a Object View criada no exercício 4.21 para incluir a leitura da tabela TEL_FUNC de tal forma que cada
funcionário possa ter mais de um telefone.
Listagem-resposta 4.28A
SQL> CREATE OR REPLACE VIEW VFUNC OF TFUNC
2 WITH OBJECT IDENTIFIER (CD_PESSOA) AS
3 SELECT NM_FUNC||' '||NM_SOBRENOME NM_PESSOA, FUNC.CD_MAT CD_PESSOA,
4 'PF' IN_TIPO_PESSOA,
5 CAST(MULTISET(SELECT TF.NR_DDD, TF.NR_TEL, TF.IN_CELULAR
6 FROM TEL_FUNC TF
7 WHERE TF.CD_MAT = FUNC.CD_MAT) AS TVTEL) NR_TELEFONE,
8 DT_NASC, DT_ADM, VL_SAL, MAKE_REF(VCARGO, NR_CARGO) CD_CARGO,
9 TEND(NM_RUA, NM_BAIRRO, NM_CIDADE,
10 (SELECT REF(T) FROM TB_TESTADO T WHERE T.CD_ESTADO = END_FUNC.CD_ESTADO),
11 NR_RUA, NR_CEP) NM_ENDERECO, NR_GIT
12 FROM FUNC, END_FUNC
13 WHERE FUNC.CD_MAT = END_FUNC.CD_MAT(+)
14 /
View criada.
4.29) Modifique o trigger associado à view para que comporte a atualização da tabela TEL_FUNC.
Listagem-resposta 4.29A
SQL> CREATE OR REPLACE TRIGGER TG_VFUNC
2 INSTEAD OF INSERT OR DELETE ON VFUNC
3 DECLARE
4 OESTADO TESTADO;
5 OEND TEND;
6 OTEL TTEL;
7 OCARGO TCARGO;
8 RFUNC FUNC%ROWTYPE;
9 POS NUMBER;
10 REND END_FUNC%ROWTYPE;
11 BEGIN
12 IF INSERTING THEN
13 OEND := :NEW.NM_ENDERECO;
14 BEGIN
15 SELECT DEREF(:NEW.CD_CARGO) INTO OCARGO
16 FROM DUAL;
17 RFUNC.NR_CARGO := OCARGO.CD_CARGO;
18 EXCEPTION
19 WHEN NO_DATA_FOUND THEN
20 RFUNC.NR_CARGO := NULL;
21 END;
22 BEGIN
23 SELECT DEREF(OEND.CD_ESTADO) INTO OESTADO
24 FROM DUAL;
25 REND.CD_ESTADO := OESTADO.CD_ESTADO;
26 EXCEPTION
27 WHEN NO_DATA_FOUND THEN
28 REND.CD_ESTADO := NULL;
29 END;
30 POS := INSTR(:NEW.NM_PESSOA, ' ');
31 INSERT INTO FUNC(CD_MAT, NM_FUNC, NM_SOBRENOME, NR_RAMAL, DT_NASC,
32 DT_ADM, VL_SAL, NR_CARGO, NR_GIT)
33 VALUES (:NEW.CD_PESSOA,SUBSTR(:NEW.NM_PESSOA, 1,(POS -1)),
34 SUBSTR(:NEW.NM_PESSOA,(POS +1)), NULL,
35 :NEW.DT_NASC, :NEW.DT_ADM, :NEW.VL_SAL, RFUNC.NR_CARGO, :NEW.NR_GIT);
36 INSERT INTO END_FUNC (CD_MAT, NM_RUA, NM_BAIRRO, NM_CIDADE,
37 CD_ESTADO, NR_RUA, NR_CEP)
38 VALUES (:NEW.CD_PESSOA, OEND.NM_RUA, OEND.NM_BAIRRO, OEND.NM_CIDADE,
39 REND.CD_ESTADO, OEND.NR_RUA, OEND.NR_CEP);
40 FOR I IN 1..:NEW.NR_TELEFONE.LAST LOOP
41 OTEL := :NEW.NR_TELEFONE(I);
42 INSERT INTO TEL_FUNC
43 VALUES (:NEW.CD_PESSOA, OTEL.NR_DDD, OTEL.NR_TEL, OTEL.IN_CELULAR);
44 END LOOP;
45 ELSE
46 DELETE FROM TEL_FUNC WHERE CD_MAT = :OLD.CD_PESSOA;
47 DELETE FROM END_FUNC WHERE CD_MAT = :OLD.CD_PESSOA;
48 DELETE FROM FUNC WHERE CD_MAT = :OLD.CD_PESSOA;
49 END IF;
50 END;
51 /
Gatilho criado.
Listagem-resposta 4.30A
SQL> INSERT INTO VFUNC VALUES
2 ('Cláudia Rezende', 9998, 'PF',
3 TVTEL(TTEL(21, 22746531, 'N'), TTEL(21, 22139887, 'N'), TTEL(21, 92866181, 'S')),
4 TO_DATE('01011975', 'DDMMYYYY'),
5 TO_DATE('01101999', 'DDMMYYYY'), 3500,
6 (SELECT REF(C) FROM VCARGO C WHERE CD_CARGO = 60),
7 TEND('Rua Marechal Jofre', 'Grajaú', 'Rio de Janeiro',
8 (SELECT REF(E) FROM TB_TESTADO E WHERE CD_ESTADO = 'RJ'),
9 127, 20765341), 55);
1 linha criada.
Capítulo 5
CONHECENDO O BANCO DE DADOS
Neste capítulo veremos alguns tópicos sobre assuntos gerais do banco de dados que os desenvolvedores devem
conhecer para que possam ser mais eficientes no uso do software. Muitos dos comandos não são utilizados pelos
desenvolvedores e sim pelos DBAs; no entanto, o conceito envolvendo o assunto pode ser discutido e entendido
por ambos para que as soluções possam ser mais eficazes.
CONCEITO
Table Functions são funções que geram como resultado um conjunto de linhas, ou seja, retornam uma Nested
Table ou um Varray e que podem ser utilizadas na cláusula FROM de um comando SELECT como se fosse uma
tabela. Estas funções podem receber como parâmetro um conjunto de linhas através de uma coleção ou Ref Cursor.
A execução de uma Table Function pode ser feita em paralelo e as linhas podem ser enviadas diretamente para o
próximo processo, sem intermediários (streamed). As linhas podem ser retornadas iterativamente (pipelined), isto
é, à medida que forem sendo geradas são enviadas para o próximo processo, não havendo necessidade (como
normalmente ocorre) de preenchimento completo da coleção para transferência para o próximo estágio.
PERFORMANCE
A utilização de pipeline, stream e parallel pode otimizar a performance do processamento:
♦ Quando habilitamos multi-thread (parâmetro habilitado pelo DBA), poderá haver a execução concorrente de
table functions.
♦ A eliminação de estágios intermediários para a passagem de informações entre processos elimina o overhead associado.
♦ O uso de pipeline faz com que as linhas sejam retornadas tão logo elas são produzidas. Isto reduz a memória
necessária para as Table Functions uma vez que não há a necessidade de se materializar a coleção inteira.
♦ Outra vantagem do uso de pipeline é que o retorno de informação é mais rápido, não havendo necessidade de o
processo que acionou a Table Function ficar esperando que todo o resultado seja construído para, então, ser retornado.
PASSO A PASSO
Nosso estudo será desenvolvido em etapas sucessivas. Veremos exclusivamente Table Functions, e posteriormente
acrescentaremos Pipeline, Parallel, etc.
5 VL_SAL NUMBER);
6 /
Tipo criado.
Na Listagem 5.01 criamos um tipo de objeto com quatro atributos. Não criamos nenhuma tabela objeto, apenas o
tipo. Da mesma forma agimos com a Nested Table. Somente o tipo, a partir do tipo de objeto foi criado.
Na Listagem 5.02 criamos uma função que preenche a coleção e, ao término da execução, retorna a coleção para o
processo “chamador”, com a cláusula RETURN.
O comando Select, utilizando a cláusula TABLE, recebe as linhas da Nested Table fictícia (pois não existe fisicamente
em disco) e a apresenta como se fosse uma consulta a uma tabela física.
Por exemplo, as duas opções a seguir são similares em relação a consumo. A função F é executada duas vezes nas
duas situações:
a) SELECT * FROM TABLE( F(…) ) T1, TABLE( F(…) ) T2 WHERE T1.ID = T2.ID; e
Se os valores resultantes da função forem determinados exclusivamente pelos parâmetros, isto é, se a função
produzir sempre o mesmo resultado para uma combinação específica de valores passados no parâmetro, podemos
indica a função como DETERMINISTIC e o Oracle irá, automaticamente, armazenar as linhas em memória (“Buffer
rows”). Cuidado, porém, nesta especificação pois o banco de dados não tem como garantir que uma função
especificada como DETERMINISTIC realmente o é. Caso venhamos a especificar esta cláusula para uma função que
não se enquadre, que não seja DETERMINISTIC, o resultado será imprevisível.
Observe as diferenças entre esta função e a outra criada na Listagem 5.02. No exemplo da Listagem 5.03 não
criamos variável do tipo da Nested Table, somente para o tipo de objeto OT_GERENTE. A referência à Nested Table
foi feita somente na cláusula RETURN do comando CREATE FUNCTION.
A cada linha “produzida”, o comando PIPE ROW incorporava a linha à coleção Nested e a retornava para o comando
Select. O comando RETURN na linha 15 identificou apenas o fim de uma função (que sempre deve conter Return).
Neste exemplo (Listagem 5.04) a especificação do que seria lido foi retirada da função e substituída por um REF
CURSOR. Utilizamos o Ref Cursor default do sistema (SYS_REFCURSOR) para que não tivéssemos de criar um
package com a especificação do tipo cursor.
No comando SELECT a expressão CURSOR (veja sintaxe de expressões no Capítulo 10 e exemplos de uso no
Capítulo 3) foi usada para entregar à função as diversas linhas obtidas com o comando SELECT.
Note que a subquery da expressão CURSOR é passada do SQL para um REF CURSOR e o argumento que a recebe já
está aberto. Não precisamos realizar OPEN em PCURSOR dentro da função.
ERROS E RESTRIÇÕES
As seguintes operações não são permitidas para variáveis REF CURSOR baseadas em Table Functions:
A utilização é normal tanto para cursores quanto para variáveis cursor. O otimizador SQL não irá otimizar comandos
de PL/SQL tais como:
OPEN R FOR SELECT * FROM TABLE( F( CURSOR( SELECT * FROM FUNC)));
SELECT * BULK COLLECT INTO <área de retorno> FROM TABLE(G( R ));
Na primeira linha abrimos uma variável cursor para um comando SELECT a partir de uma Table Function. No
segundo caso a função G recebeu como parâmetro a variável cursor aberta previamente.
Sabemos que uma Table Function retorna uma coleção. Em alguns casos, porém, tais como quando uma variável
cursor é passada para uma Table Functions a partir de um bloco de PL/SQL, podemos precisar realizar uma operação
de CAST para a Table Function.
O resultado acima, apesar de ser igual em termos de dados, não terá a mesma performance que:
SELECT * FROM TABLE(G(CURSOR(SELECT * FROM TABLE(F(CURSOR(SELECT * FROM TAB))))));
Isto é o mesmo que ignorar o overhead associado com a execução de dois comandos de SQL e assumir que o
resultado pode ser pipelined entre os dois comandos.
Não temos restrições relativas a este número, porém a utilização de paralelismo está restrita a um dos parâmetros,
como veremos a seguir.
Uma Table Function é chamada na cláusula FROM e retorna uma coleção. Isto afeta o modo como a entrada dos
dados é particionada pois a forma de particionamento deve ser apropriada às operações realizadas pela Table
Function. Por exemplo, uma operação de ORDER BY requer uma entrada particionada por intervalo (Range),
enquanto que uma função GROUP BY requer uma entrada particionada por grupo (Hash).
Na própria declaração da Table Function podemos determinar a forma de particionamento mais adequada para
ela. A função é executada em dois estágios. No primeiro estágio um conjunto de processos particiona os dados
conforme a especificação da função. No segundo estágio um conjunto de processos executa a função em paralelo
nos dados particionados.
A cláusula PARALLEL_ENABLE indica qual dos cursores recebidos como parâmetro (somente um deles pode ser
construído em paralelo) será particionado e que colunas devem ser usadas para particionamento. Quando indicamos
as colunas a serem usadas para particionamento, o método pode ser RANGE ou HASH.
A palavra-chave ANY indica que a função independe do método de particionamento (como é o nosso caso).
Quando isto ocorre, o sistema, randomicamente, particiona os dados pelos processos. Esta forma é adequada para
uso com funções que obtêm uma linha, manipulam suas colunas e geram um resultado baseado apenas nas colunas
desta única linha (não comparam valores com dados de linhas anteriores, por exemplo).
No exemplo da Listagem 5.06 o particionamento fica a critério do sistema uma vez que a função não precisa
receber os dados em nenhuma ordem ou sob nenhum grupamento específico.
Observe, também, que no exemplo da Listagem 5.05 criamos uma package PGLOBAL para a definição do tipo REF
CURSOR. Isto é obrigatório quando, no particionamento, indicamos RANGE ou HASH, uma vez que definimos a
coluna em relação à qual será feito este paralelismo.
Uma vez que no exemplo da Listagem 5.06 indicamos particionamento indeterminado, ou seja, a critério do
sistema, pudemos voltar a usar SYS_REFCURSOR.
DATA STREAMING
O modo como uma Table Function ordena ou grupa as linhas que ela obtém do argumento cursor é chamado de
“data streaming”. Uma função pode stream seus dados de entrada em uma das seguintes formas:
♦ Não determinar restrições em relação à ordem dos dados recebidos.
♦ Ordená-los por uma coluna ou conjunto de colunas (order).
♦ Grupá-los em relação a uma chave em particular (cluster).
Os dados de entrada podem ser “stream” tanto para uma execução em paralelo quanto para uma execução seqüencial.
Se as cláusulas ORDER BY ou CLUSTER BY não forem utilizadas, os dados serão fornecidos em uma ordem aleatória.
Neste exemplo os dados do cursor PCURSOR estão sendo agrupados por nome do funcionário para serem entregues
a cada uma das instâncias da função que serão executadas em um processo paralelo.
12 OGERENTE.CD_DEPTO := R1.CD_DEPTO;
13 OGERENTE.NR_RAMAL := R1.NR_RAMAL;
14 OGERENTE.VL_SAL := R1.VL_SAL;
15 PIPE ROW(OGERENTE);
16 END LOOP;
17 RETURN;
18 END;
19 /
Função criada.
Neste exemplo não utilizamos a cláusula Parallel, e desta forma os dados serão executados por um único processo
que executará a função para todas as linhas selecionadas.
Durante uma execução em paralelo, cada instância da Table Function cria uma transação independente.
Uma alternativa seria criar uma View sobre a Table Function e usar um trigger do tipo INSTEAD OF para realizar a
atualização desejada.
Se uma exception é recebida dentro de uma Table Function, a função desvia para o controle de erro e prossegue
normalmente. O término do manuseio da exception leva o controle para o bloco superior àquele que recebeu a
exception. Se a exception é controlada (limpa), a execução prossegue normalmente.
Uma exception não controlada em uma Table Function faz com que a transação pai realize um Rollback.
O tipo de implementação deve utilizar a interface ODCITable e deve existir no momento em que a Table Function for
criada. Esta forma de criação é útil para Table Functions que venham a ser implementadas em linguagens externas.
O Oracle aciona os métodos para realizar os seguintes passos na execução da query contendo uma Table Function:
♦ Start – inicializa o parâmetro Scan Context, que é usado durante a segunda fase (ODCITableStart).
♦ Fetch – produz um subconjunto de linhas na coleção resultante. Esta rotina é acionada tantas vezes quanto
necessário para retornar toda a coleção (ODCITableFetch).
♦ Close – libera memória no encerramento (ODCITableClose).
Para esta forma de uso devemos criar um tipo de objeto que contenha os três métodos mencionados acima. A
implementação dos métodos é de responsabilidade do usuário. O Oracle fará apenas o acionamento destes métodos
nos momentos necessários.
Este assunto não será detalhado neste material pois o estudo de Java e/ou C não faz parte deste livro.
Os três tipos são implementados como “tipos opacos”, ou seja, a estrutura interna destes tipos não é conhecida do
banco de dados. Seus dados podem ser consultados somente por funções (tipicamente rotinas de 3GL). A Oracle
fornece tanto rotinas OCI quanto PL/SQL APIs para a implementação destas funções.
Os três tipos são Sys.Anytype, Sys.Anydata e Sys.AnydataSet.
Maiores detalhes sobre implementação podem ser obtidos no manual Oracle Call interface Programmer’s Guide.
EXERCÍCIOS
5.01) Crie uma Table Function que retorne, para cada funcionário, seu nome e endereço. Utilize-a na cláusula
From de um comando Select.
5.02) Crie uma Table Function que apresente para cada Funcionário seu nome, salário e cargo. Use Pipelined.
Utilize-a na cláusula From de um comando Select.
OBJETIVO
As funções de agregação definidas pela Oracle somente trabalham com dados escalares. Neste tópico veremos
como criar nossas próprias funções de agregação, o que nos permitiria trabalhar com dados complexos tais como:
multimídia, tipos de objeto, lobs, etc.
FORMA
A criação de uma rotina de agregação do usuário é feita através da implementação de um conjunto de rotinas chamadas
de ODCIAggregate. Estas rotinas serão implementadas como métodos de um tipo a ser definido pelo usuário.
As quatro rotinas ODCIAggregate são requeridas para a definição de uma função de agregação do usuário. Cada
uma delas corresponde à codificação de uma etapa das operações que qualquer função de agregação deve realizar:
Inicialização, Iteração, Merge (opcional) e Terminação.
Como exemplo, tomemos a função AVG. Para realizar o cálculo necessário teríamos as seguintes etapas:
♦ Inicialização: zera os contadores internos (por exemplo wtotal = 0 e wqtd = 0)
♦ Iteração: processa o valor de entrada (por exemplo wtotal = wtotal + valor; wqtd = wqtd + 1)
♦ Terminação: calcula o resultado e encerra (por exemplo return wtotal / wqtd)
Se a função AVG fosse uma função de usuário, deveríamos criar um tipo de objeto contendo as variáveis wtotal e
wqtd como atributos e as três etapas mencionadas como métodos do tipo de objeto.
Algumas vezes esta operação combina o resultado de agregações sobre subconjuntos para a obtenção da agregação
sobre todo o conjunto. Se este passo extra for necessário, devemos definir também um método para Merge.
As quatro rotinas ODCIAggregate são:
♦ ODCIAggregateInitialize – É acionada pelo Oracle para inicializar o cálculo da agregação.
♦ ODCIAggregateIterate – É acionada repetidamente pelo Oracle a cada linha selecionada. Esta rotina é acionada
para cada valor não nulo do grupo de entrada.
♦ ODCIAggregateMerge – Esta rotina é acionada pelo Oracle para a combinação de dois contextos de agregação.
♦ ODCIAggregateTerminate – Esta rotina é acionada pelo Oracle como último passo para a tarefa.
PARÂMETROS
As rotinas de agregação ODCI possuem a sintaxe apresentada a seguir:
Onde:
♦ SELF – representa o próprio tipo onde as funções estão definidas.
♦ val – corresponde ao valor que será computado.
♦ CTX2 – representa o próprio tipo, porém de um segundo conjunto de dados.
♦ retorno – representa a resposta final.
♦ RETURN – todas as funções retornam uma das constantes: ODCIConst.Success (no caso de sucesso) ou
ODCIConst.Error (no caso de problemas).
♦ função DELETE – esta rotina é acionada pelo Oracle para remover dados pertencentes ao grupo de dados da
entrada. A rotina é acionada com o contexto e o valor a ser removido. Ela deverá processar a entrada, atualizar
o contexto correspondente e retornar o contexto (SELF) atualizado para o Oracle.
♦ função WrapContext – esta rotina é acionada pelo Oracle se a função de agregação houver declarado ter um
contexto externo e houver transmissão parcial das agregações pelos processos de execução. Esta rotina deve
integrar todos os pedaços externos do contexto corrente para criar um contexto completo.
FUNÇÃO
Após a criação do tipo contendo os métodos padrões e os atributos necessários devemos criar a função de agregação
propriamente dita. Esta função usa a cláusula AGGREGATE USING para identificar que se trata de uma função de
agregação. O tipo de implementação corresponde ao tipo de objeto definido previamente.
Podemos especificar nossas funções de agregação na lista do SELECT, na cláusula HAVING e na cláusula ORDER BY.
RESTRIÇÃO
Quando usamos a cláusula AGGREGATE USING podemos especificar somente um argumento para a função, o
qual deve ser de entrada.
FUNÇÃO ANALÍTICA
Quando especificamos uma função de agregação em uma query, podemos tratá-la como uma função analítica.
Para isto devemos usar a cláusula OVER.
Observe que na função de inicialização acionamos o método construtor do tipo de objeto para atribuir valor
inicial zero aos atributos do tipo (maior e secmax), como já fizemos anteriormente no Capítulo 4.
Observe que como criamos a rotina com a especificação de paralelismo a função de merge pode vir a ser usada pelo Oracle.
No resultado observamos uma diferença no tratamento do resultado final entre FSECMAX e a função padrão
MAX. Quando não existe a situação pesquisada para a função MAX, o resultado é NULL. Para a função FSECMAX
o resultado é zero (pois foi como inicializamos os valores de MAIOR e SECMAX). Para igualarmos os resultados
devemos no método Terminate testar o valor de SECMAX. Se este for zero, retornar null.
EXERCÍCIOS
5.03) Crie uma função de agregação para calcular o número médio de vogais do parâmetro.
5.04) Crie uma função de agregação para calcular o tamanho médio do texto informado.
CONCEITO
Uma tabela temporária é uma tabela com vida útil de uma sessão ou transação. Ela está vazia quando a sessão ou
transação começa e descarta os dados ao fim da sessão ou transação.
SQL> COMMIT;
Validação completa.
No exemplo da Listagem 5.13 criamos uma tabela temporária associada à transação. Isto significa que ao término
da transação os dados da tabela são perdidos, porém sua descrição permanece gravada no banco de dados mesmo
após a mudança de sessão.
O que é temporário é o armazenamento dos dados. Com este tipo de tabela não temos necessidade de remover os
dados ao término da transação. Podem ser muito úteis na geração de dados de trabalho temporários.
CARACTERÍSTICAS
As tabelas temporárias possuem as seguintes características:
♦ Sua definição é visível para todas as sessões, mas seus dados são visíveis e acessíveis somente pela sessão que os
incluiu.
♦ O comando LOCK não tem efeito em tabelas temporárias uma vez que cada sessão tem acesso exclusivo a seus dados.
♦ Um comando TRUNCATE trunca somente os dados referentes à sessão do usuário.
♦ Os dados são criados no tablespace temporário do usuário.
♦ A área para utilização pelos dados da tabela só é alocada quando o primeiro INSERT ou CREATE TABLE ... AS
SELECT for executado.
♦ Operações de Rollback to Savepoint são suportadas, mas os dados não são recuperáveis caso ocorra um “crash”
porque as modificações não são logadas (gravadas no REDO LOG).
♦ Podemos criar índices para uma tabela temporária usando o comando CREATE INDEX. Estes índices também
são temporários.
♦ Podemos criar triggers para tabelas temporárias assim como views que utilizem simultaneamente tabelas
temporárias e permanentes.
♦ Os utilitários IMPORT e EXPORT podem exportar e importar a definição de uma tabela temporária, porém
nenhum dado é exportado.
♦ Da mesma forma podemos replicar a definição de uma tabela temporária, mas não podemos replicar seus dados.
♦ Só podemos executar operações de DDL (ALTER TABLE, DROP TABLE, CREATE INDEX, etc.) para a tabela
temporária se não houver nenhuma sessão fazendo acesso a ela.
♦ Uma tabela temporária associada à transação é acessível por uma determinada transação e suas transações
filhas. Porém, uma tabela temporária associada à transação não é acessível por duas transações simultâneas na
mesma sessão, apesar de poder ser usada por transações em diferentes sessões.
♦ Se uma transação do usuário faz um INSERT em uma tabela temporária, então nenhuma de suas transações
filhas pode usar a tabela temporária após isto.
♦ Se uma transação filha faz um INSERT em uma tabela temporária, ao fim da transação filha, o dado associado
com a tabela temporária é removido. Após isto, tanto a transação do usuário quanto qualquer outra transação
podem fazer acesso à tabela temporária.
SQL> COMMIT;
Validação completa.
No exemplo da Listagem 5.14 a tabela foi criada com a indicação de que após o término da transação os dados
deveriam ser mantidos, ou seja, a tabela é temporária porém seus dados ficam disponíveis por toda a sessão.
Quando ocorre o fim da sessão, os dados são removidos (ou liberados).
EXERCÍCIOS
5.05) Criar uma tabela temporária com dados preservados por uma transação. Verifique a descrição desta tabela
após sua criação.
5.06) Incluir linhas nesta tabela, efetuar um COMMIT e verificar a quantidade de linhas final.
5.07) Criar uma tabela temporária sendo as linhas preservadas até o término da sessão. Preenchê-la com dados e
executar um COMMIT.
5.08) Abrir uma segunda sessão em paralelo, incluir dados na tabela temporária e consultá-los.
5.09) Criar um trigger, um índice e uma view, utilizando esta tabela temporária.
5.10) Utilize a view criada.
INTRODUÇÃO
Neste tópico estaremos estudando rudimentos da análise de performance. Não temos a pretensão de esgotar este
assunto pois o mesmo é bastante extenso; no entanto, é importante sabermos que existem técnicas capazes de nos
auxiliar na melhoria da performance de uma query e que o primeiro passo neste processo é entender seu funcionamento.
CONCEITO
A preocupação com a qualidade do trabalho realizado é um hábito que deve acompanhar o desenvolvedor em
todas as etapas do desenvolvimento de um sistema de computador.
A performance deve ser construída!
O refinamento da performance não pode ser feito depois que o sistema estiver em produção. Para obtermos bons
resultados em tempo de resposta, desempenho e segurança, devemos avaliar a performance a tempo de análise,
desenvolvimento e implementação.
Em cada uma das etapas listadas a seguir existem tarefas a serem realizadas que têm influência no resultado final
do trabalho desenvolvido e devem ser criteriosamente avaliadas:
♦ Na definição e implementação das regras de negócio – O conhecimento preciso e a escolha das regras de negócio
passíveis de implementação são considerados os primeiros pontos focais na busca por performance das futuras aplicações.
♦ Na etapa de modelagem dos dados – Nesta fase estamos determinando as relações que o futuro banco de dados
terá. Devemos considerar o uso de técnicas de normalização e avaliar a necessidade de desnormalizações.
♦ Na etapa de avaliação do desenho da aplicação – Nesta fase estaremos definindo o que cada aplicação deverá
realizar para atender às regras de negócio estabelecidas na primeira etapa. Esta etapa é de grande importância
uma vez que estaremos determinando os acessos necessários ao banco de dados, as expectativas de tempo de
resposta, o que deve ser feito em tempo real e o que pode ser postergado, etc.
♦ Durante o refinamento do modelo de dados – Após a definição da etapa anterior, podemos determinar quais
índices adicionais devem ser incluídos no modelo para que o acesso aos dados seja eficiente sem prejuízo dos
processos atualizadores. Podemos, ainda, determinar os tipos de índice (B-TREE ou BITMAP) e o uso de clusters.
♦ Durante a análise do sql das aplicações – Esta etapa é obrigatória em qualquer estudo de performance, uma vez
que pequenas mudanças no SQL podem trazer grandes diferenças no desempenho de um programa.
A utilização de bancos de dados relacionais trouxe a ilusão de que o acesso aos dados é de total responsabilidade do
software uma vez que o modo como o dado é obtido não é, explicitamente, definido no programa.
No entanto, apesar dos grandes progressos que o Otimizador (software) já realizou, quem detém o conhecimento
da informação ainda é o analista e as decisões de acesso são de responsabilidade de quem está programando. Sendo
assim, é importante que os desenvolvedores conheçam o mecanismo de acesso aos dados da Oracle e como
influenciá-lo a fim de obter comandos de SQL escritos eficientemente.
♦ Em outras etapas – Outras etapas que também influenciam o resultado final são: Avaliação das necessidades de
hardware (deve-se levar em consideração crescimento a médio e longo prazos visando à estabilidade da perfor-
mance, já prevendo futuras expansões) e Avaliação do banco de dados (onde o DBA definirá a freqüência de
avaliação visando a obtenção de sinais de contenção de recursos, uso eficiente de disco e alocação de memória).
Como já dissemos anteriormente, neste capítulo não pretendemos explorar completamente a análise de perfor-
mance, estamos apenas chamando a atenção dos desenvolvedores sobre o que significa isto e a importância de se
aprofundar um estudo neste sentido com seu DBA.
PARSE
Nesta fase o Oracle realiza as seguintes tarefas:
♦ Verificação sintática – checa a sintaxe e validade semântica.
♦ Pesquisa a existência do comando em memória – o Oracle verifica se o comando de SQL que está sendo analisado
já foi submetido anteriormente e se o resultado desta submissão ainda está em memória. Caso o comando seja
encontrado, significa que o plano de execução já está traçado, não havendo necessidade de refazermos esta
ação; sendo assim, será iniciada a fase EXECUTE.
♦ Pesquisa o dicionário de dados – caso o comando de SQL não seja encontrado na memória, o Oracle verifica no
dicionário de dados se existem as tabelas e colunas mencionadas no comando e se as permissões para acesso aos
objetos desejados são suficientes.
♦ Construção do plano de execução – após a pesquisa no dicionário de dados o Otimizador poderá traçar um
caminho de acesso para cada tabela presente no comando, montando um plano de execução (também chamado
de Parse Tree) para obtenção e/ou atualização dos dados do comando SQL submetido.
♦ Alocação da memória – com o plano traçado, o Oracle inclui este plano na memória para que sua execução seja
possível e para permitir que este plano seja executado por outro comando idêntico ao atual.
Na fase de Parse é que o Oracle, mais especificamente, um algoritmo chamado de Otimizador escolhe como deve
ser feita a pesquisa nos dados para obtenção das informações solicitadas. Ele decidirá entre acesso seqüencial,
através de índice, o método de join, etc.
EXECUTE
As tarefas da fase de Execute são as seguintes:
♦ Aplicar o plano de execução – como primeira tarefa a leitura dos dados requeridos deve ser efetuada. Esta leitura
pode ser física ou lógica. Caso os dados requeridos já estejam presentes em memória, não há necessidade da
leitura da informação do disco. Caso contrário, sua leitura física é disparada e a informação é armazenada na
área de memória do banco de dados.
♦ Análise das restrições – esta tarefa é aplicável a processos de atualização em que ocorre a verificação das regras de
integridade (constraints).
♦ Modificação dos dados – esta tarefa também só é executada por processos de atualização. Para que a atualização
seja realizada, as linhas de dados devem ser bloqueadas (locked), o segmento de rollback alocado e a modificação
na linha (dentro da memória) efetuada.
FETCH
Se o comando SQL em execução for um SELECT, onde existe o retorno da informação para o processo usuário que
fez a solicitação, o Oracle, nesta etapa, efetua o retorno das informações.
OTIMIZAÇÃO
Otimização é o processo de escolha do modo mais eficiente para a execução de um comando SQL (SELECT, IN-
SERT, UPDATE ou DELETE).
Podem existir diferentes formas para o Oracle executar um comando, de acordo com a ordem em que as tabelas ou
índices sofrerão acesso, de acordo com as restrições estabelecidas, de acordo com a quantidade de linhas das
tabelas envolvidas, de acordo com os índices disponíveis, etc.
PLANO DE EXECUÇÃO
Para executar um comando SQL (DML), o Oracle pode ter de executar diversos passos. Cada um destes passos pode
recuperar, fisicamente, linhas das tabelas referenciadas no comando.
Para cada tabela envolvida no comando SQL haverá um caminho de acesso para obtenção dos dados daquela tabela.
Ao conjunto destes passos chamamos Plano de Execução ou Plano de Acesso.
O OTIMIZADOR
O Otimizador é o responsável pela definição do plano de acesso aos dados, ou seja, escolhe a opção mais eficiente
para obtenção da informação.
Ele leva em consideração um determinado número de fatores para estabelecer a melhor opção dentro das alternativas
disponíveis. Porém, apesar dos melhores esforços do otimizador, em algumas situações, um desenvolvedor pode
escolher um caminho mais eficiente para obtenção do dado que o Otimizador.
entanto, se a construção sintática fosse WHERE vl_sal / 1.5 < 2500 a simplificação não ocorreria. O otimizador
não simplifica expressões presentes antes do operador de comparação. Por este motivo devemos, sempre que
possível, escrever condições que comparem colunas com constantes, isolando as colunas, isto é, devemos evitar
condições com expressões envolvendo colunas.
♦ Like – O otimizador simplifica condições que usem o operador LIKE com expressões sem os caracteres especiais
(% ou _ ). Por exemplo, o otimizador simplifica a expressão nm_func LIKE ‘CRISTINA’ na expressão nm_func =
‘CRISTINA’. Esta simplificação somente poderá ser feita se a coluna usada na comparação for de tamanho
variável (VARCHAR2). Caso a coluna seja do tipo CHAR, a simplificação fica inviabilizada.
♦ In – O otimizador expande a condição que usa o operador IN em uma condição equivalente usando OR. Por
exemplo nm_func IN (‘PEDRO’, ‘MARIA’) seria substituído por nm_func = ‘PEDRO’ OR nm_func = ‘MARIA’.
Em outras situações o otimizador analisa e pode modificar as condições de comparação. Isto pode ocorrer em
condições usando ANY, ALL, BETWEEN, NOT, etc.
TRANSFORMAÇÃO DE COMANDOS
Os comandos são transformados em comandos mais simples e eficientes.
♦ ORs em queries compostas – Se uma query contém uma cláusula WHERE com múltiplas condições combinadas
com operadores OR, o otimizador poderá transformar a query em uma query composta que use o operador UNION
ALL se isto vier a tornar o acesso mais eficiente, por exemplo se cada condição tiver um índice de acesso disponível.
♦ Comandos complexos em Joins – O otimizador transforma um comando complexo em um JOIN se tal transformação
resultar em um JOIN que retorne, garantidamente, as mesmas linhas que o comando complexo. Esta transformação
permitirá ao Oracle executar o comando com a vantagem das técnicas de otimização de JOINs.
♦ Transitividade – Se duas condições na cláusula WHERE envolvem uma coluna comum, o otimizador pode,
algumas vezes, inferir uma terceira condição usando o princípio da transitividade. A condição inferida pode,
potencialmente, tornar disponível um caminho de acesso (índice) que não esteja disponível com as condições
originais. Por exemplo: where a=constante and a = b, significa que b=constante.
♦ Merge do SQL das Views com o SQL analisado – No caso de alguma das tabelas presente na cláusula FROM do
comando ser uma View, o otimizador tentará unificar o comando SQL com o comando implícito da VIEW. Caso
isto não seja possível, o otimizador resolverá a View e utilizará as linhas resultantes como se fosse uma tabela.
Para efetuar esta unificação, o otimizador pode usar uma das seguintes técnicas: juntar a query da view dentro
do comando de SQL ou juntar o comando de SQL dentro da query da view.
OS MÉTODOS DE OTIMIZAÇÃO
Existem dois métodos de otimização disponíveis para uso: RULE ou COST.
RULE
Neste método o otimizador leva em consideração uma escala de regras, através das quais será feita a definição do
melhor caminho de acesso. Neste método o Otimizador não leva em consideração a natureza do dado (número de
linhas da tabela, por exemplo).
Ele escolhe um plano de execução baseado nos caminhos de acesso disponíveis e na pontuação destes caminhos.
Desta forma, havendo um índice para a tabela, ele sempre será usado mesmo que resulte num tempo de acesso maior.
A ordem de preferência para acesso aos dados, da mais rápida para a mais lenta, é a seguinte:
♦ Acesso de uma única linha via ROWID
♦ Acesso de uma única linha via Cluster Join
♦ Acesso de uma única linha via Hash Cluster Key com Unique ou Primary Key
♦ Acesso de uma única linha via índice Unique ou Primary Key
♦ Cluster Join
♦ Hash Cluster Key
♦ Cluster Key indexada
♦ Índice composto
♦ Índices de uma coluna
♦ Intervalo de pesquisa com fronteira, em colunas indexadas
♦ Intervalo de pesquisa sem fronteira, em colunas indexadas
♦ Sort Merge Join
♦ MAX ou MIN de colunas indexadas
♦ ORDER BY em colunas indexadas
♦ FULL TABLE SCAN
COST
Neste método o Otimizador calcula as opções de acesso ao dado e utiliza o seu “conhecimento” (informações
estatísticas armazenadas no dicionário de dados) do dado para escolher o melhor plano de acesso.
A escolha utiliza a mesma tabela de Ordem de Preferência, porém observando a seletividade do dado, número de
blocos necessários para se fazer um Full Table Scan versus o número de blocos obtidos em uma operação de leitura,
número de linhas na tabela e outras informações estatísticas geradas pelo DBA com o uso do comando Analyze ou
do package DBMS_STATS.
inicial no menor intervalo de tempo, em detrimento da resolução da query como um todo. Esta opção faz com
que o otimizador use o método de custo para todos os comandos de SQL, independente da presença de estatísticas)
ou RULE (utiliza o método RULE, independente da presença de estatísticas).
♦ Existência de estatísticas no dicionário de dados.
♦ Existência de hints nos comandos.
A utilização do parâmetro OPTIMIZER_MODE tanto pode ser estabelecida em nível de banco de dados, se este for especificado
no arquivo de inicialização (init.ora), quanto em nível de sessão, se o utilizarmos no comando ALTER SESSION.
A PL/SQL ignora o parâmetro de inicialização OPTIMIZER_MODE = FIRST_ROWS, uma vez que não é possível a
resposta de uma linha para um usuário, e todo o PL/SQL tem de ser executado.
Se o otimizador usar o método de custo para um determinado comando SQL e algumas das tabelas que sofrerem
acesso por este comando não tiverem estatísticas, o otimizador usa informações internas, tais como o número de
blocos de dados alocados para estas tabelas para estimar as outras estatísticas para estas tabelas.
Neste estudo veremos apenas os métodos Explain Plan e AutoTrace uma vez que o uso do utilitário TKPROF
exigiria intervenção do DBA.
Antes de prosseguirmos, veremos quais os métodos para acesso aos dados disponibilizados pelo Oracle:
♦ FULL TABLE SCAN (tabela) – Recupera todas as linhas da tabela. O Oracle lê cada bloco de dados da tabela
seqüencialmente.
♦ SAMPLE TABLE SCAN (tabela) – Recupera uma quantidade determinada e randômica (pela cláusula Sample,
como percentual) de linhas da tabelas. O Oracle lê uma percentagem determinada de linhas da tabela.
♦ TABLE ACCESS BY ROWID (tabela) – Recupera a(s) linha(s) indicada(s) pelo(s) ROWID(s). A localização pelo
ROWID é a forma mais rápida de o Oracle obter uma determinada linha.
♦ CLUSTER SCAN (cluster) – De uma tabela armazenada em um INDEXED CLUSTER, recupera linhas que tenham
o mesmo valor de cluster key. Como todas as linhas com a mesma cluster key estão armazenadas no mesmo bloco
de dados, o Oracle, inicialmente, obtém o ROWID de uma das linhas a serem selecionadas pesquisando o
CLUSTER INDEX, e então localiza as linhas baseado neste ROWID.
♦ HASH SCAN (cluster) – Localiza linhas em um HASH CLUSTER baseado no hash value. Em um HASH CLUSTER,
todas as linhas com o mesmo hash value são armazenadas no mesmo bloco de dados. O Oracle, primeiro, obtém
o hash value aplicando a função HASH ao valor da cluster key especificado pelo comando, então, pesquisa os
blocos de dados contendo as linhas com aquele hash value.
♦ INDEX SCAN (índice) – Recupera dados de um índice baseado no valor de uma ou mais colunas do índice. Se o
comando fizer referência somente a colunas do índice, o Oracle não fará acesso à tabela; caso contrário, para
cada valor obtido no índice, o Oracle fará acesso à tabela pelo ROWID. Um INDEX SCAN pode ser de um dos
seguintes tipos: UNIQUE (retorna somente um ROWID), RANGE (retorna uma ou mais linhas).
EXPLAIN PLAN
EXPLAIN PLAN é um comando que mostra o plano de acesso utilizado por um único comando SQL. Para utilizá-
lo devemos efetuar a criação da tabela PLAN_TABLE subordinada ao usuário que fará a utilização do comando,
com o seguinte layout.
O script com o comando CREATE TABLE é fornecido pela Oracle. Para o Personal Oracle 9i o arquivo é o seguinte:
<oracle-home>\RDBMS\ADMIN\UTLXPLAN.SQL.
Não entraremos em detalhes sobre o resultado uma vez que este assunto exige um estudo muito mais profundo do
que este aqui apresentado e uma informação parcial poderá dar margem a interpretações equivocadas.
A sintaxe do comando Explain é a seguinte:
EXPLAIN PLAN SET STATEMENT_ID = <nome> [INTO <tabela>] FOR <sql>;
Onde:
♦ <nome> – nome da análise a ser efetuada. Pode ser qualquer nome a ser dado pelo usuário limitado a 30 caracteres.
♦ <tabela> – indica o nome da tabela onde será gerada a análise do comando SQL. Por default Plan_Table.
♦ <sql> – comando SQL a ser analisado.
Para realizarmos testes a partir deste ponto precisamos que a tabela Plan_table esteja criada, e portanto obtenha o script
comentado anteriormente e crie a tabela no usuário Desenv. Outro ponto importante é a criação ou remoção das
estatísticas armazenadas no dicionário de dados. Para este fim usaremos o comando ANALYZE TABLE XXX COMPUTE
STATISTICS (para otimização por custo) ou ANALYZE TABLE FUNC DELETE STATISTICS (para otimização por regra).
Suponhamos que desejássemos a relação dos funcionários (e seus respectivos departamentos) que não sejam
responsáveis por projetos.
O comando acima carregará a tabela PLAN_TABLE com informações sobre o caminho de acesso escolhido pelo otimizador.
Para melhor visualizarmos os dados coletados podemos usar o comando SELECT a seguir.
Plano de Acesso
-------------------------------------------
SELECT STATEMENT CUSTO =
1 FILTER
2 NESTED LOOPS
3 TABLE ACCESS FULL FUNC
4 TABLE ACCESS BY INDEX ROWID DEPTO
5 INDEX UNIQUE SCAN SYS_C002931
6 TABLE ACCESS FULL PROJ
7 linhas selecionadas.
vemos um TABLE ACESS FULL FUNC sabemos que será feito o acesso a todas as linhas da tabela Func. Quando
vemos um TABLE ACESS BY XXXX ROWID DEPTO sabemos que será feito o acesso à tabela DEPTO através de um
ROWID. O fornecimento deste ROWID é feito pelo comando subordinado (identado) inferior, isto é, INDEX SCAN
SYS_C002931. Mas não comentamos, ainda, o que é um NESTED LOOPS ou um FILTER.
Podemos concluir, então, que em um plano existem dois tipos de processos, aqueles que fazem acesso às linhas (de
tabelas, índices ou clusters) diretamente no banco de dados e aqueles processos que recebem linhas de outros
processos, trabalham estas linhas e as passam adiante.
No exemplo da Figura 5.16, identificamos os processos 3 a 6 como processos de acesso ao banco de dados (processos
fornecedores) e os processos 1 e 2 como processos de manuseio de linhas (processos receptores).
A ordem com que estes processos são executados pode ser considerada do mais indentado para o menos indentado,
de baixo para cima. Sendo assim, o processo receptor 2 precisa receber dois conjuntos de linhas. Estes conjuntos de
linhas são obtidos pelos processos 3 e 4, sendo que o processo 4 precisa de um acesso a índice primeiro, ou seja, do
processo 5. Nosso paralelismo seria, então: como passo 1 processo 3 e dupla 4-5. Estes dois conjuntos passariam as
linhas para o processo receptor 2 (Nested Loops). Este processo receptor juntaria as linhas oriundas dos processos
3 e 4 e passaria linha a linha para o processo receptor 1 (Filter), que também recebe entrada de dois processos o 2
e o 6. Quando a filtragem fosse encerrada, o resultado seria passado para o comando que solicitou a otimização. No
nosso caso o comando SELECT.
O AUTOTRACE DO SQL*PLUS
Apresenta um relatório sobre a execução dos comandos de SQL DML (Select, Insert, Update ou Delete) bem-
sucedidos. O relatório pode incluir a apresentação de estatísticas e o caminho de execução (Explain).
A opção TraceOnly apresenta o relatório sem apresentar os dados da Query. Se Statistics for solicitado a execução
do comando é realizada, porém sem a apresentação dos resultados.
Para que a opção Explain possa ser executada deve ser criada a tabela Plan_Table para a geração do caminho de
acesso, da mesma forma que anteriormente.
A sintaxe do comando SET do SQL*Plus (já vista no Capítulo 2) é a seguinte:
SET AUTOT[RACE] {OFF|ON|TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
Execution Plan
-------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=8)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'DEPTO' (Cost=1 Card=1 Bytes=8)
2 1 INDEX (UNIQUE SCAN) OF 'SYS_C002931' (UNIQUE)
Statistics
-------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
350 bytes sent via SQL*Net to client
372 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
7. Indexed Cluster Key – Este caminho de acesso estará disponível se a cláusula WHERE dos comandos de acesso usar
todas as colunas de uma INDEXED CLUSTER KEY em condições de igualdade. Para chaves compostas, as condições
de igualdade devem ser combinadas com operadores AND. Para executar o comando, o Oracle executa um UNIQUE
SCAN no índice do CLUSTER para recuperar o ROWID de uma linha com o valor correspondente da chave.
O Oracle, então, usa este ROWID para fazer acesso à tabela com um CLUSTER SCAN. Uma vez que todas as linhas
com o mesmo valor de chave estão armazenadas juntas, o CLUSTER SCAN necessita somente de um único ROWID
para que todos sejam encontrados.
8. Composite Index – Este caminho de acesso estará disponível se a cláusula WHERE dos comandos de acesso usar
todas as colunas de um índice composto em condições de igualdade combinadas com operadores AND. Para
executar o comando, o Oracle executa um RANGE SCAN no índice para recuperar os ROWIDs das linhas
selecionadas e, então, fazer acesso a tabelas através dos ROWIDs.
O índice IX_NOME possui duas chaves correspondendo às colunas NM_FUNC e NM_SOBRENOME da tabela FUNC.
9. Single Column Indexes – Este caminho de acesso estará disponível se a cláusula WHERE dos comandos de acesso
usar as colunas de um ou mais índices (de uma única chave) na condição de igualdade. Para uso de diversos
índices simultaneamente, as condições devem ser combinadas com operadores AND.
Se a cláusula WHERE utiliza a coluna de um único índice, o Oracle executa o comando utilizando um RANGE SCAN
no índice para recuperar os ROWIDs das linhas selecionadas e, então, fazer acesso à tabela através destes ROWIDs.
10. Bounded Range Search on Indexed Columns – Este caminho de acesso estará disponível se a cláusula WHERE dos
comandos de acesso contiverem condições que usem uma coluna de um índice que contenha uma única coluna
ou uma ou mais colunas que façam parte da porção esquerda de um índice composto por mais de uma coluna.
Cada uma das condições a seguir especifica um intervalo com fronteira de valores indexados que podem ser
utilizados pelo comando. O intervalo é considerado com fronteira porque as condições especificam os dois limites
do intervalo (inferior e superior).
<coluna> = <expressão>
<coluna> >[=] <expressão> AND <coluna> <[=] <expressão>
<coluna> BETWEEN <expressão> AND <expressão>
<coluna> LIKE 'c%'
Estes caminhos de acesso não estarão disponíveis se <expressão> fizer referência a colunas indexadas. Para executar
o comando, o Oracle executa um RANGE SCAN no índice e, então, faz acesso à tabela pelo ROWID.
11. Unbounded Range Search on Indexed Columns – Este caminho de acesso estará disponível se a cláusula WHERE
dos comandos de acesso possuir uma das condições (abaixo) que usem a coluna de um índice com uma única
chave ou uma ou mais colunas da porção esquerda de um índice composto:
<coluna> >[=] <expressão>
<coluna> <[=] <expressão>
Cada uma destas condições especifica um intervalo sem fronteira de valores indexados que sofrem acesso pelo
comando. O intervalo é dito sem fronteira porque as condições especificam apenas um dos limites (inferior ou
superior), não ambos.
Para executar este comando o Oracle executa um RANGE SCAN no índice e, então, faz acesso à tabela pelo ROWID.
12. Sort Merge Join – Este caminho de acesso está disponível para comandos que juntem tabelas que não sejam
armazenadas juntas em um CLUSTER e que as cláusulas WHERE dos comandos de acesso usem colunas de cada
tabela pela condição de igualdade. Para executar este comando o Oracle usa uma operação de SORT-MERGE ou
NESTED LOOP ou HASH JOIN para executar o JOIN.
13. Max or Min of Indexed Column – Este caminho de acesso estará disponível para comandos SELECT nos quais as
seguintes condições sejam verdadeiras:
♦ A consulta use a função MAX (ou MIN) para selecionar o maior ou menor valor de uma coluna que faça parte
de um índice com uma única coluna ou de uma coluna que seja a mais à esquerda de um índice composto.
O índice não pode ser um CLUSTER INDEX.
♦ O argumento para as funções MAX ou MIN pode ser qualquer expressão envolvendo uma coluna, uma
constante, um operador de adição (+), um operador de concatenação (||) ou a função CONCAT.
♦ Não existem outras expressões na lista do SELECT.
♦ O comando não possui cláusula WHERE ou cláusula GROUP BY.
Para executar a consulta, o Oracle executa um RANGE SCAN (ou Index Full Scan) no índice para encontrar o maior
e o menor valor indexado. Uma vez que somente este valor é selecionado, o Oracle não necessita fazer acesso à
tabela após esta busca.
14. Order By on Indexed Column – Este caminho de acesso está disponível para um comando SELECT para o qual
todas as condições a seguir sejam verdadeiras:
♦ A consulta contenha uma cláusula ORDER BY que use a coluna de um índice composto por uma única chave
ou use a coluna mais à esquerda de um índice composto. O índice não pode ser um CLUSTER INDEX.
♦ Deve existir uma restrição de integridade (PK ou NOT NULL) que garante que pelo menos uma das colunas
indexadas listadas na cláusula ORDER BY não contenha NULLs.
♦ O parâmetro NLS_SORT esteja com o valor BINARY.
Para executar a consulta, o Oracle executa um RANGE SCAN no índice para recuperar os ROWIDs das linhas
selecionadas na ordem. O Oracle faz, então, acesso à tabela por estes ROWIDs.
15. Full Table Scan – Este caminho de acesso está disponível para qualquer comando SQL independente de sua
cláusula WHERE.
As condições a seguir não tornam o acesso através de índice disponível:
<coluna1> > <coluna2>
<coluna1> < <coluna2>
<coluna1> >= <coluna2>
<coluna1> <= <coluna2>
onde <expressão> é uma expressão que opera em uma coluna através de um operador ou função, independente de
a coluna ser indexada.
NOT EXISTS <subquery>
USO DE ÍNDICES
Índices aumentam a performance de consultas que selecionem um pequeno percentual de linhas.
Como regra geral só devemos criar índices em tabelas que sejam freqüentemente consultadas para aproximadamente
2% a 4% das linhas. Este valor pode ser considerado um pouco maior quando todas as informações puderem ser obtidas
diretamente do índice ou quando as colunas indexadas puderem ser usadas para operações de Join com outras tabelas.
Devemos lembrar que um índice é mantido pelo Oracle mesmo que ele não seja nunca usado.
A manutenção de um índice apresenta uma significativa demanda de CPU e I/O. Desta forma devemos avaliar com
cuidado a necessidade de criá-los.
Se pudéssemos analisar todas as aplicações e verificar quais os índices realmente utilizados, poderíamos remover
(DROP) aqueles que não aparecem nos EXPLAIN PLAN apresentados. Estes índices não são necessários, não são
seletivos e devem ser descartados.
A Oracle oferece dois tipos de índices para acesso aos dados.
OS ÍNDICES B*TREE
Como características principais para este tipo de índice, temos:
♦ Árvores balanceadas rapidamente localizam os valores de chaves.
♦ Os endereços fornecidos pelos ROWID provêm acesso direto às linhas das tabelas.
♦ Consultas que usam somente colunas indexadas podem ser resolvidas no índice.
♦ Pesquisas em índices são uma alternativa para pesquisas seqüenciais em tabelas, já que podem reduzir o I/O de disco.
♦ Os índices são usados e mantidos, automaticamente, pelo Oracle Server.
Este é o tipo de índice mais utilizado em ambientes de atualização online.
OS ÍNDICES BITMAP
Os índices do tipo BITMAP são uma alternativa aos índices B*TREE quando:
♦ As tabelas são muito grandes (milhões de linhas).
♦ As tabelas possuem uma cardinalidade baixa, isto é, a coluna (ou colunas) na qual o índice seria baseado possui
um número pequeno de valores distintos (ex.: sexo, estado civil, estado).
♦ As consultas (mais usadas) podem ter índices bitmap em todas as colunas que normalmente aparecem nas
cláusulas WHERE.
♦ As consultas possuem condições na cláusula que são satisfeitas com milhares de linhas.
Para um índice comum isto é obtido pelo armazenamento de uma lista de ROWIDS para cada chave correspondente às
linhas da tabela com aquele valor de chave (no Oracle, cada chave é armazenada juntamente com o ROWID correspondente).
Com um índice BITMAP, um mapa de bits para cada valor de chave é usado em vez de uma lista de ROWIDS. Cada
bit corresponde a um possível ROWID e se o bit estiver marcado isto significa que a linha com o ROWID
correspondente contém o valor da chave.
Uma função de mapeamento é usada para converter a posição do BIT para o valor correspondente do ROWID, para
que o índice forneça a mesma funcionalidade que um índice comum mesmo usando uma representação diferente.
Se o número de valores de chave diferentes for bem pequeno, os índices BITMAP são muito eficientes. O Oracle faz
um MERGE dos índices correspondentes às várias condições presentes na cláusula WHERE. As linhas que satisfizerem
algumas condições, mas não todas, serão filtradas antes que a tabela sofra qualquer acesso. Como resultado, temos
um incremento significativo na performance para consultas.
USANDO HINTS
Apesar de todas as informações coletadas e todo o algoritmo sofisticado do otimizador, provavelmente o nosso
conhecimento da informação armazenada é maior que a que o otimizador possui. Por exemplo, podemos saber
que um índice é mais seletivo em certas queries que o otimizador possa determinar.
Baseado nisto podemos estar mais aptos a escolher um plano de execução mais eficiente que o otimizador. Neste
caso, podemos usar hints para forçar o otimizador a usar o plano de execução que desejamos.
Hints são sugestões que fornecemos ao otimizador para um comando SQL. Podemos usar Hints para especificar:
♦ O método de otimização.
♦ O goal para o método de custo.
♦ O caminho de acesso para uma determinada tabela presente no comando.
♦ A ordem de join.
♦ A operação de join.
ou
<cláusula DELETE, INSERT, UPDATE ou SELECT> — <hints>
<restante do comando>
Onde:
♦ <cláusula DELETE, INSERT, SELECT ou UPDATE> – são as palavras iniciais dos comandos correspondentes. Os
comentários contendo os hints só podem ser informados após uma destas palavras.
♦ + – Este sinal faz com que o Oracle interprete o comentário como uma lista de hints. O sinal + segue imediatamente
após o delimitador de comentário, nenhum espaço é permitido.
♦ <hints> – corresponde a um ou mais dos hints permitidos. Se um comentário contiver diversos hints, cada par de
hints deve vir separado por pelo menos um espaço.
Se especificarmos hints incorretamente, o Oracle ignora-o mas não retorna um erro:
♦ Se o comentário não seguir uma das palavras-chaves DELETE, SELECT, etc.
♦ Ignora aqueles hints que tiverem erro de sintaxe e considera aqueles escritos corretamente.
♦ Ignora combinações de hints conflitantes mas considera outros hints dentro do mesmo comentário.
♦ Ignora todos os hints em ambientes que usem o PL/SQL versão 1 tais como SQL*FORMS 3.0, Oracle Forms 4.5,
and Oracle Reports 2.5.
♦ Só reconhece hints se estiver usando o método de custo. Se incluirmos qualquer hint (exceto RULE), o otimizador
passará a usar o método de custo.
Se um comando SQL possui um hint especificando um método de otimização, o otimizador usa a especificação
determinada independente da presença ou ausência de estatísticas e do valor do parâmetro OPTIMIZER_MODE
(de inicialização e da sessão).
EXERCÍCIOS
Antes de iniciar a execução dos exercícios execute o comando ANALYZE para as tabelas FUNC, DEPTO, PROJ e
PRJATV. Posteriormente retire as estatísticas armazenadas para cada uma das tabelas e repita todos os exercícios
para efeito de comparação.
5.11) Determine o caminho de acesso dos comandos abaixo. Neste exercício a principal preocupação é entender o
resultado e determinar qual a opção de acesso à cada tabela presente no comando.
a) SELECT nm_func
FROM func
WHERE ROWID = :valor
b) SELECT *
FROM EMP1
WHERE CD_MAT = 100
d) SELECT NM_FUNC
FROM FUNC
WHERE NR_GIT = 20
5.12) Determine o caminho de acesso, a operação realizada e a ordem em que as operações foram realizadas. Neste
exercício a principal preocupação é determinar a operação realizada, a ordem em que estão sendo efetuadas, qual o
método de Join (quando for o caso) empregado para a solução do problema e o caminho de acesso para cada tabela.
a) SELECT *
FROM func
WHERE CD_MAT BETWEEN 100 AND 500
AND nm_func = 'DANIEL'
ORDER BY CD_MAT
b) SELECT NM_DEPTO
FROM DEPTO
UNION
SELECT NM_FUNC
FROM FUNC
WHERE CD_MAT BETWEEN 100 AND 300
c) SELECT *
FROM FUNC
WHERE CD_MAT = :MAT
AND NM_FUNC = 'MARIA'
d) SELECT NM_FUNC
FROM FUNC
WHERE rownum < 200
ORDER BYcd_mat
CONCEITOS GERAIS
Quando trabalhamos com distribuição de dados precisamos, freqüentemente, transferir informações de um banco
de dados para outro. Para realizar esta operação a Oracle disponibilizava um objeto chamado de Snapshot.
Este objeto evoluiu e ganhou o nome de View Materializada. Além dos usos já conhecidos as views materializadas
também podem ser criadas no mesmo banco de dados em que se encontram as tabelas de onde se originam, porém com
o objetivo de sumariar e/ou pré-calcular os dados. Este novo uso é muito útil para ambientes de Data Warehouse.
Nestes ambientes as views materializadas são usadas para pré-cálculo e armazenamento de dados agregados tais
como totais e médias. Também podem ser usadas para pré-calcular joins com ou sem agregações. O Otimizador por
Custo pode utilizar as views materializadas para aumentar a performance das consultas reconhecendo,
automaticamente, quando uma view materializada pode ser usada para atender a uma requisição. O Otimizador,
transparentemente, reescreve a consulta para usar a view materializada. Nesta situação, as consultas são direcionadas
para as views materializadas em vez das tabelas-detalhe originais.
Observe que esta característica do otimizador pode trazer enormes benefícios para ambientes com grandes volu-
mes de dados pois, sem qualquer modificação na query do usuário, que utiliza tabelas com grandes volumes, ele
interpreta (dentro de critérios previamente estabelecidos) a query e percebe que o mesmo resultado pode ser
obtido mais rapidamente em uma das views materializadas presentes no ambiente.
Em ambientes distribuídos, as views materializadas são usadas para replicação de dados e para sincronismo de
atualizações nos diversos sites.
Em ambientes de computação móvel, as views materializadas são usadas para download de um subconjunto dos
dados residentes em um ambiente central, com recarga periódica e propagação das atualizações de volta para o
ambiente centralizado.
EXEMPLOS
Apresentaremos a seguir alguns exemplos de criação de view materializada. Nosso objetivo, no entanto, é apenas
conceitual uma vez que o usuário perceberá apenas alteração na performance de suas aplicações. Efetivamente,
nenhuma modificação necessita ser realizada pelos desenvolvedores. Todas as tarefas aqui apresentadas se referem
a tarefas de DBA.
O comando a seguir cria uma view materializada de nome MV_POR_VENDEDOR que calcula as vendas por vendedor.
A view materializada não contém qualquer dado porque foi determinado que o método de construção é DEFERRED.
Quando ela for refrescada (manualmente), será realizado um Refresh completo. Após esta etapa, esta view
materializada poderá ser usada pelo otimizador para substituição do acesso à tabela origem (Func e Vendas) pelo
acesso à view MV_por_Vendedor. Este mecanismo se chama Query Rewrite.
Neste exemplo calculamos a média de produtos vendidos por um determinado vendedor por dia. A view
materializada é preenchida com dados imediatamente após sua criação em função da escolha do método IMMEDI-
ATE e está disponível para uso pelo mecanismo de Query Rewrite.
Desta forma não haverá Refresh até que uma requisição manual seja informada pois foi utilizada a cláusula ON
DEMAND (que é default).
No exemplo da Listagem 5.19 a view materializada calcula o desvio padrão para o número de unidades vendidas
por um vendedor em uma determinada data. A view materializada é preenchida imediatamente com dados porque
o método é IMMEDIATE e ela fica disponível para ser usada pelo mecanismo de Query Rewrite.
O método de Refresh é FAST, o que significa que somente as modificações serão usadas para atualização da view
materializada. Por este motivo tivemos necessidade de criar um log associado a cada uma das tabelas envolvidas. A
cada modificação na tabela origem uma informação é armazenada no log.
No próximo exemplo criaremos uma view materializada contendo apenas Joins. Para que possamos especificar a
cláusula FAST REFRESH, devemos garantir que uma atualização deste tipo possa ser executada se houver modificações
em quaisquer das tabela-detalhe envolvidas.
MÉTODOS
O otimizador usa diferentes métodos para reescrever uma query. O primeiro e mais importante passo é determinar
se todo ou parte dos resultados requisitados pela query podem ser obtidos dos resultados previamente calculados
na view materializada.
O caso mais simples ocorre quando o resultado armazenado na view é exatamente a solicitação requisitada pela query.
O otimizador percebe isto comparando o texto do comando de SQL com o texto da definição da view materializada.
NÍVEIS DE INTEGRIDADE
O parâmetro de inicialização Query_Rewrite_Integrity determina a integridade da reescrita e pode receber três valores:
♦ Enforced – É o modo default. O otimizador irá usar somente as views materializadas que estejam com seus dados
totalmente atualizados (“frescas”) e somente usa aqueles relacionamentos que sejam baseados em constraints
válidas (asseguradas, enforced).
♦ Trusted – Neste modo o otimizador “acredita” que os dados das views materializadas baseados em tabelas pré-
existentes estejam corretos e os relacionamentos declarados nas dimensões e as constraints RELY estejam corretas.
Neste modo o otimizador usa Prebuilt Materialized Views e usa relacionamentos que não estejam assegurados
assim como aqueles assegurados. Ele também “acredita” em relacionamentos de dados especificados utilizando
Dimensions, mas que não estejam assegurados por constraints.
♦ Stale_Tolerated – Neste modo, o otimizador usa views materializadas que estejam válidas mas que contenham
dados envelhecidos (stale) assim como aquelas que contenham dados atualizados (“frescas”). Este modo oferece
o máximo de reescrita, mas aumenta o risco de obtenção de resultados incorretos.
EXERCÍCIOS
5.15) Criar uma view materializada simples e verificar seu uso em comandos de SQL.
a) Criar uma view materializada que apresente o valor total vendido por cada vendedor da empresa, independente
do período da venda. O preenchimento da VIEW deve ser manual.
b) Avalie a utilização desta view em comandos de SQL associados à tabela VENDAS.
c) Avalie a utilização desta view quando o comando de SQL é diferente do comando da view.
5.16) Criar uma view materializada simples e verificar seu uso em comandos de SQL.
a) Criar uma view materializada com construção imediata e que contenha mais de uma agregação. Verifique
seu preenchimento.
b) Teste o uso desta view em comandos de SQL similares à construção da view.
Todas as partições de uma tabela ou índice têm os mesmos atributos lógicos (colunas, restrições, colunas dos
índices), porém seus atributos físicos (pctfree, pctused, initrans, maxtrans) podem variar para diferentes partições
da mesma tabela ou índice.
Cada partição é armazenada em um segmento separado e, opcionalmente, poderá, também, estar em Tablespace diferenciado.
MÉTODOS DE PARTICIONAMENTO
Estão disponibilizados três métodos de particionamento. Estes métodos fornecem ao DBA opções de divisão dos
dados de acordo com as características de uso das aplicações, de tal forma que possa ser escolhido o método mais
eficiente para a situação específica. São eles:
RANGE
Neste método estabelecemos intervalos de valores para uma ou mais colunas (chaves de particionamento), as
quais definirão como ocorrerá o particionamento.
HASH
Indica que a tabela será subdividida baseado em um algoritmo (função Hash). O Oracle associa linhas a partições
usando uma função sobre as colunas definidas como chaves de particionamento.
COMPOSITE
O particionamento composto (Range/Hash) divide os dados por intervalo de valor para o particionamento princi-
pal da tabela ou índice e especifica o número de subpartições Hash.
Desta forma os dados são subdivididos por intervalo de valor e para cada intervalo é feita uma nova subdivisão de
acordo com a quantidade de subpartições (do tipo Hash) estabelecida.
O usuário pode adicionar e remover subpartições (para que os dados fiquem bem distribuídos) e, ainda, pode
adicionar ou remover partições principais, sem efeito em outras partições.
CARACTERÍSTICAS E RESTRIÇÕES
É possível o particionamento de tabelas contendo colunas do tipo LOB. Os valores podem ser armazenados dentro
da linha ou em segmentos separados. Todos os tipos de Lobs são suportados (Blob, Clob Nclob e Bfile).
O particionamento também foi estendido a tabelas do tipo Index-Organized.
Como restrição, temos:
♦ Uma tabela não pode ser particionada se fizer parte de um Cluster.
♦ As tabelas particionadas não podem conter colunas do tipo LONG ou LONG RAW.
♦ Se a tabela ou índice é particionado em relação a uma coluna do tipo DATE e o formato NLS não possuir
especificação de século com o ano, as descrições das partições devem usar a função TO_DATE para a especificação
do ano completa; caso contrário não poderá ser criada a tabela ou índice.
Neste exemplo a tabela está particionada em relação à coluna dt_promocao e foram estabelecidas 4 partições de
nomes Anos80, Anos90_94, Anos95_99 e Anos2000.
A consulta em uma tabela com estas características pode ser feita normalmente. De acordo com a sintaxe apresentada
o Oracle direcionará a consulta para uma ou mais partições.
No exemplo a seguir como a cláusula Where faz referência à data da promoção, que é justamente a coluna sobre a
qual ocorre o particionamento, é possível que o banco de dados, através da descrição da tabela, perceba que só há
necessidade de pesquisar a partição Anos90_94.
Se a pesquisa, por outro lado, não fornecer possibilidade de o Oracle restringir a busca a determinadas partições,
todas serão selecionadas.
Utilizando uma sintaxe própria do comando SELECT, podemos contornar esta situação (se desejarmos) limitando
a busca a uma determinada partição, bastando que mencionemos a cláusula Partition após a cláusula From, como
mostrado no exemplo a seguir.
O uso de tabelas particionadas pode ser muito útil, justamente para dados históricos, que não precisam ser
consultados todo o tempo e que estando armazenados em áreas (tablespaces) separadas das linhas mais
freqüentemente utilizadas da tabela podem trazer significativo ganho na performance das aplicações diárias.
MOVIMENTAÇÃO DE LINHAS
A cláusula Enable Row Movement dos comandos Alter Table e Create Table permite que as linhas sejam movidas
entre partições.
Quando a movimentação de linhas é permitida, atualizações que afetem as chaves podem fazer com que uma
linha que não mais pertença à partição corrente seja migrada para a partição apropriada.
TO_CHAR(DT_PROMO CD_MAT
------------------ ------
17/08/1989 00:00 50
15/09/1989 00:00 170
17/08/1989 00:01 50
TO_CHAR(DT_PROMO CD_MAT
------------------ ------
17/08/1989 00:00 50
17/08/1989 00:01 50
TO_CHAR(DT_PROMO CD_MAT
------------------ ------
17/08/1999 00:00 170
O default (Disable Row Movement) indica que a movimentação de uma linha não é permitida e uma atualização
na chave que cause este tipo de resultado fará com que um erro seja retornado para o usuário.
PARTICIONAMENTO DE ÍNDICES
Os índices, no Oracle, podem ser particionados ou não. Os índices particionados são aplicáveis a tabelas particionadas
ou não. Os índices não particionados são aplicáveis a tabelas particionadas ou não.
Os índices podem ser subdivididos em dois tipos: Globais e Locais.
ÍNDICES GLOBAIS
Um índice global é aquele que endereça todas as linhas de uma tabela (seja ela particionada ou não). Este índice
também pode ser particionado. Por default os índices não particionados são globais.
Um índice global quando particionado significa que seu particionamento não é comparável ao particionamento
da tabela. As características de particionamento são definidas pelo usuário em cláusulas específicas.
Para que seja possível o particionamento de um índice global, a porção esquerda da “chave de particionamento”
deve corresponder às chaves do índice. Podemos especificar parâmetros físicos tanto em nível de índice como em
nível de partição.
ÍNDICES LOCAIS
Os índices locais são particionados nas mesmas colunas, com o mesmo número de partições e com as mesmas
fronteiras que a tabela à qual se relacionam.
♦ PREFIXADOS – Um índice local é dito prefixado quando a porção esquerda da “chave de particionamento”
corresponde à chave do índice.
♦ NÃO PREFIXADOS – Da mesma forma, um índice local é dito não prefixado quando não existe correspondência
entre a “chave de particionamento” e a chave do índice.
Para um índice local o número de partições do índice deve ser igual ao número de partições da tabela e na mesma
ordem. Se omitirmos a cláusula Partition, o Oracle gerará um nome que seja consistente com partição correspondente
da tabela. Se o nome conflitar com um nome de índice existente, o formato SYS_Pn será usado.
Para índices associados a tabelas particionadas pelo método Hash a única característica física possível de ser
especificada para cada partição é a cláusula Tablespace. Caso seja omitida, será herdada da especificação feita em
nível de índice. Caso seja omitida, o armazenamento de cada partição do índice será feito no mesmo tablespace
que a partição da tabela correspondente.
Da mesma forma que para índices associados a tabelas particionadas pelo método Hash, índices associados a
tabelas com particionamento composto podem especificar parâmetros físicos apenas para a partição. Cada
subpartição poderá especificar apenas a cláusula Tablespace.
EXERCÍCIOS
5.17. Crie uma tabela com particionamento por intervalo de valores e preencha esta tabela com os dados originais
da tabela FUNC.
5.18) Crie um índice local prefixado, um índice local não prefixado, um índice global particionado prefixado, um
índice global particionado não prefixado e um índice global não particionado.
5.19) Divida a partição Z em duas partições. Verifique o estado dos índices associados.
5.20) Remova a última partição da tabela. Verifique o estado dos índices associados.
5.21) Adicione uma nova partição à tabela. Verifique o estado dos índices associados.
5.22) Junte as partições B e C.
Listagem-resposta 5.01A
SQL> CREATE OR REPLACE TYPE OT_LINHA AS OBJECT
2 (NM_PESSOA VARCHAR2(25),
3 NM_RUA VARCHAR2(25),
4 NM_BAIRRO VARCHAR2(25),
5 NM_CIDADE VARCHAR2(25),
6 NM_ESTADO VARCHAR2(25),
7 NR_RUA NUMBER,
8 NR_CEP NUMBER(8));
9 /
Tipo criado.
2 WLINHA OT_LINHA;
3 TBLINHA NT_LINHA := NT_LINHA();
4 BEGIN
5 FOR R1 IN (SELECT F.NM_PESSOA, F.NM_ENDERECO.NM_RUA NM_RUA,
6 F.NM_ENDERECO.NM_BAIRRO NM_BAIRRO, F.NM_ENDERECO.NM_CIDADE NM_CIDADE,
7 F.NM_ENDERECO.CD_ESTADO.NM_ESTADO NM_ESTADO, F.NM_ENDERECO.NR_RUA NR_RUA,
8 F.NM_ENDERECO.NR_CEP NR_CEP FROM TB_TFUNC F) LOOP
9 WLINHA := OT_LINHA(R1.NM_PESSOA, R1.NM_RUA, R1.NM_BAIRRO, R1.NM_CIDADE,
10 R1.NM_ESTADO, R1.NR_RUA, R1.NR_CEP);
11 TBLINHA.EXTEND;
12 TBLINHA(TBLINHA.LAST) := WLINHA;
13 END LOOP;
14 RETURN TBLINHA;
15 END;
16 /
Função criada.
6 linhas selecionadas.
Para que a rotina possa ser executada na cláusula From, os tipos devem ser previamente definidos. Neste primeiro
exercício não utilizamos a opção de Pipelined.
5.02) Crie uma Table Function que apresente para cada Funcionário seu nome, salário e cargo. Use Pipelined.
Utilize-a na cláusula From de um comando Select.
Listagem-resposta 5.02A
SQL> CREATE OR REPLACE TYPE OT_SALCARGO AS OBJECT
2 (NM_PESSOA VARCHAR2(25),
3 VL_SAL NUMBER,
4 NM_CARGO VARCHAR2(25));
5 /
Tipo criado.
Neste exercício usamos Pipelined. Desta forma a cada linha montada o resultado é passado de volta para o comando Select.
5.03) Crie uma função de agregação para calcular o número médio de vogais do parâmetro.
Listagem-resposta 5.03A
SQL> CREATE OR REPLACE TYPE OT_VOGAL AS OBJECT
2 (
3 QTDVOG NUMBER,
4 QTDLIN NUMBER,
5 STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT OT_VOGAL) RETURN NUMBER,
6 MEMBER FUNCTION ODCIAGGREGATEITERATE (SELF IN OUT OT_VOGAL,
7 VALOR IN VARCHAR2) RETURN NUMBER,
8 MEMBER FUNCTION ODCIAGGREGATETERMINATE (SELF IN OT_VOGAL, RETORNO OUT NUMBER,
9 FLAGS IN NUMBER) RETURN NUMBER,
10 MEMBER FUNCTION ODCIAGGREGATEMERGE (SELF IN OUT OT_VOGAL,
11 CTX2 IN OUT OT_VOGAL) RETURN NUMBER
12 );
13 /
Tipo criado.
5.04) Crie uma função de agregação para calcular o tamanho médio do texto informado.
Listagem-resposta 5.04A
SQL> CREATE OR REPLACE TYPE OT_TEXTO AS OBJECT
2 (
3 QTDLET NUMBER,
4 QTDLIN NUMBER,
5 STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT OT_TEXTO) RETURN NUMBER,
6 MEMBER FUNCTION ODCIAGGREGATEITERATE (SELF IN OUT OT_TEXTO,
7 VALOR IN VARCHAR2) RETURN NUMBER,
8 MEMBER FUNCTION ODCIAGGREGATETERMINATE (SELF IN OT_TEXTO, RETORNO OUT NUMBER,
9 FLAGS IN NUMBER) RETURN NUMBER,
10 MEMBER FUNCTION ODCIAGGREGATEMERGE (SELF IN OUT OT_TEXTO,
11 CTX2 IN OUT OT_TEXTO) RETURN NUMBER
12 );
13 /
Tipo criado.
5.05) Criar uma tabela temporária com dados preservados por uma transação. Verifique a descrição desta tabela
após sua criação.
Listagem-resposta 5.05A
SQL> CREATE GLOBAL TEMPORARY TABLE TEMPF
2 (CD_MAT NUMBER(5),
3 NM_FUNC VARCHAR2(30),
4 VL_SAL NUMBER(10,2));
Tabela criada.
Observe que não existe especificação de tablespace para esta tabela. Isto ocorre porque como os dados não são
permanentes, eles são alocados na área temporária do sistema.
5.06) Incluir linhas nesta tabela, efetuar um COMMIT e verificar a quantidade de linhas final.
Listagem-resposta 5.06A
SQL> INSERT INTO TEMPF(CD_MAT, NM_FUNC, VL_SAL)
2 SELECT CD_MAT, NM_FUNC, VL_SAL
3 FROM FUNC
4 WHERE CD_MAT < 300;
28 linhas criadas.
SQL> COMMIT;
Validação completa.
COUNT(*)
--------
0
Listagem-resposta 5.07A
SQL> CREATE GLOBAL TEMPORARY TABLE TEMPFS
2 (CD_MAT NUMBER(5),
3 NM_FUNC VARCHAR2(30),
4 VL_SAL NUMBER(10,2))
5 ON COMMIT PRESERVE ROWS;
Tabela criada.
SQL> COMMIT;
Validação completa.
COUNT(*)
--------
28
5.08) Abrir uma segunda sessão em paralelo, incluir dados na tabela temporária e consultá-los.
Listagem-resposta 5.08A
SQL> INSERT INTO TEMPFS (CD_MAT, NM_FUNC, VL_SAL)
2 SELECT CD_MAT, NM_FUNC, VL_SAL
3 FROM FUNC
4 WHERE CD_MAT BETWEEN 300 AND 500;
7 linhas criadas.
SQL> COMMIT;
Validação completa.
SQL> SELECT CD_MAT, NM_FUNC FROM TEMPFS WHERE ROWNUM < 10;
CD_MAT NM_FUNC
---------- -------
300 FELIPE
310 MARINA
320 ROBERTO
330 WILSON
340 DILSON
341 JOANA
401 NOVO
7 linhas selecionadas.
Observe que apesar de a sessão anterior ter dado commit nos dados eles não são visíveis pela sessão do exercício
5.08. Cada usuário só tem acesso a seus dados.
5.09) Criar um trigger, um índice e uma view, utilizando esta tabela temporária.
Listagem-resposta 5.09A
SQL> CREATE OR REPLACE TRIGGER TG_TEMP
2 BEFORE UPDATE ON TEMPFS
3 FOR EACH ROW
4 DECLARE
5 NOME VARCHAR2(20);
6 BEGIN
7 SELECT NM_SOBRENOME INTO NOME FROM FUNC
8 WHERE CD_MAT = :NEW.CD_MAT;
9 :NEW.NM_FUNC := :NEW.NM_FUNC ||' '|| NOME;
10 END;
11 /
Gatilho criado.
A criação do índice somente pode ser realizada antes da inclusão de dados. Desta forma, ao estabelecermos conexão
e perdermos todos os dados, pudemos criar o índice. Teste realizar esta operação com a tabela já preenchida.
5.10) Utilize a view criada.
Listagem-resposta 5.10A
SQL> INSERT INTO TEMPFS (CD_MAT, NM_FUNC, VL_SAL)
2 SELECT CD_MAT, NM_FUNC, VL_SAL
3 FROM FUNC
4 WHERE CD_MAT < 300;
28 linhas criadas.
SQL> COMMIT;
Validação completa.
SQL> COMMIT;
Validação completa.
5.11) Determine o caminho de acesso dos comandos abaixo. Neste exercício a principal preocupação é entender o
resultado e determinar qual a opção de acesso à cada tabela presente no comando.
a) SELECT nm_func
FROM func
WHERE ROWID = :valor
Listagem-resposta 5.11A
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT nm_func
3 FROM func
4 WHERE ROWID = :valor
5 /
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 1
TABLE ACCESS BY USER ROWID FUNC
Este é o acesso mais rápido pois é informado o rowid (endereço da linha). O acesso é direto pelo endereço, sem intermediários.
b) SELECT *
FROM EMP1
WHERE CD_MAT = 100
Listagem-resposta 5.11B
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT *
3 FROM FUNC
4 WHERE CD_MAT = 100
5 /
Explicado.
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 1
TABLE ACCESS BY INDEX ROWID FUNC
INDEX UNIQUE SCAN SYS_C002934
O acesso começa com uma pesquisa no índice SYS_C002934. Este é o índice que garante a PK da tabela Func (no
meu caso). O acesso é UNIQUE porque em primeiro lugar este índice não contém duplicidades; desta forma quando
usamos a expressão CD_MAT = 100, se não existem duas linhas com o mesmo número de matrícula, então sabemos
que somente uma matrícula será encontrada. Poderíamos ter feito a pesquisa por um intervalo (CD_MAT BE-
TWEEN 100 AND 300). Esta seria uma forma de obtermos diversas linhas e, portanto, realizar um RANGE SCAN
em um índice de PK (sem duplicidades).
Listagem-resposta 5.11C
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT E2.*, DP.*
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 2
NESTED LOOPS
TABLE ACCESS BY INDEX ROWID FUNC
INDEX UNIQUE SCAN SYS_C002934
TABLE ACCESS BY INDEX ROWID DEPTO
INDEX UNIQUE SCAN SYS_C002931
6 linhas selecionadas.
Este Select realiza um Join entre Func e Depto. O primeiro passo a ser executado é o UNIQUE SCAN no índice
SYS_C002934 porque incluímos a cláusula AND E2.CD_MAT = 100. Uma vez que CD_MAT é primary key da tabela
Func. Uma pesquisa no índice SYS_C002934, que é o índice da PK, somente retornará uma linha pois estamos
solicitando apenas um valor. Ao término desta pesquisa será feito o acesso à tabela Func através do ROWID obtido na
leitura do índice. Sendo assim obtivemos a linha desejada relativa à tabela Func. Esta linha é entregue ao processo de
Nested Loops. Este processo, de posse desta linha, fará acesso à Depto para obter todas as linhas correspondentes ao
departamento encontrado em Func. Uma vez que cd_depto é PK, o acesso ao índice SYS_C002931 também será
UNIQUE. Com o ROWID obtido no acesso ao índice, é feito o acesso à tabela DEPTO usando este ROWID.
Com as duas linhas obtidas, o processo Nested Loops, que é o coordenador do Join, junta a linha encontrada em
Func com a linha encontrada em Depto para o processo “pai” Select e o resultado é apresentado ao usuário.
d) SELECT NM_FUNC
FROM FUNC
WHERE NR_GIT = 20
Listagem-resposta 5.11D
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT NM_FUNC
3 FROM FUNC
4 WHERE NR_GIT = 20
5 /
Explicado.
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 1
TABLE ACCESS FULL FUNC
Neste exemplo a restrição presente na cláusula WHERE fazia referência a uma coluna para a qual não existe nenhum
índice criado. Desta forma o Oracle não tem nenhuma outra alternativa a não ser ler toda a tabela para obter as
linhas desejadas.
Listagem-resposta 5.11E
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT E2.*, DP.*
3 FROM FUNC E2, DEPTO DP
4 WHERE E2.CD_DEPTO = DP.CD_DEPTO
5 /
Explicado.
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 3
HASH JOIN
TABLE ACCESS FULL DEPTO
TABLE ACCESS FULL FUNC
Neste exemplo a operação de Join não estabeleceu nenhuma restrição prévia, isto é, todas as linhas de Func serão unidas
a todas as linhas de Depto de acordo com a chave de relacionamento (CD_DEPTO). O Oracle optou, então, por realizar
um Hash Join. Neste método de Join os dados das duas tabelas envolvidas são lidos e separados em partições, a princípio
em memória (se houver). As partições correspondentes são pesquisadas e unidas para obtenção do resultado solicitado.
5.12) Determine o caminho de acesso, a operação realizada e a ordem em que as operações foram realizadas. Neste
exercício a principal preocupação é determinar a operação realizada, a ordem em que estão sendo efetuadas, qual o
método de Join (quando for o caso) empregado para a solução do problema e o caminho de acesso para cada tabela.
a) SELECT *
FROM func
WHERE CD_MAT BETWEEN 100 AND 500
AND nm_func = 'DANIEL'
ORDER BY CD_MAT
Listagem-resposta 5.12A
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT *
3 FROM func
4 WHERE CD_MAT BETWEEN 100 AND 500
5 AND nm_func = 'DANIEL'
6 ORDER BY CD_MAT
7 /
Explicado.
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 2
TABLE ACCESS BY INDEX ROWID FUNC
INDEX RANGE SCAN SYS_C002934
Neste exercício o otimizador escolheu fazer a pesquisa (RANGE SCAN) sobre o índice SYS_C002934 e, para cada
um dos endereços (ROWID) obtidos, fazer acesso à tabela FUNC. Um dos motivos da escolha foi o fato de havermos
solicitado que o resultado viesse ordenado por matrícula. Caso o otimizador houvesse optado por um FULL TABLE
SCAN, após a seleção das linhas que atendessem à condição ainda haveria necessidade de uma operação de SORT
para a produção do resultado desejado. Experimente retirar a cláusula ORDER BY e verifique o resultado obtido.
b) SELECT NM_DEPTO
FROM DEPTO
UNION
SELECT NM_FUNC
FROM FUNC
WHERE CD_MAT BETWEEN 100 AND 300
Listagem-resposta 5.12B
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT NM_DEPTO
3 FROM DEPTO
4 UNION
5 SELECT NM_FUNC
6 FROM FUNC
7 WHERE CD_MAT BETWEEN 100 AND 300
8 /
Explicado.
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 10
SORT UNIQUE
UNION-ALL
TABLE ACCESS FULL DEPTO
TABLE ACCESS FULL FUNC
Neste exemplo tivemos a oportunidade de comprovar o que estudamos teoricamente, isto é, uma operação de
Union realiza um Sort implícito para retirar as duplicidades. Observe que, apesar de havermos restringido as linhas
vindas da tabela Func, em função do número reduzido de linhas, o otimizador optou por um acesso FULL tanto a
Func quanto a Depto. O processo de UNION-ALL recebeu os dados vindos das duas tabelas, juntou-os e os entregou
ao processo SORT UNIQUE, que além da ordenação teve a incumbência de somente entregar ao processo “pai “
SELECT um resultado sem duplicidades. As duplicatas são retiradas do resultado.
c) SELECT *
FROM FUNC
WHERE CD_MAT = :MAT
AND NM_FUNC = 'MARIA'
Listagem-resposta 5.12C
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT *
3 FROM FUNC
4 WHERE CD_MAT = :MAT
5 AND NM_FUNC = 'MARIA'
6 /
Explicado.
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 1
TABLE ACCESS BY INDEX ROWID FUNC
INDEX UNIQUE SCAN SYS_C002934
Neste exemplo pudemos observar que a determinação do caminho de acesso é feita mesmo quando usamos variáveis
do programa no comando SELECT. Não é preciso que o valor esteja explicitamente definido para que o otimizador
avalie o melhor caminho. No caso do exemplo, uma vez que CD_MAT é PK, independentemente do valor a ser
pesquisado, o acesso através do índice SYS_C002934 trará apenas o endereço de uma linha.
d) SELECT NM_FUNC
FROM FUNC
WHERE rownum < 200
ORDER BYcd_mat
Listagem-resposta 5.12D
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT NM_FUNC
3 FROM FUNC
4 WHERE rownum < 200
5 order by cd_mat
6 /
Explicado.
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 3
COUNT STOPKEY
TABLE ACCESS BY INDEX ROWID FUNC
INDEX FULL SCAN SYS_C002934
Neste exemplo, a pesquisa foi feita através do índice SYS_C002934, não porque houvéssemos informado uma
condição de pesquisa e sim porque solicitamos que os dados viessem ordenados por CD_MAT. O processo de
COUNT STOPKEY interrompe a leitura quando atingirmos 199 linhas.
e) SELECT CD_DEPTO, SUM(VL_SAL)
FROM FUNC
GROUP BY CD_DEPTO
/
Listagem-resposta 5.12E
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT CD_DEPTO, SUM(VL_SAL)
3 FROM FUNC
4 GROUP BY CD_DEPTO
5 /
Explicado.
Plano de Acesso
---------------------------------
SELECT STATEMENT CUSTO = 5
SORT GROUP BY
TABLE ACCESS FULL FUNC
Com este resultado também comprovamos algo que estudamos em teoria anteriormente. Uma operação de
grupamento também realiza um SORT. Todos os dados da tabela FUNC foram lidos uma vez que não há qualquer
restrição de linha. A ordenação se faz necessária para aplicação da função de grupo e também porque a coluna
escolhida para grupamento não possui nenhum índice associado a ela.
5.13) Determinar o caminho de acesso para os seguintes comandos:
Listagem-resposta 5.13A
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT /*+ INDEX (func ix_depto) */ cd_mat, nm_func
3 FROM func
4 WHERE cd_depto = 'C01'
5 /
Explicado.
Plano de Acesso
---------------------------------
OPER = SELECT STATEMENT CUSTO = 2
OPER = TABLE ACCESS OPT= BY INDEX ROWID FUNC
OPER = INDEX OPT= RANGE SCAN IX_DEPTO
Para que pudéssemos realizar o teste acima criamos um índice sobre a coluna CD_DEPTO. Na definição do comando
SELECT incluímos um HINT indicando ao otimizador que desejávamos que a busca fosse feita utilizando este
índice. Observe que o custo para acesso utilizando este índice é maior que o custo de uma leitura completa a todos
os dados; no entanto, o otimizador obedece à solicitação feita e realiza a busca conforme indicado. Primeiramente
faz um RANGE SCAN (várias linhas podem ser trazidas de um índice que admite duplicidade na chave, que é o
caso) e para cada ROWID obtido faz acesso à tabela FUNC.
Listagem-resposta 5.13B
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT cd_mat, nm_func
3 FROM func
4 WHERE cd_depto = 'C01' OR cd_mat > 200
5 /
Explicado.
Plano de Acesso
---------------------------------
OPER = SELECT STATEMENT CUSTO = 1
OPER = TABLE ACCESS OPT= FULL FUNC
O que dissemos no exemplo anterior se comprova agora. O custo da pesquisa à tabela toda (FULL SCAN) é menor
que a pesquisa através de índices, no nosso caso, pois a tabela FUNC possui apenas 35 linhas.
c) SELECT /*+ USE_CONCAT */ cd_mat, nm_func
FROM func
WHERE cd_depto = 'C01' OR cd_mat > 200;
Listagem-resposta 5.13C
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT /*+ USE_CONCAT */ cd_mat, nm_func
3 FROM func
Plano de Acesso
---------------------------------
OPER = SELECT STATEMENT CUSTO = 2
OPER = CONCATENATION
OPER = TABLE ACCESS OPT= FULL FUNC
OPER = TABLE ACCESS OPT= FULL FUNC
A operação de CONCATENATION recebe os dados de cada uma das restrições unidas por um OR e junta para produzir
o resultado final. Observe que esta não foi a escolha do otimizador, forçamos a situação usando um HINT. A tabela
FUNC foi lida duas vezes, e na primeira vez somente as linhas com CD_DEPTO=’C01’ foram trazidas. Na segunda
leitura apenas as linhas com CD_MAT maior que 200 e CD_DEPTO <> ‘C01’ foram trazidas. Uma vez que os conjuntos
são disjuntos não há necessidade de uma operação de SORT, somente precisamos concatenar os resultados.
5.14) Verificando a operação de JOIN escolhida nos exemplos abaixo:
Listagem-resposta 5.14A
SQL> set echo on
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT /*+ USE_NL(func depto) */ cd_mat, nm_func, nm_depto, nm_proj
3 FROM proj, depto, func
4 WHERE func.cd_depto = depto.cd_depto
5 AND depto.cd_depto = proj.cd_depto
6 /
Explicado.
Plano de Acesso
---------------------------------
OPER = SELECT STATEMENT CUSTO = 14
OPER = HASH JOIN
OPER = NESTED LOOPS
OPER = TABLE ACCESS OPT= FULL DEPTO
OPER = TABLE ACCESS OPT= FULL FUNC
OPER = TABLE ACCESS OPT= FULL PROJ
6 linhas selecionadas.
Neste exemplo estamos operando um Join entre três tabelas. No HINT incluído solicitamos que fosse utilizado o
método de NESTED LOOPS para a operação de Join entre FUNC e DEPTO. Desta forma, todos os dados de FUNC
foram concatenados (“joined”) aos dados correspondentes em DEPTO utilizando o método NESTED LOOPS (ob-
serve que este é o primeiro passo, mais identado). O resultado do NESTED LOOPS, assim como o resultado do
acesso FULL PROJ, são entregues para o processo HASH JOIN que juntará estes dois conjuntos de linha usando este
método. O resultado é passado para o processo “pai” SELECT que fez a solicitação de dados.
Listagem-resposta 5.14B
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT /*+ USE_HASH(func depto) */ cd_mat, nm_func, nm_depto, nm_proj
3 FROM proj, depto, func
4 WHERE func.cd_depto = depto.cd_depto
5 AND func.cd_depto = proj.cd_depto
6 /
Explicado.
Plano de Acesso
---------------------------------
Neste caso solicitamos que a junção entre DEPTO e FUNC fosse feita usando-se o método HASH JOIN. O resultado
desta junção com o total de linhas da tabela PROJ será, novamente, “joined” através do método HASH JOIN, desta
vez por escolha do otimizador.
Com este último exemplo encerramos o nosso estudo superficial sobre otimização de performance do SQL. Olhando
para os Explain Plan apresentados podemos concluir que a ordem de execução das operações ocorre, sempre, de
dentro para fora, isto é, a operação mais identada é a que ocorre primeiro. Outra observação é que as operações de
Join são realizadas aos pares. Mesmo que venhamos a realizar um Join de mais de duas tabelas, elas são “joined”
duas a duas. Ainda verificamos que o otimizador é “obediente”, isto é, mesmo que ele não concorde com o caminho
solicitado (o custo do caminho solicitado seja maior que aquele encontrado por outro caminho), ele obedece à
determinação do usuário. Isto somente não ocorrerá se a solicitação não puder ser atendida.
Mesmo contando somente com estes poucos exemplos você pode fazer modificações na sua base de dados para
realizar mais testes. Por exemplo:
♦ Inclua mais linhas nas tabelas Func e Depto. Em seguida volte a executar o comando ANALYZE sobre todas as tabelas.
♦ Remova todas as estatísticas das tabelas em teste (ANALYZE TABLE XXX DELETE STATISTICS) e repita todos os testes.
♦ Altere os scripts modificando as condições de busca.
Este assunto é bastante extenso e possui diversos detalhes para análise. Para esgotá-lo precisamos de um livro
exclusivo. O objetivo do tópico aqui foi apresentá-lo a um assunto delicado e que requer toda a nossa atenção, que
é a performance relativa ao acesso aos dados. Trabalhe junto com seu DBA neste assunto, principalmente para
situações que envolvam milhares de linhas.
5.15) Criar uma view materializada simples e verificar seu uso em comandos de SQL.
a) Criar uma view materializada que apresente o valor total vendido por cada vendedor da empresa, independente
do período da venda. O preenchimento da VIEW deve ser manual.
Listagem-resposta 5.15A
ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE;
ALTER SESSION SET QUERY_REWRITE_INTEGRITY = TRUSTED;
COMMIT;
EXECUTE DBMS_MVIEW.REFRESH('MV_POR_VENDEDOR', 'C', NULL, TRUE, FALSE, 1, 0, 0, TRUE)
Procedimento PL/SQL concluído com sucesso.
Listagem-resposta 5.15B
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT F.NM_FUNC, SUM(V.VL_VENDA)
3 FROM FUNC F, VENDAS V
4 WHERE F.CD_MAT = V.CD_VENDEDOR
5 GROUP BY NM_FUNC
6 /
Explicado.
Plano de Acesso
---------------------------------
OPER = SELECT STATEMENT CUSTO = 1
OPER = TABLE ACCESS OPT= FULL MV_POR_VENDEDOR
Observe pelo resultado que o otimizador percebeu que o acesso à view materializada MV_POR_VENDEDOR resultaria
em um custo menor que todas as operações necessárias para o join e posterior group by de Func e Vendas. Para que
este processo dê resultado é indispensável que as estatísticas sejam calculadas tanto para a tabela Func quanto para
a tabela Vendas. Caso isto não seja feito, será acionado o otimizador por regra, que não implementa o mecanismo
de query rewrite.
c) Avalie a utilização desta view quando o comando de SQL é diferente do comando da view.
Listagem-resposta 5.14C
SQL> set echo on
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT SUM(V.VL_VENDA)
3 FROM FUNC F, VENDAS V
4 WHERE F.CD_MAT = V.CD_VENDEDOR
5 GROUP BY NM_FUNC
6 /
Explicado.
Plano de Acesso
---------------------------------
OPER = SELECT STATEMENT CUSTO = 1
OPER = TABLE ACCESS OPT= FULL MV_POR_VENDEDOR
Observe que as modificações não desviaram o otimizador do uso da view MV_POR_VENDEDOR. Ele faz uma análise
para saber se o resultado, apesar de diferente da view materializada, pode ser obtido a partir de informações da view.
5.16) Criar uma view materializada simples e verificar seu uso em comandos de SQL.
a) Criar uma view materializada com construção imediata e que contenha mais de uma agregação. Verifique seu
preenchimento.
Listagem-resposta 5.16A
SQL> CREATE MATERIALIZED VIEW MV_QTD_VENDAS_DIA
2 PCTFREE 0 TABLESPACE USERS
3 STORAGE (INITIAL 16K NEXT 16K PCTINCREASE 0)
4 BUILD IMMEDIATE
5 REFRESH COMPLETE
6 ENABLE QUERY REWRITE
7 AS SELECT F.NM_FUNC, AVG(V.QT_VENDA) AS MED_VENDA,
8 COUNT(DISTINCT V.CD_PRODUTO) AS QT_PRODUTO
9 FROM FUNC F, VENDAS V
10 WHERE F.CD_MAT = V.CD_VENDEDOR
11 GROUP BY F.NM_FUNC, TRUNC(V.DT_VENDA);
View materializada criada.
Listagem-resposta 5.16B
SQL> set echo on
SQL> EXPLAIN PLAN SET STATEMENT_ID = 'TESTE' FOR
2 SELECT F.NM_FUNC, AVG(V.QT_VENDA) AS MED_VENDA,
3 COUNT(DISTINCT V.CD_PRODUTO) AS QT_PRODUTO
4 FROM FUNC F, VENDAS V
5 WHERE F.CD_MAT = V.CD_VENDEDOR
6 GROUP BY F.NM_FUNC, TRUNC(V.DT_VENDA)
7 /
Explicado.
Plano de Acesso
---------------------------------
OPER = SELECT STATEMENT CUSTO = 4
OPER = TABLE ACCESS OPT= FULL MV_QTD_VENDAS_DIA
Neste exemplo repetimos o comando SELECT da view e o otimizador, automaticamente, alterou o destino do
acesso para a view.
5.17) Crie uma tabela com particionamento por intervalo de valores e preencha esta tabela com os dados originais
da tabela FUNC:
Listagem-resposta 5.17A
SQL> CREATE TABLE PART_FUNC
2 (CD_MAT NUMBER(5) NOT NULL
3 ,VL_SAL NUMBER(9,2)
4 ,CD_DEPTO CHAR(3)
5 ,NR_CARGO NUMBER(3))
6 storage (initial 200k next 100k minextents 1 maxextents 15)
7 pctfree 10
8 pctused 80
9 PARTITION BY RANGE (CD_DEPTO)
10 (PARTITION PRT_A VALUES LESS THAN ('B'),
11 PARTITION PRT_B VALUES LESS THAN ('C'),
12 PARTITION PRT_C VALUES LESS THAN ('D'),
13 PARTITION PRT_D VALUES LESS THAN ('E'),
14 PARTITION PRT_E VALUES LESS THAN ('F'),
15 PARTITION PRT_F VALUES LESS THAN ('G'),
16 PARTITION PRT_Z VALUES LESS THAN (MAXVALUE));
Tabela criada.
Listagem-resposta 5.17B
SQL> INSERT INTO PART_FUNC (CD_MAT, VL_SAL, CD_DEPTO, NR_CARGO)
2 SELECT CD_MAT, VL_SAL, CD_DEPTO, NR_CARGO
3 FROM FUNC;
37 linhas criadas.
SQL> COMMIT;
Validação completa.
5.18) Crie um índice local prefixado, um índice local não prefixado, um índice global particionado prefixado, um
índice global particionado não prefixado e um índice global não particionado:
Listagem-resposta 5.18A
SQL> CREATE INDEX IXLP_PFUNC ON PART_FUNC(CD_DEPTO, CD_MAT) LOCAL;
Índice criado.
Neste exercício observamos que um índice global deve ser prefixado, isto é, a coluna mais à esquerda da chave do
índice deve ser igual à chave de particionamento.
5.19) Divida a partição Z em duas partições. Verifique o estado dos índices associados:
Listagem-resposta 5.19A
SQL> ALTER TABLE PART_FUNC
2 SPLIT PARTITION PRT_Z AT ('M');
Tabela alterada.
Pelo resultado podemos verificar que a operação de Split determinou a criação de duas partições SYS_P1 e SYS_P2.
Com isto o índice global particionado ficou em estado inválido, assim como o índice da segunda partição SYS_P2.
5.20) Remova a última partição da tabela. Verifique o estado dos índices associados:
Listagem-resposta 5.20A
SQL> ALTER TABLE PART_FUNC
2 DROP PARTITION SYS_P2;
Tabela alterada.
5.21) Adicione uma nova partição à tabela. Verifique o estado dos índices associados:
Listagem-resposta 5.21A
SQL> SET ECHO ON
SQL> ALTER TABLE PART_FUNC
2 ADD PARTITION PRT_PENULTIMA VALUES LESS THAN ('S');
Tabela alterada.
Listagem-resposta 5.22A
SQL> SET ECHO ON
SQL> ALTER TABLE PART_FUNC
2 MERGE PARTITIONS PRT_B, PRT_C INTO PARTITION PRT_BC;
Tabela alterada.
Com estes exercícios relativos à partição verificamos que o Oracle oferece diversas flexibilidades para a manutenção
das partições, o que facilita as manutenções a serem realizadas pelo DBA.
Capítulo 6
INSTALANDO O ORACLE
DEVELOPER 6I NO WINDOWS
CONSIDERAÇÕES INICIAIS
O pacote Oracle Developer é composto de diversas ferramentas para desenvolvimento de aplicações. Este pacote
foi desenvolvido para estabelecer acesso a uma base de dados Oracle (preferencialmente). Os procedimentos de
instalação que veremos neste capítulo são semelhantes para os Windows 95, 98, NT e 2000.
Nesta instalação poderemos incluir, para efeito de teste, a instalação do Forms Server e do Reports Server localmente,
a fim de estudarmos os requisitos e particularidades do uso destes produtos (Forms e Reports) em um ambiente
Web (Capítulo 9).
Começaremos, normalmente, fazendo a instalação do produto passo a passo e, se necessário, realizaremos os
ajustes à utilização do ambiente disponível.
IDIOMA
A primeira questão apresentada é relativa ao idioma em que os produtos serão instalados. O idioma escolhido tem
influência nas mensagens de erro enviadas pelo banco de dados, formato-padrão de datas, formato-padrão de
numeração decimal, assim como nas telas dos produtos instalados.
Uma vez que a linguagem-padrão é English, este idioma será instalado independente de nossa escolha, ou seja, se
escolhermos Brazilian Portuguese, será instalado o idioma português do Brasil e o Inglês.
Para que tenhamos uma maior flexibilidade de uso, manteremos o que fizemos na instalação do banco de dados,
usaremos o idioma Brazilian Portuguese.
Neste mesmo diálogo, deve ser informado o nome da empresa que, normalmente, já aparece preenchido (com
informação obtida do próprio Windows), e o diretório-raiz (Oracle Home), sob o qual todos os demais subdiretórios
de todos os aplicativos (Oracle) que vierem a ser instalados serão criados. De um modo geral, o valor default
C:\ORA<sistema operacional>, que já está preenchido pode ser usado.
Nesta versão, porém, existe a possibilidade de utilizarmos Oracle Home diferentes, particulares por produto. Isto
permite tanto a atualização quanto a remoção independente dos produtos. Desta forma testaremos a instalação do
Forms e do Reports em diretórios diferenciados.
Observe que na Figura 6.01 identificamos o Oracle Home como FormsHome e o diretório real em disco como
C:\ORAFORMS (não pode ultrapassar 8 caracteres).
TOOLS OPTIONS
Nova tela de diálogo será apresentada para que façamos a escolha do que desejamos instalar.
INSTALLATION OPTIONS
Antes de passarmos a um novo diálogo escolheremos a instalação do Oracle Forms Developer, como mostrado na
Figura 6.02. Na nova tela de diálogo apresentada devemos escolher uma instalação típica ou customizada.
Na instalação típica todos os produtos necessários à ferramenta que escolhemos anteriormente é instalado. Na
instalação customizada podemos decidir pela instalação de apenas uma ferramenta específica, por exemplo só
instalar o Forms (sem o Query Builder, Graphics, etc.).
PROCESS STARTUP
Quando prosseguimos a instalação, o diálogo da Figura 6.05 é apresentado questionando se desejamos que os
serviços sejam iniciados pelo instalador. Os produtos Forms Server e Reports Server são instalados como serviços
no ambiente Windows, precisando de criação e instalação.
Por este motivo, aceitaremos esta sugestão. O diálogo da Figura 6.06 é apenas informativo e não temos nenhuma
outra alternativa além de OK.
Eventualmente, pode ser apresentada uma questão caso o Oracle perceba que não existe espaço suficiente no
disco. Podemos acionar o Windows Explorer, verificar se realmente não há espaço suficiente, efetuar as remoções
necessárias e prosseguir com o processo de instalação.
O diálogo da Figura 6.07 nos indica que alguns arquivos serão instalados no diretório de sistema do windows (por
exemplo C:\WINNT\SYSTEM32). Se estes arquivos já existirem com versões antigas, eles serão sobrepostos. Os
arquivos são: MFCANS32.DLL, MSVCRT2X.DLL, OC30.DLL, CTL3D32.DLL, ODBC32.DLL e ODBCINT.DLL.
O diálogo seguinte (Forms Server Parameter), Figura 6.08, apresenta o número da porta para onde serão enviadas
as requisições ao Forms Server e de onde o Listener (do Forms Server) estará esperando coletar informações para
transmitir ao servidor. O número da porta não pode ser coincidente com o número da porta de outro produto
instalado; desta forma, se não houver outro produto instalado nesta mesma porta, podemos deixar o valor default,
que vier preenchido, como o mais adequado.
Neste diálogo devemos, ainda, escolher o protocolo de comunicação entre o Forms Runtime e a Forms Java Applet
que será executada no browser da máquina cliente. A opção Sockets somente precisa ser modificada para HTTP se
a comunicação precisar passar através de um FireWall (software de segurança para ambientes Web). Não teremos
esta necessidade por enquanto, pois tanto o servidor quanto o cliente estarão na mesma máquina. Quando viermos
a utilizar um ambiente de produção, em que disponibilizaremos o uso do Forms através da Web, deveremos
modificar esta opção.
O diálogo a seguir indica o fim do processo de instalação com sucesso. O Oracle Installer nos dá a opção de lermos as
instruções de configuração agora. Em seguida o diálogo de fim de instalação é apresentado.
Figura 6.09 – Configuration instructions for Forms Server & Reports Server
Além dos produtos instalados em disco, foram criadas algumas pastas no menu do Windows:
♦ Oracle para Windows NT – FormsHome – Nesta pasta encontramos o instalador, o SQL*Plus, Net8 Assistant, etc. O
nome da pasta depende do sistema operacional em que estivermos instalando.
♦ Oracle Forms & Reports 6i – FormsHome – Contendo acesso a todos os softwares necessários ao desenvolvimento
de aplicações, exceto o Forms Developer.
♦ Oracle Forms 6i – FormsHome – Contendo acesso aos executáveis do Forms e sua documentação (configuração
e Release Notes).
♦ Oracle Forms 6i Admin – FormsHome – Contém acesso a aplicações de demonstração.
♦ Oracle Forms & Reports 6i Doc – FormsHome – Contém acesso aos manuais online (através de um Browser) e à
documentação do produto PVCS para controle de versão de aplicativo.
O número da porta não precisa ser modificado, a menos que exista um outro produto utilizando esta mesma porta
em sua máquina.
Da mesma forma que para o Forms6i, além dos produtos instalados em disco, foram criadas algumas pastas no
menu do Windows:
♦ Oracle para Windows NT – ReportsHome – Nesta pasta encontramos o instalador, o SQL*Plus, Net8 Assistant, etc. O
nome da pasta depende do sistema operacional em que estivermos instalando.
♦ Oracle Forms & Reports 6i – ReportsHome – Contendo acesso a todos os softwares necessários ao desenvolvimento
de aplicações, exceto o Reports Developer.
♦ Oracle Reports 6i – ReportsHome – Contendo acesso aos executáveis do Reports e sua documentação (configuração
e Release Notes).
♦ Oracle Reports 6i Admin – ReportsHome – Contém acesso a aplicações de demonstração.
♦ Oracle Forms & Reports 6i Doc – ReportsHome – Contém acesso aos manuais online (através de um Browser) e
à documentação do produto PVCS para controle de versão de aplicativo.
♦ Oracle Olap Client 2.2 – ReportsHome – Contém acesso ao Connection Editor a ser usado com o Oracle Express.
Ao término das duas instalações o diretório OraForms ocupa 234Mb de disco e o diretório OraRep ocupa 229Mb de disco.
Pudemos observar que parte deste espaço está duplicado, uma vez que muitos dos produtos adicionais instalados
são comuns ao Forms e ao Reports, de forma que, se você não tiver muito espaço em disco, talvez prefira realizar a
instalação em um único Oracle Home.
Nosso próximo passo é configurar o arquivo TnsNames.Ora para que possamos estabelecer a comunicação com
nosso banco de dados local (Personal) ou da rede.
CONFIGURANDO O TNSNAMES.ORA
A configuração deste arquivo é simplificada, pois contamos com a ajuda de um utilitário. No entanto, uma vez que
criamos dois diretórios diferentes (dois Oracle Homes) para a instalação das ferramentas, deveremos repetir os
passos a seguir duas vezes, uma para FormsHome e outra para ReportsHome.
Devemos, portanto, selecionar o botão Iniciar do Windows, Programas, Oracle para Windows NT – <FormsHome
ou ReportsHome>, Oracle Net8 Easy Config.
Nesta primeira tela apresentada, escolheremos criar um novo serviço cujo nome será Desenv.
Na próxima tela, indicaremos o protocolo de comunicação como TCP/IP.
Nesta tela (Figura 6.12), informaremos o endereço de IP da máquina e a porta do Listener associado ao banco. No
nosso caso, o endereço de IP é 127.0.0.1 (indica a própria máquina-origem) e a porta em que configuramos o
Listener foi 1521 (que é o default). O Listener é o “ouvidor” do banco de dados. Quando uma solicitação de
conexão aparece nesta porta o programa Listener a recebe e estabelece a sessão do usuário, ou seja, a ligação entre
o software usuário e o banco de dados.
Na próxima tela, informamos o SID do banco de dados. Quando fizemos a instalação do banco de dados escolhemos
ORACLE para nome do banco de dados global e do SID. É este nome que devemos indicar agora.
O diálogo seguinte sugere que façamos um teste do serviço configurado. Para efeito de teste podemos usar o
usuário desenv criado na instalação do banco de dados.
Observe que estão descritos todos os parâmetros que informamos passo a passo com o utilitário.
O mesmo procedimento devemos realizar para o Report. Preferencialmente utilize o mesmo nome (DESENV) para
serviço a fim de ficar transparente o uso do Forms e do Reports. A necessidade de criação de dois TNSNAMES foi
gerada pela instalação em Oracle-Homes distintos.
Com os produtos instalados e o TNSNAMES configurado, podemos iniciar nosso estudo sobre o Forms Builder e o
Report Builder.
Parte 2
DEVELOPER
Capítulo 7
O FORM BUILDER R6I
Neste capítulo, estudaremos a ferramenta de desenvolvimento Form Builder 6i que faz parte de um pacote de
ferramentas para desenvolvimento chamado Forms Developer. Iniciaremos nosso estudo conhecendo um pouco
sobre o pacote. Logo depois, serão dadas informações gerais sobre a ferramenta ora em estudo e, em seguida,
trabalharemos com a ferramenta em diversos exemplos e exercícios.
Para o desenvolvimento e entendimento adequado deste capítulo, o leitor já deve estar muito bem familiarizado
com a linguagem SQL e a linguagem PL/SQL previamente estudadas. Nos itens referentes a pré-requisitos,
indicaremos apenas os requisitos necessários ao tópico em estudo, considerando o conhecimento prévio de SQL e
PL/SQL satisfeito.
SOBRE O PACOTE
O Forms Developer corresponde a um dos ambientes de produtividade da Oracle – RAD (Rapid Application Devel-
opment) capaz de construir, rapidamente, aplicações que a partir das definições do banco de dados possam dar
manutenção a bases de dados. Estas aplicações tanto podem ser implementadas em ambiente cliente-servidor
quanto em uma arquitetura de três camadas ou na Internet.
O Form Builder 6i é a principal ferramenta deste ambiente, pois é a ferramenta para desenvolvimento de aplicações
online para acesso e atualização de uma base de dados Oracle.
Para apoiar o Form Builder 6i, as seguintes ferramentas fazem parte do pacote Forms Developer:
♦ Procedure Builder – É a ferramenta que nos auxilia no desenvolvimento de programas PL/SQL, tanto no ambiente
cliente (em bibliotecas de programas compartilhadas por aplicações Form), quanto no ambiente servidor (criação de
procedures, functions, packages e database triggers), permitindo uma depuração passo a passo das aplicações criadas.
♦ Graphics Builder – É a ferramenta que permite que visualizemos os dados do banco de dados de forma gráfica.
Os produtos gerados por essa ferramenta podem ser utilizados em aplicações Forms.
♦ Project Builder – Esta é uma ferramenta integradora e organizadora, permitindo que associemos as diversas
aplicações que componham um projeto de desenvolvimento em uma hierarquia manipulável. Projetos são
associações de arquivos com as ferramentas usadas para editá-los. Esses arquivos podem ser de qualquer tipo:
form, report, display (gráficos), módulos de 3GL, documentação e scripts de teste. O grupamento e visualização
de todos os componentes de um projeto é apenas uma das vantagens. A ferramenta permite também ações
coletivas, como por exemplo uma compilação.
♦ Query Builder – É uma ferramenta auxiliar na construção de consultas ao banco de dados. Possui uma interface
gráfica e intuitiva que nos permite rápida e facilmente a montagem de queries para a recuperação de informações.
♦ Schema Builder – Esta ferramenta nos auxilia na criação, cópia, modificação e remoção de objetos (e
relacionamentos) do banco de dados.
♦ Translation Builder – Esta é uma ferramenta para suporte e gerenciamento no processo de conversão de aplicações
Oracle para uma das linguagens suportadas. Suporta a conversão de arquivos do tipo .fmb, .ogd, .rdf, .res e .msg.
O pacote Forms Developer contém ferramentas que abrangem todas as áreas necessárias ao desenvolvimento de aplicações
(gráficos, queries, manutenção do banco de dados, tradução), e, ainda, uma ferramenta para controle do ambiente.
Neste livro, o objeto de nosso estudo será o Form Builder 6i.
SOBRE A FERRAMENTA
O desenvolvimento de uma aplicação online envolve diversas etapas, dentre elas: construção da aplicação,
compilação, execução e depuração.
A ferramenta Form Builder é composta de cinco executáveis para cumprimento dessas etapas:
♦ IFBLD60 – Form Builder – Este é o aplicativo para desenvolvimento e compilação individual de uma aplicação.
Gera arquivos de quatro categorias: FMB / FMX (fonte e executável Form), MMB / MMX (fonte e executável
Menu), PLL / PLX (PL/SQL Library) e OLB (Object Library).
♦ IFRUN60 – Forms Runtime – Este é o aplicativo para execução das aplicações desenvolvidas (Form, Menus e
Libraries PL/SQL).
♦ IFWEB60 – Web Previewer – Esta ferramenta tem a finalidade de permitir a execução local de uma aplicação
como se ela estivesse executando sob o Forms Server em um browser ou no Appletviewer. O Web Previewer
executa o arquivo produzido pelo Form Compiler (FMX).
♦ IFCMP60 – Form Compiler – Este aplicativo permite a conversão de aplicações do formato binário para texto (e
vice-versa) ou para armazenamento no banco de dados (e vice-versa). É utilizado, ainda, para compilação em
batch de diversas aplicações, inclusão da definição dos módulos no banco de dados, upgrade de versões anteriores
do Form Builder, SQL*Forms e SQL*Menu.
♦ IFDBG60 – É acionado, indiretamente, através do Forms Runtime ou do Form Builder para depuração da aplicação.
Durante este capítulo, trataremos da construção, compilação e teste de aplicações individuais. Desta forma,
trabalharemos basicamente com o Form Builder e o Forms Runtime. No Capítulo 9 estaremos estudando a execução
de nossas aplicações em um ambiente de três camadas, seja na Internet ou na Intranet, porém é indispensável que
venhamos a conhecer todas as características da ferramenta primeiro antes de virmos a utilizá-la no ambiente Web.
SOBRE O ESTUDO
Neste capítulo desenvolveremos o estudo com exemplos passo a passo. Os capítulos da parte Referências conterão
lista de propriedades, de variáveis de sistema, de rotinas predefinidas, de triggers, etc.
A cada tópico criaremos um aplicativo contendo o assunto em estudo. Nos exercícios referentes a cada tópico
trabalharemos algumas outras características que estarão contidas nos Capítulos 13 a 17 e deverão ser consultadas
para desenvolvimento dos exercícios.
Durante os textos do estudo, enfatizaremos o modo como o Form Builder trabalha e como deveremos agir para
customizar ou modificar sua ação básica e sua funcionalidade default.
INTRODUÇÃO
A ferramenta Form Builder é capaz de construir três tipos de módulos principais diferentes:
♦ Módulo Form – Consiste da aplicação online, contendo lógicas de atualização, telas, botões, itens, etc. O fonte
de um módulo Form possui a extensão FMB e o executável, FMX.
♦ Módulo Menu – Consiste de um conjunto de submenus e lógicas para acionamento dos diversos módulos Form
ou de outros submenus, execução de aplicações PL/SQL em batch, acionamento de gráficos, etc. O fonte de um
módulo Menu possui a extensão MMB e o executável, MMX.
♦ Módulo PL/SQL Library – Consiste de um conjunto de programas PL/SQL que pode ser compartilhado por
diversas aplicações Form (ou Report) que executam no ambiente. O fonte de um módulo PL/SQL Library possui
a extensão PLL e o executável, PLX.
Um quarto tipo de arquivo pode ser gerado com esse aplicativo:
♦ Object Library – Consiste de um conjunto de objetos internos do Form que podem ser definidos uma única vez
e utilizados em outras aplicações. Esta biblioteca de objetos auxilia o desenvolvedor na criação de padrões.
Durante este capítulo, trataremos de cada um destes módulos individualmente a fim de analisarmos suas
características e usos.
♦ Forms – Subordinado a este nó estará(ão) o(s) módulo(s) de Form que viermos a desenvolver. Na Figura 7.02
aparece uma aplicação de nome Module1. Observe que o nó Forms está preenchido com o símbolo ( - ), indicando
que o nó está expandido. O nó do módulo Module1 está preenchido com o símbolo ( + ), indicando que o nó
está contraído, ou seja, existem elementos subordinados a este nó que não estão visíveis.
♦ Menus – Subordinado a este nó estará(ão) o(s) módulo(s) de Menu que viermos a desenvolver. Na Figura 7.02
não existe nenhum módulo aberto, portanto o nó está vazio. Não há nenhum símbolo preenchendo o nó.
♦ Bibliotecas PL/SQL – Subordinado a este nó estará(ão) o(s) módulo(s) Library de PL/SQL que viermos a desenvolver.
Na Figura 7.02 também não existe nenhum módulo aberto, portanto o nó está vazio.
♦ Bibliotecas de Objetos – Subordinado a este nó estará (ou estarão) a biblioteca de objetos-padrão que criarmos e
desejarmos reutilizar.
♦ Pacotes Embutidos – Subordinado a este nó existem diversos pacotes (packages) contendo diversas rotinas que
poderemos utilizar no desenvolvimento da aplicação. Observe que este nó está contraído ( + ).
♦ Objetos do Banco de Dados – Subordinados a este nó serão visualizados os diversos objetos do banco de dados
a que o usuário ao qual estamos conectados tem acesso. Atualmente o nó está vazio pois não estabelecemos,
ainda, conexão com o banco.
A seguir, veremos as diversas ações que podemos realizar no Navegador de Objetos.
EXPANDIR OU RECOLHER
Para expandir um nó ou contraí-lo basta que pressionemos o mouse sobre o símbolo ( + ), para expandi-lo, ou
sobre o símbolo ( - ), para contraí-lo.
A Figura 7.02 apresenta o navegador com o nó Module1 contraído.
As ações de expansão e contração podem ser feitas com os botões Expandir e Recolher da barra de ferramentas.
A Figura 7.03 apresenta os botões que realizam as ações de expansão e contração na barra de ferramentas.
Como teste, utilize o botão Expandir Tudo sobre o nó Pacotes Embutidos. Você verificará que a expansão se dará
em todos os nós subordinados ao nó principal. Todos serão expandidos simultaneamente. A ação inversa é obtida
com o botão Recolher Tudo.
CRIAR OU DELETAR
A criação de qualquer elemento no Form Builder pode ser feita utilizando-se o botão Criar, apresentado na Figura 7.04.
Para realizarmos esta ação, basta que selecionemos o nó ou um objeto do mesmo tipo daquele que desejamos criar
e pressionemos o botão Criar.
Como teste, selecione o nó Module1 (corresponde a um elemento do tipo Form) e pressione o botão Criar. Você
observará que será criado um novo módulo de nome Module2. Expanda o nó Module1.
Selecione o nó Alertas (subordinado a Module1) e pressione o botão Criar, selecione o nó Editores e pressione o
botão Criar. Você observará a criação de objetos subordinados ao nó especificado.
Outra forma de realizar a mesma operação é realizarmos um clique duplo sobre o nó no qual desejamos criar um
elemento. Teste sobre o nó Parâmetros.
Com esses testes, verificamos que podemos manipular com mais de um módulo ao mesmo tempo usando a
ferramenta, pois criamos Module1 e Module2. Isto se aplica a todos os nós principais (Forms, Menus e Libraries).
Enquanto ainda não tivermos prática no desenvolvimento de aplicações com essa ferramenta, trabalharemos com
um módulo por vez.
Para removermos um elemento, devemos selecioná-lo e pressionar a ferramenta Deletar ou o botão Del do teclado.
Teste com o nó Module2.
Ao removermos o módulo Module2, o Form Builder perguntará se desejamos salvar as modificações efetuadas.
Com essas ferramentas, podemos mover um elemento de um ponto para outro ou copiar um elemento de um
ponto para outro.
A movimentação ocorre quando selecionamos um elemento, pressionamos o botão Recortar, movimentamos o
cursor para o destino desejado e pressionamos o botão Colar.
A cópia ocorre quando selecionamos um elemento, pressionamos o botão Copiar, movimentamos o cursor para o
destino desejado e pressionamos o botão Colar.
Existem algumas restrições relativas às operações de movimentação e cópia:
♦ Os elementos devem ser colados em localização apropriada na hierarquia do módulo. Por exemplo, um alerta
pode ser copiado de um módulo para outro, mas sempre subordinado ao nó Alerta.
♦ Somente elementos de mesmo tipo podem ser copiados em conjunto.
Como teste, efetue as seguintes ações:
EXECUTAR E DEPURAR
A execução do módulo Form ativo, ou seja, aquele em que temos algum elemento selecionado, ocorre quando
pressionamos os botões Executar Form Cliente/Servidor, Executar Form Web ou Executar Depuração de Form.
Na Figura 7.06, apresentamos os três botões ligados à execução da aplicação.
Quando pressionamos o botão Executar Form Cliente/Servidor, acionamos o Forms Runtime para execução da
aplicação corrente. Se pressionarmos o botão Executar Form Web estaremos acionando o Web Previewer para
simularmos a execução de uma aplicação em ambiente Web. Se pressionarmos o botão Executar Depuração de
Form, a execução será realizada com o auxílio do depurador que permitirá que acompanhemos passo a passo cada
ação a ser efetuada.
Uma vez que esta é a primeira vez que salvamos este módulo, o Form Builder apresenta um diálogo para que
determinemos o diretório onde efetuaremos a salva e o nome desejado para o módulo.
A Figura 7.08 mostra o diálogo apresentado. A partir do momento que definirmos o diretório e o nome do módulo,
o Form Builder não mais apresentará esse diálogo nas próximas vezes em que pressionarmos o botão Salvar.
Como teste, salve o módulo ativo com o nome de Teste. Observe após a salva que no navegador o nome do
módulo foi alterado para Teste e que na parte inferior da janela do Form Builder aparece não só o nome do módulo
ativo como também seu nome físico, isto é, seu nome completo.
LOCALIZAR
Podemos usar o pesquisador do Navegador para encontrar elementos e nós dentro do Navegador. Para iniciarmos
uma busca devemos digitar a string que desejamos procurar no campo Localizar, que fica posicionado no canto
superior direito da janela do Navegador. A cada caracter que digitamos, o Form Builder movimenta o cursor para
o próximo elemento com o qual as letras digitadas sejam compatíveis.
Por exemplo, selecionemos o módulo Teste. Ao posicionarmos o cursor sobre o campo Localizar e digitarmos a
letra “A”, o Form Builder posicionará o cursor sobre o nó Alertas.
Quando necessário, podemos utilizar as duas lanternas posicionadas ao lado do campo Localizar para efetuar uma
busca para frente ou para trás.
NAVEGANDO NA HIERARQUIA
Do lado esquerdo (na barra superior) da janela do Navegador existe um campo que apresenta o nome do elemento
atualmente selecionado. Ao abrirmos a lista desse campo, verificaremos que ele contém todos os ancestrais
hierarquicamente superiores em relação ao objeto selecionado. Ele apresenta a árvore de subordinação do elemento
selecionado. Podemos escolher qualquer elemento dessa hierarquia, bastando que façamos a seleção do elemento
desejado, clicando o mouse sobre o nome do elemento na lista.
PAINÉIS DO NAVEGADOR
Podemos dividir o navegador em múltiplos painéis horizontal ou verticalmente. Para tal, devemos pressionar e
arrastar o mouse sobre o ponto de divisão horizontal ou vertical.
Só é possível dividi-lo num sentido (vertical ou horizontal) de cada vez. Podemos realizar múltiplas subdivisões,
desde que num mesmo sentido. Veja a Figura 7.09.
Observe na Figura 7.10 que apenas duas letras da palavra Alert2 estão selecionadas e parte da palavra foi removida.
Para efetivarmos a modificação, basta pressionarmos o mouse sobre qualquer outro nó para que seja encerrado o
estado de digitação.
Uma vez que já não estamos mais com este diálogo ativo, usaremos a opção Assistente de Bloco de Dados do menu
Ferramentas para acionar o assistente desejado.
Antes de acioná-lo, porém, analisemos sobre o que é um bloco de dados.
BLOCO DE DADOS
O bloco é a estrutura básica e fundamental do Form Builder. É o centro de toda a ação. É em torno dele que todas
as ações se processam.
Podemos dizer que um bloco é um repositório (ou container) de itens.
Um bloco não tem representação visual. Um usuário visualiza itens, pois são eles que são apresentados em uma
tela; porém, hierarquicamente, os itens estão subordinados a blocos, pertencem a blocos e estão sujeitos às ações
que efetuarmos para o bloco que o contém.
Um bloco pode estar ligado a uma tabela no banco de dados. Quando isto ocorre, existe uma paridade entre bloco
e tabela, registro e linha da tabela e entre item e coluna da tabela.
Toda a funcionalidade do Form gira em torno do bloco. Conheceremos essa funcionalidade aos poucos.
A Figura 7.11 mostra o diálogo com a lista de opções. Escolheremos, neste primeiro exemplo, a criação de um
bloco baseado em uma tabela.
O próximo diálogo, apresentado na Figura 7.12, permite que façamos a escolha da tabela ou view na qual desejamos
basear o bloco.
Para que nos seja apresentada a lista de tabelas ou views disponíveis, devemos pressionar o botão Pesquisar. Caso
não tenhamos feito logon no banco de dados até este momento, será necessário que o façamos agora.
O diálogo da Figura 7.13 será apresentado para que informemos o nome do usuário, senha e a string de conexão
com o banco de dados. Se o banco de dados não estiver ativo, ao pressionarmos o botão Conectar ele será ativado.
O diálogo da Figura 7.14 permite que façamos uma restrição sobre a lista de objetos a ser apresentada:
♦ Usuário Atual – Apresenta objetos do banco de dados pertencentes unicamente ao usuário que estabeleceu a conexão.
♦ Outros Usuários – Apresenta objetos do banco de dados pertencentes a outros usuários. Naturalmente, o usuário
que estabeleceu a conexão deverá ter privilégios de acesso sobre os objetos a serem selecionados.
Se simultaneamente marcarmos as duas opções, na janela inferior serão apresentados objetos pertencentes ao
usuário atual e aos demais usuários do banco de dados.
♦ Tabelas – Os objetos apresentados são tabelas.
♦ Views – Os objetos apresentados são views.
♦ Sinônimos – Os objetos apresentados são sinônimos de outras tabelas ou de views.
Se simultaneamente marcarmos mais de uma opção, veremos objetos dos tipos marcados.
No nosso caso, pretendemos criar a aplicação baseada na tabela Func do usuário Desenv.
O próximo diálogo (Figura 7.15) apresenta a lista de tabelas presentes no banco de dados e pertencentes a diversos
usuários. Observe que o nome do Proprietário não aparece preenchido quando escolhemos apenas Usuário Atual.
Esta situação fica diferente quando solicitamos visualização de objetos de outros usuários.
Observe que, ao pressionarmos o botão OK com o nome da tabela selecionado, retornamos ao diálogo da Figura
7.12, porém com os campos Tabela ou View e Colunas Disponíveis preenchidos.
Nosso próximo passo será definir quais as colunas a que daremos manutenção nesta aplicação.
A Figura 7.16 apresenta a lista de colunas desejada. As colunas devem ser transferidas para o campo Itens do Banco de
Dados. Essa transferência é feita quando selecionamos a coluna no campo à esquerda e pressionamos o botão ( > ).
Se desejássemos selecionar todas as colunas, poderíamos pressionar o botão ( >> ) sem haver necessidade de selecionar
nenhuma coluna.
O botão Renovar, presente acima do campo Colunas Disponíveis, reordena a lista de acordo com a ordem das
colunas no banco de dados.
Faça o seguinte teste: Passe para o lado direito as colunas na seguinte ordem: nm_func, vl_sal, dt_nasc, in_sexo.
Agora pressione o botão Renovar. Observe que as colunas foram reordenadas para nm_func, in_sexo, dt_nasc, vl_sal.
A ordem em que as colunas são definidas no campo Itens do Banco de Dados será a ordem default para a construção
da tela, que passaremos a chamar de canvas.
O último campo presente na tela tem a seguinte informação: Impor integridade de dados. Isto significa que as
regras de integridade presentes no banco de dados também serão asseguradas em nível de ambiente cliente.
Neste momento não utilizaremos essa opção.
A seguir, é apresentado o último diálogo deste assistente. Nesse diálogo, podemos acionar o assistente de layout
para construção da canvas (tela) ou podemos encerrar e posteriormente acioná-lo.
No nosso caso, faremos primeiro uma verificação nos objetos gerados nesta primeira fase (usando o navegador);
portanto escolhemos a opção de encerramento (Apenas cria o bloco de dados).
A Figura 7.17 apresenta o resultado da geração do bloco. Observe que existem três nós subordinados a um bloco de
dados: Gatilhos (Triggers), Itens e Relações (Relations).
Verifique, no navegador, se existe o nó Itens presente na hierarquia principal. Não encontramos. Isto significa que
todo e qualquer item deve, obrigatoriamente, estar subordinado a um bloco. Seja este item de trabalho associado
a uma coluna do banco de dados, um botão, etc. Todo e qualquer item está subordinado a um bloco de dados.
Expanda o nó CD_MAT. Observe que subordinado a este nó encontramos novamente o nó Gatilhos (Triggers).
Observe, ainda, que na hierarquia principal também existe um nó Gatilhos (Triggers).
Nesse tipo de nó escreveremos nossa lógica de programação, ou seja, críticas, movimentação, atribuição, etc.
Trataremos deste assunto detalhadamente mais tarde.
Acionaremos o Assistente de Layout através do menu Ferramentas.
O primeiro diálogo apresentado pode ser descartado das próximas vezes da mesma forma que no caso do Assistente
de Blocos de Dados.
Na Figura 7.18 iremos determinar a canvas em que os itens do bloco Func serão criados. Nesse diálogo temos três
campos para preencher.
No primeiro, chamado Canvas, devemos selecionar entre uma canvas já existente ou uma nova canvas. Não temos
definida nenhuma canvas em nossa aplicação; desta forma, a única escolha possível é uma nova canvas.
No segundo campo devemos escolher o tipo de canvas (tela) que desejamos criar. Nos são apresentadas cinco
opções: Conteúdo (Content), Barra de Ferramentas Vertical (Vertical ToolBar), Barra de Ferramentas Horizontal
(Horizontal ToolBar), Empilhado (Stack) e Guia (Tab). Desenvolveremos aplicações com cada uma delas, porém,
neste momento, utilizaremos a opção Conteúdo.
O terceiro campo fica desabilitado quando definimos no segundo campo qualquer opção diferente de Guia (Tab).
No diálogo da Figura 7.19, escolheremos quais campos serão apresentados na canvas e qual a forma de apresentação.
Como desejamos apresentar todos os campos, deveremos pressionar o botão ( >> ). O campo Itens Exibidos deve
ser preenchido com o conjunto de itens que serão apresentados.
Selecione, agora, um item dentre os presentes no campo Itens Exibidos. O campo Tipo de Item ficará habilitado,
permitindo que façamos a especificação de como desejamos que o item seja apresentado na canvas.
Nossa escolha atual será Item de Texto. Posteriormente, trabalharemos as propriedades dos itens e as modificações
necessárias para a apresentação de outros tipos.
O próximo diálogo, apresentado na Figura 7.20, permite a determinação dos labels ou prompts a serem usados na
construção da canvas.
No diálogo da Figura 7.21 devemos definir um título para o conjunto de registros apresentados, a quantidade de
registros apresentados, a distância entre os registros e a presença ou não da barra de rolagem de registros.
Escolhemos como título Funcionários, apenas 1 (um) registro na tela, distância zero (só será exibido 1 (um) registro)
e solicitamos a presença da barra de rolagem.
O próximo diálogo (não apresentamos) encerra a preparação do layout.
Ao retornarmos para o Form Builder, é mostrado o editor de layout contendo todos os itens pertencentes ao bloco
Func, organizados numa área de tela a que chamamos Canvas.
Retorne agora ao navegador e observe a criação de um objeto subordinado ao nó Canvases.
Nosso próximo passo será compilar e executar a aplicação criada.
Tanto a barra de ferramentas quanto o menu apresentado podem ser substituídos por objetos customizados, como
veremos posteriormente. Agora trataremos de manipular os dados desta aplicação.
As ações presentes na barra de ferramentas existem também no menu apresentado e correspondem às ações realizadas
com mais freqüência.
Se sua “canvas” não ficou com o desenho exatamente igual ao da Figura 7.22, não se preocupe. Fiz algumas modificações, não documentadas
aqui, para que o desenho ficasse menor.
CONSULTANDO FUNCIONÁRIOS
A consulta das informações gravadas pode ser feita com ou sem restrições. Se pressionarmos o botão Executar Consulta
da barra de ferramentas ou a opção Executar do menu Consultar faremos uma consulta a todas as linhas de Func.
A navegação entre os registros consultados poderá ser feita através da barra de ferramentas (Anterior e Próximo),
através das opções Anterior e Próximo do menu Gravar e, ainda, através da barra de rolagem posicionada à direita dos
dados. Essa barra de rolagem visa à navegação entre os registros, não tem qualquer relação com rolagem da tela.
Para consultarmos informações específicas, devemos escolher a opção Entrar com Consulta (Enter-Query) da barra
de ferramentas ou a opção Entrar do menu Consultar.
Podemos digitar um valor fixo em um campo qualquer, por exemplo, 100 no campo Matrícula. Essa informação
adicionará a restrição cd_mat = 100 no momento em que a consulta for executada. Podemos preencher também >
100, o que causará uma restrição do tipo cd_mat > 100 a tempo de execução. Outra forma de restringir as linhas
lidas que podemos usar é o elemento %, como em %R% (para a coluna nm_func), indicando que devem ser
consultadas todas as linhas em que nm_func tenha R em alguma posição (Like ‘%R%’).
Preencha o campo Nome com o valor %R% e execute a consulta. Observe que as linhas consultadas fazem referência
apenas a nomes de funcionários com R.
No menu Consultar ainda existem as opções:
♦ Cancelar – Para cancelar uma consulta em andamento. Esta ação fica habilitada quando estamos no modo de
Enter-Query, ou seja, utilizamos a opção Entrar Consulta para definir um critério de pesquisa. Após acionarmos
a execução da consulta, não há necessidade de cancelamento.
♦ Último Critério – Para apresentar o último critério de restrição efetuado. Esta opção fica habilitada quando
estamos no modo de Enter-Query.
♦ Contar Acertos – Para apresentar a quantidade de linhas retornadas de acordo com o critério efetuado, sem que
haja necessidade de realizarmos a consulta. Esta opção deve ser acionada no lugar da Executar Consulta, após
termos preenchido o critério de restrição desejado (Enter-Query).
♦ Extrair Próximo Conjunto – Esta opção faz uma operação de Fetch de dados. Quando realizamos uma consulta,
o Forms Runtime não lê todas as linhas do banco de dados de uma única vez, ele faz leituras parciais, ele traz um
conjunto de n linhas de cada vez. Conforme navegamos para os registros seguintes, ele vai ao banco de dados e
efetua novas leituras. Essa opção força uma leitura no próximo conjunto de registros sem que haja necessidade
de navegarmos um a um até lermos todos os registros do conjunto. A quantidade de registros em um conjunto
depende de parâmetros associados ao bloco de dados, que serão vistos posteriormente.
ALTERANDO FUNCIONÁRIOS
O Forms Runtime considerará alterado todo registro que for lido e posteriormente modificado ou, mais precisamente,
todo registro lido e modificado além de todo registro incluído, gravado (salvo) e modificado em seguida.
Desta forma, após uma consulta, qualquer modificação que venhamos a fazer em um registro será considerada
para alteração no banco de dados.
Da mesma forma que no caso da inclusão, podemos modificar diversos registros e posteriormente acionar o botão
para salvar. Experimente.
Suponhamos agora que tenhamos feito uma alteração ou uma inclusão e venhamos a desistir dessa modificação.
Antes de salvarmos, podemos limpar o registro e cancelar a atualização prevista para ele.
Para efeito de teste, pressione o botão Incluir em qualquer linha dos dados consultados. Será aberto um novo
registro para digitação. Digite os dados e, em seguida, escolha a opção Limpar do menu Gravar (Registro) e pressione
o botão Salvar. Receberemos a mensagem de que não há modificações a serem aplicadas ao banco de dados.
Suponhamos, agora, que desejamos copiar alguma informação de um registro para outro.
Uma forma de efetuarmos esta operação é navegarmos para o registro origem, selecionarmos o dado desejado, usarmos a
ferramenta de copiar, navegar para o registro destino, posicionar o cursor no campo desejado e pressionar o botão Colar.
As ferramentas de Recortar, Copiar e Colar se aplicam a itens da tela. Devemos selecionar o item desejado e
pressionar o botão correspondente na barra de ferramentas. Essas mesmas opções estão presentes no menu Editar.
Nesse menu Editar, ainda aparecem mais duas opções:
♦ Editar – Esta opção apresenta um editor com o conteúdo do campo que tiver o foco, isto é, do campo em que o
cursor estiver posicionado. Essa opção é útil quando a coluna correspondente no banco de dados é muito
grande para ser mostrada integralmente na tela. Quando acionamos o editor, podemos visualizar todo o conteúdo
do campo. A edição está limitada ao tamanho do item.
♦ Exibir Lista – Esta opção exibe a lista de valores para o campo que tiver o foco, se a esse campo tivermos
associado uma lista de valores (cujo uso será visto ao longo do estudo).
Quando incluímos um registro em seguida de outro, podemos copiar dados do registro anterior de tal forma que a
quantidade de informações digitadas seja menor. Essa operação pode ser feita sempre que houver um registro
anterior ao registro incluído.
Faça o seguinte teste: realize uma consulta ao banco de dados, em seguida pressione a ferramenta Inserir Registro
da barra de ferramentas (um registro vazio será apresentado); use, a seguir, a opção Duplicar do menu Gravar e
observe o resultado (todos os valores presentes no registro anterior foram copiados para o registro atual).
Podemos duplicar todo o registro usando a opção Duplicar do menu Gravar (Registro) ou um determinado campo
com a opção Duplicar do menu Campo.
EXCLUINDO FUNCIONÁRIOS
Para que o Form considere uma ação de exclusão no banco de dados, deveremos ter consultado um determinado
registro e, em seguida, o excluído.
A ação de exclusão pode ser acionada na barra de ferramentas ou através da opção Remover do menu Gravar (Registro).
BLOQUEANDO FUNCIONÁRIOS
O Form, quando faz uma consulta e apresenta os registros para o usuário, não efetua bloqueio (Lock) nas linhas consultadas.
Esta ação só é realizada se o usuário efetuar alguma modificação na linha ou pressionar o botão de Remover.
Tão logo uma destas ações ocorra, o Form dispara um bloqueio para o registro corrente. Isso ocorre antes da ação
de salva.
Se desejarmos bloquear uma linha mesmo antes de modificá-la, podemos usar o botão Bloquear Registro ou a
opção Travar do menu Gravar (Registro).
NAVEGAÇÃO
A navegação de uma aplicação Form ocorre entre campos, entre registros e entre blocos.
Para navegarmos de um item para o outro, podemos pressionar a tecla Tab (navegação para frente), Tab+Shift
(navegação para trás) ou podemos utilizar as opções Anterior e Próximo do menu Campo.
A navegação entre registros pode ser feita através dos botões da barra de ferramentas, através da barra de rolagem,
através das opções Anterior e Próximo do menu Gravar (Registro) e, ainda, com as teclas de seta para cima e seta
para baixo do teclado, se o cursor estiver posicionado sobre um campo do registro.
A navegação entre blocos pode ser feita com os botões da barra de ferramentas (Bloco Anterior e Próximo Bloco) ou
com as opções Anterior e Próximo do menu Bloco. Para que essa ação tenha efeito devemos ter criado mais de um
bloco na aplicação.
MENU AJUDA
No menu Ajuda aparecem quatro opções:
♦ Ajuda – Esta opção apresenta uma tela contendo as propriedades atuais do item que tiver o foco. Onde o cursor
estiver posicionado.
♦ Teclas – Esta opção apresenta uma tela contendo de um lado uma ação e do outro a tecla (ou conjunto de teclas)
a ser acionada para efetuarmos aquela ação. A lista de ações se refere ao conjunto de ações que realizamos com
o menu e com a barra de ferramentas. A tela apresentada é sensível ao contexto, isto é, haverá uma variação de
acordo com a ação em execução (consulta, inclusão, etc.).
♦ Erro de Exibição – Esta opção apresenta a sintaxe do comando de SQL disparado pelo Form que deu erro de
sintaxe e ainda a mensagem recebida do banco de dados.
♦ Depurar – Esta opção fica habilitada quando executamos a aplicação no modo de depuração (botão Executar
Depuração de Form da barra de ferramentas do Navegador de Objetos). Ele permitirá a interrupção da aplicação,
a qualquer momento, para que possamos verificar o valor de variáveis de ambiente, de bloco ou globais e para
que possamos determinar um ponto de interrupção (dentro de um trigger) para acompanhamento da execução
passo a passo. Estudaremos mais sobre este botão no tópico relativo a depuração.
Como teste, para visualizarmos a janela de Erro de Exibição, basta que modifiquemos um determinado registro, preenchendo
um código de departamento inexistente na tabela de departamento, por exemplo XXX, e pressionemos o botão Salvar.
Observe que a mensagem apresentada nesse quadro é diferente da mensagem mostrada na linha de mensagens do
Form (no rodapé da página). Isto ocorre porque o Forms, em diversas situações, modifica a mensagem recebida do
banco de dados e exibe sua própria mensagem.
Esta opção será de grande utilidade para nós quando estivermos testando nossa aplicação. Ela permitirá que verifiquemos, precisamente, qual o
erro retornado pelo banco de dados.
SALVA IMPLÍCITA
O Forms Runtime tem controle sobre as modificações que efetuamos sobre os registros. Esse controle se dá em
nível de bloco e de Form (aplicação).
Quando, por algum motivo, precisamos limpar o bloco (ou Form, isto é, todos os blocos de uma aplicação) e,
anteriormente, efetuamos modificações não salvas, o Forms Runtime percebe que existem registros pendentes
(não enviados para o banco de dados) e apresenta um diálogo questionando se desejamos ou não efetuar uma
salva dos dados modificados.
A Figura 7.24 apresenta esse diálogo. Se pressionarmos Sim é efetuada uma Salva (Commit). Se pressionarmos Não,
todas as modificações são descartadas. Se pressionarmos Cancelar, a ação comandada não é efetuada.
Esse diálogo pode aparecer quando efetuamos as ações: Limpar Bloco, Limpar Tudo (Form), Executar Consulta,
Entrar Consulta ou Sair da Aplicação.
CONCLUSÕES
Até o momento não escrevemos uma linha sequer de código; no entanto, a ferramenta já foi capaz de realizar as
operações básicas de inclusão, exclusão, alteração, consulta e navegação.
Nossa tarefa ao longo deste estudo será perceber como modificar esta funcionalidade básica de acordo com a
nossa vontade.
EXERCÍCIOS
Neste primeiro grupo de exercícios, você criará as aplicações utilizando o Assistente de Bloco de Dados e o Assistente
de Layout com as diversas variações que proporemos a seguir.
7.01) Crie uma aplicação com o nome de EX01 baseada na tabela Func. Selecione as colunas cd_mat, nm_func,
cd_depto, dt_nasc, nr_cargo e in_sexo.
Crie uma nova canvas do tipo Conteúdo (Content). Defina os prompts adequados para cada coluna.
O formato do Layout deve ser Form, com a apresentação de dois registros.
A distância entre os registros deve ser 10. O título do quadro deve ser Funcionários. Apresente uma barra de rolagem.
A tempo de execução:
♦ Crie dois registros sem salvar.
♦ Salve.
♦ Leia todas as linhas cujo código do departamento comece com D.
♦ Altere um registro colocando um valor inválido para o código do departamento.
♦ Tente salvar a alteração. O que acontece? Qual o erro enviado pelo database?
♦ Cancele essa alteração.
7.02) Crie uma aplicação com o nome de EX02 baseada na tabela Func. Selecione as colunas cd_mat, nm_func,
cd_depto, dt_nasc, nr_cargo e in_sexo.
Crie uma nova canvas do tipo Guia. Defina os prompts adequados para cada coluna.
7.05) Crie uma aplicação com o nome de EX05 baseada na tabela Func. Selecione as colunas cd_mat, nm_func,
cd_depto, in_sexo, vl_sal. Marque a opção Impor Integridade de Dados (Enforce Data Integrity).
Crie uma nova canvas do tipo Conteúdo (Content). Defina os prompts adequados para cada coluna.
ANALISANDO
Agora que você já tem condições de criar aplicações Form, vamos rever as aplicações criadas e analisar os resultados.
Você observou que o Forms Runtime decidiu pela inclusão de um novo funcionário sem que tivéssemos informado
que estávamos incluindo? Ou que ele decidiu fazer um Update quando alteramos uma determinada linha? Como
é feito o controle para que a ferramenta tome a decisão certa?
PROPRIEDADES
Cada objeto criado em nossa aplicação possui um conjunto de propriedades que determinam suas características básicas.
Para termos acesso às propriedades de um bloco ou de qualquer outro objeto, devemos selecionar o objeto no
navegador e pressionar o botão direito do mouse. Será mostrada uma lista de opções, dentre elas aquela que ativa
a paleta de propriedades.
Nessa paleta existem grupos que relacionam propriedades associadas a um mesmo assunto.
Na Figura 7.26 mostramos a paleta de propriedades de um bloco. Observe que no grupo Geral existem propriedades
comuns a todos os objetos: Nome, Subclasses e Comentários. Quando selecionamos uma das propriedades (basta
clicar com o mouse sobre a linha), seu valor torna-se disponível para modificação e no rodapé da paleta aparece
uma pequena explicação sobre a propriedade selecionada.
No exemplo (Figura 7.26), selecionamos a propriedade Nome e a explicação apresentada é “Nome interno do
Objeto”. Isso facilita bastante o entendimento do conjunto de propriedades, que é bem extenso. Se você achar a
informação insuficiente, consulte o Capítulo 13, pois apresentamos todas as propriedades (português e inglês)
com a respectiva explicação (português). Se você consultar o menu Ajuda, a primeira opção, chamada Tópicos da
Ajuda do Form Builder, permite o acesso aos manuais de ajuda fornecidos pela Oracle (em inglês).
A ÁREA DE BUFFER
Quando criamos um bloco, podemos determinar o tamanho da área de memória reservada para a leitura das linhas
de dados associadas a ele. Isso é feito através da propriedade Número de Registros Armazenados no Buffer (Number
of Records Buffered). Nessa área são armazenadas as linhas vindas do banco de dados. Essa área contém diversos
registros (um para cada linha lida); cada registro possui um campo para cada um dos itens pertencentes ao bloco.
HIERARQUIA FUNCIONAL
Desta forma, podemos dizer que um item está subordinado a um registro, que por sua vez está subordinado a um
bloco. Essa hierarquia, que está representada na Figura 7.27, é chamada de Hierarquia Funcional, pois está associada
à forma como o Forms Runtime trabalha.
Todos os itens de um determinado bloco estão sujeitos à funcionalidade do bloco. Por exemplo, para incluirmos
linhas na tabela Func (exemplo do tópico anterior), preenchemos os itens. Esses dados foram sendo armazenados
na área de Buffer (registros) até que pressionamos o botão Salvar. Neste momento, essa área de Buffer foi lida e
enviada para o banco de dados para inclusão.
Essas ações foram possíveis devido à ligação dos itens com os registros e destes com o bloco.
Como um registro não possui representação gráfica na ferramenta, suas propriedades só podem ser obtidas ou
modificadas por programação, através das rotinas Set_Record_Property e Get_Record_Property, que serão vistas no
tópico relativo à programação.
TIPOS DE BLOCOS
Um Bloco no Form pode ser de dois tipos: Data Block (Bloco de Dados) e Control Block (Bloco de Controle).
Um Bloco de Dados está associado a dados oriundos do banco de dados seja através de uma tabela (ou view) ou
através de rotinas armazenadas no banco de dados. Esse tipo de bloco possui uma funcionalidade default implícita,
que garante a inclusão, exclusão, alteração e consulta sem que tenhamos de escrever uma única linha de código.
Esse tipo de bloco foi utilizado em todas as aplicações desenvolvidas até o momento.
Um Bloco de Controle não está associado ao banco de dados e, portanto, não possui qualquer funcionalidade
implícita. São usados freqüentemente para a criação de botões, itens de cálculo, áreas de trabalho, itens para
entrada de valores requeridos pela aplicação, etc.
Os itens subordinados a cada um desses blocos também possuem tipos que os caracterizam. Em um bloco de dados
podemos ter itens associados ao banco de dados ou itens de controle (ou seja, itens não associados ao banco de dados). Já
num bloco de controle, que não possui associação com o banco de dados, os itens são todos de controle, obrigatoriamente.
Quando precisamos, por algum motivo, limpar a área de buffer de um Bloco de Dados, o Form analisa a situação
de atualização daquele bloco. Se existirem registros pendentes de atualização, ou seja, registros no estado INSERT
ou CHANGED, antes de executar a ação solicitada, o Form questiona o usuário se deseja ou não efetivar as
modificações pendentes (ver a Figura 7.24).
Neste caso, o usuário poderá escolher três ações:
♦ Sim (Yes) – Indica que o processo de atualização do banco deve ser efetuado antes da ação solicitada pelo usuário.
♦ Não (No) – Indica que os registros pendentes devem ser descartados, mas a ação solicitada, causadora da limpeza
no buffer, deve ser realizada.
♦ Cancelar (Cancel) – Indica que o usuário está desistindo da ação solicitada. Neste caso, a ação é interrompida e
o programa volta para o estado de leitura do teclado aguardando que o usuário inicie outra ação. Nesta situação
todos os registros pendentes de atualização continuam pendentes.
♦ Clear_Block – A primeira e mais direta é a própria solicitação de limpeza do bloco, opção Limpar (Clear) do menu
Bloco (Block). Essa ação causa a limpeza da área de buffer associada ao bloco. Essa ação também pode ser iniciada
com a opção Limpar Bloco (Clear Block – Shift+F5) do teclado ou por programação com o uso da rotina Clear_Block.
♦ Clear_Form – A solicitação de limpeza de toda a aplicação causa a limpeza da área de buffer de todos os blocos.
Se em algum deles houver registros pendentes, ocorrerá a mensagem. Essa ação pode ser iniciada pelo usuário
através da opção Limpar Tudo (Clear All) do menu Ação (Action), do teclado com a opção Limpar Form (Clear
Form – Shift + F7) ou através de programação com o uso da rotina Clear_Form.
♦ Exit_Form – O término da aplicação com registros não aplicados também causa a presença da mensagem, apesar
de não causar a limpeza direta do buffer e sim a indireta, pois toda a memória da aplicação será liberada para o
sistema operacional. Essa ação pode ser solicitada pelo usuário através da opção Sair (Exit) do menu Ação
(Action), do botão Sair (Exit) da barra de ferramentas, do botão Fechar (X) da janela do Forms Runtime, da
opção Sair (Exit – Ctrl + q) do teclado ou por programação com o uso da rotina Exit_Form.
♦ Enter_Query – Ao solicitarmos uma nova consulta, o Forms Runtime deve limpar o buffer a fim de carregar os
dados da nova consulta solicitada, o que faz com que a mensagem seja apresentada. O usuário poderá causar
essa situação ao escolher a opção Entrar (Enter) ou a opção Último Critério (Last Criteria) do menu Consultar
(Query), pois aciona a entrada de uma nova consulta (similar ao Entrar), também o botão Entrar com Consulta
(Enter-Query) da barra de ferramentas e a opção Entrar com Consulta (Enter-Query – F7) do teclado ou por
programação com o uso da rotina Enter_Query.
♦ Execute_Query – Da mesma forma que a opção anterior, se tentarmos executar uma consulta sem previamente
estabelecermos as restrições, o Forms Runtime deve limpar o buffer a fim de carregar os dados da nova consulta
solicitada, o que faz com que a mensagem seja apresentada. O usuário poderá causar essa situação ao escolher a
opção Executar (Execute) ou a opção Contar Acertos (Count Query Hits) do menu Consultar (Query), pois executa
uma consulta para contar o número de linhas que satisfazem os critérios estabelecidos. Também o botão Executar
Consulta (Execute Query) da barra de ferramentas e a opção Executar Consulta (Execute Query – F8) do teclado ou
por programação com o uso da rotina Execute_Query podem causar o aparecimento da mensagem.
Para que você tenha bastante intimidade com a funcionalidade default do Forms, faça teste com todas essas opções
(exceto as de programação) em uma das aplicações que você já montou no Tópico 1 antes de seguir para o próximo
assunto. O entendimento da funcionalidade default do Form é a etapa mais importante para o bom uso da ferramenta.
NAVEGAÇÃO
Nos próximos itens deste Tópico Blocos, deveremos estudar diversas propriedades associadas ao bloco, e portanto
será necessário que você dê uma olhada prévia nesse conjunto de propriedades.
Utilizaremos a aplicação EX03 (da lista de exercícios) para confeccionar os testes necessários.
O que acontece quando, através da navegação, atingimos o último item de um bloco e acionamos a navegação
para o próximo item? Qual ação será realizada pelo Form?
Estas questões serão definidas pelo desenvolvedor ao preencher as propriedades Estilo de Navegação (Navigation
Style), Bloco de Dados Anterior de Navegação (Previous Navigation Data Block) e Próximo Bloco de Dados de
Navegação (Next Navigation Data Block). Todas essas propriedades se encontram grupadas no nó Navegação (Navi-
gation) da Paleta de Propriedades.
acima do Bloco Func; desta forma, quando a aplicação for executada o cursor ficará posicionado inicialmente no
bloco Depto e depois no bloco Func.
Se pressionarmos (botão esquerdo) o mouse sobre o ícone de um dos blocos e o arrastarmos, podemos modificar a
ordem de navegação.
Faça um teste. Observe que o cursor se posiciona inicialmente no bloco Func e não mais no bloco Depto, embora
o desenho dos dois blocos permaneça inalterado. O que mudamos foi a seqüência de navegação.
A opção default é Mesmo Registro. Nosso primeiro teste será executar a aplicação EX03, consultar dados em cada
um dos blocos, posicionar o cursor no último campo do último registro de departamento e navegar para o próximo
item. O que acontece?
Veremos que o cursor retorna ao primeiro item navegável desse mesmo bloco e, ainda, no mesmo registro.
Isto ocorre porque a opção Same Record (Mesmo Registro) define que, quando uma operação de navegação para o
próximo item é acionada e o posicionamento do cursor é exatamente no último item navegável do bloco, o foco deve
retornar para o primeiro item navegável desse mesmo registro. Refaça este teste, porém posicione o cursor no primeiro
item navegável do bloco Func(cd_mat) e efetue uma operação de navegação para o item anterior. O que acontece?
O resultado é similar à situação anterior. O Form navega para o último item navegável desse mesmo bloco, no
mesmo registro.
Modifiquemos, agora, o valor da propriedade Estilo de Navegação (Navigation Style) do bloco Depto para Alterar
Registro (Change Record) e do bloco Func para Alterar Bloco de Dados (Change Block) e refaçamos os testes.
Observamos que, quando efetuamos uma operação de navegação para o próximo item (estando posicionado no
último item navegável do bloco) no bloco Depto, ele navega para o primeiro item navegável, porém, agora, no
próximo registro.
Já no bloco Func, essa operação de navegação causa a mudança de bloco.
Com essas três propriedades podemos estabelecer as regras de navegação entre os blocos de uma aplicação.
Crie um novo bloco nesta aplicação para a tabela Ativ (somente código e sigla) e defina que a orientação será
horizontal. Observe a diferença de navegação a tempo de execução.
A propriedade Orientação do Registro (Record Orientation) com o valor horizontal faz com que a navegação se
processe da esquerda para a direita (próximo registro) ou da direita para a esquerda (registro anterior).
Nesse grupo ainda temos como propriedade:
♦ Número de Registros Exibidos (Number of Records Displayed) – Que permite que após o desenvolvimento do
bloco modifiquemos a quantidade de registros presentes na canvas (tela).
♦ Número de Registros Armazenados no Buffer (Number of Records Buffered) – Esta propriedade determina o
número mínimo de registros armazenados em memória durante uma consulta ao bloco de dados. Quanto
maior este número, mais ágil é o processo de manipulação da informação localmente, porém precisaremos de
mais memória real disponibilizada. Quando o número de registros que precisamos armazenar no buffer local
(em função da leitura de uma tabela grande, por exemplo) é maior que o valor especificado por esta propriedade,
o Form faz overlay para disco a fim de guardar o restante. O valor default de 0 (ou Null) indica que será armazenada
em memória a mesma quantidade de registros exibidos (Number of Records Displayed) mais 3 (três).
♦ Tamanho do Array de Consulta (Query Array Size) – Esta propriedade define a freqüência com que o Form faz
acesso ao banco de dados para obtenção dos dados a serem apresentados, pois determina a quantidade máxima
de registros obtidos a cada Fetch. Um número muito baixo pode dar ao usuário a impressão de uma resposta
mais imediata se ele estiver analisando os registros passo a passo. Se estiver fazendo navegação, uma quantidade
maior de registros permitirá que ele navegue mais rapidamente até que o Form necessite obter o próximo
conjunto. Se analisarmos pelo lado da performance, um número maior de registros é mais eficiente, pois temos
de fazer menos acesso ao servidor para obtenção dos dados, porém o tempo de resposta de cada acesso pode ser
maior (embora o tempo de resposta total, certamente, seja menor).
O grupo Registros (Records) possui outras propriedades. Leia as características das demais para que você possa fazer
os exercícios sem dúvidas.
A propriedade Bloco de Dados do Banco de Dados (Database Data Block) indica que o bloco é um bloco de dados
(Sim) ou um bloco de controle (Não). Quando escolhemos Sim, o Form verifica as informações relativas à origem
dos dados, ou seja, como se dará a captura das informações a serem apresentadas. Caso nossa opção seja Não, essas
informações serão ignoradas pelo Form.
Observe que, no caso do Bloco Func, o Tipo de Origem de Dados de Consulta (Query Data Source Type) está
preenchido com Tabela (Table) e o nome dessa tabela de onde se originam os dados está preenchido na propriedade
Nome de Origem de Dados de Consulta (Query Data Source Name). Selecione a propriedade Colunas de Origem de
Dados de Consulta (Query Data Source Columns) e verifique que se encontram presentes todas as colunas da
tabela Func de que estamos tratando nesta aplicação (todos os itens de dados do bloco Func).
Agora, defina uma cláusula Where para este bloco. Por exemplo, façamos a seleção apenas dos funcionários do
departamento D11. Para tal, devemos digitar o texto cd_depto = ‘D11’ na propriedade correspondente (Cláusula WHERE).
Simultaneamente ordenaremos o resultado por nome do funcionário. Para tal, devemos digitar o texto nm_func
na propriedade correspondente (Cláusula ORDER BY), e em seguida, executar a aplicação e conferir os resultados.
Leia as demais propriedades deste grupo e faça testes complementares. Nos exercícios deste tópico, abordaremos
outras propriedades desse grupo.
O PACOTE PFUNC
Para entendermos como são as regras para estabelecer este tipo de bloco, vejamos um exemplo. Neste primeiro
exemplo criaremos um pacote no banco de dados que contém os tipos necessários ao acesso, uma rotina de
consulta e uma rotina de atualização. Quando já houvermos estudado a criação de procedimentos no ambiente
cliente, você poderá optar por incluir as rotinas tanto no ambiente cliente quanto no servidor.
A Listagem 7.01 mostra a parte de especificação do pacote Pfunc. Nele incluímos um tipo Record (Rfunc) referente
às colunas da tabela Func, que desejamos atualizar. Definimos também dois outros tipos: um tipo Cursor (Cfunc)
e um tipo Table (Tfunc), ambos fazendo referência ao tipo Record (Rfunc).
Estabelecemos, ainda, a parte de especificação das rotinas de que necessitamos para consulta à tabela Func e sua atualização.
A rotina de consulta recebe como parâmetro a matrícula, o departamento, o cargo e o grau de instrução e retorna
uma variável cursor do tipo Cfunc. Os parâmetros para essa rotina são opcionais: o usuário poderá fornecer apenas
a matrícula ou uma combinação de cargo com grau de instrução ou nenhum deles, e assim por diante. De acordo
com estas informações, serão selecionadas as linhas de funcionário que atendem às condições.
A Listagem 7.02 mostra a rotina Consulta efetuando a pesquisa condicional à situação apresentada.
A rotina de atualização recebe dois parâmetros: uma tabela cujo layout é Rfunc e uma variável alfanumérica, que
pode ser preenchida com os valores I (na inclusão), E (na exclusão), A (na alteração) e B (no bloqueio).
De acordo com o valor do segundo parâmetro, a ação a ser realizada pela rotina muda.
Na Listagem 7.02 vemos, ainda, a parte do pacote Pfunc contendo a rotina Atualiza.
Observe que os dados a serem alterados são enviados através da tabela. A expectativa do programa é processar os
registros enquanto houverem linhas na tabela enviada como parâmetro.
Os exemplos apresentados aqui não fazem nenhuma ação especial de crítica ou seleção. O objetivo é apresentar
apenas o que deve ser codificado nas rotinas para que a interface com o Form seja adequada.
No primeiro diálogo apresentado pelo assistente, escolheremos a criação do bloco usando um procedimento
armazenado no banco de dados.
Na Figura 7.28 se encontra o segundo diálogo, onde somos instados a informar o nome da rotina de consulta. Para
tal, preenchemos seu nome e pressionamos o botão Renovar para que o Form faça a leitura da parte de especificação
do pacote (que já deve ter sido criado anteriormente no banco de dados).
Para o campo Itens do Banco de Dados, movimentamos as colunas que desejamos trazer para a aplicação. Essas
serão as colunas que o Form criará como itens do bloco associado ao procedimento.
No nosso caso, passaremos todas as colunas (>>) para o segundo campo.
Observe que na parte inferior da tela aparecem os argumentos recebidos pela rotina e a possibilidade de informarmos
como esses parâmetros serão preenchidos.
O Form Builder, para criação do bloco baseado em procedimento, agirá da mesma forma que agia quando da
criação de bloco baseado em tabela, ou seja, se o nome dos itens ficava igual (por default) ao nome das colunas, no
caso de procedimento o nome dos itens ficará igual ao nome das colunas do registro Rfunc no qual o parâmetro
Ptab (que é do tipo Ref Cursor de Cfunc) se baseia (veja novamente a Listagem 7.01).
Uma vez que os parâmetros de entrada deverão ser passados pelo usuário (na tela), preencheremos da seguinte forma:
♦ Para o parâmetro pcd_mat preencheremos a coluna Valor com :cd_mat. Isto significa que quando o usuário
preencher o item cd_mat do bloco, a tempo de Enter-Query, o valor deste item será associado ao parâmetro
pcd_mat para possibilitar a consulta por matrícula.
Observe que, após pressionarmos o botão Renovar, o quadro abaixo do nome do procedimento é preenchido
automaticamente com o conteúdo do tipo table Ptab. Este será nosso parâmetro de entrada; desta forma, atribuiremos
a ele todo o conteúdo do bloco que está sendo criado neste momento. Assumiremos que o nome do bloco será
Bfunc. Assim, os parâmetros serão preenchidos da seguinte forma:
♦ O parâmetro Ptab receberá o conteúdo do bloco, ou seja: BFunc.
♦ O parâmetro Ptipo receberá a constante I, para indicar à rotina que é uma chamada de inclusão.
Os diálogos seguintes a este são preenchidos de forma similar, de acordo com o quadro abaixo:
Tabela 7.02 – Preenchimento do Diálogo do Assistente de Bloco de Dados para Atualizar, Excluir e Bloquear
Se você estiver achando muito difícil fazer este preenchimento agora (a tela é muito apertada), pode deixar esta ação para depois, através da
paleta de propriedades.
Após estes preenchimentos, será gerado um layout com todas as colunas do tipo Rfunc definidas em uma canvas
de conteúdo, formato Form e uma barra de rolagem (bem simples).
A seguir, veremos o que foi preenchido para o bloco, ou seja, suas propriedades. Antes, porém, altere o nome do
bloco para BFunc para que fique compatível com as informações que passamos.
Abra a paleta de propriedades do bloco com o nó Banco de Dados expandido. Deveremos encontrar a propriedade Tipo
de Origem de Dados de Consulta (Query Data Source Type) preenchida com “Procedimento” e a propriedade Nome de
Origem de Dados de Consulta (Query Data Source Name) com o nome da nossa rotina, ou seja, “Pfunc.Consulta”.
As propriedades Colunas de Origem e Argumentos não parecem preenchidas, mas estão. Vamos selecioná-las uma
de cada vez para que sejam mostrados os diálogos correspondentes.
Na Figura 7.30, mostramos o diálogo referente à propriedade Colunas de Origem de Dados para Consulta (Query
Data Source Columns). No nosso caso, as informações já estão preenchidas, pois utilizamos o Assistente para tal.
Essas informações correspondem aos parâmetros do tipo OUT ou IN OUT que existirem na rotina associada. No
nosso caso, são apresentadas as colunas da variável cursor Cfunc, que faz referência ao tipo Rfunc.
Para o Form, neste conjunto de colunas estarão os dados vindos do banco de dados (origem). Para a rotina, estes
são os dados de saída (out).
Na Figura 7.31, mostramos o diálogo Argumentos de Origem de Dados para Consulta (Query Data Source Argu-
ments), que também já se encontra preenchido. Neste diálogo informamos como se processará o preenchimento
das informações a serem passadas como argumentos da rotina. No nosso caso, a rotina recebe até quatro parâmetros
de entrada, que já foram devidamente associados.
Esse diálogo apresenta quatro informações a serem preenchidas: o tipo do argumento, seu nome (se derivado de
um tipo do usuário), o modo do argumento (entrada, saída ou ambos) e o valor que deve ser atribuído a ele, que
pode ser um item do programa ou uma constante (no nosso caso, usamos um dos itens do bloco, verifique).
Retornemos à paleta de propriedades, expandindo o nó Banco de Dados Avançado para a especificação das
propriedades das demais rotinas, da seguinte forma:
♦ Tipo de Destino dos Dados de DML (DML Data Target Type) – Esta propriedade indica para onde os dados a
serem incluídos, alterados, bloqueados ou excluídos serão enviados. No nosso caso, Procedimento.
♦ Nome do Destino dos Dados de DML (DML Data Target Name) – Se a propriedade anterior estivesse preenchida
com Tabela, nesta propriedade teríamos o nome da tabela. No nosso caso, em cada situação os dados serão
enviados para rotinas diferentes, e portanto essa propriedade é irrelevante.
♦ Inserir Nome do Procedimento (Insert Procedure Name) – Indica o nome do procedimento para onde serão
enviados os dados a tempo de inclusão: Pfunc.Atualiza.
♦ Atualizar Nome do Procedimento (Update Procedure Name) – Indica o nome do procedimento para onde serão
enviados os dados a tempo de alteração: Pfunc.Atualiza.
♦ Excluir Nome do Procedimento (Delete Procedure Name) – Indica o nome do procedimento para onde serão
enviados os dados a tempo de exclusão: Pfunc.Atualiza.
♦ Bloquear Nome do Procedimento (Lock Procedure Name) – Indica o nome do procedimento para onde serão
enviados os dados a tempo de bloqueio: Pfunc.Atualiza.
Os argumentos e retornos nas quatro situações são similares. Desta forma, veremos apenas na situação de inclusão.
Na Figura 7.32, apresentamos o diálogo referente à propriedade Inserir Colunas de Conjuntos de Resultado (Insert
Procedure Result Set Columns), onde são apresentados todos os parâmetro do tipo OUT ou IN OUT. Como nosso
parâmetro Table é do tipo IN OUT, ele é automaticamente listado nesse diálogo.
Na Figura 7.33, mostramos o diálogo referente à propriedade Inserir Argumentos de Procedimento (Insert Proce-
dure Arguments), onde são apresentados todos os parâmetros do tipo IN ou IN OUT para que possamos informar
de onde serão obtidos os dados. Observe que para o argumento Ptab preenchemos o tipo do argumento (Table) e
o Nome (Pfunc.Tfunc), pois se trata de um tipo do usuário. Em ambos os argumentos, preenchemos a coluna
Valor. No caso de Ptab, com o nome do bloco (:BFunc) e no caso de Ptipo, com um valor constante, que varia de
acordo com a ação da rotina (I – Inclusão, B – Bloqueio, A – Alteração e E – Exclusão).
As demais propriedades relativas a argumentos são preenchidas de forma similar. Verifique se os valores estão
corretos. Se você ainda não os preencheu faça isto agora.
Retornemos agora ao Navegador de Objetos (Object Navigator). Subordinado ao nó do bloco Func, observamos a
presença do nó Gatilhos e do nó Itens. O nó Itens está preenchido com as colunas obtidas do registro Rfunc do
pacote Pfunc. Já o nó Gatilhos contém quatro rotinas de PL/SQL que serão acionadas a tempo de execução a fim de
transferirem valores para os procedimentos do banco de dados.
Estas rotinas são criadas, automaticamente, quando executamos a aplicação pela primeira vez ou quando acionamos
o menu Arquivo (File), opção Administração (Administration), Compilar Arquivo (Compile) ou apenas Ctrl + T.
Não podemos modificar o conteúdo dessas rotinas uma vez que elas são geradas novamente cada vez que compilamos
a aplicação. Se houver qualquer erro de sintaxe relativamente a elas, retorne ao passo anterior e verifique o
preenchimento das propriedades relativas a argumento.
Estes gatilhos (triggers) são executados da seguinte forma:
♦ Cada vez que modificamos o valor de um campo na tela ou acionamos o comando de remover a linha, o gatilho
para bloqueio é acionado, ou seja, a rotina PFunc.Atualiza (com a opção B) é acionada uma vez para cada linha.
A tabela parâmetro é preenchida com um único elemento.
♦ Quando solicitamos a opção Salvar (Commit), caso haja inclusões a serem realizadas, a rotina de inclusão é
acionada uma única vez, recebendo como parâmetro todas as linhas a serem incluídas. O mesmo ocorre com a
rotina de alteração e exclusão.
Você, agora, já pode testar a execução dessas rotinas e verificar os resultados.
Origem Consultas Demais Operações de DML (Inc, Exc e Alt) Array Processing
O bloco derivado de uma Sub-Query será estudado apenas no tópico relativo a itens.
As demais propriedades não detalhadas serão testadas durante os exercícios. Antes de começá-los, dê uma olhada
no conjunto de propriedades restantes.
EXERCÍCIOS
7.06) Crie uma aplicação de nome EX06 baseada nas tabelas Func e Depto, com as seguintes características:
♦ Para a tabela Func as colunas cd_mat, cd_depto, nm_func, vl_sal, nr_cargo e in_sexo devem ser selecionadas.
♦ Para a tabela Depto as colunas cd_depto, nm_depto e cd_gerente devem ser selecionadas.
♦ Não estabelecer relacionamento.
♦ Tanto Depto quanto Func devem ser apresentadas em formato Form com 1 (um) registro cada um.
♦ Ambas devem ser apresentadas na mesma canvas. Definir barra de rolagem para ambos os blocos.
♦ Os dados de Funcionário devem estar ordenados por cargo e nome do funcionário.
♦ Os dados de Departamento devem estar ordenados por nome do departamento.
♦ Na última coluna de Funcionário, deve ser feita a navegação para Departamento.
♦ Na última coluna de Departamento, no entanto, deve ser feita a navegação para o próximo registro de Departamento.
♦ O bloco Departamento somente poderá realizar consultas.
♦ Já o bloco Funcionário poderá realizar consultas, exclusões e alterações, mas não poderá efetuar inclusões.
♦ Deve ser permitida ao usuário navegação com o uso de Block Menu.
7.07) Crie uma aplicação de nome EX07 baseada na tabela Func com as seguintes características:
♦ As colunas cd_mat, cd_depto, nm_func, vl_sal e nr_cargo devem ser selecionadas.
♦ O formato de apresentação deve ser Tabular com seis registros.
♦ Devem ser especificados 12 registros na área de buffer.
♦ A pesquisa no banco de dados deve ser feita de seis em seis registros.
♦ Somente os registros com cargo superior a 18 devem ser apresentados no resultado.
7.08) Crie uma aplicação de nome EX08 baseada na tabela Func com as seguintes características:
♦ As colunas cd_mat, nm_func e nr_cargo devem ser selecionadas.
♦ O formato de apresentação deve ser Tabular com seis registros.
HIERARQUIA VISUAL
Já sabemos que funcionalmente os itens dependem dos blocos, porém visualmente um bloco não existe, isto é,
não tem representação visual. Os objetos vistos pelo usuário são a canvas (tela) e os itens.
Sendo assim, os itens estão subordinados, visualmente, à canvas em que são apresentados. A tempo de atualização,
crítica, leitura, gravação e todas as ações funcionais estão subordinadas aos blocos, porém itens pertencentes a um
mesmo bloco podem ser apresentados em diferentes canvas, da mesma forma que itens pertencentes a blocos
diferentes podem ser apresentados numa mesma canvas.
Para que tenhamos, graficamente, informações a respeito dessa hierarquia, o Navegador de Objetos oferece uma
alteração das informações para este padrão. Selecione na janela do navegador o item de menu Visualizar (View) e
marque a opção View Visual (Visual View).
Na Figura 7.34, alteramos a visualização do programa-exemplo Tproc, utilizado na construção do bloco através
de procedimentos (visto no tópico anterior). Observe que o nó Janelas (Windows) apresenta duas janelas:
Null_Window e Janela1.
Na janela Janela1 encontramos a Canvas3, onde se acham subordinados todos os itens visíveis desta aplicação.
Podemos, desta forma, concluir que a hierarquia visual é composta de Windows – Canvas – Itens.
A janela Null_Window é uma janela fictícia. Representa a hierarquia de todos os objetos que não serão visualizados,
ou seja, dos objetos que não estão subordinados a uma canvas. Esses objetos são ditos Null_Canvas Itens ou
objetos que se apresentariam em uma canvas fictícia chamada Null_Canvas (como aparece na Figura 7.34).
Sendo assim, a Figura 7.34 apresenta todos os objetos visíveis subordinados às suas canvas e janelas (onde se apresentarão)
e todos os objetos escondidos aparecem subordinados a uma canvas não visível e uma janela não visível.
Observe que, ao retornar ao modo View de Propriedade (Property View), o nó Canvas somente apresenta a Can-
vas3 e o nó Janelas (Windows) só apresenta a Janela1.
ITENS
Em uma aplicação gráfica, os dados não se apresentam de uma única forma. Podem ser botões, listas, imagens,
gráficos, etc.
Em uma aplicação Forms, portanto, poderemos apresentar os dados de uma forma mais agradável e amigável para
o nosso usuário, bastando para isto que modifiquemos os tipos de itens em que os dados são apresentados.
Lembre-se, porém, de que a informação armazenada no buffer associado àquele item continua a mesma, ou seja,
se foi lido do banco o valor 42 para grau de instrução, a forma de visualização pode ser uma lista de nomes, mas o
que está no banco de dados e na memória é 42. Por isso devemos, de acordo com o tipo do item, estabelecer regras
de conversão entre o valor real do dado e o valor apresentado para o usuário.
Estudaremos as propriedades dos itens através de um exemplo que caracterize as diversas opções de visualização
da informação.
Criaremos, então, uma nova aplicação chamada Item, a partir da tabela Func com as seguintes características, a
serem modificadas com o Assistente de Layout:
♦ Todas as colunas devem ser selecionadas, exceto nm_foto.
♦ A coluna cd_depto deve ser definida como Item da Lista. No Assistente de Layout, a opção é PopList.
♦ A coluna nr_cargo deve ser definida como Item da Lista. No Assistente de Layout, a opção é Caixa de Combinação
(Combo Box).
♦ A coluna nr_git deve ser definida como Item da Lista. No Assistente de Layout, a opção é Lista de Textos (Text List).
♦ A coluna in_sexo deve ser definida como Grupo de Opções (Radio Group).
♦ A coluna dt_adm deve ser definida como Exibir Item.
♦ Os demais itens devem ser definidos como Item de Texto.
♦ Canvas de Conteúdo, formato tabular, ocorrência de cinco registros (distância entre os registros 5), exibir barra
de rolagem.
A Figura 7.35 mostra a primeira imagem da canvas com os itens criados. Para fazermos acesso ao layout da canvas
(tela), podemos acionar o editor de layout através do menu Ferramentas (Tools) ou com a tecla F2. Com ele ativo
podemos fazer a navegação de uma janela para outra através do menu Janela (Window).
Veremos a seguir as propriedades comuns e aquelas relativas às características individuais do tipo.
PROPRIEDADES COMUNS
Ao abrirmos a paleta de propriedades do item cd_mat, verificaremos que os itens possuem uma quantidade
significativa de características a serem analisadas. Vamos a elas.
O grupo funcional será o último analisado, uma vez que possui características específicas ao tipo do item.
A primeira propriedade a ser analisada é justamente o Tipo do Item (Item Type), do grupo Geral (General). Essa propriedade
determina quais as características de visualização específicas do item, pois modifica o conjunto de propriedades definidas
no grupo funcional, ou seja, para cada tipo de item existem propriedades diferentes no grupo funcional.
Em relação à navegação, vemos uma propriedade chamada Navegável com Teclado (Keyboard Navigable) que
indica se o usuário poderá, utilizando a tecla Tab, levar o cursor até este item.
No grupo Dados (Data), definimos as características do item em relação aos dados que ele armazenará:
♦ Tipo de Dado (Data Type) – Indica se o dado armazenado é numérico, data, caracter, etc.
♦ Tamanho Máximo (Maximum Length) – Indica o tamanho máximo do dado armazenado no buffer.
♦ Tamanho Fixo (Fixed Length) – Indica que o dado a ser armazenado sempre terá o comprimento igual ao
tamanho máximo. Isto pode ser útil para informações de comprimento fixo como, por exemplo, CEP.
♦ Valor Inicial (Initial Value) – Indica qual o valor do item quando estamos fazendo a inclusão de um novo
registro no buffer. O usuário poderá modificar esse valor quando vier a digitar os dados do registro.
♦ Obrigatório (Required) – Indica que o item deve ser preenchido. Não pode ser omitido em uma inclusão ou
apagado em uma alteração.
♦ Máscara de Formato (Format Mask) – Nesta propriedade podemos determinar uma máscara para formatação
dos itens numéricos e de data.
♦ Mínimo e Máximo Valor Permitido (Lowest / Highest Allowed Value) – Indicam uma restrição relativa aos
valores aceitáveis para o item: o menor e o maior valor permitido.
No grupo Cálculo, poderemos estabelecer um item que seja um somatório ou uma fórmula resultante dos itens de
outro bloco. Esse grupo será estudado nos exercícios.
No grupo Registros, encontramos duas propriedades já vistas em nível de bloco, que agora se individualizam no item:
♦ Distância entre Registros (Distance Between Records) – A presença desta propriedade indica que a distância
entre os registros pode ser diferente de um item para o outro. Alteraremos o valor apenas em cd_mat (para 10)
e observaremos o resultado.
♦ Número de Itens Exibidos (Number of Items Displayed) – Esta informação está preenchida com zero, o que
indica que a quantidade de itens exibidos acompanha a quantidade do bloco. Modificaremos este valor para o
item nm_func (para 1) e observaremos o resultado.
♦ Item do Banco de Dados (Database Item) – Esta propriedade indica se o item em questão pertence ou não à base
de dados. Isto significa que podemos criar um item que não pertence ao banco de dados, mesmo em um Bloco
de Dados (que tem interface direta com o banco de dados). Para que o Form não tente enviar ou receber do
banco de dados um item que não se encontra na tabela ou procedimento correspondente, devemos preencher
esta propriedade com Não, quando este for o caso.
Para efeito de teste, criaremos um novo item neste bloco, não pertencente ao banco de dados e cujo tipo é imagem.
Para tal, posicionaremos o cursor sobre o item vl_sal (que é o último) e usaremos a ferramenta de criação para
adicionar um novo item. Na paleta de propriedades, trocaremos o tipo do item para Imagem e indicaremos que esse
item não está presente no banco de dados. Observe o ícone característico do tipo do item no Navegador de Objetos.
No grupo Banco de Dados, ainda temos:
♦ Nome da Coluna (Column Name) – Indica o nome da coluna no banco de dados. Isto nos dá a liberdade de
nomear o item como quisermos, ou seja, o nome do item não precisa ser idêntico ao nome da coluna no banco
de dados (apesar de visualmente isto ficar mais claro quando estivermos olhando para o Navegador), uma vez
que esta propriedade indica exatamente o nome da coluna no banco de dados.
♦ Somente Consulta (Query Only) – Esta propriedade indica que este item não será atualizado ou alterado nesta
aplicação. Sua informação será apenas vista pelo usuário. Esta propriedade impede que o item seja modificado.
♦ Consulta Permitida (Query Allowed) – Esta propriedade indica que a tempo de Entrar Consulta (Enter-Query),
o usuário poderá estabelecer uma restrição de pesquisa neste item. Só devemos habilitar para pesquisa aqueles
itens em que, realmente, permitimos que os usuários venham a pesquisar. Bloqueie o uso de consulta nos
demais itens. Isto pode trazer modificações significativas na performance.
♦ Tamanho da Consulta (Query Length) – Esta propriedade define que no momento de Entrar Consulta (Enter-
Query) este item pode ter o mesmo tamanho da propriedade Tamanho Máximo (Maximum Length) ou poderá
ser maior. Isto é útil pois sabemos que uma restrição poderia ser preenchida com “> 500”, por exemplo, para o
item Matrícula. Isso precisa de mais espaço que o limite do campo (normalmente com três caracteres).
♦ Consulta Insensível a Maiúsculas/Minúsculas (Case Insensitive Query) – Esta propriedade indica que a tempo
de consulta as colunas alfanuméricas habilitadas para pesquisa poderão ser preenchidas com qualquer valor
(maiúsculo ou minúsculo) que o Forms Runtime encontrará a informação de qualquer forma. Isto significa que
o Form executará a função Upper do lado da coluna e do lado do valor. Por exemplo: Upper(cd_depto) =
Upper(‘e01’). Esse tipo de ação deve ser verificado pois pode trazer conseqüências na performance da aplicação.
Consulte seu DBA a respeito deste uso.
♦ Inserção Permitida (Insert Allowed) – Esta propriedade indica que, quando estivermos criando um novo registro
no buffer, este item estará apto a ser preenchido.
♦ Atualização Permitida (Update Allowed) – Da mesma forma que a anterior, indica que quando houvermos
consultado um item, ou seja, quando não estivermos mais em um novo registro (com estado de New ou Insert),
poderemos modificar o valor deste item.
♦ Atualizar Somente se Null (Update Only if Null) – Já esta propriedade é exclusiva à anterior e indica que somente
poderemos modificar o valor desse item se ele não tiver qualquer valor preenchido (Null).
♦ Bloquear Registro (Lock Record) – Indica que se o item atual for modificado o Form deve, imediatamente, tentar
o bloqueio da linha correspondente no banco de dados. Essa propriedade pode ser útil quando temos um item
no bloco que não pertence ao banco de dados e, no entanto, desejamos que se seu valor for modificado, toda a
linha seja reservada. Para um item associado ao banco de dados, esse bloqueio é automático.
Para efeito de teste, faremos as seguintes modificações nos itens criados em nossa aplicação:
♦ A coluna nm_sobrenome só pode ser consultada (Query Only).
♦ A pesquisa no banco de dados só pode ser feita para as colunas cd_mat, nr_git, nr_cargo e cd_depto (Query Allowed).
O próximo grupo diz respeito às características físicas do elemento, tais como largura, altura, canvas em que será
apresentado, se o item é visível, nome da página Tab (se a canvas for do tipo Tab) e:
♦ Bevel – Esta propriedade caracteriza a borda do objeto, podendo dar uma aparência tridimensional ao item. Só
é aplicável a itens Chart, Custom, Text e canvas do tipo Stack.
♦ Finalizado (Rendered) – Esta propriedade indica se um item que não detém o foco continua conservando os
recursos do sistema. Se a propriedade receber True (default), o item somente precisará se utilizar dos recursos de
apresentação (display) do sistema quando detiver o foco; caso contrário, os recursos são liberados.
♦ Mostrar Barra de Rolagem Vertical (Show Vertical Scroll Bar) – Esta propriedade indica se o item deve ou não
apresentar uma barra de rolagem vertical. Essa propriedade somente faz sentido para itens cujos dados possam
ser apresentados em mais de uma linha (texto) ou imagens.
Os grupos seguintes estão associados à apresentação visual do item: Atributos Visuais (que será estudado em tópico
específico), Cor e Fonte (que testaremos através do Editor de Layout).
O grupo Prompt diz respeito ao texto (label) que aparece ao lado do item para nomeá-lo ou identificá-lo a fim de
facilitar o preenchimento por parte do usuário. Trabalharemos estas características em um item específico ainda
neste mesmo tópico.
O grupo Ajuda possui algumas propriedades interessantes, como veremos a seguir:
♦ Dica (Hint) – Aqui poderemos preencher um texto que indique ao usuário como preencher o item. Essa informação
será apresentada na linha de mensagens quando o usuário navegar para esse item, e se a propriedade Exibir Dica
(a seguir) estiver habilitada.
♦ Exibir Dica Automaticamente (Display Hint Automatically) – Indica se o texto definido na propriedade anterior
deve ser apresentado quando o item ganha o foco.
♦ Dica da Ferramenta (Tooltip) – Corresponde a uma etiqueta flutuante que aparece ao lado do item para indicar
seu nome ou alguma pequena informação que indique seu propósito ao usuário.
Passemos agora às características específicas de cada item para que possamos executar a aplicação.
Para incluirmos um elemento novo no meio da lista, devemos selecionar o elemento imediatamente anterior e pressionar as teclas Ctrl + Shift +
>. Se desejarmos excluir um elemento da lista, devemos nos posicionar sobre o elemento e pressionar as teclas Ctrl + Shift + <.
A última propriedade chamada Mapeamento de Outros Valores (Mapping of Other Values) indica ao Oracle como
deve ser posicionada a lista quando for lido do banco ou atribuído por programação um valor a este item que não
esteja presente na lista de valores.
Se deixarmos esta propriedade sem preenchimento, estamos indicando que não serão admitidos outros valores. Desta forma, a tempo de leitura
do banco de dados, um item com um valor não compatível com a lista é rejeitado, isto é, não é lido para o programa.
Para o exemplo em desenvolvimento, preencheremos da seguinte forma: cd_depto com DIRETORIA (ou seja A00),
nr_cargo ficará sem preenchimento e nr_git receberá 18.
O item In_Sexo deve conter dois botões, um com o nome de Fem e outro com o nome de Masc. Cada botão
representa um valor que o item pode assumir. Nossa coluna no banco de dados só pode assumir os valores F ou M.
Nas propriedades do botão, indicaremos estes valores.
IMAGEM (IMAGE)
O item Imagem criado por nós não pertence ao banco de dados, e portanto quando executarmos a aplicação não
será trazido nenhum valor para preenchê-lo. Nos exercícios encontraremos uma forma de preenchê-los
adequadamente. Por ora, vejamos apenas suas propriedades:
♦ Formato da Imagem (Image Format) – Com esta propriedade podemos determinar o formato no qual a imagem
será armazenada no banco de dados. Os valores válidos são: BMP, CALS, GIF, JFIF, PICT, RAS, TIFF, TPIC.
♦ Profundidade da Imagem (Image Depth) – Aqui especificamos a intensidade ou tonalidade da imagem a ser lida ou
gravada para um arquivo do sistema operacional. Os valores válidos são: Original, Monochrome (monocromática),
Gray (escala de cinzas), LUT (Lookup Table), RGB (Red, Green, Blue – colorida usando padrão RGB).
♦ Qualidade de Compactação (Compression Quality) – Determina se a imagem que está sendo lida de um arquivo
ou que está sendo gravada para um arquivo deve ser compactada e, no caso afirmativo, qual o grau de
compactação. Os valores válidos são: None (nenhum), Minimum (mínimo), Low (baixo), Medium (médio),
High (alto), Maximum (máximo).
♦ Qualidade de Exibição (Display Quality) – Determina a qualidade de exibição de uma imagem. Os valores
válidos são Low (baixo), Medium (médio), High (alto). Quanto melhor a qualidade mais memória e recursos são
necessários à exibição.
♦ Estilo de Dimensionamento (Sizing Style) – Indica o que deve ser feito quando a imagem não cabe no item
definido para ela na canvas. A opção Crop (Recortar) indica que será apresentada uma parte da imagem, ela
aparecerá cortada. A opção Adjust (Ajustar) indica que a imagem será ajustada (sem perder a proporção) ao
tamanho definido para o item na canvas.
Um botão não armazena dados; observe na janela de propriedades que não existem propriedades relativas ao
banco de dados, nem ao grupo de dados. Um botão (ou tecla) tem a finalidade de iniciar uma ação.
Antes de executar a aplicação e testar os valores modificados em cada item, navegue para o editor de layout (tecla
F2) e ajuste (com o mouse) os itens na canvas.
A Figura 7.38 apresenta a execução do programa com o layout já ajustado.
Você observou que nem todos os registros foram lidos nessa execução?
Para corrigir este problema, preencha a propriedade Mapeamento de Outros Valores do item Nr_Cargo com 55 e
do item In_Sexo com M. Execute novamente.
Devemos anexar esse item à nossa aplicação para que façamos uma análise das propriedades. Portanto, selecione o
botão criado anteriormente, crie um novo item e troque seu tipo para Caixa de Seleção.
As principais propriedades do grupo funcional são:
♦ Etiqueta (Label) – Indica o texto a ser apresentado próximo ao item.
♦ Valor Quando Assinalado (Value When Checked) – Esta propriedade indica ao Form para interpretar como
checado (ou assinalado) o valor que informarmos. Isto significa que quando o item receber este valor o usuário
verá a caixa marcada.
♦ Valor Quando não Verificado (Value When Unchecked) – Esta propriedade indica ao Form para interpretar
como não checado (ou não assinalado) o valor que informarmos. Isto significa que quando o item receber este
valor o usuário verá a caixa sem marcação.
♦ Mapeamento de Outros Valores da Caixa de Seleção (Check Box Mapping of Other Values) – Esta propriedade
indica qual deve ser a atitude do Form quando o item receber um valor diferente daqueles definidos nas duas
propriedades acima (seja lendo do banco de dados ou por programação). Os valores válidos para essa propriedade
são: Assinalado (a caixa aparecerá marcada, porém, em memória, o valor não será alterado), Seleção Cancelada
(a caixa aparecerá desmarcada. O valor atribuído a ela não será alterado) e não Permitido (neste caso, o registro
será ignorado a tempo de leitura ou ocorrerá um erro no caso de atribuição).
Preencheremos as propriedades de nosso novo item com:
♦ Etiqueta (Label) – Caixa.
♦ Valor Quando Assinalado (Value When Checked) – ‘S’
♦ Valor Quando não Verificado (Value When Unchecked) – ‘N’
♦ Mapeamento de Outros Valores da Caixa de Seleção (Check Box Mapping of Other Values) – Seleção Cancelada.
Antes de executar, não se esqueça de definir a Canvas (grupo Físico) para o item e verificar se seu tipo de dado é Char com
comprimento 1 (grupo Dados) e, ainda, indicar que esse item não pertence ao banco de dados (grupo Banco de Dados).
DEFININDO PROMPTS
Nosso último teste se refere ao posicionamento do prompt do item.
Para alterarmos o posicionamento e entendermos o resultado, no editor de layout arrastamos o item nm_func para
a parte inferior da canvas e aumentamos seu tamanho (ver Figura 7.39).
Atualmente, suas propriedades são:
♦ Prompt (Prompt) – Nesta propriedade, temos o valor Nome que corresponde ao texto exibido.
♦ Estilo de Exibição do Prompt (Prompt Display Style) – Esta propriedade está preenchida com Primeiro Registro
(First Record), indicando que o prompt só deve ser apresentado no primeiro registro (ver Capítulo 13).
♦ Justificação do Prompt (Prompt Justification) – Aqui indicamos se o prompt será justificado à direita, esquerda,
inicial, final ou centralizado. No nosso caso utilizamos a opção Inicial.
♦ Limite de Conexão do Prompt (Prompt Attachment Edge) – Esta propriedade indica em qual dos quatro lados o
prompt deve ser apresentado. Escolhemos topo, ou seja, acima do item.
♦ Alinhamento do Prompt (Prompt Alignment) – Aqui indica-se como o texto é alinhado em relação à lateral a
que está associado. Escolhemos Centralizado.
♦ Deslocamento de Conexão do Prompt (Prompt Attachment Offset) – Esta propriedade indica a distância entre
o item e seu prompt.
♦ Deslocamento de Alinhamento do Prompt (Prompt Alignment Offset) – Indica o deslocamento do prompt em
relação ao ponto definido para alinhamento.
Para testarmos, faremos as seguintes alterações:
Tabela 7.04
EXERCÍCIOS
Os exercícios deste tópico trabalharão exclusivamente com as propriedades. Portanto, tenha-as à mão para realizá-los.
7.11) Crie uma aplicação com o nome de EX11 baseada na tabela Func. Selecione as colunas cd_mat, nm_func,
cd_depto, dt_nasc, nr_cargo e in_sexo.
Crie uma nova canvas do tipo Conteúdo (Content). Defina os prompts adequados para cada coluna.
O formato do Layout deve ser Form, com a apresentação de 1 (um) registro. O título do quadro deve ser Funcionários.
Apresente uma barra de rolagem.
O formato do Layout deve ser Form, com a apresentação de dois registros. O título do quadro deve ser Projetos.
Apresente uma barra de rolagem.
♦ Criar um bloco de controle que contenha uma coluna que some a quantidade total de pessoas na equipe de
projetos selecionados.
♦ O código do projeto deve ser armazenado sempre em letras maiúsculas, assim como o código do departamento.
♦ O campo Equipe deve ter seu alinhamento pela direita.
♦ Todos os itens desta aplicação devem ter fonte Arial com tamanho 8.
♦ Todos os prompts devem ser definidos em vermelho.
♦ As datas de início e de fim do projeto somente devem ser modificadas se não estiverem preenchidas (Null), e em
caso contrário não devem ser alteradas. O usuário deve, obrigatoriamente, digitar toda a máscara.
♦ Quando o mouse for passado sobre cada campo, deve ser apresentado o nome do item.
♦ A data de início do projeto, se preenchida, deve ser maior que a data atual.
♦ O campo Código do projeto é de preenchimento obrigatório, assim como o código do departamento, o nome
do projeto e o responsável.
7.13) Criar uma aplicação de nome EX13, baseada nas tabelas Depto e Func. Os dados devem ser distribuídos em
duas Pastas: Dados de Departamento na pasta 1 e Dados do Gerente do Departamento (Funcionário) na pasta 2.
O formato do Layout deve ser Form, com a apresentação de 1 (um) registro em cada pasta. Escolha o título de cada
Quadro. Apresente uma barra de rolagem apenas para a pasta de Depto.
♦ Torne invisível a coluna cd_ativ da tabela Ativ e a coluna cd_proj da tabela Proj.
♦ Os itens cd_ativ e cd_proj da tabela PRJATV devem ser de preenchimento obrigatório.
♦ As consultas só podem ser feitas pelos campos cd_ativ e cd_proj.
♦ A tempo de consulta, o campo cd_ativ deve ter seu tamanho ampliado para que seja possível a pesquisa por
strings do tipo >= 80.
♦ Todos os itens dessa aplicação devem ter fonte Arial com tamanho 8.
♦ Todos os prompts devem ser definidos em vermelho.
♦ As datas devem possuir máscara.
♦ Deve-se garantir que, quando um campo for totalmente preenchido, a navegação para o próximo campo seja automática.
♦ Quando cada campo adquirir o foco, deve ser apresentada uma explicação sobre o preenchimento na linha de mensagem.
♦ Deve-se apresentar a quantidade de dias do projeto.
♦ A data de início do projeto deve ter como valor default o dia atual.
♦ Os itens desssa aplicação não devem ser apresentados em formato de terceira dimensão.
7.15) Criar uma aplicação de nome EX15 baseada na tabela Func, contendo os campos cd_mat, nm_func, nr_cargo
e vl_sal.
O formato do bloco deve ser tabular com dez registros na canvas.
♦ Deve ser acrescentado um item nessa canvas (sem repetição) para que o usuário preencha com uma senha
válida no intervalo 123456 a 234567. Essa senha não deve ser visível.
♦ O nome do funcionário deve ser digitado sempre em maiúsculas.
♦ A matrícula é de preenchimento obrigatório.
♦ Retire o quadro dessa aplicação.
♦ Deve-se incluir uma coluna cd_depto manualmente e sem repetição que garanta que toda pesquisa seja feita
apenas para o departamento informado.
♦ Deve-se apresentar sempre o total de salários de cada departamento.
INTRODUÇÃO
Neste tópico, estudaremos a ligação entre a tela (Canvas) e a janela (Window) em que ela é apresentada, os diversos
tipos de canvas e as propriedades desses dois objetos.
Para entendermos a relação entre esses dois elementos, façamos uma comparação com uma pintura. Quando
adquirimos um quadro, reconhecemos a existência de dois elementos: a tela e a moldura. Da mesma forma, no
Form podemos entender a presença desses dois elementos, sendo a Canvas considerada a tela e a Janela (Windows)
considerada a moldura.
Estudaremos, primeiramente, a janela (Window).
JANELAS (WINDOWS)
Quando criamos uma nova aplicação, forma-se, automaticamente, uma janela (Janela1 ou Window1). Veja sua
presença no nó Janelas.
Para que possamos apresentar as diversas telas (canvas) da aplicação, necessitamos montar pelo menos uma janela.
A janela faz a interface com o ambiente Windows.
Ao abrir o diálogo de propriedades de uma janela, você observará que ela possui poucos grupos de propriedades,
sendo o de maior interesse as propriedades do grupo Funcional, o qual estudaremos mais detalhadamente a seguir.
O bloco Bloco26 foi criado após o bloco Func. A Canvas23 está posicionada na frente da Canvas2 dentro da
seqüência do navegador. Ao executarmos a aplicação, no entanto, veremos que a primeira canvas a ser apresentada
é a Canvas2, pois contém o primeiro elemento a receber o foco (cd_mat do bloco Func).
Modificaremos esta seqüência ao posicionarmos o bloco Bloco26 antes do bloco Func e a Canvas23 depois da Canvas2.
Ao executarmos a aplicação, verificamos que a Canvas23 é apresentada em primeiro lugar, pois o foco é recebido
pelo elemento presente no bloco Bloco26.
Como último teste, preencha a Canvas Principal (Primary Canvas) com o valor Canvas2 e execute novamente a
aplicação. Não haverá mudança de resultado, ou seja, a Canvas23 é mostrada primeiro.
Concluímos, então, que a seqüência de navegação é definida pelos blocos e itens. Um elemento que detém o foco
nunca fica escondido, ele sempre é apresentado, forçando o aparecimento da canvas onde ele está “espetado”.
♦ Canvas da Barra de Rolagem Horizontal (Horizontal Toolbar Canvas) – Uma barra de ferramentas corresponde
a uma canvas contendo elementos, mas principalmente botões, que efetuam ações sobre os itens apresentados
na canvas principal. Nesta propriedade, informamos qual o nome da canvas (do tipo Barra de Ferramentas – não
é Rolagem – Horizontal) que será apresentada nesta janela. Mesmo que criemos na aplicação uma canvas deste
tipo, se essa propriedade não for preenchida ela não será apresentada.
Esta propriedade foi traduzida incorretamente. Seu nome deveria ser similar à propriedade seguinte, ou seja, Canvas da Barra de Ferramentas
Horizontal e não Canvas da Barra de Rolagem Horizontal.
♦ Canvas da Barra de Ferramentas Vertical (Vertical Toolbar Canvas) – Nesta propriedade, informamos qual o
nome da canvas (do tipo Barra de Ferramentas Vertical) que será apresentada nessa janela. Esta propriedade
deve ser preenchida para que a canvas seja apresentada (não é automático).
♦ Estilo da Janela (Window Style) – Esta propriedade possui duas opções: Documento (Document) e Caixa de
Diálogo (Dialog). Indica se a janela atual será apresentada dentro da janela do Runtime ou se ficará solta.
Nosso primeiro teste será executar a aplicação atual com o estilo documento. Tente tirar a janela da nossa aplicação
de dentro da janela do Runtime. No estilo documento esta ação não é possível.
Alteraremos o valor da propriedade Estilo da Janela para Caixa de Diálogo (Dialog) e novamente executaremos a aplicação.
Observe na Figura 7.43 que a janela da nossa aplicação fica solta sobre a janela do Forms Runtime.
♦ Modal (Modal) – Esta propriedade indica se a janela atual pode ou não perder o foco. Quando indicamos que
uma janela é Modal, o Form impede que o usuário navegue para outra janela sem fechar a janela atual. Esta
opção é muito utilizada para a apresentação de mensagens ou informações de ajuda.
Se você preencher esta propriedade com Sim e o estilo da janela com Caixa de Diálogo, a tempo de execução não
será possível a navegação para a janela do Forms Runtime. Uma vez que os controles de término (botões e menu)
estão presentes na janela do Runtime, há necessidade de abortar a aplicação.
♦ Ocultar na Saída (Hide on Exit) – Esta propriedade determina que, se o foco for movido para um item apresentado
em outra janela, a janela atual deve ser posicionada atrás da janela que tem o item que deterá o foco. Caso essa
propriedade esteja preenchida com Não, esta ação só ocorrerá se o item que receberá o foco estiver escondido
atrás da janela atual. Se ele estiver visível, a janela atual continua na frente das demais.
♦ Fechamento Permitido (Close Allowed) – Indica se o ícone ( X ) de fechamento da janela pode ser utilizado pelo
usuário. Preencha o valor desta propriedade com Não e execute a aplicação. Observe que o ícone ( X ) da janela
aparece desabilitado.
Esta propriedade, quando habilitada, não fecha a aplicação a menos que tenhamos programado (When-Window-
Closed) esta ação. Isto significa que a aplicação recebe a indicação de que o usuário tentou fechar a janela, mas
como não existe nenhuma ação automática, nada acontece.
Caso o usuário tente fechar a janela do Forms Runtime, o próprio Form determina o fechamento da aplicação
subordinada executando um comando Do_key(‘exit_form’).
♦ Movimentação Permitida (Move Allowed) – Esta propriedade determina se o usuário poderá ou não movimentar
a janela da aplicação. A movimentação é obtida ao pressionarmos o botão esquerdo do mouse sobre a parte azul
da janela e movimentarmos o mouse sem soltar o botão. Teste!
♦ Redimensionamento Permitido (Resize Allowed) – Esta propriedade define se o usuário poderá ou não aumentar
(ou diminuir) o tamanho da janela. Esta modificação de tamanho é obtida quando posicionamos o mouse
sobre uma das laterais da janela e aparece um símbolo (↔) indicativo da elasticidade. A maximização ou
minimização é permitida independentemente do valor desta propriedade.
♦ Maximização Permitida (Maximize Allowed) – Esta propriedade indica se a janela da aplicação poderá ser maximizada.
♦ Minimização Permitida (Minimize Allowed) – Esta propriedade indica se a janela da aplicação poderá ser minimizada.
♦ Título Minimizado (Minimized Title) – Informamos aqui o texto a ser apresentado quando a janela é minimizada.
♦ Nome do Arquivo de Ícones (Icon Filename) – Indica o ícone a ser usado quando a janela é minimizada.
♦ Herdar Menu (Inherit Menu) – Indica se a janela atual deve apresentar o Menu associado à aplicação.
Em nossa aplicação de teste não será possível minimizar, nem redimensionar, nem movimentar, apenas maximizar.
Nossa janela será do tipo documento e não modal, ou seja, modeless. Execute a aplicação com estas especificações.
Passaremos agora às canvas.
CANVAS
Já sabemos que uma canvas corresponde à tela de um quadro. Neste item ampliaremos um pouco mais os nossos
conhecimentos a respeito das características das canvas.
Em uma mesma janela podem ser apresentadas diversas canvas simultaneamente, porém apenas uma delas pode
ser de conteúdo (Content), pois esta é a canvas principal da janela.
Na Figura 7.44 apresentamos a simultaneidade permitida.
Podemos apresentar simultaneamente em uma janela (Window):
♦ Uma canvas do tipo Conteúdo (Content).
♦ Uma canvas do tipo Barra de Ferramentas Horizontal (Horizontal Toolbar).
♦ Uma canvas do tipo Barra de Ferramentas Vertical (Vertical Toolbar).
♦ Várias canvas do tipo Empilhado (Stack).
A propriedade que determina o tipo da canvas (Canvas Type) está presente no grupo Geral.
A Figura 7.45 mostra o trecho da canvas tornado visível pelo posicionamento do viewport.
Para que ela fique visível, devemos preencher a propriedade Canvas da Barra de Ferramentas Horizontal (Horizon-
tal Toolbar Canvas) da janela (window) com o nome dessa nova canvas.
A propriedade Altura da Canvas Barra será alterada para 20 (não se esqueça de movimentar o botão para dentro da canvas).
Na Figura 7.46 verificamos o resultado final do teste.
Normalmente, uma canvas do tipo Empilhado não é visível logo que a aplicação mostra a canvas de Conteúdo. De
acordo com ações do usuário, ela é acionada por programação. É desta forma que passaremos a utilizá-la nos exercícios.
EXERCÍCIOS
7.16) Crie uma aplicação de nome EX16 baseada na aplicação EX11. Inclua a seguinte funcionalidade:
♦ Inclua no bloco Controle seis botões com os nomes próximo, anterior, primeiro, último, rolar_acima, rolar_abaixo,
que devem ser apresentados na barra de ferramentas vertical.
♦ Inclua no bloco de Controle seis botões com os nomes: salvar, sair, consultar, incluir, remover e limpar, que
devem ser apresentados na barra de ferramentas horizontal.
♦ Todos os botões devem apresentar ícones e indicadores das ações a serem efetuadas.
♦ Dê cores diferenciadas a cada uma das canvas.
♦ O usuário poderá minimizar e maximizar a janela desta aplicação, porém não poderá redimensionar, fechar ou
movimentá-la.
♦ Devem ser especificados ícone e título para a janela minimizada.
Esse exercício é semelhante aos anteriores, com a intenção de reforçarmos a localização das propriedades.
INTRODUÇÃO
Como primeiro passo, removeremos a canvas Tab para utilizarmos inicialmente apenas a canvas de Conteúdo.
Para que a imagem e o botão voltem a aparecer, preencha novamente a propriedade Canvas (grupo Funcional) de
cada um deles.
QUADRO (FRAME)
Ao expandirmos o nó Gráficos, subordinado à canvas Canvas2, verificaremos a existência de um objeto chamado
Frame5 (na sua aplicação o nome pode ser diferente) que se constitui de um objeto exclusivamente gráfico para
apresentação de informações em uma canvas.
Iniciaremos nosso estudo avaliando algumas propriedades desse objeto.
O grupo Quadro de Layout (Layout Frame) possui algumas propriedades já comentadas anteriormente, mas que
adquirem aspectos particulares nesse objeto.
♦ Bloco de Dados de Layout (Layout Data Block) – Quando esta propriedade possui o valor preenchido com o nome
de um bloco de dados e a propriedade Atualizar Layout (Update Layout) estiver com o valor Automaticamente
(Automatic), qualquer modificação que fizermos nas propriedades do Frame são refletidas nas propriedades do
bloco, do item, etc. Os outros elementos herdam as características que estabelecermos aqui.
♦ Atualizar Layout (Update Layout) – Indica se as modificações que efetuarmos para os elementos, para as
propriedades do quadro, etc. serão refletidas automaticamente. Caso esta propriedade esteja preenchida com o
valor Manualmente, devemos pressionar o botão Atualizar da barra de ferramentas superior do editor de layout
para que elas sejam refletidas. A opção Bloqueado impede a atualização.
♦ Estilo de Layout (Layout Style) – Indica a forma de organização dos elementos. Se a atualização estiver automática
(propriedade Atualizar Layout), os objetos são reorganizados cada vez que aumentarmos ou diminuirmos o
tamanho do quadro.
Para testarmos essas três propriedades, preencheremos a primeira (Bloco de Dados de Layout) com Func, a segunda
(Atualizar Layout) com Automaticamente e a terceira (Estilo de Layout) com Tabular.
Ao abrirmos o editor de Layout (F2) já teremos uma surpresa. Os itens do bloco Func foram todos alinhados
horizontalmente, na ordem do navegador e todos com a mesma quantidade de ocorrências. Verifique que as
propriedades dos itens foram modificadas.
Outra forma de verificarmos este comportamento é alterarmos o tamanho do Frame no editor de Layout. Podemos
diminuir (ou aumentar) o tamanho do quadro. Para realizarmos esta operação, devemos clicar sobre a linha do
quadro para que sejam mostrados os indicadores de limites (quadrados nos centros das linhas). Ao clicarmos e
arrastarmos o mouse sobre um destes indicadores, alteraremos o tamanho do quadro. Tente!
♦ Preenchimento Vertical (Vertical Fill) – Esta propriedade indica se o Form Builder deve ou não colocar o maior
número possível de objetos por linha. Se essa propriedade estiver preenchida com Sim, a propriedade que
determina o número máximo de objetos por linha é ignorada.
Para obtermos o resultado da Figura 7.49, preenchemos as propriedade de Deslocamento Horizontal e Vertical com
10, Expansão com Sim, ShrinkWrap com Sim e Preenchimento Vertical com Não, em seguida, usando o Editor de
Layout, alteramos horizontalmente o tamanho do Quadro. Faça outros testes modificando o valor dessas propriedades.
A seguir, temos propriedades relativas aos prompts dos itens definidos neste quadro, que serão exploradas nos
exercícios. Da mesma forma, as propriedades relativas ao título devem ser verificadas (Capítulo 13) para que
possamos testá-las adequadamente nos exercícios.
A presença de um quadro não é obrigatória na Canvas. Para efetuarmos os demais testes com mais liberdade,
removeremos o quadro (frame).
WORKSPACE
É a área de janela do Layout, ou seja, a área disponível para desenho. Seu tamanho é independente do tamanho
atual da janela, isto é, o Workspace pode ser maior ou menor que a área da janela.
Quando o Workspace é maior que a janela, podemos rolar a janela para ver outras partes do Workspace.
Para alterar o tamanho do Workspace, devemos selecionar no menu Formato (Format) o submenu Opções de
Layout (Layout Settings) e neste a opção Layout.
O diálogo apresentado permitirá que determinemos o tamanho do Workspace (em centímetros ou polegadas) e
ainda que façamos a definição da ordem de impressão (Vertical ou Horizontal) se escolhermos a opção Imprimir
(Print) do menu Arquivo (File).
RÉGUAS (RULERS)
Uma régua horizontal (em cima) e uma vertical (lateral esquerda). Esta régua pode ser apresentada em unidades
diferentes (por exemplo, centímetros, caracteres, pés, etc.), de acordo com a unidade em vigor no Form.
GUIAS
Podem ser selecionadas guias (tracejadas) horizontais e verticais para referência. Para selecionarmos uma guia,
basta que posicionemos o mouse sobre uma das réguas e pressionemos e arrastemos até a posição desejada para
apresentação da guia.
GRID
Existe uma grade dentro do Workspace para auxílio no posicionamento de objetos. Se desejarmos visualizar essa grade,
devemos esconder a visibilidade da canvas. Usar o menu Visualizar (View), opção Mostrar Canvas (Show Canvas).
Se você testar essa opção e a grade não aparecer, não se assuste. Isto às vezes ocorre quando a distância entre as
linhas da grade é tão grande que dá a impressão de não ter grade. Para teste, selecione no menu Formato, Opções
de Layout, o item Régua (será apresentado um diálogo que permitirá o espaçamento).
AS BARRAS DE FERRAMENTAS
Ao olharmos para a tela do Layout Editor, observamos a presença de duas barras de Ferramentas Superiores e uma
Vertical, na lateral esquerda. Começaremos nosso estudo por elas.
Em seguida, temos os botões que afetam as características das letras B (Bold – Negrito), I (Italic – Itálico), U (Under-
line – Sublinhado).
A Figura 7.50 mostra os prompts de departamento e ramal em negrito e itálico, de cargo e grau de instrução
sublinhados e de data de nascimento e do botão masculino do grupo de opções em itálico.
Os botões seguintes aumentam ou diminuem o nível de zoom. A indicação do nível atual se acha presente no
rodapé da tela de layout. Cada vez que pressionamos o botão Ampliar ( + ), o nível de zoom é duplicado. Da mesma
forma, cada vez que pressionamos o botão Reduzir ( - ), o nível de zoom é dividido por dois.
O grupo de botões a seguir realiza alinhamento de elementos uns em relação aos outros. Os três primeiros realizam
o alinhamento horizontal e os três seguintes, o alinhamento em relação ao eixo Y (vertical).
Para realizarmos esse alinhamento, devemos selecionar simultaneamente (clique com o mouse e, ao mesmo tempo,
o botão Ctrl pressionado) os itens para os quais desejamos realizar o alinhamento (os quais devem estar posicionados
verticalmente uns acima dos outros) e pressionar um dos botões de alinhamento (esquerda, central ou direita).
Para realizarmos o alinhamento horizontal, os itens selecionados devem estar lado a lado; caso contrário, serão
posicionados uns sobre os outros.
Na Figura 7.51 trocamos a letra e tamanho do prompt de todos os itens para Arial tamanho 10. Alinhamos
verticalmente cada grupo: o grupo à esquerda foi alinhado pela direita, o grupo do meio foi alinhado centralmente
e o grupo à direita foi alinhado pela esquerda. Observe as guias colocadas em cada grupo. Horizontalmente alinhamos
cada três elementos, um de cada grupo, sempre pelo topo. Para que o quadro não viesse a modificar a operação
desejada, alteramos a propriedade Atualizar Layout para Bloqueado. Tente, então, montar este resultado!
O layout do Form é construído em duas camadas (Layers) principais. A primeira camada é a camada de itens. A
segunda camada é a de objetos gráficos.
Os itens podem ser sobrepostos entre si, assim como os objetos gráficos, porém um objeto gráfico não fica sobre
um item. Um item sempre tem precedência.
Os dois botões seguintes desta barra de ferramentas possuem as ações de trazer para frente e enviar para trás e se
aplicam a objetos gráficos. Serão explorados após definirmos as características desses objetos.
O último botão chama-se Prompt Associado e tem a função de associar um texto (boilerplate de texto) a um item. O texto
atualizará a propriedade prompt do item, estabelecendo a associação entre eles. Esta característica pode nos auxiliar
quando tivermos definido um label para um item usando um boilerplate e, posteriormente, desejarmos que o boilerplate
de texto torne-se o Prompt do item. Também o estudaremos após conhecermos os objetos gráficos do layout.
O primeiro grupo contém botões que se aplicam a diversos tipos de objetos, são gerais para os diversos elementos
presentes nas canvas:
♦ Selecionar (Select) – Seleciona um objeto ou grupo de objetos. Basta que efetuemos um clique sobre o objeto desejado.
♦ Girar (Rotate) – Gira os objetos (gráficos, itens não podem ser rodados). Para girarmos um elemento, devemos
selecioná-lo, clicar na ferramenta e, com o mouse, pressionar um dos indicadores de tamanho (presentes nos
cantos do objeto) e, sem soltar o botão esquerdo do mouse, rodar.
♦ Ampliar (Magnify) – Aumenta ou reduz a apresentação do Layout (fator - 2x), isto é, zoom. Para obtermos este
efeito, devemos clicar sobre o botão e em seguida sobre a canvas. O efeito inverso é obtido com os mesmos
movimentos, porém a tecla Ctrl (ou Shift) deve estar pressionada simultaneamente.
♦ Reformar (Reshape) – Permite que se modifique um objeto (gráfico) selecionado (por exemplo, ângulo de um
arco). Para efetuarmos um teste com esta ferramenta, devemos criar um objeto do tipo Arco (selecione-o na
paleta de ferramentas e faça um arco). Com esse objeto selecionado pressione o botão Reformar. Você perceberá
que apenas dois pontos ficam indicados no elemento. Utilize o mouse para arrastar um desses pontos e modificar
o ângulo do arco.
O segundo grupo de botões é composto de ferramentas gráficas, ou seja, ferramentas para a criação de elementos
gráficos, também chamados de boilerplates gráficos. Neste grupo se encontram as ferramentas:
apresentará uma lista de grupos para que façamos uma seleção entre os existentes (ou optemos pela criação de
um novo).
♦ Item de Texto (Text Item) – Cria itens do tipo Texto (Text).
♦ Item de Imagem (Image Item) – Cria um item do tipo imagem (Image).
♦ Item de Gráfico (Chart Item) – Cria um item do tipo gráfico (Chart) desenhado no Oracle Graphics.
♦ Recipiente OLE (OLE2 Object) – Cria um item do tipo OLE2 para interface com outras aplicações do ambiente
Windows.
♦ ActiveX Control (ActiveX Control) – Cria um item do tipo Controle X Ativo (ActiveX) para interface com um
objeto OCX do ambiente Windows.
♦ Área Bean (Bean Area) – Cria uma área que identifica uma Java Bean e fornece um controle para este item, ou
seja, faz interface com um controle em um componente Java.
♦ Item de Exibição (Display Item) – Cria um item do tipo Exibição (Display).
♦ Item de Lista (List Item) – Cria um item do tipo Lista (List).
♦ Item de Som (Sound) – Cria um item do tipo Som (Sound).
♦ Árvore Hierárquica (Hierarchical Tree Item) – Cria um item que apresenta as informações com a forma de uma
árvore hierárquica. Similar ao Navegador do próprio Form Builder.
Neste conjunto ainda existem dois botões referentes à criação da canvas Tab (Tab) e da canvas Empilhado (Stack).
A vantagem da definição da canvas diretamente no Layout é que podemos definir, visualmente, seu posicionamento
sobre uma canvas de Conteúdo (Content).
♦ Canvas de Guia (Canvas Tab) – Cria uma canvas do tipo Tab (Pasta) e permite seu posicionamento sobre a
canvas Content desejada.
♦ Canvas Empilhado (Canvas Stack) – Cria uma canvas do tipo Empilhado (Stack) e permite seu posicionamento
sobre a canvas Content desejada.
O último grupo de botões contém o que chamamos de paleta de atributos visuais, pois os botões presentes nessa
paleta têm a finalidade de atribuir cor aos objetos (itens e boilerplates).
C) Padrões (Patterns) – Exibe a janela de textura quando desejamos que o objeto possua duas cores de
preenchimento simultaneamente (Foreground Color e Background Color).
D) Tirar Paleta (Tear Off Palette) – Fixa a janela de cores para movimentação.
Não podemos criar itens transparentes. A opção No Fill é válida apenas para objetos gráficos e de texto. Se desejarmos que
um item torne-se transparente, isto é, que visualizemos apenas seu contéudo (texto), devemos preencher a propriedade
Bevel (Formato Bevel) com Nenhum (None) e colocar sua cor de preenchimento igual à da Canvas onde o objeto se acha.
♦ Cor de Linha (Line Color) – Indica as características da linha que envolve o objeto (borda). Pode ser preenchido
com um dos seguintes valores:
A) Uma cor do conjunto – A linha terá esta cor de preenchimento.
B) Nenhuma Linha (No line) – O objeto não terá borda visível.
C) Tirar Paleta (Tear Off Palette) – Fixa a janela de cores para movimentação.
Não podemos especificar cor de linha para itens. Esta opção é válida apenas para objetos gráficos e objetos de texto.
♦ Cor de Texto (Text Color) – Indica a cor do texto. Podemos escolher uma das opções a seguir:
A) Uma cor do conjunto – O texto terá a cor selecionada.
B) Tirar Paleta (Tear off Palette) – Fixa a janela de cores para movimentação.
A informação de cor de cada objeto é armazenada com um índice para localização de cor na paleta. Se alterarmos a paleta, como conseqüência,
teremos a modificação involuntária da cor do objeto.
REDIMENSIONAR A CANVAS
O redimensionamento é feito com o cursor. Clicando-se no canto inferior direito da canvas e arrastando-se o
mouse até a posição desejada, podemos modificar seu tamanho.
MOVER O VIEWPORT
Para mover o viewport, usamos o mouse ou o teclado (teclas de setas para direita, para esquerda, para cima ou para baixo).
Esta opção irá alterar as coordenadas do viewport, que podem ser verificadas no conjunto de propriedades da canvas.
POSICIONAR UMA CANVAS DO TIPO EMPILHADO OU DO TIPO TAB SOBRE UMA CANVAS DE CONTEÚDO
Podemos visualizar uma canvas do tipo Empilhado sobre uma canvas de Conteúdo a fim de, mais facilmente,
determinarmos seu tamanho e posição.
Para tal, devemos abrir o editor de Layout com a canvas de Conteúdo e, no menu Visualizar (View), escolher a
opção Views Sobrepostas (Stacked Views). Será, então, apresentado um diálogo contendo uma lista de canvas do
tipo Tab ou Empilhado (Stack) definidas em sua aplicação.
Para apresentarmos uma dessas canvas, devemos clicar sobre ela (ficará em azul) e apertar o botão OK. O Layout
será novamente mostrado com a Canvas apresentada sobre a outra.
Para escondermos novamente esta Canvas devemos abrir o diálogo anterior novamente (opção Views Sobrepostas
do menu Visualizar). Será apresentada uma lista com a canvas em questão marcada (azul). Para desmarcá-la, devemos
pressionar a tecla Ctrl e clicar sobre a linha contendo o nome da canvas. Em seguida, apertar o botão OK. O Layout
será novamente mostrado sem a canvas apresentada sobre a outra.
Se desejarmos efetuar seu dimensionamento, devemos selecioná-la (canto esquerdo inferior) para que sejam
apresentados os indicadores de tamanho e possamos dimensioná-la adequadamente. Uma maneira mais fácil de
identificarmos o posicionamento dessa canvas é, antes de iniciar esse processo, pintá-la de outra cor para sua
visualização ser total.
A movimentação requer que a canvas esteja selecionada. Utilize o teclado (seta para cima, seta para baixo, seta para
direita e seta para esquerda) ou o mouse sobre os quadradinhos que aparecem em volta da canvas.
CRIANDO ITENS
Para criarmos um novo item, devemos cumprir os seguintes passos:
♦ Selecionar o bloco onde o item será criado (Barra de Ferramentas Horizontal Superior).
♦ Na paleta de ferramentas, selecionar a ferramenta para o tipo de item que desejamos criar.
♦ Posicionar o cursor na canvas onde desejamos que o canto esquerdo superior do item seja posicionado.
♦ Pressionar o mouse uma vez para criação de itens no tamanho default (de acordo com a fonte selecionada) ou
pressionar e arrastar o mouse até o desenho atingir o tamanho desejado.
O Form Builder vai associar o novo item ao bloco corrente. Se esse bloco for do tipo multi-record, mostrará n
desenhos do item, um para cada registro do bloco.
MOVER ITENS
Para mover um item, usamos o mouse. Esta opção irá alterar as coordenadas do item, que podem ser verificadas no
conjunto de propriedades do item selecionado.
Neste diálogo, poderemos dimensionar os objetos selecionados pelo maior, pelo menor, pela média ou atribuir um
valor específico.
Esse valor pode ser fornecido nas unidades: polegadas, centímetros, pontos ou caracteres.
Posteriormente, podemos reutilizar as opções definidas sem necessidade de reabrir o diálogo usando a opção
Repetir Dimensionamento (Repeat Sizing) do mesmo menu Organizar (Arrange).
As opções de alinhamento dependem da direção horizontal ou vertical. Algumas dessas opções já foram vistas nos
botões da Barra de Ferramentas Horizontal Inferior.
Horizontalmente, temos: esquerda, direita, centralizar, distribuir (espaços entre objetos horizontalmente iguais) e
pilha (objetos colados lateralmente uns nos outros).
Verticalmente, temos: no topo, na base, centralizar, distribuir (espaços entre objetos verticalmente iguais) e pilha
(objetos colados verticalmente uns nos outros).
O alinhamento também pode ser repetido com a opção Repetir Alinhamento (Repeat Alignment) do menu
Organizar (Arrange).
BOILERPLATE GRÁFICO
Para adicionarmos um boilerplate gráfico a uma canvas, usamos as ferramentas adequadas da paleta de ferramentas.
O modo de criação é semelhante ao visto anteriormente para Boilerplate de Texto, Itens, etc.
MODIFICANDO A LINHA
Existem cinco opções para customização de linha:
♦ Largura da Linha (Line Width) – Apresenta um conjunto de opções de espessuras de linha. Não podemos
determinar espessura de linha para itens. Esta opção é válida apenas para objetos gráficos ou de texto.
♦ Bevel (Bevel) – Apresenta um conjunto de opções de relevo para linha. Esta opção também não é aplicável a
itens (pelo menos no que se refere ao tipo). Podemos apenas indicar o uso de Bevel ou não. O conjunto de
opções é válido para objetos gráficos ou de texto.
♦ Traço (Dash) – Apresenta um conjunto de tipos de linhas (tracejado, pontilhado, contínua, etc.).
♦ Setas (Arrow) – Apresenta opções para inclusão de setas nas linhas.
♦ Borda – Apresenta a possibilidade de apresentarmos ou escondermos qualquer um dos quatro lados da borda de
um elemento.
ALINHAMENTO E ESPACEJAMENTO
O alinhamento e espacejamento dos textos dos itens podem ser feitos com as opções Espacejamento de Texto
(Spacing) e Justificar (Alignment).
O espacejamento diz respeito ao espaço interno entre linhas de um objeto. Facilmente visível quando um boilerplate
de texto ocupa mais de uma linha.
OPERAÇÕES
As seguintes operações podem ser feitas com objetos (itens e boilerplates):
♦ Movimentação – Pode ser feita diretamente com o cursor.
♦ Redimensionamento – Pode ser feito diretamente com o cursor.
♦ Recorte – Após a seleção, devemos escolher a opção Recortar (Cut) ou Copiar (Copy) do menu Editar (Edit).
♦ Colagem – Selecionar a opção Colar (Paste) do menu Editar (Edit).
♦ Exclusão – Usar a opção Limpar (Clear) do menu Editar (Edit) ou apertar a tecla Delete.
♦ Duplicação – Após a seleção, usar a opção Duplicar (Duplicate) do menu Editar (Edit).
Quando duplicamos um item no mesmo bloco, o Form Builder associa um novo nome a esse item, uma vez que os
nomes devem ser únicos dentro de um bloco.
Quando duplicamos um item, todos os triggers (veremos no próximo tópico) associados a ele são duplicados também.
EXERCÍCIOS
Neste conjunto de exercícios, utilizaremos a paleta de propriedades apenas para as propriedades referentes aos
quadros; as demais características você deverá customizar diretamente no editor de Layout.
7.21) Crie uma aplicação de nome EX21 a partir da aplicação EX16. Inclua a seguinte funcionalidade:
♦ Estabelecer uma distância entre a linha do quadro e cada objeto de 5 pontos, tanto na vertical quanto na horizontal.
♦ A distância interna entre os objetos deve ser de 3.
♦ No máximo devem ser colocados três objetos em cada linha.
♦ O título do quadro deve ser posicionado no centro do quadro (horizontalmente).
♦ A distância entre os prompts dos objetos e os próprios objetos deve ser de 5 pontos.
♦ Altere o título do quadro usando o editor de Layout.
♦ Todos os prompts dos itens devem ser vermelhos.
♦ Coloque os objetos com cor de fundo amarela.
♦ Altere o tipo da letra dos objetos para Arial com tamanho 9.
7.22) Crie uma aplicação de nome EX22 a partir da aplicação EX17. Inclua a seguinte funcionalidade:
♦ Ajustar o tamanho do quadro aos objetos.
♦ Alinhar o prompt pela parte inferior do objeto.
♦ Deslocar o prompt lateralmente em relação ao objeto em 5 pontos.
♦ Alinhar o título do quadro pela direita com um distanciamento da vertical de 15 pontos.
CONCEITUANDO EVENTOS
A partir deste tópico iniciaremos a parte de programação, propriamente dita, de uma aplicação Forms.
Uma aplicação Form é sensível a eventos ou orientada a eventos. Isto significa que, quando determinadas situações
ocorrem, a aplicação recebe uma indicação e pode efetuar uma ação.
Por exemplo, suponhamos que o usuário tenha pressionado o mouse sobre um item do tipo botão. A aplicação
recebe uma indicação de que esta situação (evento) ocorreu e pode ou não realizar uma ação.
Para usarmos a nomenclatura da ferramenta, diremos que um trigger é ativado pelo Form em resposta a um evento.
Os nomes dos gatilhos (triggers) correspondem aos eventos. É o nome que estabelece a associação entre o evento
e o código do trigger.
Destas três afirmativas concluímos que, quando um evento ocorre, o Form verifica se adicionamos algum código de
PL/SQL a esse evento (ou seja, a um trigger). Caso isto tenha ocorrido, ele executa o código que tivermos definido.
Neste tópico estaremos estudando a quais eventos o Form é sensível e como podemos adicionar funcionalidade,
ou seja, lógica (código PL/SQL) a este momento especial.
Todos os exercícios que desenvolvermos a partir deste ponto utilizarão gatilhos (triggers) a fim de que tenhamos o
máximo de intimidade possível com esta característica da ferramenta.
ITEM
Um trigger definido em nível de item, isto é, associado a um determinado item, só é acionado se o evento ocorrer
enquanto o foco estiver exatamente no item escolhido.
BLOCO
Um trigger definido em nível de bloco, isto é, associado a um determinado bloco, só é acionado se o evento ocorrer
enquanto o foco estiver em algum dos itens ou em algum dos registros do bloco escolhido.
MÓDULO
Um trigger definido em nível de módulo é o mais abrangente. O trigger será acionado se o evento ocorrer enquanto
o foco estiver em qualquer dos itens, registros ou blocos da aplicação (módulo).
ORDEM DE EXECUÇÃO
Quando definimos o mesmo trigger em diferentes níveis, normalmente o Form define que o trigger de nível mais
baixo, ou seja, aquele mais específico, seja acionado.
Suponhamos que tivéssemos definido um mesmo trigger para o item cd_mat e para o bloco Func. Se o evento
ocorresse enquanto o foco estivesse sobre o item cd_mat, o trigger acionado seria aquele definido em nível de
item, porém, se o evento ocorresse enquanto o foco estivesse em qualquer outro item do bloco Func, o evento
acionado seria aquele definido em nível de bloco.
Esta é a forma normal de ação da ferramenta. Podemos, no entanto, desejar que, quando o evento ocorrer no item
cd_mat, ambos os gatilhos (triggers) (em nível de item e de bloco) sejam acionados. Esta opção é uma das propriedades
que poderemos definir para um trigger (hierarquia de execução).
RESTRIÇÕES
Alguns gatilhos (triggers) somente podem ser definidos em um nível específico, ou seja, não podemos criar sua
definição em todos os três níveis.
Para que não haja dúvidas e erros de definição, o Form não disponibiliza todos os gatilhos (triggers) em todos os
níveis. Quando criamos um trigger, escolhemos de uma lista predefinida a cujo evento faremos referência. Na lista
apresentada, somente os eventos válidos para o nível particular são mostrados.
Na Figura 7.60 encontramos uma imagem do Navegador de Objetos (Object Navigator) contendo três gatilhos
(triggers) criados nos três níveis disponíveis: When-New-Form-Instance (em nível de módulo), When-Validate-
Record (em nível de bloco – Func) e When-Validate-Item (em nível de item – cd_mat).
Para a criação de um gatilho (trigger), devemos realizar as etapas a seguir:
♦ Como primeiro passo selecionamos o nó onde desejamos criar o gatilho.
♦ Como segundo passo podemos:
A) Pressionar o botão direito do mouse e escolher um evento da opção Gatilhos Inteligentes (Smart Triggers), a
qual apresenta uma lista reduzida contendo os eventos mais usados para o nível e tipo de elemento escolhido,
ou seja, uma lista sensível ao contexto.
B) Pressionar a tecla Criar (Create) da barra de ferramentas do Navegador, que apresentará um diálogo contendo
toda a lista de eventos disponíveis para o nível definido; também é uma lista sensível ao contexto.
♦ Nosso próximo passo será a definição do texto de PL/SQL associado ao gatilho, pois que o editor de PL/SQL será
acionado neste momento.
Se você seguir os passos descritos acima, a janela do editor de PL/SQL será mostrada para que seja definido o
código adequado.
O EDITOR DE PL/SQL
A janela do editor nos apresenta algumas informações a respeito do código de PL/SQL em definição.
Na parte superior encontramos um conjunto de botões com as seguintes funcionalidades:
♦ Compilar (Compile) – Aciona a execução do compilador PL/SQL para o código.
♦ Reverter (Revert) – Desfaz todas as modificações realizadas desde a última salva ou compilação bem-sucedida
(que realiza uma salva).
♦ Novo (New) – Cria um novo gatilho (trigger) com o mesmo escopo do atual. Um diálogo contendo a lista de
eventos é apresentado.
♦ Deletar (Delete) – Remove o gatilho atual.
INDENTAÇÃO AUTOMÁTICA
Observe que a cada linha digitada o posicionamento do cursor na linha subseqüente acompanha a indentação da
linha que lhe é superior. Digite o seguinte trecho de programa e avalie o resultado da digitação.
INDENTAÇÃO MANUAL
Para indentação manual contamos com as opções Endentar e Endentar Invertido do menu Editar (se usarmos o
mouse) e com as teclas Tab e Shift + Tab, respectivamente, se usarmos o teclado.
CORES
No texto digitado, pudemos observar que houve variação no colorido das informações. As palavras-chaves,
comentários, constantes strings e numéricas, os símbolos de atribuição ( := ) e de concatenação ( || ) são destacados
com cores diferentes que os identificam facilitando a localização das informações.
SELEÇÃO
Podemos selecionar tanto linhas de texto quanto colunas.
Para selecionar uma linha, posicione o mouse no canto esquerdo da linha (sobre a faixa existente na lateral
esquerda) até que o formato do ícone seja a seta e clique no botão esquerdo.
Para selecionar uma coluna pressione a tecla ALT e com o mouse selecione (“pinte”) a(s) coluna(s) desejada(s).
Para realizar estas ações basta que façamos a seleção do trecho de código desejado (linha) e em seguida soltemos o
mouse. Quando aproximarmos o mouse novamente sobre a área selecionada, o desenho do cursor mudará para
seta (em vez do i).
Neste momento se desejarmos efetuar uma movimentação, simplesmente arrastamos o mouse (sem soltar o botão)
para o ponto desejado e, em seguida, soltamos o botão do mouse. Você notará que o cursor mudará de posição
indicando a localização onde o trecho será incluído. Durante a movimentação, o desenho do ícone do mouse
ganhará um retângulo sob a seta.
Se desejarmos copiar o trecho em vez de apenas movimentá-lo, devemos pressionar a tecla Ctrl e efetuar as mesmas
ações descritas anteriormente. Neste caso o desenho do ícone do mouse além do retângulo apresentará, também,
um quadrado preenchido com o sinal +, ambos sob a seta.
No canto inferior esquerdo, ao lado da seta da barra de rolagem horizontal, a mesma barra de split. Novamente
clique sobre ela e arraste o mouse para a direita (sem soltar o botão). Veja o resultado na Figura 7.62.
Para desfazer este efeito basta um clique duplo sobre a linha separadora dos quadros, destacada na Figura 7.62.
Outra ação válida é a de Importar Texto ou Exportar Texto também presente no menu Arquivo.
OPÇÃO DESFAZER
A opção Desfazer (Undo) pode ser repetida muitas vezes (e não apenas uma). O Form Builder guarda todas as
modificações realizadas no código desde a última operação de Salvar. Esta ação está disponível no menu Editar.
♦ Processamento do Bloco – Os eventos classificados neste grupo estão associados a ações sobre o buffer do bloco.
O Form controla a necessidade de inclusão, exclusão ou alteração de linhas no banco de dados através da área
de buffer. Quando ocorrem mudanças na situação de um registro ou mesmo de todo o buffer, temos condições
de incluir ações em adição àquelas já realizadas por ele.
♦ Interface – Neste grupo se encontram todos os eventos ligados a ações do usuário, sejam elas realizadas com o
mouse ou com o teclado. Alguns eventos deste grupo são acionados apenas quando o usuário efetua uma ação
(pressiona o mouse sobre um botão, por exemplo), outros são acionados quando o usuário efetua uma ação ou
por programação (redimensionamento de uma janela, por exemplo).
♦ Query – Os eventos classificados neste grupo estão associados ao momento da consulta ao banco de dados, ou
seja, quando o Form monta a query que efetivamente será enviada para o banco de dados e quando ele faz a
leitura de cada uma das linhas selecionadas. Nestes dois momentos, poderemos incluir ações em adição àquelas
já estabelecidas por ele.
♦ Navegação – Os eventos classificados neste grupo estão associados à navegação, ou seja, ao momento em que o
foco muda de um item para outro. Esta mudança pode ocorrer entre itens de um mesmo registro, de registros
diferentes, de blocos diferentes e, ainda, para fora da aplicação ou na entrada de uma aplicação. De acordo com
o tipo de navegação, um conjunto particular de eventos é causado. Quem causa esse tipo de evento pode ser o
usuário, ao mudar de item, ou a programação, ao comandar a mudança.
♦ Controle de Mensagem – Este grupo de eventos está associado à recepção e apresentação de mensagens por
parte do Forms. Podemos interceptar e modificar as mensagens recebidas por ele ao criarmos gatilhos (triggers)
para os eventos deste grupo.
♦ Relacionamento entre Blocos (Master-Detail) – Esse grupo de eventos encontra-se ligado às ações-padrão
desenvolvidas pelo Form quando ele realiza o controle de leitura e atualização de blocos relacionados. Podemos
interferir neste controle e modificar as ações-padrão realizadas pelo Forms.
♦ Transação – Este grupo de eventos encontra-se ligado ao momento em que o Form realiza a comunicação com
o banco de dados, seja para efetivação da transação, leitura de dados (Select), início e fim de conexão ou bloqueio
(lock). Deste grupo os gatilhos mais importantes são aqueles ligados à efetivação da transação. É a estes que
daremos especial atenção.
Estudaremos individualmente cada um dos grupos desta segunda classificação e simultaneamente chamaremos
atenção para os gatilhos que venham a adicionar ou modificar a funcionalidade-padrão.
ROTINAS PREDEFINIDAS
O Form possui mais de 100 rotinas que permitem a realização de diversas ações por programação, tais como:
navegação entre itens, envio de mensagens, obtenção do valor de propriedades, alteração no valor de propriedades
e muitas outras ações.
A lista dessas funções se acha presente no Capítulo 15 e pode ser consultada por você diretamente no Form dentro do
nó Pacotes Embutidos (Built-In Packages) e, ainda, dentro dos manuais de ajuda (obtidos através do menu Ajuda).
Durante os exemplos desenvolvidos a partir deste ponto e dos exercícios, utilizaremos a maior quantidade possível
para que você se familiarize com essas rotinas.
♦ When-Validate-Item – Este evento é causado todas as vezes que o Form percebe que um item sofreu algum tipo
de modificação e precisa ser validado novamente. Após haver modificado o valor do item, o usuário poderá
tentar navegar para outro item ou salvar o registro ou quando a programação executar uma ação de navegação
ou de atualização.
Um gatilho associado a esse evento é ideal quando desejamos adicionar algum tipo de validação a um determinado
item; neste caso, podemos criar este gatilho em nível de item. Ou quando desejarmos adicionar algum tipo de
validação comum a qualquer um dos itens do registro, podemos criar esse gatilho em nível de bloco.
♦ When-Validate-Record – Este evento é causado todas as vezes que o Form percebe que houve alguma mudança
no registro e este precisa ser validado novamente. Essa validação ocorre no momento em que o usuário tenta
navegar para outro registro ou quando ocorre o processamento-padrão do Form (um Commit, por exemplo) e,
ainda, quando causamos uma dessas duas situações por programação.
Como todos esses gatilhos começam com When, eles serão acionados após o evento-padrão, isto é, após a validação-
padrão do Forms, e em adição a esta.
Utilizaremos um exemplo para testar estas situações; portanto, crie uma nova aplicação chamada Valida para a
tabela Func com as seguintes características:
a) Formato Form, colunas cd_mat, cd_depto, nr_cargo, nr_git, dt_nasc, nm_func, vl_sal, in_sexo, incluir barra de rolagem.
b) Criar um gatilho subordinado ao item cd_mat com o tipo When-Validate-Item (utilize o botão direito do mouse,
gatilhos inteligentes ou smart triggers). O código de PL/SQL deve ser preenchido de acordo com a Figura 7.63.
c) Criar um gatilho subordinado ao item nr_cargo com o tipo When-Validate-Item (utilize o botão direito do
mouse, gatilhos inteligentes ou smart triggers). O código de PL/SQL deve ser preenchido de forma similar à Listagem
7.03, porém com mensagem apropriada.
d) Criar um gatilho subordinado ao bloco Func com o tipo When-Validate-Record. O código de PL/SQL deve ser
preenchido com uma mensagem.
Utilizaremos para efeito de teste a mesma aplicação Valida, com as seguintes modificações:
♦ Remova todos os gatilhos (triggers) existentes atualmente.
♦ Crie os quatro gatilhos em nível de bloco (com mensagens identificadoras).
♦ Crie o gatilho When-Database-Record para o item nm_func com uma mensagem específica.
♦ Crie o gatilho When-Clear-Block em nível de Form com uma mensagem específica.
♦ Para o gatilho When-Clear-Block criado em nível de bloco, altere a propriedade Hierarquia de Execução (Execu-
tion Hierarchy) para Anterior (Before); isto fará com que os dois gatilhos sejam acionados.
Execute a aplicação e realize os seguintes testes:
♦ Observe que, ao iniciarmos a aplicação, a mensagem referente ao gatilho When-Create-Record já aparece. Isto
ocorre porque o programa começa em situação de inclusão. O registro recebe o estado de New.
♦ Faça uma consulta usando diretamente o botão Executar Consulta (Execute Query). Observe que o bloco é
limpo duas vezes. Aparecem as mensagens associadas aos gatilhos When-Clear-Block em nível de bloco e em
nível de módulo duas vezes cada uma.
♦ Faça agora uma consulta usando inicialmente o botão Entrar Consulta (Enter-Query) e, posteriormente, o botão
Executar Consulta (Execute-Query). Observe que o bloco é limpo duas vezes, a primeira antes do Enter-Query e,
em seguida, antes do Execute-Query.
♦ Altere o valor da coluna nr_git e navegue para outra coluna. O estado do registro é alterado quando ocorre a navegação.
♦ Repita a operação anterior (para outro registro), porém salve em vez de navegar. O estado do registro é alterado
da mesma forma.
♦ Altere o valor do nome do funcionário. Observe que somente agora o gatilho em nível de item foi acionado.
Salve as modificações.
♦ Inclua um novo registro. Desista (limpe o registro) e salve. Observe que o gatilho When-Remove-Record foi
acionado, apesar de não haver nenhuma modificação para o banco de dados.
♦ Remova o registro 160 e limpe o bloco sem salvar. O gatilho When-Remove-Record foi acionado também.
♦ Faça outros testes, tire suas conclusões e compare a seguir.
Pudemos observar que, quando efetuamos qualquer modificação que afete o buffer, algum gatilho deste grupo é
acionado. Quando indicamos ao Form para remover um registro (do banco de dados), ele o retira do buffer e
armazena seu rowid em uma lista de linhas a serem removidas. Quando modificamos (ou incluímos) um registro
e desistimos da modificação acionando a ação de Clear-Record (Limpar Registro), o Form o retira do buffer, porém
sem armazenar qualquer outra informação. Sendo assim, todas as vezes que retiramos uma linha do buffer, seja lá
qual for o motivo, estaremos acionando o gatilho When-Remove-Record.
Todos os eventos deste grupo podem ser acionados por programação. Nos exercícios, iniciaremos algumas destas
ações a tempo de programação.
♦ When-CheckBox-Changed – Inicia uma ação quando o operador troca o estado de um item do tipo caixa de
seleção (CheckBox). Este evento pode ser causado por mouse, teclado ou programação.
♦ When-Image-Activated – Inicia uma ação quando o operador realiza um clique duplo em um item do tipo imagem.
♦ When-Image-Pressed – Inicia uma ação quando o operador realiza um clique simples em um item do tipo imagem.
♦ When-List-Activated – Inicia uma ação quando um operador efetua uma clique duplo em uma lista do tipo T-List.
♦ When-List-Changed – Inicia uma ação quando um operador modifica o valor do item, selecionando outro
elemento da lista. Quando a lista é do tipo Combo, este evento também é causado quando o operador esvazia
ou digita um novo valor para o item.
♦ When-Mouse-Click – Este gatilho é acionado quando o operador faz um clique em qualquer item do módulo ou
em qualquer canvas se o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de bloco ou de item,
somente se o clique for dado no item específico ou em um dos itens do bloco específico. Quando um usuário faz
um clique com o mouse, os seguintes eventos são causados: Mouse Down, Mouse Up e Mouse Click, nesta ordem.
♦ When-Mouse-DoubleClick – Este gatilho é acionado quando o operador faz um clique duplo em qualquer item
do módulo ou em qualquer canvas, se o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de
bloco ou em nível de item, somente se o clique duplo for dado no item específico ou em um dos itens do bloco
específico. Quando um usuário faz um clique duplo com o mouse, os seguintes eventos são causados: Mouse
Down, Mouse Up, Mouse Click, Mouse Down, Mouse Up e Mouse DoubleClick, nesta ordem.
♦ When-Mouse-Down – Este gatilho é acionado quando o operador faz um clique em qualquer item do módulo
ou em qualquer canvas, se o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de bloco ou em
nível de item, somente se o clique for dado no item específico ou em um dos itens do bloco específico.
♦ When-Mouse-Enter – Este gatilho é acionado quando o operador move o mouse (sem pressioná-lo), entrando,
em qualquer item do módulo ou em qualquer canvas e se o gatilho estiver em nível de módulo. Se o gatilho
estiver em nível de bloco ou em nível de item, somente se o operador mover o mouse (entrando) em um item
específico ou em um dos itens do bloco específico.
♦ When-Mouse-Leave – Este gatilho é acionado quando o operador move o mouse (sem pressioná-lo), saindo, de
qualquer item do módulo ou de qualquer canvas, e se o gatilho estiver em nível de módulo. Se o gatilho estiver
em nível de bloco ou em nível de item, somente se o operador mover o mouse (saindo) de um item específico
ou de um dos itens do bloco específico.
♦ When-Mouse-Move – Este gatilho é acionado quando o operador move o mouse (sem pressioná-lo) em qualquer
item do módulo ou em qualquer canvas e se o gatilho estiver em nível de módulo. Se o gatilho estiver em nível
de bloco ou em nível de item, somente se o operador mover o mouse em um item específico ou em um dos itens
do bloco específico.
♦ When-Mouse-Up – Este gatilho é acionado quando o operador solta o botão do mouse após um clique em
qualquer item do módulo ou em qualquer canvas se o gatilho estiver em nível de módulo. Se o gatilho estiver
em nível de bloco ou em nível de item, somente se o operador soltar o botão do mouse no item específico ou em
um dos itens do bloco específico.
♦ When-Radio-Changed – Inicia uma ação quando o operador altera o botão selecionado em um grupo de opções
(radio group).
♦ When-Tab-Page-Changed – Inicia uma ação quando o operador modifica a página ativa de uma canvas Tab. O
evento só é causado se a mudança de página for explícita. Uma navegação entre itens em páginas diferentes não
causa o evento.
♦ When-Timer-Expired – Inicia uma ação quando o tempo programado expira.
♦ When-Tree-Node-Activated – Inicia uma ação quando o operador efetua um click duplo (ou pressiona a tecla
enter e o item já está selecionado) em um nó de item do tipo Árvore Hierárquica.
Faça outros testes com os demais tipos de gatilhos. Você ainda tem muitas descobertas a fazer.
Neste grupo, ainda se encontram alguns gatilhos acionados exclusivamente pelo teclado. O quadro a seguir
apresenta a lista de gatilhos disponíveis, a ação-padrão associada e a tecla necessária para o acionamento da
ação no Windows.
Os gatilhos deste grupo começam com Key, portanto já possuem uma funcionalidade-padrão implícita. Quando
incluímos um trigger deste conjunto em nossa aplicação, a ação-padrão associada deixa de ser executada. Por este
motivo, o Form Builder possui um conjunto de rotinas que executam as ações-padrão, tanto de teclado como
também transacionais (veremos num dos próximos tópicos).
Em versões anteriores do Form, o usuário contava apenas com o teclado para efetuar as ações que desejasse. Com
a introdução do mouse nas aplicações, o usuário conta agora com duas formas de acionar as ações: com o teclado
ou com o mouse.
A diferença entre essas duas formas é que na segunda é necessário que o programador inclua um botão na tela para
realizar uma determina ação ou que inclua um item em um menu para executar o procedimento desejado
(considerando-se que retiraremos o menu e a barra de ferramentas-padrão da aplicação).
Desta forma, as lógicas incluídas são validadas e verificadas. Não podemos nos esquecer, porém, que as mesmas
ações (Consultar, Salvar, Navegar, etc.) podem ser feitas exclusivamente com o teclado, sem que haja necessidade
de qualquer programação adicional.
Esses gatilhos, então, permitirão que sejam desabilitadas (por exemplo) todas as teclas em que um botão ou item
de menu possua uma programação mais complexa e não desejemos que o usuário pule esta programação ao
acionar uma tecla de função, ou, ainda, poderemos incluir a mesma programação na tecla para que o usuário
tenha opções de executar a mesma ação usando o mouse ou o teclado.
O importante é que durante a programação não venhamos a esquecer que isto pode acontecer e sejamos surpreendidos por uma ação do usuário
não prevista na programação.
O Form possui um trigger neste grupo, muito especial, criado para nos dar mais segurança na programação. Ele se chama Key-Others. Quando
incluímos este trigger em nossa aplicação, toda e qualquer ação de teclado fica desabilitada por default. Apenas serão válidas aquelas ações que
forem incluídas explicitamente na programação, ou seja, apenas aqueles gatilhos do tipo Key que tivermos definido no Form.
Esta forma de trabalhar garante que não seremos surpreendidos pelo usuário na implantação do sistema.
Principalmente para aqueles programadores que estão começando a usar esta ferramenta, o uso do Key-Others é
mais seguro e mais documentável (pois torna os gatilhos usados visíveis na aplicação).
Antes de passarmos aos testes, execute sua aplicação e liste o conjunto de teclas (menu Ajuda-Help, opção Teclas-
Keys). Você perceberá que aparecem na lista ações que não foram mencionadas acima.
Isto ocorre porque nem todas as ações do teclado são passíveis de controle ou da criação de gatilhos associados.
Ações normalmente executadas pelo gerenciador do ambiente (e não pelo Form), dentre outras, não são passíveis
de intervenção.
Estas ações estão listadas a seguir:
continua
Passemos agora aos testes. Como primeiro passo vamos remover todos os triggers criados na aplicação Valida. Em
seguida faremos:
♦ Incluir os seguintes triggers em nível de módulo: Key-Down, Key-Up, Key-Next-Item, Key-Commit. Coloque
apenas uma mensagem em cada um deles.
Teste a aplicação criada. Utilize as teclas, o menu e os botões. O que você descobriu?
Quando o Form Builder constrói o menu e a barra de ferramentas-padrão ele inclui comandos que simulam o
teclado; sendo assim, quando incluímos um trigger de teclado para a ação correspondente, a ação executada neste
gatilho também é executada pelo menu e botões da barra-padrão.
♦ Não retire as mensagens. No trigger Key-Down inclua a rotina Down. No trigger Key-Up inclua a rotina Up. No
trigger Key-Next-Item inclua a rotina Next_Item e, finalmente, no trigger Key-Commit inclua a ação
Commit_Form.
Refaça os testes. Você perceberá que, além das mensagens, as ações também são executadas.
♦ Inclua um botão (não esqueça de colocá-lo na Canvas) com o trigger When-Button-Pressed. Para simular uma
ação de teclado, utilizaremos a rotina Do-Key. Os parâmetros dessa rotina correspondem às rotinas predefinidas
que realizam as ações-padrão. Preencha o gatilho de acordo com a Listagem 7.04.
Execute a aplicação, modifique um registro qualquer e pressione o botão criado. Observe que as mensagens presentes
nos triggers Key-Commit e Key-Down são apresentadas. Isto ocorre porque a rotina Do-Key simula o teclado;
sendo assim, antes de executar a ação de salvar ou navegar o Form, verifique se existe algum trigger de teclado
correspondente a estas ações. Havendo, ele executa esses triggers em vez da rotina Commit_Form ou Down. Se
você criar triggers de teclado sem a ação correspondente, o botão não funciona.
Para testar esta última explicação. Retorne à aplicação e retire a rotina Down e a rotina Commit_Form dos triggers de
teclado. Repita os testes anteriores. Observe que as mensagens são mostradas, mas a ação não é executada. Como
último teste relativo a este assunto, remova os triggers Key-Down e Key-Commit. Repita os testes. A ação é executada
agora. Como a rotina Do-Key não encontrou os triggers de teclado, ela mesma acionou as ações de salva e navegação.
♦ Inclua o trigger Key-Others com uma mensagem. E para que seja possível encerrar a aplicação, inclua também
um trigger Key-Exit com o texto Exit_Form. Execute e teste a aplicação. Quais as ações que ainda funcionam?
Você descobrirá que apenas as ações de teclado mapeadas no programa são possíveis. Em todas as outras condições,
a mensagem apresentada no gatilho Key-Others é apresentada.
♦ Crie um gatilho de Post-Query em nível de bloco. Atribua um valor ao item TEXTO criado.
♦ Crie um gatilho When-Validate-Record com mensagem.
♦ Crie um gatilho When-Validate-Item para o item TEXTO com uma mensagem.
Agora, faça os seguintes testes:
♦ Realize uma consulta geral.
♦ Navegue de um registro para outro.
♦ Pressione o botão Entrar Consulta e preencha o item cd_mat com “> 60”. Execute a consulta.
Como primeira conclusão, verificamos que apenas as linhas com código do departamento igual a D11 foram
trazidas em ambas as consultas, uma vez que modificamos a restrição-padrão por aquela preenchida no gatilho de
Pre-Query (pesquise no Help quais as propriedades do bloco que você pode modificar através da rotina
Set_Block_Property). A restrição estabelecida pelo usuário foi adicionada àquela que estabelecemos por programação.
Observamos também que os gatilhos de validação foram acionados. Isto ocorreu porque fizemos uma modificação
no registro. Preenchemos um valor para o item TEXTO recém-criado. Mesmo esta alteração tendo ocorrido em um
item que não pertence ao banco de dados, o item e o registro precisam ser revalidados após a modificação.
Estes triggers são acionados quando o Form navega internamente através de diferentes níveis de hierarquia do objeto.
Os triggers deste grupo iniciam com Pre ou Post, e portanto adicionam funcionalidade imediatamente antes ou
depois do evento ou When.
♦ Pre-Form – Inicia uma ação imediatamente antes de o Form navegar para o módulo atual vindo de outro
módulo. Funciona como um Startup (só a primeira vez em que o módulo ganha o foco).
♦ Pre-Block – Inicia uma ação quando o Form navega para o nível de bloco, tendo vindo do nível de módulo.
♦ Pre-Record – Inicia uma ação quando o Form navega para o nível de registro, tendo vindo do nível de bloco.
♦ Pre-Text-Item – Inicia uma ação quando o Form navega para o nível de item, tendo vindo do nível de registro.
♦ Post-Text-Item – Inicia uma ação quando o Form deixa o nível de item e navega para o nível de registro.
♦ Post-Record – Inicia uma ação quando o Form deixa o nível de registro e navega para o nível de bloco.
♦ Post-Block – Inicia uma ação quando o Form deixa o nível de bloco e navega para o nível de módulo.
♦ Post-Form – Inicia uma ação antes que o Form navegue para fora do módulo.
Quando o Form navega de um objeto para o outro, ele retorna ao nível superior. Por exemplo, quando ele navega
entre itens ele retorna ao nível de registro e seleciona o próximo item na seqüência de navegação. Isto faz com que
os gatilhos de Post-Text-Item (associados ao item anterior) e Pre-Text-Item, associados ao item atual, sejam executados
(mas não os gatilhos associados a registro – Post-Record e Pre-Record).
Esses gatilhos são acionados em diferentes situações de acordo com a navegação realizada. Por exemplo, entre dois
itens em registros diferentes ou entre dois itens em blocos diferentes ou quando iniciamos ou encerramos a aplicação.
Modifique a aplicação Valida removendo os triggers existentes e criando todos os triggers (Pre/Post) no nível de
módulo com mensagens indicativas. Faça os seguintes testes:
♦ Inicie a aplicação. Você verá a navegação desde o nível de módulo até o nível de item.
♦ Faça uma consulta geral. Você verá a navegação sair do nível de item, ir para o nível de registro e retornar após
a consulta.
♦ Navegue entre itens do mesmo registro.
♦ Navegue entre registros.
♦ Altere uma informação qualquer e salve o registro.
♦ Saia da aplicação.
Inclua no trigger Post-Text-Item o comando Go_Item(‘cd_mat’). O que acontece quando você navega entre itens
(de qualquer nível)? Você recebe uma mensagem de erro.
Isto ocorre porque o Form é responsável por efetuar a navegação entre os objetos, e enquanto esta navegação estiver
em andamento não podemos interferir no processo, isto é, não podemos desviar o caminho a ser seguido pelo Form.
Em vista disso e havendo necessidade de desvio, o Form Builder possui um conjunto de triggers criados
especificamente para que possamos realizar desvios durante o processo de navegação.
São aqueles triggers do tipo When-New-Instance:
♦ When-New-Form-Instance – Inicia uma ação na inicialização do módulo.
♦ When-New-Block-Instance – Inicia uma ação após o foco ser movido de um item em um bloco para outro item
em outro bloco.
♦ When-New-Record-Instance – Inicia uma ação após o foco se mover para um novo registro. Se o novo registro
estiver também em um novo bloco, este gatilho é acionado após When-New-Block-Instance, mas antes do
When-New-Item-Instance.
♦ When-New-Item-Instance – Inicia uma ação imediatamente após o foco se mover para um item diferente. Se o
item estiver em um novo registro, este gatilho é disparado após When-New-Record-Instance.
Esses gatilhos podem receber comandos que desviem a ação normal de navegação. Para efeito de teste, vamos criar
os quatro em nível de módulo (não remova os gatilhos anteriores Pre/Post).
No gatilho When-New-Item-Instance, inclua a rotina Go_Item (‘cd_mat’) e retire esta rotina do Post-Text-Item.
Execute a aplicação. Faça uma consulta geral. Tente navegar para um item diferente do cd_mat. O que ocorre?
Observe que, embora o trigger When-New-Item-Instance seja acionado, o processo de navegação não é interrompido.
Quando tentamos o desvio (com o mouse ou teclado) para outro item, primeiro ocorre o Post-Text-Item do item
cd_mat, o Pre-Text-Item do item desejado e então o When-New-Item-Instance. Como neste último gatilho
executamos um desvio por programação, ocorre novamente o Post-Text-Item do item atual, o Pre-Text-Item do
item cd_mat e o When-New-Item-Instance novamente (que não tem ação sobre o próprio item).
Repare que a navegação ocorre: o foco vai para um novo item e retorna, cumprindo todo o processo normal de navegação.
Faça outros testes navegando entre registros. Coloque estes gatilhos no nível de bloco e no nível de item e verifique
as diferenças. Teste o uso do Commit, via tecla, e de um botão de salva. Verifique se os triggers são acionados em
todas as situações.
As rotinas utilizadas neste gatilho obtêm as mensagens de erro padrão do Form (error-xxx) e do banco de dados
(dbms-xxx).
Inclua também um trigger On-Message (em nível de Form) com o texto da Listagem 7.07.
BEGIN
MESSAGE(COD || '@' || TIPO || '@' || TEXTO);
END;
Os gatilhos deste grupo são acionados em função de o Form ter entrado na fase transacional na aplicação, ou seja,
algo ocorreu que fez com que o Form tivesse necessidade de efetivar as modificações realizadas nos registros para
o banco de dados.
A fase transacional é ativada em uma das seguintes circunstâncias:
♦ Foi acionada, explicitamente, a salva. Esta ação pode ser iniciada por teclado, por botão, por menu ou por
programação (em um botão, por exemplo).
♦ Foi acionada a limpeza de um bloco com registros pendentes de atualização. Quando isto ocorre é apresentada
uma tela de mensagem indicando que o usuário deve escolher entre salvar as pendências ou ignorá-las. Se for
escolhido salvar, o processo transacional é acionado. Esta ação (de limpeza) pode ser disparada por teclado,
menu, botão ou por programação.
♦ Foi acionada a limpeza do Form e havia registros pendentes de atualização em algum dos blocos desta aplicação.
Quando isto ocorre, é apresentada uma tela de mensagem indicando que o usuário deve escolher entre salvar as
pendências ou ignorá-las. Se for escolhido salvar, o processo transacional é acionado. Esta ação (de limpeza)
pode ser disparada por teclado, menu, botão ou por programação.
♦ Foi feita uma tentativa de encerramento da aplicação sem salvar e havia registros pendentes. Quando isto
ocorre, é apresentada uma tela de mensagem indicando que o usuário deve escolher entre salvar as pendências
ou ignorá-las. Se for escolhido salvar, o processo transacional é acionado. Esta ação (de encerramento) pode ser
disparada por teclado, menu, botão ou por programação.
♦ Foi feita uma tentativa de Consulta (Entrar Consulta ou Executar Consulta) e o bloco continha registros pendentes
de atualização. Quando isto ocorre, é apresentada uma tela de mensagem indicando que o usuário deve escolher
entre salvar as pendências ou ignorá-las. Se for escolhido salvar, o processo transacional é acionado. Esta ação
(de consulta) pode ser disparada por teclado, menu, botão ou por programação.
♦ A programação acionou uma rotina Post ou Commit_Form.
Quando o processo transacional é disparado, o Form pesquisa em cada um dos blocos em que existam registros
pendentes e inicia a montagem dos comandos Insert, Update e Delete e os executa.
Podemos interferir nesta montagem com os gatilhos deste grupo.
♦ On-Delete – Substitui a funcionalidade padrão de remoção de registros. É acionado uma vez para cada registro
a ser removido do banco de dados.
♦ On-Insert – Substitui a funcionalidade padrão de inclusão de registros. É acionado uma vez para cada registro a
ser incluído no banco de dados.
♦ On-Update – Substitui a funcionalidade padrão de alteração de registros. É acionado uma vez para cada registro
a ser alterado no banco de dados.
♦ Post-Database-Commit – Adiciona uma ação ao processamento-padrão após a ação de Commit para o banco de
dados. É executado uma única vez ao término do processo transacional.
♦ Post-Delete – É acionado após uma determinada linha ter sido removida do banco de dados. Adiciona ações ao
processamento-padrão após o evento. É executado uma vez para cada linha a ser removida.
♦ Post-Forms-Commit – É acionado antes da ação de Commit para o banco de dados e após a ação de Post (onde
todos os comandos Insert, Update e Delete são executados). É executado uma única vez após toda a transação
ter sido enviada para o banco de dados.
♦ Post-Insert – É acionado após uma determinada linha ter sido incluída no banco de dados. Adiciona ações ao
processamento-padrão após o evento. É executado uma vez para cada linha a ser incluída.
♦ Post-Update – É acionado após uma determinada linha ter sido alterada no banco de dados. Adiciona ações ao
processamento-padrão após o evento. É executado uma vez para cada linha a ser alterada.
♦ Pre-Commit – É acionado antes do Form iniciar o processo de Post. É executado uma única vez no início de todo
o processo.
♦ Pre-Delete – É acionado antes de uma determinada linha ser removida do banco de dados. Adiciona ações ao
processamento-padrão antes do evento. É executado uma vez para cada linha a ser removida.
♦ Pre-Insert – É acionado antes de uma determinada linha ser incluída no banco de dados. Adiciona ações ao
processamento-padrão antes do evento. É executado uma vez para cada linha a ser incluída.
♦ Pre-Update – É acionado antes de uma determinada linha ser alterada no banco de dados. Adiciona ações ao
processamento-padrão antes do evento. É executado uma vez para cada linha a ser alterada.
Remova da aplicação Valida todos os triggers e inclua um trigger de cada um dos tipos vistos acima (em nível de
bloco ou Form), exceto aqueles que começam com On, com a mensagem adequada.
Observe que os triggers Pre-Commit, Post-Database-Commit e Post-Forms-Commit só podem ser criados em nível
de módulo, pois se aplicam a toda aplicação e não apenas a um bloco.
Para testar os resultados, execute duas inclusões, duas alterações e duas exclusões.
2. Pre-Delete e Post-delete para cada linha a ser removida, independente da ordem em que esta ação foi feita
ou da ordem dos registros no buffer.
3. Pre-Update e Post-update para cada linha a ser alterada, independente da ordem em que esta ação foi feita
ou da ordem dos registros no buffer.
4. Pre-Insert e Post-insert para cada linha a ser incluída, independente da ordem em que esta ação foi feita ou
da ordem dos registros no buffer.
5. Post-Forms-Commit uma única vez.
6. Commit.
7. Post-Database-Commit.
Inclua agora um trigger On-Delete e refaça os testes de remoção. Observe que os registros não são mais removidos,
pois triggers do tipo On substituem a funcionalidade-padrão. Verifique no Capítulo 15 qual a rotina do pacote
Extensões que realiza a funcionalidade-padrão de remoção de registros do banco de dados.
Como teste adicional, inclua um comando de desvio dentro de um destes triggers transacionais. Coloque o comando
Go_Item(‘cd_mat’) no trigger de Pre-Update e execute uma atualização. O que acontece?
A mensagem de erro indica que não podemos navegar durante o período transacional. O desvio é inválido da
mesma forma que nos gatilhos de navegação. Durante o processo transacional, o Form percorre os blocos e registros
de acordo com seu próprio algoritmo, que não pode ser modificado pela programação.
Verifique no Capítulo 16 os demais triggers incluídos neste grupo e sua utilização. Faça outros testes para completar
seu entendimento do mecanismo de programação do Form.
♦ Texto da ‘Ajuda do Teclado’ (‘Keyboard Help’ Text) – Texto a ser apresentado na tela de ajuda (Teclas – Keys) a
tempo de execução.
PALETA DE SINTAXE
Se você expandir o nó Pacotes Embutidos observará que a quantidade de pacotes é bem significativa. Se, adicionalmente,
expandirmos o pacote Extensões-Standard verificaremos que a quantidade de rotinas é muito grande.
Para nos auxiliar na edição de trechos de PL/SQL ou para obtenção da chamada de uma rotina predefinida, o Form
Builder disponibiliza uma paleta de sintaxe.
Abra o editor de PL/SQL e escolha a opção Paleta de Sintaxe do menu Programa (apresentado na Figura 7.64).
Esta paleta possui duas pastas, uma relativa a sintaxe de PL/SQL e a outra relativa às rotinas predefinidas.
No exemplo da Figura 7.64, selecionamos o conjunto de instruções relativas a Controlar Fluxo (veja a janela
superior). Dentro da lista apresentada escolhemos a instrução IF ELSIF ELSE. Quando pressionarmos o botão Inserir,
o trecho de código mostrado na janela inferior é copiado para a posição do cursor no editor de PL/SQL aberto.
Esta paleta nos ajudará no uso das sintaxes tanto de PL/SQL quanto das rotinas predefinidas que passaremos a
estudar juntamente com os triggers.
EXERCÍCIOS
A partir deste tópico, além de testarmos os triggers, começaremos a utilizar nos exercícios as rotinas disponibilizadas
pelo Form Builder para realizar diversas ações. Você conhecerá muitas dessas rotinas durante o nosso estudo,
porém, no nó Pacotes Embutidos (Extensões Standard), existem muito mais rotinas. No Capítulo 15 você contará
com a presença de todas essas rotinas organizadas por tipo de uso. O objetivo é simplesmente dar alguma facilidade
na hora de definir qual a rotina a usar; no entanto, a consulta à Ajuda do Form Builder é indispensável para que
você saiba quais os parâmetros possíveis e a capacidade da rotina.
Você encontrará, ainda, neste material um tópico que trata especificamente deste nó Pacotes Embutidos, porém
nosso estudo das rotinas já começa agora.
7.26) Crie uma aplicação de nome EX26 baseada na aplicação EX25, incluindo a seguinte funcionalidade.
♦ Formatar os campos de data com dd/mm/rrrr.
♦ Os campos de data são de preenchimento obrigatório e sempre com tamanho máximo.
♦ Formatar o campo de salário com L999G999G999D99.
♦ Adicione o código-padrão para os botões.
♦ Verificar a tempo de alteração ou inclusão se o salário informado está dentro da tabela de cargos e salários a seguir:
a) Para cargos até 46 (inclusive), o salário deve variar de 500 a 1.500 (inclusive).
b) Para cargos de 47 a 52 (inclusive), o salário deve variar de 1.501 a 2.000 (inclusive).
c) Para cargos de 53 a 55 (inclusive), o salário deve variar de 2.001 a 2.500 (inclusive).
d) Para cargos de 56 a 58 (inclusive), o salário deve variar de 2.501 a 3.000 (inclusive).
e) Para cargos de 59 a 60 (inclusive), o salário deve variar de 3.001 a 3.500 (inclusive).
f) Para cargos de 61 a 62 (inclusive), o salário deve variar de 3.501 a 4.000 (inclusive).
g) Para cargos de 63 (inclusive) em diante, o salário deve variar de 4.501 a 10.000 (inclusive).
Caso haja alguma incorreção, causar uma falha e enviar mensagem adequada.
♦ A janela da aplicação e a janela do Forms Runtime devem aparecer maximizadas.
♦ Garanta o preenchimento de salário, nome e sobrenome.
♦ Garanta que a data de nascimento somente aceite valores acima de 1940.
7.27) Crie uma aplicação de nome EX27 baseada na aplicação EX26, incluindo a seguinte funcionalidade:
♦ Traga a coluna nm_foto coluna para a sua aplicação.
♦ Inclua essa coluna na canvas imediatamente abaixo de um item do tipo imagem, criado no bloco Func, mas não
pertencente ao banco de dados.
♦ A tempo de execução, o campo nm_foto deverá ser preenchido com o caminho e nome de arquivos do tipo BMP
presentes em seu disco. Quando a coluna for preenchida, a imagem correspondente deverá ser trazida para a tela.
♦ Crie uma canvas do tipo stack e preencha essa canvas com um boilerplate que especifique como deve ser feito
o preenchimento dessa tela.
♦ Esta canvas deverá ser apresentada quando o usuário pressionar a tecla Help. Quinze segundos depois, esta tela
deve ser escondida novamente.
♦ Se o código do departamento (do bloco de controle) não for preenchido, deverá ser feita a consulta de todas as
linhas da tabela Func.
♦ Quando o botão Consultar for acionado, navegue para um item do bloco atual.
7.30) Crie uma aplicação de nome EX30 baseado na aplicação EX29, com a seguinte funcionalidade:
♦ Impeça que a pergunta “Você deseja salvar as alterações efetuadas?” seja apresentada para o usuário.
♦ A partir da aplicação atual, acione outra das aplicações que você fez anteriormente utilizando um botão na
barra de ferramentas vertical. Essa outra aplicação deverá ser acionada em outra sessão do mesmo usuário.
♦ Se o campo nm_foto estiver preenchido, a tempo de leitura a foto já deverá ser carregada.
♦ Todo projeto deve ter departamento e responsável.
♦ O responsável deve ser funcionário do mesmo departamento.
♦ Todas as mensagens devem ser apresentadas na linha de mensagem, inclusive as mensagens recebidas do banco
de dados. Neste caso, deve ser mostrada também a sintaxe causadora do erro.
♦ Crie um botão na barra de ferramentas horizontal que apresente as teclas disponíveis para os usuários.
CONCEITO
Um relacionamento Master-Detail nada mais é do que um relacionamento entre dois blocos de uma mesma aplicação.
MÉTODOS DE RELACIONAMENTO
Para construirmos o relacionamento podemos agir de duas formas:
♦ Na primeira marcamos a opção Fazer junção automática dos blocos de dados e pressionamos o botão Criar
Relacionamento.
Neste caso o Forms Builder pesquisará, no banco de dados, os relacionamentos existentes entre o bloco de dados
atual e aqueles que foram criados anteriormente na aplicação.
Encontrando relacionamentos, estes são apresentados em um diálogo para que façamos a escolha daquele que
desejaremos usar. Quando escolhemos uma opção é apresentado um diálogo com o campo Condição de União já
preenchido. Foi esta a forma que usamos para obter o resultado da Figura 7.65.
♦ Na Segunda forma desmarcamos a opção Fazer junção automática dos blocos de dados e pressionamos o botão
Criar Relacionamento.
Neste caso o diálogo apresentado terá duas opções apresentadas na Figura 7.66.
Ao escolhermos uma das opções será apresentada a relação de blocos presentes na aplicação para que determinemos
com qual deles desejamos estabelecer o relacionamento do bloco atual.
Ao escolhermos um dos blocos, o diálogo da Figura 7.65 é apresentado, porém com a Condição de União não
preenchida. Deveremos, então, selecionar a coluna no bloco principal que se relacionará com a coluna
correspondente no bloco detalhe (tantas vezes quantas se fizerem necessárias para que a ligação entre os blocos
fique correta). A cada ligação estabelecida o Form Builder fará o registro no campo Condição de União.
CONSEQÜÊNCIAS DO RELACIONAMENTO
Durante a construção do bloco Func, preencheremos o diálogo do Assistente de acordo com a Figura 7.65.
Como resultado desta construção, teremos a visualização dos itens pertencentes aos dois blocos. Para que tenhamos
um entendimento melhor das conseqüências da ligação incluiremos ambos os blocos na mesma canvas.
Analisaremos em seguida quais as ações resultantes desta ligação.
Estudemos, portanto, as propriedades (ou regras) do relacionamento entre esses dois blocos.
PROPRIEDADES DA RELAÇÃO
As duas primeiras propriedades do grupo Funcional, Bloco de Dados Detalhado (Detail Data Block) e Condição de
Junção (Join Condition) determinam qual o nome do bloco de dados detalhe (uma vez que este objeto está pendurado
no mestre) e qual a ligação entre esses blocos, ou seja, qual a coluna ou colunas PK no bloco-mestre e qual a coluna
(ou colunas) FK no bloco detalhe correspondente.
As demais propriedades serão estudadas individualmente:
♦ Excluir Comportamento do Registro (Delete Record Behavior) – Esta propriedade indica qual a ação que o Form deve
tomar se o usuário tentar remover registros no bloco que é o mestre da relação. Existem três possibilidades diferentes:
a) Não Isolado – Indica que, se houver registros no detalhe, a remoção no bloco-mestre deve ser invalidada. Esta
é a opção default (e o valor em uso atualmente em nossa aplicação).
b) Isolado – Indica que o Form deve enviar para o banco de dados apenas o comando de Delete dos registros do
bloco-mestre, mesmo que haja registro no detalhe. Esta ação é útil quando o relacionamento entre as tabelas
em nível de banco de dados é do tipo Cascade Delete. Isto significa que quando solicitamos ao banco de
dados uma remoção em alguma linha da tabela-mestre ele, automaticamente, remove todas as linhas
correspondentes na tabela detalhe. Neste caso, não temos necessidade de repetir esta ação no Form, pois o
banco de dados se encarrega de fazê-la.
c) Em Cascata – Esta é a situação inversa da opção anterior. Como no banco de dados o relacionamento entre as
tabelas não é do tipo Cascade, temos necessidade de prover esta situação no Form. Desta forma, quando
escolhemos esta opção, o Form programa um comando Delete para todas as linhas detalhe que correspondam
ao mestre que desejamos remover. Esta ação é incluída em um trigger de Pre-Delete no bloco-mestre.
♦ Impedir Operações sem Mestre (Prevent Masterless Operation) – Esta propriedade indica quando o operador
estará apto a consultar ou inserir registros no bloco detalhe. Essa propriedade pode ser preenchida com:
a) Sim – Indicando que não são permitidas inclusões no bloco detalhe se não houver um registro associado no
bloco-mestre e, ainda, não são permitidas consultas no bloco detalhe se não houver um registro lido e associado
no bloco-mestre.
b) Não – Pode-se consultar ou incluir registros no detalhe sem restrições. Esta é a opção default.
O grupo Coordenação (Coordination) também possui duas propriedades que precisamos estudar, pois se referem à
forma de leitura das informações.
♦ Diferido (Deferred) – Indica se a consulta no bloco detalhe deve ou não ser adiada após a identificação do
registro no bloco-mestre. Quando esta propriedade recebe o valor Não, tão logo seja feita uma consulta ou
navegação para o próximo registro no bloco principal, ocorrerá a consulta no bloco detalhe. Neste caso, a
propriedade Consulta Automática (Automatic Query) é ignorada. Quando indicamos que desejamos o adiamento
(Sim), a propriedade Consulta Automática (Automatic Query) indicará como será feita a consulta no detalhe.
♦ Consulta Automática (Automatic Query) – Para que esta propriedade tenha efeito, a propriedade Diferido (De-
ferred) deve estar preenchida com Sim. Se essa propriedade for preenchida com Sim, estamos indicando que a
consulta será feita automaticamente, porém somente quando o usuário navegar para o bloco detalhe. Enquanto
ele permanecer no bloco principal, não será feita nenhuma pesquisa no detalhe. Se essa propriedade for preenchida
com Não, o usuário além de navegar para o bloco detalhe, deverá, explicitamente, acionar uma consulta (Entrar
Consulta e/ou Executar Consulta).
Antes de prosseguirmos nosso estudo, façamos alguns testes.
a) Coloque a propriedade Excluir Comportamento do Registro (Delete Record Behavior) com o valor Isolado.
b) Coloque a propriedade Impedir Operações sem Mestre (Prevent Masterless Operation) com o valor Sim.
c) Preencha a propriedade Diferido (Deferred) com Sim e a propriedade Consulta Automática (Automatic Query)
com Sim.
♦ Inicie pela consulta. Consulte o bloco Depto. Navegue para o bloco detalhe. Observe que embora a consulta
não seja feita imediatamente após a mudança no mestre, o bloco detalhe é limpo imediatamente; caso contrário,
faríamos referências incorretas.
♦ Efetue um Clear Form (Limpar Tudo do menu Ação). Tente realizar uma consulta apenas no bloco detalhe.
Ocorre uma mensagem de erro, indicativa do impedimento.
♦ Efetue nova consulta no bloco-mestre e remova um registro (por exemplo, C01) desse bloco. Observe que o erro
é recebido do banco de dados e não do Form como havia ocorrido anteriormente. Isto se dá porque foi enviado
para o banco apenas o comando Delete do registro em Depto, o que causou um erro de restrição de integridade.
Os triggers são criados em função da propriedade Excluir Comportamento do Registro (Delete Record Behavior). O
conteúdo dos triggers é definido em função do grupo Coordenação (Coordination).
Alguns dos gatilhos mostrados acima não foram vistos no tópico anterior e serão estudados agora.
São eles:
♦ On-Check-Delete-Master – Este gatilho é acionado quando o Form tenta remover um registro em um bloco que
é o bloco-mestre em um relacionamento Mestre-Detalhe.
♦ On-Clear-Details – Este gatilho é acionado quando o Form precisa limpar os registros de um bloco detalhe em
função de estes registros não mais corresponderem ao registro corrente no bloco-mestre.
♦ On-Populate-Details – Este gatilho é acionado quando o Form precisa obter registros para o bloco detalhe em
função da coordenação de leitura entre os blocos Mestre-Detalhe.
De um modo geral, não precisamos intervir nos triggers gerados em função da presença da relação. Se desejarmos
incluir alguma funcionalidade específica podemos adicionar código aos gatilhos criados. Devemos tomar cuidado,
no entanto, se viermos a modificar alguma característica da relação, pois os gatilhos podem ser modificados
independente de os termos alterado ou não, podendo ocasionar a perda de código na aplicação.
EXERCÍCIOS
7.31) Crie uma nova aplicação de nome EX31. As seguintes tabelas devem ser apresentadas numa mesma canvas:
♦ Departamento: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Funcionário: formato Tabular, todas as colunas, oito registros por tela.
As seguintes características devem ser configuradas para esta aplicação:
♦ O bloco de funcionário deve ser construído em uma canvas do tipo Empilhado (Stack) com uma barra de
rolagem de tal forma que parte dos dados fique visível na canvas principal. Para visualização das demais
informações, o usuário deverá se utilizar da barra de rolagem. A canvas fica visível todo o tempo sobre a canvas
de Conteúdo (Content) onde foi construído Departamento.
♦ O relacionamento entre os blocos deve ser do tipo Departamento (pai), Funcionário (Filho).
♦ Não deve ser possível excluir um registro em um pai quando houver registros nos respectivos filhos.
♦ Não deve ser possível uma pesquisa em um filho se não houver registro alocado no pai correspondente.
♦ Tão logo o registro-pai seja trazido, o(s) registro(s)-filho deve(m) ser trazido(s) imediatamente.
A Figura-resposta 7.31A nos apresenta o esquema do relacionamento.
7.32) Crie uma nova aplicação de nome EX32. As seguintes tabelas devem ser apresentadas numa mesma canvas:
♦ Departamento: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Projeto: formato Tabular, todas as colunas, três registros por tela.
♦ Projeto Atividade: formato Tabular, todas as colunas, cinco registros por tela.
As seguintes características devem ser configuradas para esta aplicação:
♦ O relacionamento entre os blocos deve ser do tipo Departamento (avô), Projeto (pai) e Projeto-Atividade (filho).
♦ Não será permitida a remoção de Departamento se existirem projetos; no entanto, a remoção de projeto poderá
ser efetuada desde que todos os registros de Projeto-Atividade sejam removidos também.
♦ Deve ser possível uma pesquisa em um filho mesmo que não haja registro alocado no pai correspondente.
♦ Tão logo o registro de Departamento seja trazido o(s) registro(s)-filho deve(m) ser trazido(s) imediatamente.
Porém, somente devem ser consultados os registros de Projeto Atividade quando o usuário estabelecer a navegação
para este bloco.
A Figura-resposta 7.32A nos apresenta o esquema do relacionamento.
7.33) Crie uma nova aplicação de nome EX33. As seguintes tabelas devem ser apresentadas numa mesma canvas:
♦ Funcionário: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Departamento: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Projeto: formato Tabular, todas as colunas, três registros por tela.
As seguintes características devem ser configuradas para esta aplicação:
♦ O relacionamento entre os blocos deve ser do tipo Funcionário (pai), Departamento (filho), Projeto (filho).
Ambos pendurados em Departamento.
♦ Deve ser possível a remoção de funcionário, mesmo que haja departamentos e projetos.
♦ Deve ser possível uma pesquisa em um filho mesmo que não haja registro alocado no pai.
♦ Tão logo o registro de Funcionário seja trazido, o(s) registro(s)-filho deve(m) ser esvaziado(s), porém a pesquisa
nos filhos deve ser comandada manualmente.
A Figura-resposta 7.33A nos apresenta o esquema do relacionamento.
7.34) Crie uma nova aplicação de nome EX34. As seguintes tabelas devem ser apresentadas numa mesma canvas:
♦ Projeto: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Atividade: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Projeto Atividade: formato Tabular, todas as colunas, oito registros por tela.
As seguintes características devem ser configuradas para esta aplicação:
♦ O relacionamento entre os blocos deve ser do tipo Projeto (pai), Atividade (pai) e Projeto Atividade (filho).
♦ Deve ser possível a remoção de projeto, mesmo que haja atividades programadas (projeto-atividade)
♦ Não deve ser possível a remoção de atividade havendo registros de projeto atividade.
♦ Não deve ser possível uma pesquisa no filho se não houver registro alocado no pai.
♦ Somente se os registros de atividade e projeto forem selecionados, podem ser apresentados filhos,
automaticamente.
A Figura-resposta 7.34A nos apresenta o esquema do relacionamento.
7.35) Crie uma nova aplicação de nome EX35 baseada na aplicação EX32. As seguintes características devem ser
configuradas para esta aplicação:
♦ Não será permitida a remoção de Departamento se existirem projetos.
♦ Não será permitida a remoção de Projeto se existirem registros em Projeto Atividade.
♦ Não deve ser possível uma pesquisa em um filho se não houver registro alocado no pai correspondente.
♦ Tão logo o registro de Departamento seja trazido o(s) registro(s)-filhos devem ser trazido(s) imediatamente,
porém somente devem ser consultados os registros de Projeto Atividade quando o usuário estabelecer a navegação
para este bloco.
♦ Quando um projeto for trazido do banco de dados, deve ser trazido simultaneamente o nome do coordenador
do projeto.
♦ Quando uma atividade for trazida ou alterada, deve ser apresentada a sigla da nova atividade.
INTRODUÇÃO
Uma aplicação Form possui diversos pontos em que podemos escrever códigos de PL/SQL (os triggers). Sabemos
que a PL/SQL é uma linguagem estruturada em blocos. Sabemos, ainda, que com a PL/SQL podemos criar blocos de
código com nome, isto é, procedimentos, funções e pacotes.
Sendo assim, uma aplicação Form não poderia deixar de ter formas de estruturação de código. Locais onde nos
fosse possível escrever códigos de PL/SQL que pudessem ser utilizados em diversos pontos da aplicação. Este é o
assunto do tópico Rotinas.
O assunto do tópico Variáveis vai tratar de todos os tipos de variáveis que podemos usar em uma aplicação:
variáveis definidas dentro de um trigger, variáveis de sistema, itens de trabalho (fora da canvas), variáveis de
pacotes, variáveis globais e parâmetros.
ROTINAS
Dentro do Form podemos acionar três tipos de rotinas:
♦ Rotinas armazenadas no banco de dados.
♦ Rotinas armazenadas dentro do programa.
♦ Rotinas armazenadas em bibliotecas (Libraries).
Cada uma destas formas de armazenamento possui uma abrangência e utilidade específicas.
ROTINAS LOCAIS
São aquelas armazenadas dentro da própria aplicação. São utilizadas para estruturação do código e não têm utilização
em outros módulos.
O diálogo da Figura 7.67 será apresentado para que possamos determinar o nome e o tipo da unidade de programa.
Avaliemos quais as opções de unidades de programa e sua melhor utilização:
♦ Procedimentos (Procedures) – Podem receber parâmetros e retornar valores para a rotina chamadora através de
parâmetros de saída (out). Devem ser o tipo escolhido se mais de uma informação de retorno for necessária.
Quando temos necessidade de retornar ao programa chamador mais de uma informação, é mais comum o uso
de um procedimento do que de uma função, porém não há impedimento de uso.
♦ Funções (Functions) – Podem receber parâmetros. Sempre retornam um valor através da própria chamada da
função. Também podem retornar valores através de parâmetros de saída (out), mas é pouco comum esta forma
de uso. Devem ser o tipo escolhido se apenas uma informação de retorno for necessária.
♦ Pacotes (Packages) – Nos pacotes podemos criar procedures, functions e ainda variáveis e cursores globais
(declarados na especificação) ou de uso apenas no pacote (declarado no corpo). Pacotes favorecem a organização,
utilize-os sempre. Use e abuse de sua funcionalidade para grupar rotinas afins.
♦ Especificação do Tipo e Corpo do Tipo – Aparecem desabilitados neste momento. Serão usados para a criação de
tipo no banco de dados. Veremos a seguir.
Quando aceitarmos esse diálogo, o editor de PL/SQL será acionado para que possamos escrever o código desejado.
Neste caso, o tipo de código é Unidade de Programa. Observe que o campo Objeto fica desabilitado.
Ao lado do nome da unidade de programa (no nosso caso Teste) aparece um * (asterisco), indicando que houve
modificações e que esta rotina deve ser recompilada.
Observe que a janela do editor de PL/SQL é ligeiramente diferente daquelas vistas anteriormente. Ela mostra quem
é o usuário dono da rotina (Owner), o nome e tipo da rotina.
Para efeito de teste criaremos um objeto com 2 atributos e um método. Para tal, devemos selecionar o nó Tipos e
pressionar a ferramenta Criar para que a primeira tela do Assistente seja apresentada.
Nesta primeira tela o assistente indica o que pode ser criado:
♦ Tipo Objeto (Object Type) – neste caso podemos especificar atributos e métodos para o tipo.
♦ Tipo Coleção (Collection) – neste caso podemos especificar Array Variável (Varray) ou Tabela (Nested Table).
No segundo diálogo é que deveremos escolher, realmente, o tipo e o nome do elemento. Para efeito de teste
criaremos um tipo objeto com o nome de telefone.
No próximo diálogo devemos indicar os atributos para o tipo Telefone. Quando pressionamos o botão Adicionar,
o diálogo apresentado pela Figura 7.70 é apresentado, permitindo que indiquemos o nome do atributo, seu tipo
escalar e tamanho.
Os botões Editar e Remover, para que possam ser acionados com sucesso, precisam de que tenhamos, previamente,
selecionado um dos atributos já criados. Ao preenchermos todos os atributos desejados (numero varchar2(10) e
ddd varchar2(4)), podemos avançar para o diálogo seguinte, o qual nos ajudará na criação dos métodos.
Ao pressionarmos o botão Adicionar, o diálogo da Figura 7.71 será apresentado para que possamos definir os
métodos, seu tipo (procedimento, função, função Map ou função Order) e parâmetros. Adicionalmente poderemos
indicar as restrições de “pureza” para o método (uso da pragma Restrict_References).
Com estas especificações resolvidas podemos passar para o diálogo seguinte, o qual permitirá que verifiquemos o
resultado antes de aplicá-lo ao banco de dados. Observe a Figura 7.72.
Quando pressionamos o botão Encerrar, a especificação do tipo é aplicada ao banco de dados, porém fica faltando a
criação do corpo do tipo, onde desenvolveremos o corpo da função Ver_Tel. O Form Builder, automaticamente, aciona o
editor de PL/SQL com o corpo do tipo já indicado para que façamos, apenas, a inclusão da lógica dos métodos definidos.
Se não desejarmos realizar esta criação neste momento, poderemos fechar o editor de PL/SQL e, posteriormente,
acioná-lo (clique duplo sobre o ícone do tipo) e selecionar a parte de especificação do tipo ou o corpo do tipo (use
o campo Nome da janela do Editor para navegar de um para o outro).
Se você não desejar usar o Assistente, basta que use a ferramenta de criação sobre o nó Unidades de Programas.
Uma vez que a opção de Especificação de Tipo e de Corpo do Tipo ficam habilitadas, você poderá fazer a criação
usando diretamente o editor de PL/SQL.
EMPACOTAMENTO DA LÓGICA
As formas de empacotamento (procedimentos, funções e pacotes) apresentadas acima existem tanto no ambiente
cliente quanto no ambiente servidor.
Com todas estas opções, não há justificativa para um código não modular, não estruturado.
♦ Considere quebrar seu trigger (no Forms) em um pacote (do trigger X) se a visualização do texto ultrapassar três
páginas (em torno de 80 linhas).
♦ Considere criar rotinas (procedures ou functions) para trechos de programas repetitivos.
♦ Crie uma biblioteca com rotinas que você possa utilizar em diversos sistemas. Podem existir soluções já criadas
em um sistema que facilitem sua programação em outro.
♦ Considere a utilização de pacotes em seu Forms, grupando rotinas referentes a um mesmo trigger ou relativas a
uma mesma ação.
♦ Documente sempre.
A lista acima é apenas de sugestões. Você encontrará a forma mais adequada para o desenvolvimento das suas aplicações.
VARIÁVEIS
Neste tópico trataremos dos diversos tipos de variáveis de uma aplicação Form. Estão subdivididas em dois grandes
grupos: Variáveis do Usuário e Variáveis de Sistema.
As variáveis do usuário podem ser de diversos tipos, com características e abrangências diferentes:
♦ Variáveis Locais.
♦ Itens fora de Canvas.
♦ Variáveis Globais.
♦ Parâmetros.
♦ Variáveis de Pacotes no Form.
As variáveis de sistema não podem ser alteradas pela aplicação, somente consultadas, e fornecem diversas informações
sobre a aplicação em desenvolvimento.
VARIÁVEIS LOCAIS
São aquelas declaradas dentro de um gatilho ou rotina. Os valores dessa variável são acessíveis apenas dentro do
trecho de PL/SQL em que é declarada.
Ao término do bloco de PL/SQL onde é declarada, ela deixa de existir.
Na Listagem 7.08, criamos um bloco dentro do gatilho (Key-Exit) e definimos uma variável local, que deixa de
existir tão logo o bloco interno termine (End).
De um modo geral, o tipo destas variáveis é similar aos tipos válidos em PL/SQL (number, char, varchar2, date,
<tabela ou cursor>%rowtype, <coluna>%type, tipos do usuário, etc.), porém o Form disponibiliza alguns tipos
especiais: Alert, Block, Canvas, Groupcolumn, Editor, Formmodule, Item, Recordgroup, Lov, Menuitem, Paramlist,
Relation, Timer, Viewport, Window, etc.
Estes tipos são criados para a obtenção do ID do objeto. Quando criamos qualquer objeto (canvas, item, janela,
bloco, etc.) com o Form Builder, ele atribui um ID (interno) para esse objeto.
Cada vez que utilizamos uma rotina predefinida, temos de passar o nome ou o ID do objeto em questão. Quando
fornecemos o nome, o Form é obrigado a fazer uma pesquisa prévia para obter o identificador (ID) e só então fazer
acesso ao objeto desejado.
Sendo assim, quando em uma mesma rotina viermos a utilizar diversas vezes o mesmo objeto, pode ser interessante
obter o ID inicialmente e utilizar apenas o identificador. Para isto, o Form Builder disponibiliza uma série de
funções Find_<objeto> que recebem como parâmetro o nome do objeto e retornam o identificador.
Caso venham a ser usadas para armazenamento temporário de informações de um determinado bloco, devem ser
declaradas no próprio bloco, por exemplo, o resultado de um cálculo referente a dados do registro.
MAT FUNC.CD_MAT%TYPE := 0;
END;
As variáveis definidas na parte de especificação de um pacote têm a mesma abrangência de um item fora da
canvas, com a vantagem de não serem afetadas por Clear_Block nem Clear Form.
Na Listagem 7.11 apresentamos a utilização de uma variável de pacote na mesma rotina vista anteriormente na
Listagem 7.09. Para utilizarmos uma variável de pacote em vez da variável local, devemos usar o nome do pacote
como qualificador da variável.
PARÂMETROS
Até este momento estudamos variáveis usadas dentro da aplicação como área de trabalho e em circunstâncias
especiais referenciadas em outros módulos.
Dentro da aplicação onde o parâmetro está definido, deve-se fazer referência a ele como se existisse um bloco com
o nome de Parameter, isto é, :Parameter.<parâmetro>.
Selecionaremos, com o botão direito do mouse, as propriedades de um parâmetro. Podemos especificar seu tipo
(caracter, numérico ou data), tamanho máximo e valor inicial, se desejado.
Na aplicação chamada (Relação), usamos o parâmetro na cláusula Where do bloco Depto (propriedade Cláusula Where).
VARIÁVEIS GLOBAIS
Uma variável global não é definida explicitamente em uma aplicação Form. Sua criação é feita com a primeira
atribuição ou com o uso da rotina Default_Value.
Variáveis Globais são sempre alfanuméricas com comprimento máximo de 255 caracteres.
Tem a vantagem de ficar na memória até que seja explicitamente destruída; desta forma, pode ser usada para
passagem de informações entre aplicações, tanto de ida quanto de volta.
A desvantagem é não ter tipo opcional, são sempre Char. Isto significa que qualquer atribuição de um valor não
alfanumérico implicará uma operação de conversão. Como ela não tem definição de tamanho, não podemos
determinar seu tamanho; seu comprimento está fixado em 255 caracteres (limite).
De um modo geral, a utilização de parâmetros é mais interessante que o uso de globais, pois aqueles têm tipo,
tamanho e até valor inicial.
Na Listagem 7.14 criamos uma variável global de duas formas diferentes. A atribuição à variável V1 será feita todas
as vezes que o gatilho for executado. A atribuição à variável Cidade só ocorrerá na primeira vez que o gatilho for
executado. Se o valor da variável global não for Null, a rotina Default_Value não tem efeito. Se a variável não
existir, o Form cria a variável e atribui o valor especificado.
A referência, como vimos na Listagem 7.14, é feita sempre com a palavra reservada Global (como se fosse um bloco).
Para destruirmos uma variável Global, devemos usar a rotina Erase. Isto liberará memória local.
COMPARANDO AS VARIÁVEIS
O quadro a seguir apresenta de forma resumida as características dos tipos de variáveis vistos até agora.
Possuem um tipo definido (char, date, number, etc.). Sim Sim Sim Sim Não
Podem ser dimensionados Sim Sim Sim Sim Não
São visíveis em toda a aplicação Não Sim Sim Sim Sim
São visíveis através de múltiplos módulos Não Não Não Não Sim
Transferem informações entre módulos Não Não Não Sim Sim
A operação de Clear_Form afeta o valor da variável Não Sim Não Não Não
Podem ser usados na cláusula Where de um bloco Sim Sim Não Sim Sim
VARIÁVEIS DE SISTEMA
O Form possui um conjunto de variáveis às quais ele atribui valores automaticamente. Essas variáveis são chamadas
de variáveis de sistema.
Fornecem um conjunto de informações sobre a aplicação. Em sua maioria, são apenas legíveis (read-only).
A lista completa das variáveis de sistema está no Capítulo 14. Neste momento veremos apenas aquelas que são
mais utilizadas nas aplicações de um modo geral.
♦ System.Cursor_Item – Contém o nome do item onde o cursor (foco) está posicionado. O formato é
<bloco>.<item>.
♦ System.Cursor_Value – Contém o valor do item onde o cursor está localizado.
♦ System.Block_Status – Indica o estado do bloco em que o cursor está localizado ou o bloco corrente durante o
processamento de um gatilho. Pode assumir um dos seguintes valores:
a) CHANGED – Indica que o bloco contém pelo menos um registro alterado.
b) NEW – Indica que o bloco contém apenas registros novos.
c) QUERY – Indica que o bloco contém somente registros válidos recuperados do banco de dados.
♦ System.Last_Query – Representa o comando Select que o Form utiliza para preencher um bloco. Contém o
último comando Select.
♦ System.Last_Record – Contém o valor True se o registro que detém o foco atualmente é o último registro do
bloco. Contém o valor False para os demais registros.
♦ System.Mode – Indica como se encontra o processamento do Form. Os valores podem ser:
a) NORMAL – Indica que o Form está no estado de digitação, entrada de dados, alteração.
b) ENTER_QUERY – Indica que o Form está aguardando que o usuário informe restrições para a consulta a ser realizada.
c) QUERY – Indica que o Form está lendo dados do banco de dados. Este estado será perceptível nos triggers de
Post-Query, por exemplo.
♦ System.Mouse_Item – Indica o nome do item que está sob o mouse. O formato é <bloco>.<item>.
♦ System.Record_Status – Indica o estado do registro em que o cursor está localizado. Pode assumir um dos
seguintes valores:
a) CHANGED – Indica que o registro foi alterado e deve ser enviado para o banco de dados.
b) INSERT – Indica que um registro New foi modificado e deve ser incluído no banco de dados.
b) NEW – Indica que o registro foi criado no buffer, mas ainda não foi modificado.
c) QUERY – Indica que o registro é válido e foi recuperado do banco de dados.
♦ System.Trigger_Item – Indica o item, no formato <bloco>.<item>, no escopo do qual o trigger corrente foi
acionado. Se o trigger é do tipo Key, indica o item em que estava o cursor quando o trigger foi acionado. Seu
valor permanece o mesmo durante toda a execução do gatilho, independente de haver ou não navegação.
Nos exercícios deste tópico faremos uso das variáveis de sistema.
DATABASE TRIGGERS
Já vimos que a atualização de objetos do banco de dados é possível com a ferramenta Form Builder. Veremos,
agora, a manutenção de um trigger do banco de dados.
Expandiremos o nó Objetos do Banco de Dados (Database Objects), o nó Desenv (usuário em uso), o nó Tabelas
(Tables), a tabela Func para encontrarmos o nó Trigger.
Acionaremos, então, a ferramenta Criar (Create) para que seja mostrado o diálogo da Figura 7.74.
Neste diálogo pressionaremos o botão Novo (New) para que a tela seja habilitada.
♦ Alteração do nome das áreas de trabalho (quando usamos trigger de linha) ao preenchermos o campo
Referenciando OLD Como (Referencing Old as) e NEW Como (New as).
♦ Definição de uma restrição de leitura ao preenchermos o campo Quando (When).
♦ Finalmente, o texto do trigger no campo Texto do Gatilho (Trigger Text).
Para relembrar as características básicas de um database trigger, retorne ao Capítulo 3 (de PL/SQL).
EXERCÍCIOS
7.36) Construa uma aplicação de nome EX36 baseada na aplicação EX30. Acrescente a seguinte funcionalidade:
♦ Corrija os pontos da aplicação 30 em que não foram usadas variáveis de ambiente:
a) Tecla Ajuda – Contexto de bloco.
b) Navegação entre os blocos.
c) Nome do bloco atual.
d) Crítica de grau de instrução só na inclusão.
e) Quando o botão Consultar for acionado, navegue para um item do bloco atual.
♦ Crie um botão na barra de ferramentas horizontal que apresente o último comando Select montado na aplicação.
♦ Crie uma função chamada Idade que receba como parâmetro uma data e retorne a idade.
♦ Crie uma função chamada Letras que receba como parâmetro um texto e retorne a quantidade de letras no texto.
7.37) Construa uma aplicação de nome EX37 baseada na aplicação EX36. Acrescente a seguinte funcionalidade:
♦ Acione as rotinas Idade e Letras na leitura ou na alteração dos valores de data de nascimento, nome, sobrenome,
nome do departamento ou nome do projeto.
♦ Criar um parâmetro que indique em que horário o programa atual poderá ser executado.
a) Se o parâmetro receber A, indica período diurno (entre 8 e 18 horas).
b) Se o parâmetro receber B, indica período vespertino (entre 14 e 20 horas).
c) Se o parâmetro receber C, indica período noturno (entre 18 e 20 horas).
d) Qualquer outro valor impede a execução do programa.
Se o programa for acionado fora de seu horário, deve encerrar com mensagem adequada.
♦ Garantir que os campos alfanuméricos sejam fornecidos em letras maiúsculas (todos os blocos).
♦ Altere a forma de apresentação da foto do funcionário. Aumente-a proporcionalmente ao tamanho do desenho
do item.
7.38) Construa uma aplicação de nome EX38 baseada na aplicação EX37. Acrescente a seguinte funcionalidade:
♦ Criar um botão na barra de ferramentas horizontal que acione a aplicação EX37 passando como parâmetro o
período de execução.
♦ Quando for lido um funcionário que seja gerente, impeça que seu salário seja alterado modificando as
características do item na canvas.
♦ Na tela de funcionário, se o usuário passar o mouse sobre o código do departamento, o nome deste deve ser
apresentado em um item flutuante (semelhante ao Dica da Ferramenta) próximo ao campo.
♦ Utilizar a rotina Letras para validação de nome e sobrenome, impedindo que a soma das duas informações
ultrapasse 20 caracteres.
7.39) Construa uma aplicação de nome EX39 baseada na aplicação EX38. Acrescente a seguinte funcionalidade:
♦ Crie uma procedure na base de dados de nome Qtsexo que receba como parâmetro um determinado departamento
e retorne a quantidade de funcionários de cada sexo do departamento informado.
♦ Acione a rotina Qtsexo quando um departamento for escolhido (na canvas de Funcionário) e quando cada
departamento for lido na canvas de Departamento.
♦ A cada 30 minutos a aplicação deve verificar se a hora atual ainda está dentro dos limites de tempo autorizados
para esta aplicação.
7.40) Construa uma aplicação de nome EX40 baseada na aplicação EX39. Acrescente a seguinte funcionalidade:
♦ Crie três indicadores (caixa de seleção) que permitam ao usuário estabelecer a ordenação da consulta por:
departamento, nome do funcionário e/ou salário (podem ser aceitos todos os três, dois ou um item marcado). A
ordem será depto (primária), nome (secundária) e salário (terciária).
♦ Crie um botão nesta aplicação para acionar o relatório de nome REP17 (será testado no próximo capítulo) que
receba como parâmetro um código de departamento.
♦ Crie uma trigger na base de dados de nome Csal que impeça que o salário dos funcionários seja diminuído.
ALERTAS (ALERTS)
Você já reparou que quando enviamos uma mensagem para a linha de mensagem (no rodapé da aplicação) ela
aparece de forma bastante discreta? Imagine se enviarmos uma mensagem importante para o usuário e ele não a ver.
O Form Builder, então, nos oferece uma forma bem menos discreta de enviar mensagens, avisos, etc. para o
usuário: o objeto Alerta.
Um alerta é uma janela Modal, isto é, uma janela que o usuário deve responder e fechar para que seja possível o
prosseguimento da aplicação. Quando o usuário receber uma mensagem em uma janela Modal, ele não poderá
continuar a aplicação a menos que responda à questão apresentada pela janela.
Um exemplo de janela Modal: é aquela que aparece quando temos registros pendentes de atualização em nossa
aplicação e decidimos sair da aplicação. Aparece um diálogo (janela Modal) perguntando ao usuário se ele deseja
salvar ou não os registros pendentes. Até que venhamos a aceitar uma das opções apresentadas, não podemos
prosseguir. A aplicação parece congelada.
Podemos usar esta forma de trabalho para envio de qualquer mensagem que desejarmos, bastando que coloquemos
essa mensagem em um alerta.
Ainda utilizando a aplicação Valida, sem todas as unidades de programa adicionadas, selecione o nó Alerta (Alert)
e crie um alerta para teste.
Na Figura 7.75 incluímos um alerta chamado Erro. As propriedades do grupo Funcional aparecem na janela de
propriedades ao lado.
♦ Título (Title) – Corresponde ao título da janela a ser apresentada (será mostrado na barra azul da janela).
♦ Mensagem (Message) – Mensagem a ser apresentada para o usuário.
♦ Estilo de Alerta (Alert Style) – Determina o ícone a ser apresentado ao lado da mensagem. Pode ser: Parar
(Caution), Precaução (Warning) ou Observação (Informational).
♦ Etiqueta de Botão (Button Label) – Determina o texto a ser apresentado no botão (em um dos três) de uma janela
de Alerta. Os valores defaults para as etiquetas são: OK, Cancel e Null. Quando um botão não recebe etiqueta,
significa que não será apresentado na janela de Alerta. Ao menos um dos botões de um Alerta deve ter etiqueta.
♦ Botão de Alerta Default (Default Alert Button) – Determina o botão default. O usuário poderá acionar este botão
com a tecla Enter.
Após a definição do alerta, devemos acioná-lo. Usaremos o trigger Key-Down em nível de módulo para acionar o alerta.
A Listagem 7.15 mostra o código de PL/SQL utilizado para acionarmos o alerta. A rotina Show_Alert é uma função
que retorna um código numérico indicativo do botão que o usuário selecionou. Isto nos permitirá tomar ações
diferentes de acordo com o botão escolhido.
As constantes Alert_Button1 a 3 podem ser utilizadas para comparação com a variável local criada para verificarmos
o botão escolhido.
Suponhamos que a mensagem a ser apresentada não fosse fixa; que desejássemos mostrar todas as mensagens de
erro do Form em janelas de alerta. Precisaríamos alterar o texto da mensagem.
A Listagem 7.16 mostra esta ação no trigger On-Error. Alteramos o alerta para que fosse apresentado um único
botão (basta retirar o texto da propriedade Etiqueta do Botão 2) e o resultado aparece na Figura 7.77.
Quando definimos um atributo visual, não somos obrigados a especificar todas as propriedades visuais, podemos
definir apenas aquelas que desejamos padronizar.
Como exemplo, criaremos um atributo visual (de nome Corrente) visando identificar para o usuário qual o registro
corrente (use a ferramenta Criar sobre o nó Atributos Visuais da sua aplicação).
Para realizarmos este teste, utilizaremos a aplicação Relação, que contém mais de um registro por bloco.
No atributo visual Corrente modificamos apenas a primeira Cor de Fundo (BackGround Color) para White (Branco)
e a segunda propriedade Cor de Fundo (Foreground Color) para DarkGreen (Verde Escuro).
Para obtermos o resultado desejado, preenchemos o nome do atributo visual na propriedade Grupo de Atributos
Visuais do Registro Corrente (Current Record Visual Attribute Group) do grupo Registros (Records) do Bloco Func
e do Bloco Depto.
O resultado na execução é o apresentado pela Figura 7.78.
Este foi apenas um tipo de uso para os atributos visuais. Você poderá definir padrões para utilização em situações
diferentes. Teste!
EDITOR
Um editor é uma janela para digitação de texto pelo usuário. Em vez de ficar restrito ao tamanho da área delimitada
para o item na tela, ao acionarmos o editor será apresentada uma janela para digitação livre até o tamanho definido
para o campo.
O Form fornece um editor-padrão, predefinido, que não precisa de nenhuma programação especial para ser
apresentado. Basta que o usuário posicione o cursor sobre o item que deseja editar e pressione o conjunto de teclas
correspondente à ação Editar (CTRL+e). Isto fará com que seja apresentada a janela de edição.
Posicione o mouse sobre o nó Editor e utilize a ferramenta Criar para adicionar esse objeto à sua aplicação. O
objetivo da criação desse editor é a possibilidade de modificarmos algumas das características do editor-padrão,
como veremos por suas propriedades:
♦ Título (Title) – Título a ser apresentado para a janela do editor. Preenchemos com o texto Editor de Teste.
♦ Título de Base (Bottom Title) – Título a ser apresentado abaixo do campo de edição na janela do editor.
Preenchemos com Rodapé do Editor.
♦ Estilo de Sobreposição (Wrap Style) – Especifica como o texto será apresentado quando seu conteúdo exceder à
largura especificada para a janela do editor. Os valores válidos para essa propriedade são: Nenhum (None),
Caractere (Character) ou Palavra (Word). Se escolhermos Palavra (Word), o texto quebrará de linha somente em
término de palavra. Escolhemos Palavra.
O grupo Físico permite a determinação de uma posição para apresentação dessa janela, além de tamanho da janela
e presença ou não de barra de rolagem.
Não é suficiente, no entanto, a criação do objeto. Temos de associá-lo aos itens onde desejamos que ele apareça.
Escolhemos o item Nm_Depto para associar o editor criado. Devemos acionar sua paleta de propriedades para que
possamos estabelecer a associação. O grupo Editor deve ser preenchido para que a apresentação seja feita nas condições
desejadas. Observe que a propriedade Editor pode ser preenchida com o nome do editor criado, o texto System_Editor
ou <Nulo>. No caso de <Nulo>, será apresentado o editor-padrão do Form. No caso de um nome, será apresentado o
editor definido, e no caso de System_Editor será acionado um editor do sistema operacional definido através de uma
variável de ambiente (FORMS60_EDITOR=C:\windows\notepad.exe) no registrador do Windows.
Podemos especificar, também, a posição de aparecimento da janela. A especificação desse valor se sobrepõe à
especificação que fizermos no objeto Editor. Para efeito de teste preencha a propriedade Posição X do Editor com
170 e a propriedade Posição Y do Editor com 125.
Na Listagem 7.17, somente quando o foco estiver sobre o item nm_depto do bloco Depto, o editor será acionado.
Com esta forma de trabalhar, podemos controlar a apresentação ou não do editor para os itens de texto da canvas.
Podemos agir ainda de uma outra maneira.
Na Listagem 7.18 apresentamos a rotina Show_Editor que aciona o editor da mesma forma que vimos anteriormente,
porém não precisamos associar o editor ao item a tempo de desenvolvimento e o usuário não precisa estar com o
cursor posicionado sobre o item a ser editado.
Observe que um dos parâmetros passados para a rotina é o texto a ser editado (:nm_depto). O retorno da edição, isto
é, o texto modificado pelo usuário é recebido pela variável local Texto. Tomamos este cuidado (em vez de atribuir
diretamente à variável :nm_depto), pois se o usuário pressionar a tecla Cancelar (Cancel) da janela do editor o texto
retornado é Null. Assim, para que não seja perdido o conteúdo da variável nm_depto, recebemos o texto editado em
uma variável de trabalho e em seguida verificamos o valor do booleano Retorno. Se o usuário escolher OK, o booleano
retorna True (e devolvemos o valor para nm_depto). Caso contrário, não sujamos o item da tela.
Você, agora, poderá escolher sua forma preferida de acionar o editor para o usuário.
EXERCÍCIOS
7.41) Construa uma aplicação de nome EX41 baseada na aplicação EX40. Acrescente a seguinte funcionalidade:
♦ Crie uma rotina que recebe um texto e mostre este texto em uma janela de Alerta que possua um único botão.
♦ Todas as mensagens enviadas pelo programa (as messages) devem ser substituídas por mensagens apresentadas
pelo Alerta.
♦ Todas as mensagens de erro ou aviso fornecidas pelo Forms Runtime devem ser apresentadas na janela do Alerta.
7.42) Construa uma aplicação de nome EX42 baseada na aplicação EX41. Acrescente a seguinte funcionalidade:
♦ Crie um editor com letra Courier New, tamanho 8, azul, quebra de linha em fronteira de palavra e que contenha
uma barra de rolagem vertical.
♦ Crie um botão na barra de ferramentas horizontal que acione o editor apenas para os itens: nm_depto, nm_foto
e nm_proj.
♦ Para os demais itens é vedada a utilização de editor.
♦ Para o item nm_proj deve ser acionado o bloco de notas (do Windows) no lugar do editor interno.
♦ O editor deve ser posicionado exatamente sobre o item em edição, exceto no caso de nm_foto, quando o editor
deve ser posicionado sobre o item vl_sal.
7.43) Construa uma aplicação de nome EX43 baseada na aplicação EX42. Acrescente a seguinte funcionalidade:
♦ Especificar os seguinte atributos visuais:
a) av_prompt – letra vermelha, Arial, tamanho 8.
b) av_editor – letra azul, Courier New, tamanho 8.
c) av_item_atu – letra preta, Arial, tamanho 8, cor de fundo branca.
d) av_item_cons – letra cinza, tipo Courier New, tamanho 8, cor de fundo branca.
e) av_item_atu_corr – cor de fundo cinza.
f) av_item_mod – cor de fundo vermelha.
Selecionaremos o nó LOVs e pressionaremos o botão Criar (Create) da barra de ferramentas do Navegador. Será
apresentada uma janela modal para que indiquemos se desejamos ou não utilizar o Assistente de LOV. Este assistente
nos ajudará, passo a passo, na criação da lista de valores que estamos desejando criar. Se não optarmos por esta
escolha, ou seja, preferirmos a criação da LOV manualmente, o Form Builder a criará e através de suas propriedades
faremos as customizações que acharmos convenientes. Neste momento, utilizaremos o Assistente.
O primeiro diálogo apresentado corresponde à tela de Boas-Vindas do editor, que pode ser descartada. No segundo
diálogo, devemos indicar se a lista de valores será criada a partir de um novo Record Group a ser criado
simultaneamente ou se baseará em um Record Group já existente. Se não tivermos nenhum Record Group em
nossa aplicação, a segunda opção já aparece desabilitada. Uma vez que não criamos ainda nenhum Record Group,
a primeira opção será, forçosamente, nossa escolhida. Veja a Figura 7.80 a seguir.
No próximo diálogo devemos informar o comando Select a ser incluído no Record Group. Podemos digitar o
comando, importar o texto de um arquivo em disco, estabelecer conexão com o banco de dados, acionar o Query
Builder para auxílio na montagem da sintaxe adequada e, finalmente, verificar a sintaxe preenchida. Preencheremos
o campo Instrução de Consulta SQL com o texto “Select cd_depto, nm_depto from Depto”.
O Query Builder é uma ferramenta auxiliar para a montagem de queries. Uma vez que seu uso é mais intenso durante um relatório. Seu estudo
detalhado foi incluído no próximo capítulo, quando estudaremos o Report Builder 6i.
Após preenchermos este diálogo nos é apresentado o quarto diálogo, no qual indicamos quais colunas do Record Group
devem fazer parte da lista de valores. São apresentados dois campos, um contendo a lista de colunas existentes no
Record Group (Colunas do Grupo de Registros) e outro contendo a lista de colunas existentes na Lov. Usando os botões
centrais podemos transferir as colunas do Record Group para a Lov (> e >>) ou da Lov para o Record Group (< e <<).
Uma vez que é nossa primeira montagem de uma LOV, passaremos todas as colunas (>>) do grupo de registros para
a LOV. Isto significa, na prática, que poderemos não só apresentar ao nosso usuário todas as colunas armazenadas
no grupo de registros, como também poderemos obter os dados destas colunas quando o usuário selecionar uma
das listas da LOV.
No próximo diálogo, visto na Figura 7.81, indicamos o texto a ser apresentado como cabeçalho de coluna, o
tamanho de cada coluna (ou a opção de dimensionamento automático) e o nome do item (ou itens) para onde
deve ser feito o retorno dos valores referentes à linha selecionada pelo usuário. Neste diálogo encontramos um
botão identificado como “Pesquisar item de retorno...” que nos apresenta uma lista com os itens presentes na
aplicação para que possamos, mais facilmente, indicar para que itens devem ser copiados os valores referentes à
linha selecionada pelo usuário.
Em nosso caso preenchemos da seguinte forma: deixamos em branco o Título da coluna CD_DEPTO e preenchemos
sua largura com 0 (zero). Isto significa que quando o usuário abrir a Lista de Valores não verá a coluna CD_DEPTO
(apesar de ela estar “escondida” na LOV), porém, quando ele selecionar uma das linhas da LOV, o valor de CD_DEPTO
correspondente à linha selecionada será atribuído ao item CD_DEPTO do bloco FUNC do registro corrente, a
tempo de execução. Para a coluna NM_DEPTO, agimos inversamente, ou seja, ela será mostrada para o usuário na
lista de valores (pois sua largura é maior que zero), porém seu conteúdo não será atribuído a nenhum item da
aplicação, pois a propriedade Valor de Retorno não foi preenchida.
Observe, ainda, que na parte inferior temos um check box que, quando marcado, faz com que o Form Builder
calcule, automaticamente, o tamanho das colunas da LOV de acordo com seu conteúdo.
Na seqüência, temos a possibilidade de informar um título para a janela da Lov, suas dimensões (largura e altura) e seu
posicionamento na tela a tempo de execução. Este posicionamento poderá ser feito, automaticamente, pelo Forms
Runtime, ou predetermindo por nós. Escolheremos, inicialmente, deixar que o Forms determine seu posicionamento.
O próximo diálogo (sétimo) permite a indicação da quantidade de linhas a serem lidas de cada vez (para carga da
Lov), isto é, a quantidade de linhas a cada Fetch. O campo Renovar dados do grupo de registros antes de exibir a
LOV determina a freqüência com que esta leitura deve ser feita. Se o marcarmos indicamos que cada vez que o
usuário acionar a LOV deve ser feito um acesso ao banco de dados para preenchimento prévio do Grupo de
Registros. Se o desmarcarmos indicamos que a renovação dos dados será feita por programação.
Devemos ponderar sobre a marcação ou não deste campo, pois está associado, diretamente, à freqüência de I/O no
banco de dados. Se as informações que estamos mostrando na lista de valores forem estáveis (por exemplo Unidades
da Federação, Departamentos da empresa, Estado Civil, etc.) devemos desmarcar o campo para que não venhamos
a fazer leituras desnecessárias. Se, por outro lado, as informações forem constantemente modificadas, podemos
optar por renová-las a cada acesso (marcando) ou programar uma freqüência menos intensa, se tivermos problemas
(I/O) para acesso ao banco de dados. No nosso caso, desmarcamos a opção.
O próximo campo deste diálogo refere-se à utilização de filtro para diminuição da quantidade de linhas lidas. Isto
pode ser útil se a quantidade de linhas a serem trazidas pela LOV for muito grande. Quando marcamos esta opção
do Forms Runtime apresentar-se-á um diálogo prévio para que o usuário forneça uma “pista” dos dados da lista
que deseja ver (a informação preenchida será usada na cláusula Where junto com Like, para diminuir a quantidade
de linhas transferidas para o ambiente cliente).
No diálogo seguinte (oitavo) podemos (ou não) estabelecer a associação da Lov a um item. São apresentados,
opcionalmente, todos os itens indicados como retorno (em diálogo anterior). Este diálogo é opcional, ou seja, se
você não indicar a associação, a Lov deve ser acionada por programação. Quando estabelecemos a associação, o
usuário poderá acionar a Lov usando a tecla [List] (F9). No nosso caso, apenas o item FUNC.CD_DEPTO aparece
como opção, uma vez que somente ele receberá valor da LOV. Posteriormente, através das propriedades, poderemos
escolher outras colunas para acionamento da LOV, se desejarmos. Neste momento aceitaremos a coluna apresentada.
Quando teclamos o botão Avançar neste diálogo, nos é apresentado o diálogo de encerramento, sendo, em seguida,
criada a lista de valores e o Record Group.
Passaremos ao estudo das características da lista de valores através de suas propriedades. Você perceberá que estas
propriedades correspondem às opções que preenchemos utilizando o Assistente.
PROPRIEDADES DA LOV
Analisemos as propriedades da lista (Lov) presentes no grupo funcional.
♦ Título (Title) – Indica o título da janela da lista.
♦ Tipo de Lista (List Type) – Indica se a lista é baseada em um Record Group. Somente a opção Grupo de Registros
está disponível.
♦ Grupo de Registros (Record Group) – Define o nome do record group ao qual a lista se refere.
♦ Propriedades de Mapeamento de Coluna (Column Mapping Properties) – Esta propriedade será utilizada para
mapearmos, dentre as colunas no record group, quais serão apresentadas na lista. Veremos em detalhes após as
propriedades básicas.
♦ Filtrar Antes da Exibição (Filter Before Display) – Quando marcamos esta opção com Sim, a tempo de execução
é apresentada uma tela para que o usuário digite algum texto que restrinja a pesquisa na base de dados. O texto
digitado pelo usuário é completado com ‘%’ e utilizado em uma cláusula Where adicionada à query. Esta restrição
é montada para a primeira coluna visível (não é a primeira coluna da lista) na janela da Lov. Para efeito de teste,
preencheremos essa propriedade com Sim.
♦ Exibição Automática (Automatic Display) – Indica que, quando o item ao qual a Lov está associada receber o
foco, a lista é apresentada automaticamente. Preencha com Sim.
♦ Renovação Automática (Automatic Refresh) – Indica que, a cada vez que o usuário acionar a Lov, o comando
Select associado com o Record Group será executado para “refrescar” os dados armazenados em memória.
Preencha com Não.
♦ Seleção Automática (Automatic Select) – Indica que, se a lista apresentada contiver apenas uma linha, a seleção
é automática. A janela da Lov é fechada e a linha selecionada. Preencha com Sim.
♦ Salto Automático (Automatic Skip) – Indica que após a seleção de uma das opções da lista o cursor deve navegar
automaticamente para o próximo campo. Preencher com Sim.
♦ Posição Automática (Automatic Position) – Especifica que o Form deve posicionar a janela da Lov próxima ao
campo de onde foi acionado. Preencher com Sim.
♦ Largura Automática da Coluna (Automatic Column Width) – Quando marcamos esta propriedade para Sim, o
Form verificará o que é maior: o título da coluna (propriedade Título da Coluna – Column Title) ou seu
comprimento (propriedade Largura da Exibição – Display Width), e faz o ajuste da largura da coluna necessário.
Se marcarmos essa propriedade com Não, a largura será dada pela propriedade Largura da Exibição (Display
Width). Preencha com Sim.
Pode-se preencher o grupo Físico com o posicionamento da Lov, se desejarmos uma posição fixa, ou preencher
apenas na associação com o item, ou ainda deixar o posicionamento a cargo do Form (com a propriedade Posição
Automática). Após os testes preliminares, faça outros para verificar estas opções.
Na parte superior deste diálogo são mostradas as colunas presentes do Record Group. Quando selecionamos (basta
colocar o cursor em uma delas e clicar) uma das colunas da parte de cima, as características apresentadas abaixo são
referentes a essa coluna.
♦ Item de Retorno (Return Item) – Quando o usuário selecionar uma das linhas exibidas pela Lov, podemos atribuir
o valor dessa coluna (atualmente selecionada) para um dos itens da aplicação. No nosso caso, ao selecionarmos a
linha da coluna cd_depto esta propriedade deve estar preenchida com “Func.cd_depto”. Caso não esteja, pressione
o botão Procurar e selecione este item da lista apresentada. Para a linha de nm_depto, essa propriedade deve ficar
em branco, pois não desejamos copiar o nome do departamento para nenhum item da aplicação.
♦ Largura da Exibição (Display Width) – Esta propriedade determina a largura da coluna selecionada na janela da
Lov. Preencheremos 0 para a coluna cd_depto e 277 para a coluna nm_depto. Com estas especificações, queremos
que a janela da Lov mostre apenas a coluna nm_depto, mas quando o usuário escolher um nome de departamento
queremos que o código seja transferido para o item especificado.
♦ Título da Coluna (Column Title) – Título da Coluna. Uma vez que apenas a coluna nm_depto será mostrada na
janela da LOV, esta propriedade deve ficar em branco para a coluna cd_depto e preenchida com o texto “Nome”
para a coluna nm_depto.
♦ Faça uma consulta geral e em seguida navegue para o item cd_depto. Observe que, automaticamente, foi
apresentada a tela da Lov vazia para que o usuário preencha com uma restrição.
♦ Preencha com D (maiúsculo) e pressione o botão Loc. A lista será apresentada apenas com os nomes de departamento
que comecem com D. A restrição é aplicada à coluna nm_depto, pois é a primeira coluna visível da Lov.
♦ Você reparou que a janela da Lov apareceu próxima ao item cd_depto?
♦ Selecione um dos valores apresentados, por exemplo, Diretoria de Sistemas. Dê OK. Qual o valor do item cd_depto
agora? A coluna cd_depto (contendo o valor D01) foi copiada para o item cd_depto do registro corrente.
♦ Onde está o cursor agora? Ele navegou para o próximo item da tela (no meu caso Nr_Cargo).
♦ Retorne ao desenvolvimento e desmarque as propriedades Filtrar Antes da Exibição (Filter Before Display) e
Exibição Automática (Automatic Display). No mapeamento, coloque a coluna cd_depto com largura de exibição
(display width) igual a 2 e título igual a “Código”.
♦ Execute novamente a aplicação e posicione o cursor sobre o item cd_depto.
♦ Para acionar a lista de valores, pressione a tecla F9. O que aconteceu com a coluna cd_depto? Ela e o título
ficaram totalmente visíveis, embora o tamanho definido tenha sido 2 (pontos). Isto ocorreu porque o Forms
Runtime dimensionou a coluna automaticamente.
♦ Preencha o campo Loc com o texto B%, isto é, desejamos obter todos os departamentos cujo código comece
com B. A restrição será acionada para a primeira coluna. Quando pressionarmos a tecla Loc, a tela da Lov será
fechada e o item cd_depto receberá o valor B01. É isto que faz a propriedade Seleção Automática (Automatic
Select), quando a lista contém apenas uma linha.
♦ Retornemos mais uma vez ao desenvolvimento, e na tela de propriedades do item cd_depto, no grupo Lov,
marque a propriedade Validar a Partir da Lista (Validate from List) com Sim. Execute novamente a aplicação.
♦ Faça uma consulta geral e posicione o cursor sobre o item cd_depto, porém não acione a LOV. Preencha o item com o
valor Z01 e navegue para o próximo item da tela. A janela da Lov é apresentada automaticamente. Isto ocorre porque
o valor digitado não confere com os códigos apresentados na lista. Repita o teste, mas preencha um valor válido.
A restrição é sempre sobre a primeira coluna visível. Desta forma, se desejamos validar através da LOV o preenchimento do item CD_DEPTO, a
coluna CD_DEPTO da LOV deve ficar visível na lista. Caso contrário (coloque, novamente, o tamanho de exibição da coluna CD_DEPTO da LOV
para zero), ao escolhermos A00, a LOV será acionada automaticamente, pois não temos nenhum nome de departamento começando com A00.
Show_Lov é uma função que retorna um boleano True ou False indicando se a janela foi apresentada ou não.
Verifique na sintaxe desta rotina que ela pode receber como parâmetro o posicionamento da lista e o nome da
lista, caso não venhamos a fazer a associação com o item (propriedades do item).
A COLUNA DE PESQUISA
A primeira coluna que especificamos em uma Lov será usada para pesquisa:
♦ Seleção Automática (Automatic Select) – Ocorre quando o operador digita alguma letra e a janela da LOV está ativa.
♦ Loc. – A pesquisa será realizada a partir do caracter mais à esquerda somente na primeira coluna, a não ser que
o operador inicie o texto com %. Neste caso, todas as colunas serão pesquisadas.
♦ Filtrar Antes da Exibição (Filter Before Display) – O texto entrado no diálogo é usado na cláusula Where, de
acesso ao banco de dados, acrescida de %. A pesquisa é feita apenas para a primeira coluna.
♦ Validar a partir da Lista (Validate from List) – A validação é feita em relação à primeira coluna visível.
Agora que você já está conhecendo bastante as Lovs, vamos estudar os Record Groups.
RECORD GROUPS
Um Grupo de Registros (Record Group) é uma estrutura interna do Form capaz de armazenar dados como se fosse
uma tabela (ou uma matriz), isto é, contendo linhas e colunas. Esse armazenamento, a princípio, é feito em memória.
Para efeito de teste criaremos um do tipo Query; em seguida, um do tipo Static, e durante os exercícios deste tópico
usaremos um Non-Query.
Continuaremos com a aplicação Valida para efeito de teste. Remova, porém, a Lov e o Record Group já existente.
A Figura 7.84 nos apresenta o diálogo que será mostrado na situação atual.
Escolheremos a criação baseada na consulta e preencheremos o campo Consultar Texto (Query Text) com o valor
“Select cd_depto, nm_depto from depto” e pressionaremos o botão OK.
No diálogo apresentado (Figura 7.84), escolha a opção de criar um Record Group estático.
Quando pressionamos o botão OK, o diálogo da Figura 7.85 é apresentado.
É com este diálogo que preencheremos a tabela em memória. Suponhamos que desejássemos montar uma tabela
de grau de instrução. Preencheríamos o diálogo anterior da seguinte forma:
♦ Para o campo Nomes de Coluna (Column Names) preencheríamos com cd_git na primeira linha e ds_git na
segunda linha. Se você errar e quiser remover uma linha da lista use CTRL+SHIFT+<, e para incluir uma nova
linha no meio de outras use CTRL+SHIFT+>.
♦ O tipo correspondente à coluna cd_git seria numérico (não tem tamanho) e para a coluna ds_git usaremos
caracter (car) de comprimento 30. Para fazermos esta especificação devemos colocar o cursor sobre o campo
CD_GIT e preencher o campo Tipo de Dados. Em seguida, colocar o cursor sobre o campo DS_GIT e preencher
os campos Tipo de Dados e Tamanho.
♦ O último campo desse diálogo corresponde aos valores a serem atribuídos a cada coluna. Para cargo usaremos:
12, 14, 15, 16, 17, 18, 19, 20. Para descrição usaremos: primeiro grau incompleto, primeiro grau completo,
segundo grau incompleto, segundo grau completo, superior, pós-graduação, mestrado e doutorado. Veja o
resultado na Figura 7.85. Para realizarmos este preenchimento agiremos da mesma forma anterior, ou seja,
colocaremos o cursor sobre a coluna CD_GIT e preencheremos os valores no campo Valores de Coluna (cada
número em uma linha). Em seguida colocaremos o cursor sobre a coluna DS_GIT e preencheremos os textos no
campo Valores de Coluna.
Observe que na tela de propriedades do Record Group, no grupo funcional, somente encontramos propriedades
relativas ao tipo de Record Group e o mapeamento das colunas.
Quando pressionamos o botão Avançar, neste diálogo, o Form Builder apresenta um novo diálogo (não apresentado
anteriormente na criação da LOV) para indicarmos que, se viermos a modificar o comando SELECT associado ao
Record Group, desejaremos incorporar esta modificação no grupo de registros ou desejaremos criar um novo
grupo de registros. Em nosso caso selecionaremos a opção Modificar Grupo de Registros Existente. Os demais
diálogos já foram analisados anteriormente, quando criamos a LOV e o Record Group simultaneamente.
Não esqueça de associar a Lov de departamento ao item cd_depto e a Lov de grau de instrução ao item nr_git. Nem
de preencher o retorno (Retornar Item – Return Item) para as respectivas colunas na propriedade de mapeamento das
colunas na Lov. Observe que o tamanho de exibição da coluna cd_git está muito grande (209); diminua para 18.
Execute a aplicação e faça os testes da Lov. Observe que o botão criado anteriormente serve para ambas as Lovs se
você fizer a associação da Lov ao item.
EXERCÍCIOS
7.45) Construa uma aplicação de nome EX45 baseada na aplicação EX44. Acrescente a seguinte funcionalidade:
♦ Crie um record group estático com as seguintes colunas: nm_item (30 caracteres), tx_ajuda (300 caracteres).
♦ Preencha o record group anterior com o nome de dez itens da sua aplicação juntamente com dez mensagens de ajuda.
♦ Faça uma função que receba como parâmetro o nome do item e o pesquise no record group anterior, retornando
a mensagem correspondente ou ‘Não encontrada mensagem de ajuda’.
♦ Substitua o teste presente no botão de ajuda pelo uso da rotina.
7.46) Construa uma aplicação de nome EX46 baseada na aplicação EX45. Acrescente a seguinte funcionalidade:
♦ Crie uma rotina para preencher um record group dinâmico que contenha o menor e o maior valor salarial de
cada cargo.
♦ Utilize esse record group para estabelecer a crítica de cargo x salário.
♦ Utilize esse record group para apresentar na área de mensagem a faixa salarial válida quando o usuário passar o
mouse sobre o código do cargo.
7.47) Construa uma aplicação de nome EX47 baseada na aplicação EX46. Acrescente a seguinte funcionalidade:
♦ Crie uma lov e um record group simultaneamente. Essa lov deve apresentar o nome de cada departamento e
retornar o código do departamento escolhido.
♦ Acione essa lov das colunas de código de departamento na canvas de funcionário, projeto de departamento
(depto contábil).
♦ Essa lov deve ser refrescada, no mínimo, a cada 10 minutos e não a cada acionamento.
7.48) Construa uma aplicação de nome EX48 baseada na aplicação EX47. Acrescente a seguinte funcionalidade:
♦ Crie um record group estático contendo uma coluna de data.
♦ Este record group deverá ser preenchido dinamicamente da seguinte forma:
a) O dia será sempre 10.
b) A partir da data atual, obter um mês para trás e seis meses para frente.
c) Incluir a data atual.
♦ O total de linhas deste record group é oito.
♦ Crie uma lov baseada neste record group para utilização pela coluna dt_adm.
♦ A lista deve ser exibida automaticamente quando o cursor for posicionado na data de admissão.
♦ Essa lov não pode ser refrescada.
♦ O posicionamento da lov na tela deve ser deixado a cargo do Forms Runtime.
♦ Validar a data a partir da lov.
DESCRIÇÃO
A depuração no Form significa que vamos acompanhar a execução do programa passo a passo e, eventualmente,
poderemos intervir no processo. Estamos depurando o código PL/SQL do programa.
A depuração pode ser feita de duas formas:
♦ Dinâmica – Quando iniciamos a execução do programa e, neste momento, definimos os pontos de interrupção.
♦ Estática – Definimos os triggers ou unidades de programa que desejamos analisar e usamos o pacote Debug para
forçar uma interrupção. A utilização do pacote é feita a tempo de desenvolvimento, ainda no Form Builder.
Para testarmos as duas formas de depuração, criemos, ainda na aplicação Valida, dois gatilhos (triggers): um trigger
do tipo Key-Down em nível de módulo com o texto da Listagem 7.20 e um gatilho do tipo Pre-Query em nível de
bloco Func (conforme a Listagem 7.21).
Para acionarmos o depurador devemos usar a opção Executar Depuração de Form para testar a execução no lugar
da opção Executar Form Cliente/Servidor, que vínhamos utilizando até agora.
A JANELA DE DEPURAÇÃO
Quando a execução se inicia, aparece uma janela intitulada “Depurador de Forms” (Form Debugger).
Nossa primeira tarefa será marcar um ponto de interrupção; portanto, no Painel do Navegador, expanda o nó de
módulos até que você encontre a trigger de Pre-Query do Bloco Func. Clique sobre o ícone do trigger.
BREAKPOINT
Para efeito de teste, selecione a primeira linha após o Begin (primeira linha executável) do trigger. Escolha no
menu Depurar (Debug) a opção Interromper (Break). Será mostrado o diálogo da Figura 7.89.
Retorne ao Painel de Fonte. Se não desejarmos preencher nenhum texto a ser executado juntamente com o ponto
de interrupção, podemos selecionar a linha que desejamos interromper e efetuar um clique duplo. O ponto de
interrupção será marcado da mesma forma. Teste na linha com o texto “V1 := TO_NUMBER(TO_CHAR(V3, ‘D’));”.
Para desmarcar o ponto de interrupção, selecione a linha em que o ponto está marcado e efetue um clique duplo.
Verifique o nó Ações de Depuração e observe que o ponto de interrupção foi removido.
Antes de seguir, desmarque os dois pontos de interrupção criados e posicione o cursor novamente sobre a linha 7
do Painel de Fonte.
TRIGGER
Um gatilho funciona ligeiramente diferente de um ponto de interrupção. No gatilho escreveremos uma lógica que
determinará se a interrupção ocorrerá ou não.
A criação do gatilho é similar à criação do ponto de interrupção. Selecionamos a linha desejada (7), escolhemos no
menu Depurar (Debug) a opção Gatilho (Trigger).
Observe a Figura 7.91. O ponto em que o programa está parado é marcado no Painel de Fonte com o sinal =>.
Verifique o nó Stack. Ele contém o valor das variáveis locais deste trecho de código. A variável V1 possui o valor 5.
Isto significa que o código anexado ao ponto de interrupção já foi executado.
Na parte superior da janela encontramos diversos botões, agora habilitados, que nos permitirão executar uma
linha de cada vez. São eles:
♦ Entrar (Step Into) – Esta opção executa cada linha do programa passo a passo. Ocorre a interrupção a cada
comando. Se o código acionar uma unidade de programa, esta também é acompanhada passo a passo.
♦ Transpor (Step Over) – Esta opção também executa cada linha do programa passo a passo, porém se houver chamada
a uma unidade de programa, esta não é detalhada. A sub-rotina é executada como se fosse uma linha simples.
♦ Sair (Step Out) – Esta opção é para ser usada dentro de uma unidade de programa chamada, pois ela termina a
unidade de programa atual e retorna a quem a chamou. Se estivermos no código principal, essa opção encerrará
a depuração. O trecho de código final é executado.
♦ Ir (Go) – Esta opção encerra a execução passo a passo voltando para a forma normal do programa. O restante do
código é executado.
♦ Reinicializar (Reset) – Esta opção desiste da execução passo a passo. O restante do código não é executado.
Pressione o botão Entrar (Step Into) e verifique que o valor das variáveis foi modificado, pois a linha 7 foi executada.
Faça outros testes com estas opções. Crie um trecho de código maior para analisar com mais detalhes os resultados.
Esta forma de utilização também pode ser utilizada com a procedure Break presente no pacote Standard Extensions.
A Figura 7.92 mostra o surgimento do depurador exatamente quando o valor de I é igual a 7. Expanda o Painel do
Navegador e obtenha o valor das variáveis locais (estão no nó Stack). Verifique também o valor da variável nr_git
(dentro do módulo Valida, no nó Itens do bloco Func).
Como teste adicional, usaremos o Painel de Comando para modificar o valor do item nr_git.
Execute o comando :nr_git := 1; na linha de comando do último painel. Pressione a tecla Entrar (Step Into).
Verifique agora o valor do item nr_git.
EXERCÍCIOS
7.49) Construa uma aplicação de nome EX49 baseada na aplicação EX48. Acrescente a seguinte funcionalidade:
♦ Marque um Breakpoint na leitura do registro de funcionário (Post-Query).
♦ Teste as interrupções verificando:
a) O valor das variáveis de ambiente.
b) O valor das variáveis locais.
c) O valor dos itens.
Um item do tipo ActiveX cria um container para o controle ActiveX. O controle não é uma aplicação em separado;
devemos considerá-la como um serviço ligado (conectado, plugado) a um ActiveX container (que é o nosso item).
Cada controle ActiveX possui um conjunto de propriedades, métodos e eventos que caracterizam lógica e fisicamente
o controle e permitem que executemos ações e percebamos alterações na situação do controle.
Uma aplicação cliente manipula um controle ActiveX fazendo acesso diretamente a suas propriedades (obtendo e
modificando), acionando métodos e interceptando ou causando eventos.
Um arquivo OCX é uma biblioteca. Pode conter uma ou mais classes de objetos ActiveX.
Um VBX é similar a um OCX em muitos aspectos:
♦ Um arquivo VBX pode conter diversos controles.
♦ Um VBX é desenvolvido por terceiros e podemos anexá-los em nossas aplicações para suprir ou adicionar
funcionalidade à nossa aplicação.
♦ Cada controle contém propriedades, métodos e eventos para que possamos efetuar a manipulação de suas
características e ações.
O que fundamentalmente muda de um para o outro é a tecnologia; ActiveX é baseado no modelo COM.
Como restrição para os controles VBX (no Form Builder), temos que um controle VBX funciona estritamente em
aplicações 16 bits, não funciona sob um ambiente 32 bits.
Podemos, porém, fornecer a mesma funcionalidade de um controle VBX em um ambiente de 32 bits ao utilizarmos OCX.
Na seqüência, faremos a exemplificação de uso das interfaces disponíveis no Form Builder (excetuando-se VBX,
onde faremos apenas um estudo superficial).
Este tipo de tecnologia pode tornar uma aplicação Form altamente sofisticada e complexa. Necessita, porém, de
um pleno conhecimento das propriedades, métodos e eventos dos objetos que viermos a anexar à aplicação.
Ao longo deste tópico, faremos exemplos simples de uso dessa tecnologia para que você tenha um ponto de partida,
mas, se você decidir pelo uso de uma das formas aqui apresentadas, muito estudo adicional ainda será necessário.
Utilizaremos uma nova aplicação, chamada Rotina. Essa aplicação está baseada na tabela Func com as colunas
cd_mat, nm_func, cd_depto, nr_cargo, nr_git, in_sexo, dt_nasc, vl_sal, todas do tipo texto. O layout foi montado
com 1 (um) registro, o formato Form e uma barra de rolagem. Adicionamos um botão de nome Ação, onde
desenvolveremos as lógicas (quando houver).
VBX
Infelizmente, não poderemos fazer um exemplo que o execute perfeitamente, pois nosso ambiente é de 32 bits.
Porém podemos estudá-lo em nível teórico e mostrar onde podemos interferir.
A interface de um VBX em uma aplicação Form é feita através de um item do tipo VBX. No conjunto de propriedades deste
item é que preenchemos as informações necessárias para que o Form Builder faça a ligação com o controle desejado.
♦ VBX Control Value – Onde definiríamos o nome da propriedade do controle que é a responsável pelo
armazenamento do valor.
Essas propriedades não estão visíveis no conjunto de propriedades no item criado, provavelmente pelo fato de
estarmos em um ambiente de 32 bits. Se você estiver num ambiente de 16 bits (Windows 3.11), provavelmente
encontrará as propriedades referenciadas aqui.
Na propriedade VBX Control Value, devemos indicar o nome da propriedade do controle que recebe o valor do
item. É desta forma que poderemos atribuir valor ao item, como fazemos com os demais itens em PL/SQL.
Suponhamos, então, que tivéssemos um item do tipo VBX chamado IVBX. Se desejássemos atribuir um valor a
este item, faríamos: “:IVBX := 30;”. Esta é a sintaxe padrão da PL/SQL. O controle, no entanto, precisa de que o
valor seja atribuído à propriedade TEXT (por exemplo); sendo assim, preencheríamos a propriedade VBX Controle
Value com o valor TEXT e quando executássemos o comando de atribuição na PL/SQL o Form faria a atribuição à
propriedade TEXT do controle.
Além das propriedades no Forms, o controle possui suas próprias propriedades, métodos e eventos.
A manipulação deste item é feita com o uso do pacote VBX, que possui:
♦ Rotinas para manipulação de propriedades: Get_Property, Get_Value_Property, Set_Property e Set_Value_Property.
♦ Rotina para acionamento de métodos: Invoke_Method.
♦ Rotina para disparo de eventos: Fire_Event.
Para que o item VBX fique sensível a um evento causado, devemos criar um trigger (em qualquer nível), chamado
When-Custom-Item-Event, que será causado todas as vezes que um evento do controle for causado.
Para sabermos qual o evento e termos condições de tomar as medidas adequadas, devemos utilizar a variável de
sistema System.Custom_Item_Event que identificará o evento causado.
OLE CONTAINER
Este item implementa um controle container de objetos, ou seja, um controle que poderá receber objetos dentro dele.
Esse item armazena objetos de uma das categorias OLE registradas no Windows (por exemplo, uma planilha do Excel,
documento do Word, figura do PaintBrush ou qualquer objeto de uma aplicação que implemente OLE como Server).
lista apresentada, escolha Paint.Picture. Navegue, em seguida, até o Editor de Layout, pressione o botão direito
do mouse e escolha a opção Insert Object; observe a lista apresentada. Retorne às propriedades, esvazie essa
propriedade e repita a operação. Observe a diferença. Volte a preencher esta propriedade com Paint.Picture.
♦ Estilo de Ativação de OLE (OLE Activation Style) – Aqui definiremos qual evento acionará o objeto OLE. No
nosso caso, que acionará o PaintBrush para manipulação do objeto inserido. As opções válidas são:
♦ Clique Duplo (Double Click) – Esta é a forma de ativação default. Usaremos esta opção para exemplo.
♦ Focalizar (Focus-in) – Quando ocorrer a navegação para o item, o objeto OLE se tornará ativo.
♦ Manual – Para que o objeto OLE se torne ativo, o usuário deverá usar o botão direito do mouse sobre o objeto
e escolher a opção Editar (Edit) ou Abrir (Open). Para que isto seja possível, a propriedade Mostrar Menu
Popup de OLE (Show OLE Popup Menu) deve ser preenchida com Sim (True) e o item deve estar visível
(visible) e ativado (enabled).
♦ Ativação Local de OLE (OLE In-place Activation) – Especifica se a ativação será local, isto é, se o PaintBrush (por
exemplo) será ativado dentro do espaço delimitado pela definição do item na Canvas. Se preenchermos com
Não, o PaintBrush (por exemplo) abrirá uma outra janela para que o usuário possa desenhar. Inicialmente,
usaremos Sim (dimensione o item bem grande na Canvas).
♦ Suporte Interno-Externo de OLE (OLE Inside-Out Support) – Esta propriedade só é válida para ativação In-Place,
isto é, quando a ativação do objeto ocorre dentro dos limites da dimensão do item na Canvas. Ela especifica se,
nesta situação, podemos abrir mais de um objeto simultaneamente (do mesmo tipo). Quando trabalhamos com
Word ou Excel, é comum abrirmos mais de um documento ao mesmo tempo. No caso do PaintBrush (o nosso
teste) a própria ferramenta não permite esta forma de trabalho. Você poderá fazer outros testes com outro tipo
de OLE Server e testar essa situação. Podemos deixar esta propriedade com o valor Sim.
♦ Tipos de Inquilinos de OLE (OLE Tenant Types) – Esta propriedade identifica os tipos de objetos que podem ser
inseridos, ou seja, inquilinos do item OLE Container. Os valores válidos são:
♦ Qualquer (Any) – É a opção default. Qualquer objeto OLE pode ser residente do Container.
♦ Nenhum (NONE) – Nenhum objeto pode ser residente do Container.
♦ Estático (STATIC) – Somente objetos OLE estáticos podem ser residentes. Um objeto OLE estático é uma
imagem congelada de um objeto Linked cuja ligação perdeu-se de sua origem. Este tipo de objeto não pode
ser modificado.
♦ Embutido (Embedded) – Somente um objeto OLE embutido pode ser residente.
♦ Ligado (LINKED) – Somente um objeto Linked pode ser residente.
♦ Preencheremos esta propriedade com Qualquer (opção default).
♦ Mostrar Tipo Inquilino de OLE (Show OLE Tenant Types) – Determina se uma borda em torno do OLE deve ser
apresentada. O tipo de borda varia de acordo com o tipo de objeto. Preencheremos essa propriedade com Sim.
♦ Aspecto Inquilino de OLE (OLE Tenant Aspect) – Indica o aspecto (aparência) do objeto OLE no Container
(item). As opções válidas são:
♦ Conteúdo (Content) – O conteúdo do objeto é mostrado no item. Esta será nossa escolha.
♦ Ícone (Icon) – Um ícone do objeto é mostrado no item.
♦ Pré-Visualização de Miniatura (Thumbnail) – Uma visão reduzida do objeto é apresentada.
♦ Estilo de Redimensionamento de OLE (OLE Resize Style) – Indica como o objeto OLE será mostrado na área
reservada para ele (quando ativo). Os valores válidos são:
♦ Corte (Clip) – É apresentada uma parte do objeto. Ele é cortado. A navegação é feita com barra de rolagem.
♦ Escala (Scale) – O objeto é escalado.
♦ Inicial (Initial) – O objeto é redimensionado a tempo de criação.
♦ Dinâmico (Dynamic) – O objeto é redimensionado toda vez que seu tamanho muda.
Nossa primeira escolha será Corte.
♦ Mostrar Menu Pop-up de OLE (Show OLE Popup Menu) – Indica se um menu (apresentado com o botão direito
do mouse) deve ou não ser apresentado para o Container (Item). As ações desse menu estão ligadas ao OLE
Server. Inicialmente deixaremos esta opção com Sim.
♦ Itens de Menu Pop-up de OLE (OLE Popup Menu Items) – Nesta opção poderemos definir quais ações predefinidas
desejamos habilitar. Quando você clicar nesta opção, será apresentada uma lista para que você indique, para
cada item da lista, se ele estará ativo e habilitado. Inicialmente deixaremos todas as opções ativas.
Após todas estas especificações, execute a aplicação (antes, porém, desmarque a propriedade Item do Banco de
Dados do item OLE, para que sua aplicação execute normalmente) e verifique as ações que você pode fazer. Troque
o valor das propriedades para verificar as diferenças entre elas.
Para atingirmos o resultado apresentado na Figura 7.94 executamos a aplicação, realizamos uma query total e com
o mouse sobre o item OLE, usamos o botão direito do mouse para incluir um objeto OLE dentro do nosso item.
Como limitamos o tipo de objeto a figuras do PaintBrush, escolhemos incluir a partir de um arquivo, o qual é visto
no exemplo (Bolhas.BMP). Em seguida, realizamos um clique duplo sobre o objeto. Observe que os menus do
Paint, juntamente com sua barra de ferramentas, foram incorporados à janela do Forms Runtime.
Como teste, usando o Paint, amplie a figura, faça novos desenhos, enfim, modifique o desenho original. Para encerrar
a ativação clique fora do objeto OLE. Observe que o desenho modificado foi salvo em nosso item. Navegue para o
próximo item, retorne a este inicial e veja que a informação foi armazenada no buffer do bloco normalmente. Se este
item estivesse associado a uma coluna no banco de dados poderíamos armazenar o objeto ou informações sobre ele.
Podemos, também, fazer a manipulação de um item do tipo OLE por programação. O Form Builder possui um
pacote chamado Forms_Ole para executar determinadas ações:
♦ Rotina para manipular o OLE Server (no nosso caso, o PaintBrush) – Active_Server (ativá-lo), Server_Active (para
verificar se está ativo), Close_Server (encerrar o OLE Server).
♦ Rotinas para manipulação de ações (da lista de ações disponíveis no menu Pop-up) – Exec_Verb (executar uma
ação específica), Get_Verb_Count (para obter a quantidade de ações disponíveis), Get_Verb_Name (para obter o
Precisaremos, agora, preencher as propriedades do objeto criado e escrever o código de PL/SQL apropriado para
acionar o objeto.
A propriedade do grupo Funcional chamada Propriedades de Controle (Control Properties), quando selecionada, deve
mostrar um diálogo para que possamos definir as propriedades adequadas para o objeto. Se esta opção falhar, deveremos
atribuir as propriedades por programação. Para, mais facilmente, sabermos os nomes das propriedades e sua utilidade,
selecione a propriedade Ajuda de Controle (Control Help), no grupo Funcional. Essa propriedade acionará o Help da
Microsoft; busque o texto Controle SpinButton, que você se deparará com um arquivo de ajuda sobre o objeto.
Criaremos adicionalmente um trigger (em nível de item) para o item OCX (use a opção Gatilhos Inteligentes –
Smart Triggers). Você verá aparecer um gatilho chamado On-Dispatch-Event, que será acionado se algum dos
eventos do objeto for acionado. Quando você criar este gatilho, o Form Builder, automaticamente, o preencherá
com uma lista dos possíveis eventos associados a esse objeto.
Se este gatilho for criado em nível de bloco ou de módulo, o preenchimento deve ser manual.
Após a criação do item, expanda o nó Unidades de Programa (Program Units) que você encontrará um conjunto de
pacotes. Esses pacotes são dependentes do tipo de objeto criado. A criação do pacote se dá no momento em que
importamos os métodos, eventos e propriedades do objeto. Observe no nó Unidades de Programas o pacote
adicionado para o objeto SpinButton.
Criaremos, agora, as rotinas para a manipulação das propriedades. Crie um botão de nome Ação no mesmo bloco
onde o nosso objeto OCX se encontra. Para que o objeto OCX seja ativado imediatamente, coloque este bloco
antes do bloco func (no navegador). Observe que o nome do item OCX deve ser SPIN, pois foi este nome que
incluímos no código a seguir.
A Listagem 7.22 mostra o código associado ao trigger When Button Pressed do botão Ação.
Através dos comentários, verificamos que existem três formas de atribuirmos ou alterarmos o valor de uma propriedade.
A primeira forma utiliza a sintaxe “:item(‘<nome do item>’).OCX.<nome do OLE Server>.<nome da propriedade>”.
O nome do item pode ser qualificado com o nome do bloco ou não (como usamos, normalmente). No nosso caso,
o nome do OLE Server é Forms.SpinButton.1 (classe do objeto).
A segunda forma sintática é a seguinte “:form.cursor_item.OCX.<nome do OLE Server>.<nome da propriedade>”.
Para que essa sintaxe funcione, o objeto OCX tem de estar com o foco.
A terceira forma sintática é montada pelo Form Builder dentro dos pacotes adicionados à aplicação. No nosso caso
específico, o pacote adicionado contém apenas referência aos eventos e não às propriedades.
No trigger para captura dos eventos (On-Dispatch-Event), modificamos o código criado pelo Form Builder e
acrescentamos o trecho apresentado na Listagem 7.23.
A propriedade básica do controle Spin é a propriedade Value. Cada vez que pressionamos o botão da direita, o
valor desta propriedade é adicionado de 1, e cada vez que pressionamos o botão da esquerda, a propriedade Value
é subtraída de 1. Os valores mínimo e máximo são fornecidos pelas propriedades Min e Max, a que nós atribuímos
1 e 5, respectivamente. Assim sendo, enquanto o botão for sendo acrescido, faremos uma adição ao item da canvas
nr_git. Preencha, agora, o código correspondente para a situação de subtração (SpinDown).
Faça o teste acima. Nem tudo foi esclarecido neste ponto. Você certamente terá dúvidas. Para a utilização de um
objeto OCX é indispensável que você conheça bem o que faz o objeto que você incluiu na sua aplicação. Desta
forma, suas dúvidas serão direcionadas apenas para como implementar as ações desejadas no Forms.
PACOTES EMBUTIDOS
Falaremos, agora, nos pacotes que aparecem sob o nó Pacotes Embutidos (Built-in Packages).
Conheceremos o objetivo de todos eles, mas exemplificaremos apenas alguns.
Quando estivermos falando sobre cada um deles, expanda o nó correspondente para que você possa visualizar as
rotinas pertencentes a eles e entender um pouco melhor seus objetivos.
Para os testes deste grupo, criaremos uma outra aplicação com as mesmas características da aplicação anterior. Seu
nome será Pacote. Essa aplicação está baseada na tabela Func com as colunas cd_mat, nm_func, cd_depto, nr_cargo,
nr_git, in_sexo, dt_nasc, vl_sal, todas do tipo texto. O layout foi montado com 1 (um) registro e formato Form e
uma barra de rolagem. Adicionamos um botão de nome Botão, onde desenvolveremos as lógicas (quando houverem)
e também um alerta de nome Alerta com um único botão OK para apresentação das mensagens de teste.
FTREE
Este pacote é o suporte a um novo tipo item, árvore hierárquica.
Este tipo de item permite a apresentação dos dados com o aspecto do Object Navigator, ou seja, com nós, subnós e elementos.
Os usuários poderão expandir ou contrair nós na hierarquia, obtendo visualização de subnós e elementos folha.
Podemos preencher esta árvore com valores oriundos de um Record Group ou com dados obtidos diretamente por
uma query.
Para efeito de teste, adicionaremos em nossa aplicação um novo bloco (sem a ajuda do Assistente) de nome Htree.
Neste bloco incluiremos um item chamado “Arvore”. Na paleta de propriedades do item alteraremos seu tipo para
Árvore Hierárquica.
Um item do tipo Árvore Hierárquica deve estar presente em um bloco com 1 linha e como único item. Caso
contrário, a tempo de execução receberemos a mensagem de erro: FRM-32089: As árvores devem estar em blocos
de apenas uma linha e item.
Antes de iniciarmos os testes, façamos uma verificação nas propriedades relativas ao grupo Funcional deste item
Árvore Hierárquica (as demais são similares a itens de um modo geral).
♦ Ativado (Enabled) – determina se o usuário final poderá usar o mouse para manipular o item.
♦ Permitir Ramificações Vazias (Allow Empty Branches) – indica se podem existir nós sem filhos. Se esta opção
estiver habilitada, os nós sem filhos serão convertidos para elementos (ou seja “folhas”). Caso esta propriedade
esteja desabilitada, um nó vazio será apresentado como um nó não expandido.
♦ Multisseleção (Allow Multiselect) – indica se o usuário poderá ou não selecionar mais de um elemento na árvore.
♦ Mostrar Linhas (Show Lines) – determina se as linhas de ligação entre os nós devem ser apresentadas.
♦ Mostrar Símbolos (Show Symbols) – indica se os símbolos + ou – devem ser apresentados na frente de um nó vazio.
O símbolo + indica que o nó tem filhos mas não está expandido. O símbolo – indica que o nó está expandido.
♦ Grupo de Registros (Record Group) – indica o nome do Record Group de onde os dados serão originados para o
preenchimento do item.
♦ Consulta de Dados (Data Query) – indica o texto da query de onde os dados serão originados para o preenchimento
do item.
Nosso próximo passo será o preenchimento da query para carga do item. O dados da query devem obedecer ao
layout especificado na Tabela 7.08 a seguir.
1 Estado Inicial Pode ser preenchido com 0 (indicando que este é um elemento não é um nó), 1 (indicando que
este nó deve ser apresentado inicialmente expandido), -1(indicando que este nó deve ser
apresentado inicialmente contraído).
2 Profundidade do Nó Esta posição indica o nível do nó na hierarquia, sendo o nível 1 considerado raiz e quanto maior
o número maior o nível de subordinação.
3 Label Indica o texto a ser mostrado para o usuário.
4 Ícone para o Nó Determina o nome de um arquivo (.ICO) a ser usado ao lado dos símbolos + e -. O arquivo deve
estar presente em um dos diretórios nomeados pela variável de ambiente UI_ICON. Não
preencha a extensão no nome do arquivo.
5 Dado Valor interno do elemento.
Baseado nesta especificação devemos incluir o comando SELECT descrito na Listagem 7.24 na propriedade Consulta
de Dados (Data Query) do item Árvore Hierárquica que estamos testando.
Simularemos uma hierarquia com o uso da cláusula Connect By em nossa tabela Depto. Se você se lembra, no
modelo (Capítulo 2) temos um auto-relacionamento nesta tabela.
Desta forma, na primeira coluna fizemos uso da pseudocoluna Level para indicar o estado inicial do nó. Portanto, se
o nível for 1, o nó aparecerá expandido, se o nível for 2, o nó aparecerá contraído e se o nível for 3 indicamos que se
trata de uma “folha” (um elemento). Da mesma forma para a indicação do ícone escolhemos três ícones quaisquer
no diretório default (incluído na lista da variável de ambiente UI_ICON) e os associamos a cada um dos níveis.
Para completarmos o teste, devemos, ainda, colocar este item na Canvas (altere a propriedade correspondente) e
executar uma rotina predefinida.
Para esta última etapa poderíamos escolher a trigger de Pre-Form, na qual devemos incluir o texto descrito na
Listagem 7.25.
Podemos passar, agora, à etapa de execução desta pequena aplicação. A Figura 7.97 nos mostra o resultado após
termos expandido, manualmente, o nó D01.
Mas, você já pode testar a expansão e contração dos nós. Observe que existem elementos na árvore sem o sinal de
+ à esquerda (são os elementos “folha”).
Altere, também, as propriedades Permitir Ramificações Vazias, Mostrar Linhas e Mostrar Símbolos e veja os resultados
obtidos. A diferença é visual. Teste!
STANDARD EXTENSIONS
Este é o pacote que contém as rotinas básicas para utilização dentro de uma aplicação Forms. Com ele podemos
alterar as propriedades de um objeto (item, janela, canvas, etc.), obter propriedades, navegar na aplicação e muitas
outras funcionalidades, algumas delas já utilizadas ao longo dos exemplos e exercícios deste capítulo.
A lista completa das rotinas separadas por funcionalidade está presente no Capítulo 15.
DDE
Este pacote permite a utilização do suporte a Dynamic Data Exchange (DDE) dentro dos componentes do Forms 6i.
DDE é um mecanismo pelo qual aplicações podem se comunicar e trocar dados em um ambiente Windows.
As funções DDE habilitam as aplicações Oracle (Client) a se comunicarem com outras aplicações do ambiente
Windows compatíveis com DDE (Server), possibilitando três tipos de ações:
♦ Importação de dados.
♦ Exportação de dados.
♦ Execução de comandos para o servidor DDE (a outra aplicação).
Não desenvolveremos exemplos com esse pacote. Para maiores informações, utilize a ajuda do Form Builder para
exemplos e forma de utilização.
O conjunto de procedimentos e funções referentes a ele está presente no Capítulo 15.
DEBUG
O pacote Debug oferece um conjunto de rotinas, funções e condições de erro para realizarmos depuração em
aplicações Forms.
Esse pacote foi bastante utilizado no tópico de Depuração. O conjunto de rotinas se acha presente no Capítulo 15.
Não desenvolveremos exemplos com esse pacote. Para maiores informações, utilize a ajuda do Form Builder para
exemplos e forma de utilização.
OLE2
Conjunto de rotinas PL/SQL APIs para criação, manipulação e acesso a atributos de objetos OLE2 Automation.
Os objetos OLE2 Automation encapsulam um conjunto de atributos e métodos que podem ser manipulados ou
invocados de um OLE2 Automation Client. O pacote OLE2 permite que façamos acesso aos objetos OLE2 Automa-
tion Servers diretamente do PL/SQL.
Não trabalharemos com esse pacote. Em vez disso, nos exercícios usaremos as rotinas do pacote Standard Exten-
sions que substituem a utilização desse pacote.
ORA_FFI
Este pacote provê uma interface de uso de funções C (terceira geração) diretamente dentro do PL/SQL.
No ambiente Windows, as funções externas devem ser DLLs que, depois de registradas via funções ORA_FFI,
podem ser usadas em uma aplicação Forms.
♦ Usar a função Register_Function para obter um handle da função, ou seja, uma identificação no ambiente da
função (C) a ser usada. Devem-se especificar o nome da função e sua localização (o handle da DLL).
♦ Usar a função Register_Parameter para registrar cada parâmetro e estabelecer a paridade com os tipos de parâmetro
da PL/SQL.
♦ Usar a função Register_Return para registrar o tipo de retorno da função C e estabelecer a paridade com o
equivalente PL/SQL.
Não desenvolveremos exemplos com esse pacote. Para maiores informações, utilize a ajuda do Form Builder para
exemplos e forma de utilização.
ORA_NLS
Este pacote permite que obtenhamos informações sobre o ambiente corrente.
Na Listagem 7.26 apresentamos o trigger When-Button-Pressed anexado ao item Botão. Nesse gatilho utilizamos
duas rotinas do pacote Ora_Nls: a função American_Date, que retorna um boleano indicando se o formato de data
corresponde ao padrão americano, e a função Get_Lang_Str, que pode fornecer diversas características do ambiente,
tais como o nome da linguagem, do território, do character set, abreviaturas de dias, de meses, etc.
O parâmetro recebido por esta rotina corresponde a uma constante definida no pacote. Os nomes e significados
dessas constantes estão na Ajuda do Form Builder sob o título Ora_Nls Character Constants.
ORA_PROF
Este pacote contém procedimentos, funções e condições de erro que nos permitirão verificar o tempo de execução
de uma determinada unidade de programa.
Faremos um pequeno teste a título de exemplo. Utilizaremos, novamente, o trigger When-Button-Pressed do item
Botão.
ORA_PROF.STOP_TIMER('TEMPO');
TEMPO := ORA_PROF.ELAPSED_TIME('TEMPO');
ORA_PROF.DESTROY_TIMER('TEMPO');
CHANGE_ALERT_MESSAGE(ALERTA, 'Tempo transcorrido : '||TEMPO);
BOTAO := SHOW_ALERT(ALERTA);
END;
Na Listagem 7.27, decidimos determinar o tempo total de somar 1 a uma variável 10.000 vezes. Para isto criamos
o timer, iniciamos a contagem (start), executamos a operação desejada, interrompemos a contagem (stop), destruímos
a área de contagem do tempo e obtivemos o valor do tempo transcorrido (retornado em milissegundos).
Poderíamos criar este controle no início da aplicação e contabilizar diversas ações internas que julgássemos muito
demoradas. Para reinicializar o contador de tempo, devemos usar a rotina Reset_Timer desse pacote.
TEXT_IO
Este pacote permitirá que venhamos a ler ou gravar informações para um arquivo do ambiente. É equivalente ao
pacote Utl_File da PL/SQL, com a diferença de que o arquivo lido ou gravado se encontra no ambiente cliente.
Faremos um teste a título de exemplificação ainda usando o trigger When-Button-Pressed do item Botão.
A Listagem 7.28 nos mostra a criação de um arquivo com o nome de saída com todos os registros que estiverem no
buffer naquele momento. É executada a rotina First_Record (do pacote Standard) para que seja feito o posicionamento
do cursor no primeiro registro, e a cada registro navegado é feita a gravação no arquivo até que a variável de
sistema Last_Record (é uma variável caracter, não é boleana) indicará se atingimos o último registro do buffer.
Após a gravação deste último registro, fechamos o arquivo.
Observe que as rotinas do pacote você já conhece, quando estudamos o pacote Utl_File da PL/SQL. Existem algumas
diferenças mínimas de alguns parâmetros. Para maiores informações, utilize a ajuda do Form Builder.
Para que o teste produza o resultado desejado, é necessário que o diretório C:\TESTE seja previamente criado. O Forms Runtime cria o arquivo e
não o diretório.
TOOL_ENV
Permite que obtenhamos informações das variáveis de ambiente do Oracle.
Faremos um teste a título de exemplificação. Utilize um novo item do tipo Button e crie um trigger When-Button-Pressed.
Na Listagem 7.29 utilizamos a única rotina do pacote, na qual solicitamos o nome de algumas variáveis do ambiente.
Você pode ver o nome dessas variáveis no registrador do Windows com o RegEdit (nó Hkey_Local_Machine, subnó
Software, subnó Oracle, subnó Home3, no meu caso).
A rotina permite a obtenção destas informações dinamicamente.
TOOL_ERR
O pacote Tool_Err fornece um conjunto de informações a respeito do erro acontecido em uma área chamada Error
Stack. Essa área contém códigos e mensagens de erro organizadas em uma área indexada de 0 a n-1 (onde n é o
número de erros). Esse pacote permitirá a manipulação dessa área de stack.
Não desenvolveremos exemplos com esse pacote. Para maiores informações, utilize a ajuda do Form Builder para
exemplos e forma de utilização.
TOOL_RES
Este pacote fornece um mecanismo para extrairmos informações de um arquivo de recursos. Os arquivos de recursos
são providos pelas ferramentas (Form Builder, Report Builder, etc.) e contêm informações diversas utilizadas pelos
softwares. Podemos gerar nossos próprios arquivos de recursos com o utilitário ResPa21 a partir de um texto com
extensão PRN. Esse utilitário é fornecido juntamente com o Oracle*Terminal.
Não desenvolveremos exemplos com esse pacote. Para maiores informações, utilize a ajuda do Form Builder para
exemplos e forma de utilização.
PECS
Este pacote fornece ao desenvolvedor ou ao administrador do sistema meios de análise da performance tanto do
Form Builder quanto das aplicações geradas.
Não desenvolveremos exemplos com esse pacote. Para maiores informações, utilize a ajuda do Form Builder para
exemplos e forma de utilização.
VBX
Este pacote contém um conjunto de rotinas relacionadas à interface com controles VBX, que podem ser anexadas
a uma aplicação de 16 bits.
Não desenvolveremos exemplos com esse pacote. Para maiores informações, utilize a ajuda do Form Builder para
exemplos e forma de utilização.
WEB
Este pacote, composto por uma única rotina, tem a finalidade de definir a URL do documento a ser carregado em
aplicações Web.
Não desenvolveremos exemplos com esse pacote. Para maiores informações, utilize a ajuda do Form Builder para
exemplos e forma de utilização.
FORMS_OLE
Este pacote contém um conjunto de rotinas para acionamento e manipulação de um item do tipo OLE Container.
Já foi comentado quando estudado o item OLE.
STANDARD
Este pacote é utilizado implicitamente por nós todas as vezes que trabalhamos com PL/SQL; corresponde ao conjunto
de rotinas de PL/SQL válidas no ambiente.
Está sendo utilizado em praticamente todos os exemplos e exercícios vistos até agora.
EXERCÍCIOS
7.52) Crie uma aplicação que estabeleça o cadastramento de Departamentos, os quais devem ser apresentados
como uma árvore hierárquica. Deve ser possível a inclusão e alteração de departamentos utilizando esta estrutura.
♦ Para o botão Incluir – quando o usuário apertar o botão incluir já deve ter, previamente, selecionado um nó-pai.
Este botão incluirá um elemento filho neste nó selecionado com label *** (3 asteriscos) e valor nulo.
Simultaneamente deve ser incluída uma linha no vetor de controle indicando que deve ser feita uma inclusão
no banco de dados.
♦ Para o botão Alterar – quando o usuário pressionar o botão alterar já deverá, previamente, ter selecionado um
nó. Os dados preenchidos na tela serão incorporados a este nó para posterior atualização do banco de dados.
7.53) Construa uma aplicação de nome EX53 baseada na aplicação EX48. Acrescente a seguinte funcionalidade:
♦ Criar um pacote local com as seguintes funcionalidades:
a) Declarar um arquivo de texto.
b) Abrir este arquivo de texto para gravação.
c) Gravar uma linha no arquivo de texto.
d) Fechar o arquivo de texto.
As seguintes informações devem ser gravadas neste arquivo-texto: ação (I, E, A), usuário, matrícula, nome +
sobrenome, salário, data de nascimento, código do departamento.
♦ O nome do arquivo deve ser LOGddmmyyyy.txt
♦ Se o arquivo já existir em disco, os registros devem ser adicionados; caso contrário, o arquivo deve ser criado.
♦ Cada linha incluída, excluída ou alterada deve ser logada nesse arquivo de texto.
♦ O arquivo deve ser aberto apenas no início do processo transacional.
7.54) Construa uma aplicação de nome EX54 baseada na aplicação EX53. Acrescente a seguinte funcionalidade:
♦ Criar um avaliador de tempo que inicie a marcação quando houver o início do processo transacional e contabilize
o tempo de execução deste processo.
♦ Apresente o tempo decorrido em um alerta.
♦ Altere o símbolo do ícone (para ampulheta) enquanto este processo estiver em andamento.
7.55) Construa uma aplicação de nome EX55 baseada na aplicação EX54. Acrescente a seguinte funcionalidade:
♦ Altere as máscaras de edição dos campos de data de acordo com o ambiente em que atue o programa:
a) Americano – data= fxdd-mon-yyyy
b) Brasileiro – data = fxdd/mm/rrrr
7.56) Construa uma aplicação de nome EX56 baseada na aplicação EX55. Acrescente a seguinte funcionalidade:
♦ Verifique se a variável de ambiente COM_SESSAO está com o valor True ou False.
♦ Caso esteja com TRUE, o comando OPEN_FORM do botão aplicação deve ser do tipo SESSION.
♦ Caso esteja com FALSE, o comando OPEN_FORM do botão aplicação deve ser do tipo NO_SESSION.
7.57) Construa uma aplicação de nome EX57 contendo o bloco de funcionário, com as colunas cd_mat, nm_func,
nm_sobrenome, nr_cargo, vl_sal e in_sexo.
♦ Monte uma carta no Word relativa ao aumento de salário dos funcionários, com o seguinte layout:
Figura-resposta 7.57A
♦ Salve esta carta com o nome do funcionário precedido do código do departamento e seguido da data e hora
atuais no diretório cartas.
ESTUDANDO O MÓDULO
Analisaremos as propriedades do Módulo. Para tal, selecione o módulo de uma aplicação qualquer (o nó que
contém o nome do programa). As informações que estabelecermos em nível de módulo podem vir a funcionar
como default.
No grupo Funcional vemos diversas propriedades relativas a menu. São elas: Origem de Menu (Menu Source), Módulo
de Menu (Menu Module), Menu Inicial (Initial Menu). Essas propriedades têm o objetivo de definir qual o menu a ser
utilizado com a aplicação atual. Até o momento trabalhamos sempre com o menu-padrão do Form (Default&SmartBar).
Quando criarmos nosso próprio menu, voltaremos a estudar essas propriedades com mais detalhes.
PREFERÊNCIAS
Para obtermos as preferências do Form Builder, devemos escolher o menu Ferramentas e, neste, a opção Preferências.
PASTA GERAL
A pasta Geral contém características que afetam a salva e compilação dos módulos desenvolvidos utilizando este
Form Builder.
♦ Salvar Antes de Desenvolver (Save Before Building) – Esta opção, se marcada, indica que antes de gerar um FMX,
o Form Builder deverá salvar o fonte da aplicação.
♦ Desenvolver Antes da Execução (Build Before Running) – Esta opção, se marcada, indica que quando solicitarmos
a execução da aplicação o Form Builder deverá, automaticamente, gerar o FMX. Essa opção, porém, não compila
automaticamente nem Menus e nem Bibliotecas (Libraries) associadas ao módulo. Essa compilação deve ser
feita em separado.
♦ Suprimir Dicas (Suppress Hints) – Indica se os hints (dicas) serão mostrados ou não na linha de mensagem no
Form Builder.
♦ Usar Editor do Sistema (Use System Editor) – Esta opção determina se o Form Builder deve apresentar seu editor
default ou o editor default do sistema quando acionarmos o editor de um campo multi-line.
♦ Paleta de Cores (Color Palette) – Indica o nome da paleta de cores que deve ser carregada quando criamos uma
nova aplicação. Se esta opção estiver em branco, será carregada a paleta de cores default do Form. A extensão de
uma paleta de cores é Pal.
♦ Módulo de Cor (Color Mode) – Esta opção determina como será feita a carga da paleta de cores para a aplicação.
Quando criamos, abrimos ou carregamos uma aplicação, a paleta de cores associada a ela é carregada na tabela de
cores do sistema. Como essa tabela possui uma quantidade de espaços limitada, o Form Builder pode encontrar
dificuldade em dar manutenção em aplicações utilizando diferentes paletas. Os valores válidos para essa opção são:
♦ Editável (Editable) – indica que desejamos editar, ou seja, criar nossas próprias combinações de cores. Quando
a propriedade Color Mode está preenchida com este valor, a paleta de cores fica vulnerável a modificações.
Somente devemos utilizá-la quando desejarmos fazer uma modificação na paleta. Ao término, devemos
retornar ao estado normal, que é Read Only – Shared. Para que este valor (Editável) tenha efeito, devemos
salvar as preferências e fechar o Form Builder. Ao ativarmos novamente o Form Builder, devemos acionar o
Editor de Layout e usar, no menu Formato (Format), o submenu opções de Layout (Layout Options), e neste
a opção Paleta de Cores (Color Palette).
O Form Builder utiliza uma paleta de cores, padrão, cujo arquivo se chama default.pal, com as seguintes características:
A primeira parte da paleta (região superior esquerda) é composta de 16 cores básicas:
A segunda parte da paleta (região inferior esquerda) é composta de oito células vazias em que podemos definir
cores customizadas.
As próximas quatro colunas são compostas de variações de cinza. Cada cor tem o formato ‘gray<valor>’, onde o
valor varia de acordo com a percentagem de cinza. Os valores válidos estão no intervalo de 4 a 96, com incremento
de 4. Por exemplo: ‘gray4’, ‘gray8’, ‘gray12’, ‘gray16’, ‘gray20’, ‘gray24’, ‘gray28’, ‘gray32’, ...., ‘gray96’.
O restante da paleta de cores contém cores especificadas por variações percentuais das cores vermelha, verde e azul
(RGB). Sendo que os valores percentuais para vermelho ou verde são: 0, 25, 50, 75, 88 ou 100, enquanto os valores
percentuais para a cor azul são: 0, 50, 75, 88 ou 100.
Cada cor é nomeada de acordo com o formato: ‘r<valor>g<valor>b<valor>’, de acordo com seus valores RGB. Por
exemplo, uma cor composta de 100% de vermelho, 88% de azul e 0% de verde teria o nome: ‘r100g0b88’.
Para sabermos o nome de uma determinada cor, basta que a selecionemos na paleta.
Para editar uma cor, selecione uma das cores na parte vazia (branca), clique sobre o botão Editar. Será apresentado
um diálogo com cores básicas e matizes. Selecione uma cor básica, varie seu matiz, saturação e luminosidade,
clique sobre o botão Adicionar Cores Personalizadas e dê OK. A cor definida ocupará a posição selecionada
inicialmente na tabela. Salve esta nova paleta de cores (Menu Arquivo – File, opção Exportar – Export, Paleta de
Cores – Color Palette), volte ao modo Read Only – Shared, preencha o nome do novo arquivo na opção Paleta de
Cores, feche o Form Builder e torne a abri-lo com essa nova paleta.
♦ Somente Leitura – Compartilhado (Read Only – Shared) – Nesta opção, ao fazer a carga da paleta de cores
para a tabela de cores do sistema, o Form Builder verifica através do nome se uma determinada cor já existe
na tabela de cores do sistema para fazer o posicionamento similar. Se a cor não existir, será adicionada à
tabela de cores do sistema. Isto diminui a probabilidade de, ao utilizarmos aplicações com paletas de cores
diferentes, termos problemas de falta de espaço na tabela de cores.
♦ Somente Leitura – Privado (Read Only – Private) – Esta opção não tem efeito no Form Builder, é apenas para
compatibilidade com o Graphics Builder.
A última propriedade desta pasta é a opção Impressora (Printer), que determina a impressora default.
PASTA ACESSO
Esta pasta definirá opções para as ações de abertura ou salva de uma aplicação.
PASTA ASSISTENTES
Esta pasta indica se desejamos ou não que o diálogo de abertura dos assistentes seja mostrado como primeiro diálogo.
PASTA RUNTIME
As opções desta pasta afetam a execução de uma aplicação através do Form Builder. Cada uma das opções marcadas
aqui possui uma palavra-chave que pode ser passada como parâmetro para o Forms Runtime e que é enviada
automaticamente quando iniciamos a execução através do Form Builder.
A Figura 7.101 nos apresenta as informações presentes nessa pasta. São elas:
♦ Armazenar Registros em Buffer no Arquivo (Buffer Records In File) – Atribui o número de registros armazenados
em memória para o mínimo de linhas mostradas mais 3 (para cada bloco). Se um bloco recupera mais registros
que este valor determinado, o Form guarda esses registros adicionais em um arquivo temporário no disco. Se
esta opção não estiver marcada, será considerada a propriedade Buffered de cada bloco.
♦ Depurar Mensagens (Debug Messages) – Esta opção fará com que a tempo de execução sejam mostradas mensagens
que indiquem qual o trigger em execução atualmente.
♦ Processamento de Array (Array Processing) – Quando marcamos esta opção, o Form utiliza o mecanismo de
array processing, e quando desmarcamos ele irá retornar uma única linha a cada interação entre o servidor e a
estação cliente.
♦ Otimizar Processamento SQL (Optimize SQL Processing) – Especifica que o Form irá otimizar os comados SQL
processados no estilo V2 pelo compartilhamento de cursores. Por default, o Form associa um cursor para cada
comando SQL executado em V2. Isto otimiza a performance, uma vez que o parse só é executado uma vez, ou
seja, somente a primeira vez que for executado para a sessão. Quando desmarcamos essa opção, o Form associa
um único cursor para todos os comandos SQL executados em V2. Isto economiza memória; por outro lado
perde-se em performance, uma vez que o parse será executado cada vez que o comando for executado. Essa
opção não tem efeito para triggers escritos em PL/SQL.
♦ Otimizar Processamento do Modo de Transação (Optimize Transaction Mode Processing) – Por default, o Form
associa um cursor separado para cada comando SQL que um Form executa implicitamente num Post ou Query.
Quando desmarcarmos esta opção, o Form irá associar um cursor separado apenas para cada query Select. Todos
os outros comandos SQL implícitos compartilharão cursores. Isto significa que todos os Insert, Update, Delete e
Select For Update devem ser “parsed” cada vez que forem executados.
♦ Estatísticas (Statistics) – Mostra uma mensagem ao fim da sessão, que apresenta o número máximo de cursores
usados simultaneamente durante a sessão. Essa mensagem aparece na tela do terminal e não na linha de
mensagem. Esta opção também habilita a seguinte informação para o database: Alter Session Set Sql_Trace =
True. Este comando habilita o acompanhamento do Sql Trace no servidor.
♦ Exibir Menu de Blocos (Display Block Menu) – Automaticamente, mostra o Menu de Blocos como primeira tela
(após a tela de login).
♦ Modo Somente Consulta (Query Only Mode) – Executa o Form em modo somente de consulta.
♦ Modo Silencioso (Quiet Mode) – Neste modo, as mensagens não produzem beep audível. Se desejarmos chamar
a atenção do usuário em determinado momento, podemos acionar a rotina Bell que produzirá um som, se essa
opção estiver desmarcada.
♦ Nome de Arquivo HTML (HTML File Name) – Indica um nome de arquivo a ser usado em substituição àquele
gerado por default pelo Form quando indicamos a execução via Web. Neste arquivo o Form Builder coloca as
opções de execução obtidas a partir das preferências especificadas ou por default. Caso seja de nosso interesse
podemos informar um nome de arquivo HTML que contenha nosso padrão de preferências customizadas.
O usuário pode criar um arquivo de preferências utilizando a sintaxe: Keyword = <Valor> | ON | OFF
OPÇÕES DE EXECUÇÃO
Estas opções determinam as características de execução para o Forms Runtime. Podemos definir estas opções de
duas formas:
♦ A primeira, já vista anteriormente, através do diálogo Forms Runtime Options dentro do Form Builder.
♦ A segunda, na linha de comando, a tempo de execução do Forms Runtime.
Neste item, trataremos da segunda forma de especificação. A sintaxe para definição de cada uma das opções
(parâmetros) precisa de uma palavra-chave seguida do sinal de igual e do valor, como no exemplo da Figura 7.102.
Não deve haver espaço entre o parâmetro e o sinal de igual e nem entre o sinal de igual e o valor.
Palavra-Chave Descrição
Term Este parâmetro determina o nome do arquivo de recursos para o Oracle terminal. Se não for especificado, o
Forms Runtime utilizará o padrão específico para a plataforma. Por exemplo, FMRUSW.RES para ambientes
Windows.
Debug Executar em modo de Depuração. A interrupção do processamento pode ser feita com o uso da built-in BREAK ou
com a opção Debug do menu Help (Form Runtime).
Debug_Messages Depurar Mensagens. Apresenta mensagens sobre a execução de cada trigger.
Keyout Determina o nome de um arquivo onde serão gravadas todas as teclas utilizadas durante a execução da aplicação.
Só aplicável a terminais Character Mode.
Keyin Determina o nome de um arquivo de onde serão lidas todas as ações a serem executadas durante a execução da
sessão. Este arquivo deve conter toda a seqüência de teclas para execução, salva, navegação, etc. Aplicável apenas
a terminais Character Mode.
Output_File Determina o nome de um arquivo onde todas as respostas para o vídeo serão gravadas. Aplicável apenas a
terminais Character Mode.
Interactive Boleano (True ou False). Indica se as respostas (telas de saída) deverão ou não ser mostradas no vídeo. Pode ser
utilizada juntamente com as opções Keyin e Output_File. Aplicável apenas a terminais Character Mode.
Array Mecanismo de Array Processing.
Buffer_Records Armazenar Registros no Buffer do Arquivo.
Logon_Screen Este parâmetro, quando True, força a presença da tela de Login. Neste caso, o Forms Runtime ignora o userid e
password informados na linha de comando.
Block_Menu Exibir Menu de Blocos.
OptimizeSQL Otimizar Processamento SQL (estilo V2).
OptimizeTP Otimizar Processamento do Modo da Transação.
Quiet Modo Silencioso
Statistics Estatística
UseSdi Indica se o Forms Runtime deve utilizar o padrão SDI. O default é NO, indicando que o padrão a ser utilizado é o
MDI, onde a janela do Forms Runtime é visível. No padrão SDI será mostrada apenas a janela da aplicação.
Query_Only Modo Somente Consulta.
Help Mostra diálogos com a sintaxe destes parâmetros.
Window_State Determina o estado da janela MDI no início da aplicação. Podemos informar: Maximize, Minimize ou Normal
(default).
Pecs Executa o Forms Runtime com Performance Event Collection Services (Pecs) habilitada para coleta de informações
para análise de performance.
Options_Screen Mostra a janela com esta lista de opções a tempo de execução.
Session Especifica se será possível a execução de uma operação de Open_Form com uma sessão em separado. O valor
default para esta opção é NO.
Record=Collect Indica que deve ser gerado um arquivo para acompanhamento da execução do programa para diagnóstico de
problema. Veja, no próximo tópico, a criação deste arquivo.
Log Neste parâmetro indicamos o nome do arquivo a ser gerado para o parâmetro Record=Collect.
Listagem 7.30 – Formato do texto para Triggers com Forms Runtime Diagnostics
<nome do trigger> Trigger Fired:
Form: <nome do Form>
Block: <nome do bloco>
Item: <nome do item>
Se o trigger estiver incluído em nível de bloco a linha referente ao item não será apresentada. Em nível de Form, as
linhas de bloco e item não serão apresentadas.
Além destas informações é apresentado um conjunto de informações sob o título de State Delta (como no exemplo
da Listagem 7.31), onde é apresentado o nome da aplicação, do bloco, do item corrente (se houver), o estado do
Form, do bloco, do registro, o nome de cada item e seu valor. Este “State Delta” é gravado para o arquivo após o
trigger ser acionado. Corresponde a um dump das informações que tenham sido alteradas desde a ocorrência do
estado delta anterior. O primeiro estado delta faz um dump de todo o Forms para o arquivo.
♦ Para Built-ins
Listagem 7.32 – Formato do texto para Built-Ins com Forms Runtime Diagnostics
Executing <nome da Built-in> Built-in:
In Argument 0 - Type: <tipo do argumento> Value: <valor do argumento>
In Argument 1 - Type: <tipo do argumento> Value: <valor do argumento>
...
Out Argument 0 - Type: <tipo do argumento> Value: <valor do argumento>
...
Quando uma built-in é executada, são mostrados seus argumentos de entrada e saída incluindo os valores informados
e recebidos, de acordo com o padrão mostrado na Listagem 7.32.
♦ Para Mensagens
Listagem 7.33 – Formato do texto para Mensagens com Forms Runtime Diagnostics
Error Message: <mensagem>
Qualquer mensagem produzida pela opção aparece no arquivo de acordo com o padrão mostrado na Listagem 7.33.
♦ Para Arquivos
Listagem 7.34 – Formato do texto para Arquivos com Forms Runtime Diagnostics
Opened file : <nome do arquivo>
Ou
Failed to open file: <nome do arquivo>
Listagem 7.35 – Formato do texto para Exceptions com Forms Runtime Diagnostics
Unhandled Exception: <nome da exception>
Ou
Unhandled Exception: ORA-<número da exception>
CONSTRUÇÃO DE UM EXEMPLO
Para verificarmos o conteúdo de um arquivo produzido, crie uma nova aplicação de nome Teste_Frd. Com a ajuda
do Assistente de Bloco de Dados, selecione as colunas Nm_Func, Cd_Depto, Nr_Ramal, Dt_Adm e In_Sexo. Escolha
formato tabular com 3 registros na tela.
Para ativarmos esta opção devemos incluir na linha de comando os parâmetros Record=Collect e Log=<nome de
um arquivo>. Sendo assim, compilamos nossa aplicação para que o FMX fosse gerado (menu Arquivo, submenu
Administração, opção Compilar Arquivo ou Ctrl + T). Em seguida criamos um ícone no Windows e preenchemos
o campo “Alvo” (do ícone) com o conteúdo da Listagem 7.36 a seguir.
Executamos, então, esta aplicação e efetuamos as seguintes operações: Consulta a todos os dados, navegação entre
o primeiro item e o segundo e alteração do nome de um dos funcionários. Salva e saída da aplicação.
RESULTADO GERADO
Na Listagem 7.37 apresentamos o trecho final do arquivo gerado.
# 7 - TESTE_FRD:FUNC.NM_FUNC - MENU
FORM TESTE_FRD
STATUS CHANGED
BLOCK FUNC
STATUS CHANGED
RECSTATUS CHANGED
END
# 7 - TESTE_FRD:FUNC.NM_FUNC
MENU DEFAULT Ação Salvar
# 8 - TESTE_FRD:FUNC.NM_FUNC - MENU
FORM TESTE_FRD
STATUS QUERY
BLOCK FUNC
STATUS QUERY
RECSTATUS QUERY
END
# 8 - TESTE_FRD:FUNC.NM_FUNC
MENU DEFAULT Ação Sair
No registro 6 encontramos a modificação do item nm_func. No primeiro registro 7 encontramos o State Delta
indicativo do estado em que o registro ficou após a modificação. No segundo registro 7 encontramos a execução da
ação Salvar presente no submenu Ação do menu padrão (Default). Em seguida encontramos a mensagem fornecida
pelo programa e o State Delta posterior à gravação. Finalmente no registro 8 encontramos a última ação executada
(Sair do submenu Ação do menu Default).
EXERCÍCIOS
7.58) Criar uma aplicação de nome EX58 baseada na aplicação EX56. Acrescente a seguinte funcionalidade:
♦ Retirar a janela de mensagens.
♦ Adiar a verificação de obrigatoriedade de preenchimento para quando a validação do registro ocorrer.
♦ Garantir a leitura de diversas linhas a cada acesso ao banco de dados.
♦ Estabelecer a leitura simultânea de seis linhas de cada vez para as tabelas Func e Proj e de todas as linhas para Depto.
7.59) Criar uma aplicação de nome EX59 baseada na aplicação EX58. Acrescente a seguinte funcionalidade:
♦ Gerar estatísticas e verificar o resultado (testar e em seguida desmarcar).
♦ Testar a aplicação somente para consulta (testar e em seguida desmarcar).
♦ Garantir que seja possível ao Form Builder abrir cursores independentes para cada uma das operações.
♦ Marcar as seguintes opções para desenvolvimento:
a) Salvar antes de gerar.
b) Gerar antes de executar.
c) Módulos armazenados no sistema operacional.
7.60) Criar uma aplicação de nome EX60 baseada na aplicação EX59. Acrescente a seguinte funcionalidade:
♦ Determinar um tempo máximo de consulta.
♦ Determinar uma quantidade máxima de linhas para consulta.
♦ Associar uma barra de ferramentas horizontal à janela da aplicação.
♦ Associar uma barra de ferramentas vertical à janela da aplicação.
♦ Quando ocorrer um erro de banco de dados, soar um alarme sonoro.
7.61) Criar uma aplicação de nome EX61 baseada na aplicação EX60. Acrescente a seguinte funcionalidade:
♦ Criar duas novas cores em sua paleta de cores.
♦ Exporte a paleta de cores com o nome de pteste.pal.
♦ Execute a aplicação em modo silencioso e cause um erro de banco de dados (incluir um funcionário já existente,
por exemplo).
DESCRIÇÃO
O Form Builder possui diversas formas de aproveitarmos partes da aplicação já definidas e estabelecermos um
padrão, tanto aproveitando código quanto aproveitando layouts de canvas, definições, objetos diversos.
Este tópico abordará as diversas formas de reutilização, seja com objetivo de padrão ou de simples aproveitamento
de código.
TEMPLATE
Você já observou que quando inicia uma aplicação a tela inicial do Wizard pergunta se queremos criar uma aplicação
baseada em um gabarito?
Isto significa que criaremos uma aplicação copiando todas as informações de outra aplicação, exceto seu nome.
Esta forma de trabalho é similar a abrir a outra aplicação e usar a opção Salvar Como (Save As) do menu Arquivo
(File), com a diferença de que oferece mais segurança. Não corremos o risco de esquecer e salvar por cima do original.
Para estabelecer um padrão, você poderia criar um esqueleto com objetos-padrão de uso da sua instalação, por
exemplo a barra de ferramentas, o bloco de controle com os botões da barra e suas respectivas triggers, atributos
visuais mais comuns, alertas, etc.
CLASSE DE PROPRIEDADES
A Classe de Propriedades é uma outra forma de estabelecermos uma padronização em nível de objeto.
Suponhamos que desejemos que todos os botões sejam apresentados no formato icônico, com um tamanho padrão
de 18 por 18 e que não sejam navegáveis nem por teclado e nem por mouse.
Para tal, inicialmente estabeleceremos este padrão de botão (classe de propriedades) e em seguida faremos a atribuição
desta classe a todos os botões da aplicação. Abra, portanto, a aplicação Valida.
Criemos um objeto no nó Classes de Propriedade (Property Class). Batizaremos esse novo objeto de Classe_Botao.
Abriremos em seguida sua tela de propriedades e observaremos que esta só contém o grupo Geral. Não aparecem
outras propriedades.
Faremos, agora, a inclusão dessas propriedades. Podemos fazer isto de duas formas, você escolhe a que for mais conveniente.
Quando atribuirmos esta classe a um botão, este herdará não só as propriedades como também o trigger.
Marque a propriedade Informações Sobre a Divisão em Subclasses (Subclass Information). Será apresentado o
diálogo da Figura 7.105.
Escolha o botão de opção Classe de Propriedade (Property Class). Em seguida, escolha a classe de propriedades
desejada e dê OK.
Observe o resultado na Figura 7.106. Tanto na janela do Navegador quanto na janela de Propriedades verificamos
um sinal indicativo de herança. Verifique que o trigger criado pode ser modificado localmente. Isto dá uma enorme
flexibilidade. Você pode estabelecer um padrão básico e completar com definições locais em cada objeto.
Façamos, então, o seguinte teste. Crie uma aplicação nova (sem fechar a Valida), crie um bloco de controle com
um item do tipo botão. Marque a propriedade Informações Sobre a Divisão em Subclasses (Subclass Information).
No diálogo apresentado, escolha o radio Classe de Propriedades (Property Class), escolha também o módulo Valida;
você verá que na lista de classes encontraremos agora a Classe_Botão. Marque-a.
Faça outros testes adicionais, como por exemplo: o que acontece ao módulo novo se alterarmos a classe no módulo
antigo? Teste. O resultado é satisfatório.
O BOTÃO HERDAR
Suponhamos que você, em determinado botão, não queira que ele seja icônico, mas as demais propriedades herdadas
você deseja manter. Retorne à aplicação Valida.
Selecione a tela de propriedades do botão desejado. Altere o valor da propriedade Icônico (Iconic). A indicação de
herança ficou diferente, indicando que havia uma informação herdada que foi alterada.
Suponhamos que você mudou de idéia de novo. Basta selecionar a propriedade Icônico e pressionar o botão
Herdar. A propriedade recebe novamente o valor básico da Classe.
BIBLIOTECA DE OBJETOS
Outra forma de padronização é a biblioteca de objetos.
Uma biblioteca de objetos é um outro tipo de arquivo gerado pelo Form Builder; não é parte integrante da aplicação.
O objetivo dessa biblioteca é armazenar objetos que possam ser aproveitados em outras aplicações.
Para cada uma das pastas, abra a paleta de propriedades (botão direito do mouse) e troque o nome e a etiqueta para
nomes mais adequados.
Agora faça um clique duplo em uma das pastas, no nó da própria biblioteca ou use a opção Biblioteca de Objetos (Object
Library) do menu Ferramentas (Tools) para que a janela da biblioteca seja aberta. As pastas até agora estão vazias.
Arraste objetos de sua aplicação para cada uma das pastas.
Você acaba de criar objetos-padrão que podem ser arrastados para outras aplicações.
Salve-a e feche-a.
Qual o aspecto do objeto copiado? Normal, não é? Com esta forma de reutilização, simplesmente copiamos um
objeto já existente para dentro de nossa aplicação sem vínculo com o original.
Repita a operação de arrastar um item da biblioteca. Desta vez, porém, utilize a opção SubClasse. Observe a diferença
na tela de propriedades do item arrastado.
A Figura 7.107 nos mostra a indicação da referência na propriedade Informações Sobre a Divisão em Subclasses
(Subclass Information). Qualquer modificação no item armazenado na Biblioteca afeta os objetos referenciados
nas aplicações.
Tente modificar alguma característica deste item. É possível? Podemos modificar qualquer propriedade que
desejarmos, inclusive aquelas com sinal indicativo de referência. O símbolo será apenas modificado, indicando
que a propriedade não é mais igual àquela presente na Biblioteca de Objetos.
Excetuando-se o nó Bibliotecas Anexadas (Attached Libraries), objetos de todos os demais nós de uma aplicação
podem ser armazenados em uma Biblioteca de Objetos.
Como teste, após as modificações no item anterior, arraste-o de volta para a biblioteca.
SMARTCLASS
As bibliotecas de objetos podem ser usadas para a especificação de classes que sejam freqüentemente utilizadas.
Selecione um dos itens na biblioteca, utilize a opção SmartClass do menu Objeto (Object).
O elemento receberá um sinal à esquerda, como apresentado na Figura 7.108.
Selecione, agora, um item na sua aplicação. Vá ao Navegador de Objetos e use o botão direito do mouse sobre este
item que você selecionou. Será apresentada a opção Classes Inteligentes (SmartClasses) e, na lista apresentada
aparecerá a SmartClass NR_CARGO. Observe que o mesmo não acontece para IN_SEXO, pois esta opção não
acontece com um objeto da biblioteca que não esteja marcado como SmartClass.
A utilização de SmartClass para aqueles objetos que venhamos a usar com mais freqüência facilita a modificação
(alteração) de objetos presentes em nossa aplicação e que, agora, desejamos modificar.
Para que a indicação apareça, é necessário que a biblioteca esteja aberta simultaneamente com a aplicação.
REFERÊNCIA
Com o mouse, fazendo as operações de clicar e arrastar, arraste um trigger da aplicação Relação para a aplicação
Valida (faça subclasse). Verifique a indicação na propriedade Divisão em Subclasses (Subclass Information).
Repita a operação para um item (do bloco Func de uma aplicação para o bloco Depto da outra). Olhe novamente
a propriedade Divisão em Subclasses (Subclass Information).
Como último teste, arraste um trigger de bloco de um lado para outro (ainda subclasse) e verifique a propriedade
correspondente.
A propriedade Divisão em Subclasses (Subclass Information), quando o objeto faz referência a outro, indica qual o
objeto origem e de que módulo.
CÓPIA
Abra uma aplicação vazia. Arraste de uma das aplicações anteriores para a atual um bloco inteiro, mas faça uma
cópia. Observe que somente os objetos subordinados foram copiados, isto é, os triggers e itens. A Canvas onde os
itens deste bloco são apresentados não foi copiada. Abra a tela de propriedades de um dos itens do bloco e verifique
o valor da propriedade Canvas no grupo Físico (continua preenchida).
Após a cópia devemos fazer as adaptações necessárias para que os objetos copiados estejam compatíveis com o
novo ambiente. Eles não têm nenhuma relação com os objetos originais. Verifique a propriedade Divisão em
Subclasses (Subclass Information) e comprove.
Em vez de arrastarmos um objeto de cada vez para outra aplicação, arrastamos todo o grupo de uma única vez
(para o nó Grupo de Objetos na aplicação Destino).
Quando concluímos o processo, veremos que na aplicação Destino o nó Grupo de Objetos está preenchido e também
todos os nós originais dos objetos copiados (ou referenciados), ou seja, cada objeto é incluído em seu próprio nó.
CONCLUSÕES
O Form Builder pôs a nossa disposição diversas formas de aproveitarmos as especificações de objetos pertencentes
a outras aplicações ou presentes em uma biblioteca de objetos.
Podemos estabelecer todos os tipos de padrões desejados, desde cópia de uma aplicação-esqueleto (template),
grupos de objetos ou um único objeto.
Estude com cuidado estas opções e utilize aquela que for mais conveniente para sua instalação.
EXERCÍCIOS
7.62) Criar uma aplicação de nome ExTemp, baseada na aplicação EX61, contendo apenas as seguintes informações:
♦ Todos os atributos visuais.
♦ Todos os editores.
♦ Todos os alertas.
♦ Retirar os parâmetros.
♦ O bloco de controle somente com os botões, exceto Ajuda, Lob, Depto e Navega.
♦ As triggers On-Message, On_Error, Pre-Form e Key-*.
♦ As canvas de botões com os respectivos botões.
♦ A janela Janela1.
♦ Manter a unidade de programa Mens.
♦ Retirar do Pre-Form a montagem do Record Group.
♦ Criar uma classe de propriedades Texto com as seguintes características:
a) Salto automático
b) Todas as letras maiúsculas
c) Prompt justificado à esquerda
d) Deslocamento da conexão do prompt 5.
♦ Compile esta aplicação corrigindo os erros de sintaxe encontrados (em função de objetos ausentes).
7.63) Criar uma aplicação de nome EX63 baseada no template Extemp.
♦ Crie um bloco de dados para a tabela Depto.
♦ Utilize os atributos visuais.
♦ Utilize a classe Texto para todos os itens do tipo Text Item.
♦ Associe o editor Edtexto ao item nm_depto.
7.64) Crie uma biblioteca de objetos de nome Bib64 contendo os elementos a seguir. Determine uma pasta para
cada tipo de objeto.
♦ Todos os atributos visuais.
♦ Todos os editores.
♦ Todos os alertas.
♦ Todos os parâmetros.
♦ O bloco de controle somente com os botões, exceto Ajuda, Lob, Depto e Navega.
♦ As triggers On-Message, On_Error, Pre-Form e Key-*.
♦ As canvas de botões com os respectivos botões.
♦ A janela Janela1.
♦ Uma classe de propriedades.
♦ Transforme os alertas em smart classes.
♦ Transforme as rotinas Mens e Idade em smart classes.
7.65) Crie uma aplicação de nome Ex65 contendo um bloco de funcionário e todos os campos. Obtenha os seguintes
objetos da biblioteca de objetos Bib64:
CONCEITUAÇÃO
Até este ponto trabalhamos mais freqüentemente com um módulo do tipo FMB, ou seja, um fonte Form criado
pelo Form Builder. Sabemos, no entanto, que esta ferramenta é capaz de criar outros tipos de arquivo, como por
exemplo um módulo Object Library ou um módulo Library (extensão PLL).
Uma Biblioteca (Library) é uma coleção de programas PL/SQL incluindo procedimentos, funções e pacotes.
Estas rotinas grupadas em um arquivo podem ser compartilhadas, no ambiente cliente, por diversas outras aplicações,
sejam elas Forms, Menus, outras Bibliotecas (Libraries) ou até mesmo Reports.
A biblioteca criada deve ser associada a cada módulo no qual desejamos utilizá-la (Attach).
Uma vez anexada, podemos fazer referência às rotinas presentes na biblioteca em qualquer gatilho (trigger), unidade
de programa (program unit) ou itens de menu (inclusive de Popup menu).
Para acompanharmos sua utilização, criaremos uma outra aplicação (Form) cujo nome será Form_Lib. Essa aplicação
está baseada na tabela Func com as colunas cd_mat, nm_func, cd_depto, nr_cargo, nr_git, in_sexo, dt_nasc, vl_sal,
todas do tipo texto. O layout foi montado com 1 (um) registro e formato Form e uma barra de rolagem. Adicionamos
um botão de nome Botão, onde desenvolveremos as lógicas (quando houver) e também um alerta de nome Alerta
com um único botão OK para apresentação das mensagens de teste.
Após a criação desta aplicação, salve-a e feche-a. Só a utilizaremos após a criação e compilação da biblioteca.
Para efetuarmos esta criação, selecionaremos o nó Unidades de Programa (Program Units) da Biblioteca e usaremos
o botão Criar para anexar um programa. No diálogo apresentado, informaremos que desejamos criar uma Função
chamada Nome.
A Figura 7.109 mostra o diálogo que será apresentado quando efetuarmos esta ação. Pressionaremos o botão
Pesquisar (Select) para encontrar a biblioteca em disco.
Finalmente o trigger When-Button-Pressed apresentado na Listagem 7.40 mostra a utilização de uma rotina da
biblioteca na aplicação Form_Lib (escolha um botão e teste este exemplo).
Quando decidimos pelo cadastramento de uma determinada rotina em bibliotecas da rede, desejamos o
compartilhamento apenas para o ambiente cliente. Aquele código pode ser aproveitado (reutilizado) por diversas
aplicações no ambiente cliente (módulos de tela ou relatório).
Escolheríamos seu armazenamento em uma biblioteca porque:
♦ A rotina poderá ser compartilhada por mais de um módulo.
♦ A rotina não utiliza estruturas do banco de dados, ou utiliza apenas para atualização, não causando impacto no
tráfego da rede.
♦ A rotina está associada a ações específicas do ambiente cliente (usa built-ins do Form ou do Report).
EXERCÍCIOS
7.66) Criar uma biblioteca de PL/SQL de nome BPL66 que contenha as seguintes rotinas:
♦ Rotina (Dv_Matr) para calcular o dv da matrícula do funcionário (noves fora).
♦ Rotina (Intervalo) para determinar o intervalo de anos entre duas datas recebidas como parâmetro.
♦ Rotina (Abono) para calcular o abono salarial (trimestral) de acordo com o número de anos de casa. A rotina
deve receber como parâmetros o tempo de serviço e o salário.
♦ Menos de um ano de casa – Não recebe abono.
♦ De um a menos de três anos de casa – Recebe 3% de abono.
♦ De três a menos de seis anos de casa – Recebe 10% de abono.
♦ Mais de seis anos de casa – Recebe 15% de abono.
7.67) Criar uma aplicação de nome EX67 baseada na aplicação EX60. Anexe a biblioteca Bpl66.
♦ Acionar a rotina Dv_Matr quando for feita a inclusão do funcionário (criar um item do tipo exibição).
♦ Acionar a rotina Abono quando a linha for obtida do banco de dados (criar um item do tipo exibição).
♦ Para acionar a rotina Abono, obtenha o tempo de serviço através da rotina Intervalo.
DESCRIÇÃO
Neste tópico falaremos sobre dois tipos de Menus. Sobre o módulo menu, que é um tipo de arquivo totalmente à
parte da sua aplicação, e sobre o Menu Pop-up, que faz parte integrante do módulo Forms. Ao longo do tópico
estudaremos o módulo Menu, porém, sintática e funcionalmente, os dois são iguais. Sendo assim, nos exercícios
faremos referência a um e a outro.
Para acompanharmos o estudo deste módulo, seguiremos os seguintes passos:
♦ Feche todos os módulos abertos no Form Builder.
♦ Selecione o nó Menus e use a ferramenta Criar (Create).
♦ Dentro deste novo aplicativo, selecione o nó Menus e, novamente, use a ferramenta Create.
♦ Expanda este nó.
♦ Dê a esta aplicação o nome de Menu_Principal e salve-a.
O resultado destas operações é apresentado na Figura 7.111.
O Navegador apresentado contém os seguintes nós principais: Form (vazio), Menus (Menu_Principal), Bibliotecas
PL/SQL (vazio), Bibliotecas de Objetos (vazio).
Mais uma vez enfatizamos que Menu_Principal é um módulo totalmente independente das aplicações Form vistas
até o momento. Procure no Windows Explorer a extensão do arquivo que você acabou de salvar. O fonte de um
módulo Menu é MMB e o “executável” é MMX.
Visto isto, concentremos nossa atenção nos nós internos do Menu. São eles:
♦ Bibliotecas Anexadas – Se desejarmos associar alguma biblioteca de PL/SQL ao menu. Módulo Library.
♦ Menus – Nó onde desenvolveremos, na verdade, este módulo.
♦ Grupos de Objetos – Se desejarmos grupar objetos deste módulo para enviar para outros módulos ou tivermos
copiado dados de outro módulo para o atual (semelhante ao que estudamos para uma aplicação Forms).
♦ Parâmetros – Quando desejamos que um item deste módulo receba parâmetro (será visto).
♦ Unidades de Programa – Local onde desenvolveremos códigos de PL/SQL para estruturação do código.
♦ Classes de Propriedade – Para estabelecermos padrões dentro deste módulo.
♦ Atributos Visuais – Para estabelecermos padrões visuais dentro deste módulo.
Desta lista identificada, a novidade é o nó Menus. Os demais já foram vistos no estudo do módulo Form e são
exatamente iguais àqueles presentes em uma aplicação deste tipo.
Trabalharemos, então, basicamente em relação ao nó Menu.
Você pode alterar o nome de cada elemento dentro do próprio Navegador, bastando clicar o mouse sobre o nome
do elemento que você deseja alterar. Nesta situação, o Form Builder ativa o editor de texto (não abre janela).
A seguir, analisaremos as propriedades dos itens de menu; portanto, escolha um dos itens, botão direito do mouse
e Paleta de Propriedades.
♦ Grupo de Opções de Itens de Menu (Menu Item Radio Group) – Se o item de menu for do tipo Opção, esta
propriedade deve ser preenchida com o nome de um Item de Menu que corresponderá ao grupo de Opções.
Devemos preencher o mesmo nome para todos os itens Opção que pertençam ao mesmo conjunto lógico.
Existem duas restrições relativamente a esta propriedade: os itens de menu do tipo opção devem ser adjacentes,
uns em relação aos outros; somente um item de menu correspondente ao grupo poderá ser indicado por Menu.
♦ Tipo de Comando (Command Type) – Esta propriedade determina o tipo de ação a ser realizada quando o
usuário escolher o item em questão. Os valores válidos para essa propriedade são:
♦ Nulo (Null) – Indica que nenhuma ação será realizada por aquele item de menu. Devemos escolher esta
opção para todos os itens do tipo separador (separator).
♦ Menu (Menu) – Indica que este item de menu acionará um outro menu. Na área reservada para o nome do
SubMenu deveremos preencher com o nome do menu a ser acionado.
♦ PL/SQL – Neste caso poderemos escrever um bloco de PL/SQL que realize uma ação, tal como acionar um
Form, um Report, efetuar um cálculo, executar um procedimento, etc.
♦ As demais opções da lista foram mantidas para compatibilidade com versões anteriores e não devem ser usadas.
♦ Nome do SubMenu (SubMenu Name) – Indica o nome do submenu quando o tipo de comando é Menu.
♦ Código do Item de Menu (Menu Item Code) – Indica o texto do PL/SQL quando o tipo do comando é PL/SQL.
As próximas cinco propriedades determinam se o item de menu será mostrado em uma barra de ferramentas
horizontal e/ou vertical e com que ícone (da mesma forma que acontece com o menu default). Esta opção pode ser
interessante para destacarmos aquelas ações mais comumente utilizadas no sistema.
Antes de compilarmos a aplicação, dê uma olhada no navegador. Verifique se existe um menu para cada lingüeta
do diagrama. Veja os nomes dados pelo Form Builder.
Para passarmos à compilação, escolha Ctrl+T ou Menu Arquivo, Administração, Compilar Arquivo.
Se houver algum erro, retorne às definições feitas anteriormente e refaça o que tiver ficado incorreto.
Na tela de propriedades do Módulo Form_Lib, no grupo Funcional, existem três propriedades a serem preenchidas
neste momento:
♦ Origem de Menu (Menu Source) – Indica se o nome do módulo preenchido na próxima propriedade será
encontrado em disco ou no banco de dados. Neste caso, deve ser preenchido com Arquivo (File).
♦ Módulo de Menu (Menu Module) – Preencha com o nome do módulo que você gerou, ou seja,
Menu_Principal.MMX.
♦ Menu Inicial (Initial Menu) – Preencha com Raiz.
A Figura 7.115 apresenta o resultado esperado.
Como teste adicional, tente incluir o item Sair (Magic) em outro menu (por exemplo, Atualizar). Verifique o que acontece.
Antes de passar aos exercícios, tente criar um item de menu do tipo Opção. Como tarefa adicional, você deverá indicar
qual o menu será considerado como Grupo de Opções (use o menu Editar). Inclua estes itens sob o menu Editar.
♦ Módulo de Menu (Menu Module) – Nesta propriedade continuaremos informando o nome do módulo, porém
como ele está armazenado no banco de dados, não tem extensão, sendo então informado Menu_Principal.
A terceira propriedade, Menu Inicial (Initial Menu), continua sendo preenchida com o nome do Menu a ser
apresentado como o Menu Principal (Inicial) da aplicação.
Estas informações, no entanto, são insuficientes para que o Forms Runtime encontre o módulo MMX em disco
para executar. Desta forma, há necessidade de informarmos o diretório e o nome do módulo gerado (MMX).
Isso é feito nas propriedades do módulo Menu; portanto, abra a tela de propriedades do módulo Menu.
As seguintes propriedades devem ser preenchidas neste momento:
♦ Diretório do Menu (Menu Directory) – Nesta propriedade indicamos o diretório onde o Forms Runtime deve
procurar pelo MMX. Se esta propriedade não for preenchida, o Forms Runtime inicialmente pesquisará no
diretório local e, se não encontrar o MMX, procurará nos caminhos definidos pela variável de ambiente
Forms60_Path, presente no registrador do Windows.
♦ Nome do Arquivo do Menu (Menu Filename) – Nesta propriedade informamos o nome do arquivo MMX (sem diretório).
Passemos, agora, aos testes.
CALL_FORM X NEW_FORM
Você observou o que acontece quando acionamos uma aplicação Form com a rotina Call_Form e outra com a
rotina New_Form? Não? Então execute a aplicação Form_Lib novamente e faça os seguintes testes:
♦ No menu Consultar, escolha a opção Departamento, e em seguida acione a opção Atividade.
♦ Acione a opção Sair do Menu Aplicação.
Você está observando que a aplicação anterior ainda está ativa?
A rotina Call_Form ativa uma outra aplicação sem fechar a anterior.
Você observou que o Menu se manteve o mesmo para todas as aplicações?
RESTRIÇÃO
Não devemos usar itens de menu do tipo Check, Radio ou Separator no menu principal ou em um menu que
venha a ser apresentado no nível mais alto.
PROPRIEDADES DE UM MENU
A única propriedade do grupo Funcional é apresentada seguir:
♦ Menu Tirar (Tear-off Menu) – É um submenu que os operadores podem retirar da barra de menu e reposicionar
em qualquer lugar da tela. Pode-se habilitar a funcionalidade tear-off para qualquer submenu, porém somente
quando o gerenciador de janelas suportar esta característica.
♦ Compartilhar Biblioteca com o Form (Share Library with Form) – Esta propriedade indica que o Menu deve
utilizar a mesma cópia em memória da biblioteca associada (Attached Library) se esta for a mesma em uso pelo
Módulo Form ativo. Essa propriedade pode ser interessante para economizar memória e aumentar a perfor-
mance no ambiente cliente.
No grupo Segurança de Menu, vemos:
♦ Usar Segurança (Use Security) – Marcando esta propriedade, indicamos que o Forms Runtime deve assegurar a
segurança do módulo menu através do uso de Roles. Esta propriedade pode ser marcada com Não (No) a tempo
de desenvolvimento para que sejam possíveis os testes das diversas opções de menu, e com Sim (Yes) no momento
em que o sistema for para produção.
♦ Atribuições do Módulo (Module Roles) – Nesta propriedade, incluímos uma lista das Roles (estabelecidas no banco
de dados) que podem ter acesso a este módulo de menu. Para que esta situação seja efetiva, deve existir no banco
de dados uma view de nome Frm50_Enabled_Roles. Caso essa view não seja encontrada em seu ambiente, o DBA
da instalação deverá executar o script Frm60sec.Sql (presente no CD de instalação) no usuário System.
PARÂMETROS PREDEFINIDOS
Existem seis parâmetros de menu já predefinidos e com valores atribuídos pelo Forms Runtime. São eles:
♦ UN – Username corrente.
♦ PW – Password corrente.
♦ AD – Diretório onde o MMX está armazenado, obtido das propriedades Menu FileName e Menu Directory.
♦ SO – Item de menu corrente.
♦ TT – Tipo de terminal utilizado para conexão.
♦ LN – Linguagem corrente, obtido da variável de ambiente NLS_LANG.
PARÂMETROS DO USUÁRIO
No nó Parâmetros (Parameters) podemos criar nossos próprios parâmetros.
Podemos atribuir valor a eles ou solicitar que os operadores forneçam os dados necessários.
Quando um usuário seleciona um item de menu que faz menção a um parâmetro, o Forms Runtime mostra o
diálogo Enter Parameter Values para que o usuário forneça o valor do parâmetro desejado. Em seguida, o Forms
Runtime executa o comando de menu solicitado.
A seguir, veremos as propriedades mais relevantes deste tipo de parâmetro. No grupo Funcional, encontramos:
♦ Etiqueta (Label) – Indica um texto a ser apresentado para o parâmetro quando este for solicitado.
♦ Restrição a Maiúsculas/Minúsculas (Case Restriction) – Converte a informação digitada pelo usuário se a propriedade
receber o valor Superior (Upper) ou Inferior (Lower). O valor Misto (None) não afeta a informação digitada.
♦ Ocultar Dados (Conceal Data) – Esta propriedade determina se o valor informado pelo usuário aparecerá ou não na tela.
♦ Menus Associados (Parameter Menus) – Aplicável somente a menus apresentados no formato Tela Inteira (Full
Screen). Indica os nomes dos menus com os quais o parâmetro deve ser associado.
No grupo Dados, encontramos a indicação de seu tamanho máximo (Maximum Length), se todo o usuário deve
digitar um texto para o parâmetro do mesmo comprimento de seu tamanho máximo (Tamanho Fixo – Fixed
Length), seu valor inicial (Valor Inicial do Parâmetro do Menu – Initial Value) e, finalmente, a indicação de
obrigatoriedade de preenchimento (Obrigatório – Required).
No grupo Ajuda (Help), encontramos a propriedade Dica (Hint), na qual podemos definir um texto descritivo que
indique ao usuário o que deve ser preenchido para o parâmetro, uma vez que esta informação ficará visível quando
o parâmetro for solicitado.
EXERCÍCIOS
7.68) Criar um Menu de nome MN68.
RELATÓRIOS (REPORTS)
Este tópico será visto após termos estudado o Reports Builder. Retornaremos ao Form Builder para construir a
chamada de um relatório e, neste momento, veremos do que consiste este nó.
Dentro das aplicações Forms definidas até agora utilizamos apenas os tipos clássicos padrões (char, varchar2, date,
number e rowid). No estudo deste tópico abordaremos, dentro do grupo predefinidos, os Lobs e, em seguida, os
tipos de dado definidos pelo usuário.
Estes tipos de dados podem ser utilizados em uma aplicação Form que estabeleça conexão com um banco de dados Oracle.
TLOB
Utilizaremos, para efeito de teste, a mesma tabela Tlob já criada por nós no banco de dados.
Iniciemos, então, com a ajuda do Assistente de Bloco de Dados a construção de uma aplicação que atualize as
colunas C_Clob1, C_Blob1 e C_Number.
A aplicação é bastante simples. Incluiremos apenas um botão contendo um trigger para preenchimento do Blob.
Façamos, então, a construção passo a passo.
Abra o Forms Builder e crie uma nova aplicação de nome Lob.
Com a ajuda do assistente de bloco de dados selecione da tabela Tlob as colunas C_Clob1, C_Blob1 e C_Number.
Construa o layout com 1 registro, formato Form e título do bloco Carga de Imagens. Sua canvas deve ter o aspecto
apresentado pela Figura 7.117.
Retorne ao navegador e inclua um botão de nome Botao e etiqueta Copia. Coloque-o na canvas criada no passo
anterior e inclua uma trigger When-Button-Pressed com o texto da Listagem 7.41.
Podemos trabalhar normalmente com lobs como se fossem itens escalares do banco de dados (a menos da restrição
de tamanho no ambiente cliente 65.534 bytes atualmente).
Como teste adicional, inclua um registro com as seguintes informações: c_number=4, c_clob1=<null> e c_blob1 com
uma imagem qualquer (para realizar esta ação, coloque o nome da imagem no c_clob1, carregue a imagem usando o
botão e esvazie o campo c_clob1). Salve o registro no banco de dados. Em seguida faça uma leitura completa.
Finalmente verifique no banco de dados as informações gravadas em cada uma das colunas. Como não poderemos
ler no SQL*Plus os dados de uma coluna Blob, podemos realizar a consulta apresentada na Listagem 7.42 para
verificar as informações gravadas.
Como curiosidade podemos inspecionar como o Form Builder monta o comando Insert para incluir uma linha contendo
colunas Lobs. Para que seja possível esta visualização, devemos introduzir um erro na operação de inclusão; para tal,
altere o tipo de dado da coluna C_Number para Char. Em seguida execute a aplicação preenchendo este campo com
uma letra (isto causará erro no comando Insert gerado pelo Form) e poderemos verificar como ocorre a inclusão.
RESTRIÇÕES
Como restrição ao uso de Lobs (nesta versão) temos que os lobs do tipo Bfiles são read-only uma vez que são
arquivos armazenados fora do banco de dados (no ambiente servidor). O servidor armazena apenas o endereçamento
do arquivo; desta forma, os Bfiles não podem participar de transações do banco de dados e, portanto, podem ser
utilizados apenas para leitura em aplicações Forms.
Como restrição adicional os Clobs não podem exceder 65534 bytes.
Para as duas colunas de referência você também encontra o sinal de + do lado esquerdo indicando que temos um
nó e que podemos expandi-lo.
Na Figura 7.118, apresentamos o nó cd_gerente já expandido. Observe que fizemos a escolha das colunas cd_depto (da
tabela Tb_Depto), nm_depto (da tabela Tb_Depto) e cd_mat (da tabela tb_Func apontada pelo atributo REF cd_gerente).
Desta forma, com muita facilidade, podemos apresentar na tela os dados do Departamento e dados do gerente do
departamento correspondente, sem que tenhamos de manter esta informação com triggers (post-query, por exemplo).
Verifique que esta expansão de atributos não pára no primeiro nível. O objeto apontado pelo REF também possui
um REF (cd_depto) que aponta para outro objeto (Tb_Depto); você também poderá expandi-lo, porém a obtenção
de colunas para uso na aplicação Forms pára no segundo nível. Observe, também, que o atributo Nr_Tel (em
Tb_Func) não está disponibilizado para expansão, pois se trata de uma coleção (ainda não disponível para uso
nesta versão).
Sigamos, então, com nosso exemplo, escolhendo o nome do gerente (nm_func), cd_depto, nm_depto e matrícula
gerente (cd_mat).
O próximo diálogo surge em função de termos escolhido um item REF (cd_gerente). Nele indicamos se desejamos
que seja criada uma Lov para acesso aos dados referenciados que venham a permitir a atualização da referência
(endereço). Crie a Lov, marcando o check box à esquerda (cd_gerente). Em seguida selecione na lista da direita a
tabela Tb_Func (o REF cd_gerente faz referência a um objeto armazenado na Object Table Tb_Func). Conclua,
agora, a construção do bloco e layout.
Antes da execução vamos verificar os itens gerados no bloco TB_Depto. Observe que foi criado, além dos quatro campos
selecionados (escalares), o item cd_gerente que é do tipo Ref, necessário para a atualização do gerente do Departamento.
Na Figura 7.119 encontramos as propriedades do Record Group associado à Lov. Observe que o comando Select
obtém a referência da linha para que, quando o usuário escolher um novo gerente, sua referência seja atualizada
no item cd_gerente do bloco. Abra a Lov e verifique o campo de retorno do item OID do Record Group.
Façamos a execução desta aplicação para observarmos seu desenvolvimento.
Na execução observamos que tanto o item cd_mat quanto o item nm_func estão associados à Lov. Apesar de estes
itens serem alteráveis, a troca de gerente só ocorre quando usamos a Lov e trocamos a Ref.
No exercício referente a este tópico faremos mais testes com o uso do Ref.
PERFORMANCE
A utilização de um banco de dados a partir do Oracle8 juntamente com o pacote de desenvolvimento Oracle
Developer 6i traz uma série de vantagens relativas ao uso das características do banco de dados, tais como:
♦ uso de tabelas com até 1000 colunas.
♦ acesso a tabelas e índices particionados.
♦ uso de memória cache no ambiente cliente.
Além destas características do banco de dados, outras relativas ao ambiente cliente foram implementadas no
Oracle Developer sem a necessidade da intervenção direta do desenvolvedor:
♦ Prefetch – o Forms utiliza esta característica do banco de dados (juntamente com o mecanismo de Array Size)
para aumentar a performance de acesso sem que o desenvolvedor tenha de realizar qualquer ação específica.
♦ Returning – o Forms utiliza esta característica do banco de dados quando realiza Inserts e Updates a fim de
eliminar a necessidade de efetuar uma segunda consulta após a atualização (em função de modificações realizadas
por triggers), da mesma forma aumentando a velocidade do processamento. Esta característica pode ser controlada
pelo usuário através da propriedade Valor de Retorno de DML (DML Returning Value).
♦ Instead Of Triggers – A existência deste tipo de trigger provê a possibilidade de, no ambiente cliente, criarmos
uma aplicação de atualize, normalmente, uma view, como se fosse uma tabela. Esta view tanto pode ser baseada
em uma única tabela, em joins, subselects, objetos, etc. A trigger faz a separação adequada das informações e as
atualiza quando conveniente. Isto torna a aplicação Forms bastante simplificada.
SUPORTE AO PL/SQL
A compatibilidade com a versão 8 do PL/SQL começou na versão 5 do Form Builder. Esta compatibilidade ainda
não é completa no ambiente cliente; por exemplo, as unidades de programa no ambiente cliente não suportam a
funcionalidade relativa a objetos, isto é, não podemos criar um item com tipo objeto. Uma rotina com esta
característica deveria ser criada no banco de dados para uso no ambiente cliente.
EXERCÍCIOS
7.70) Faça uma aplicação, de nome EX70, que estabeleça o cadastramento de funcionários (use a tabela TB_Func).
Na tela de cadastramento deve ser apresentado simultaneamente o nome do gerente e o nome do departamento
do funcionário. Use uma Lov para que estas informações sejam selecionadas. Gere, simultaneamente, um arquivo
que demonstre todas as ações realizadas pelos usuários e que seja auxiliar no processo de depuração.
Como primeiro passo devemos abrir o Form Builder e escolher “Usar o Assistente de Bloco de Dados”. Caso o Form
Builder já esteja aberto, podemos acionar o Assistente de Bloco de Dados através do menu Ferramentas.
Encerramos aqui o Assistente Para Montagem do Bloco de Dados. Acionaremos, então, o Assistente de Layout.
A próxima tela é onde definimos o tipo de Canvas: preencheremos o campo Canvas com o valor (Novo Canvas) e
o campo Tipo com o valor Conteúdo.
Observaremos no próximo diálogo se todas as colunas selecionadas anteriormente são mostradas. Devemos transferir
todos os itens do campo Itens Disponíveis para o campo Itens Exibidos.
O diálogo seguinte é aquele em que podemos determinar o tamanho dos campos e os prompts a serem mostrados
no resultado. Preenchemos os prompts que darão título para os campos da Canvas da seguinte forma: cd_mat
(Matrícula), nm_func (Nome), cd_depto (Depto), nr_cargo (Cargo), in_sexo (Sexo) e dt_nasc (Nasc). Se você desejar,
aumente o tamanho do item in_sexo para largura (width) de 15, para que o valor fique totalmente visível na tela.
O tamanho definido como padrão é suficiente para aparecimento da letra F, mas não da letra M.
No último diálogo, definimos a distância entre os registros, título para o quadro, etc. Conforme solicitado no
exercício, o campo Título do Quadro deve ser preenchido com Funcionários, o campo Registros Exibidos com 2, o
campo Distância Entre Registros com 10 e deve ser marcada a opção Exibir Barra de Rolagem.
Após essa tela, a montagem do layout se completa. Passaremos para o Navegador a fim de executar a aplicação. Se o
Navegador não estiver visível na sua tela, clique no menu Janela (Window) para que você encontre a janela do Navegador.
Execute a aplicação pressionando o botão Executar Form Cliente/Servidor (o ícone tem o aspecto de um sinal verde).
Quando a aplicação iniciar a execução, preenchemos os dois registros pedidos, como mostrado pela Figura-resposta 7.01B.
Na linha de mensagem aparecerá o texto FRM-40509: Erro do ORACLE: não é possível ATUALIZAR registro.
Porém essa mensagem é insuficiente para que saibamos o ocorrido. Sendo assim, devemos escolher a opção Erro de
Exibição do menu Ajuda para descobrirmos o que realmente aconteceu. Como esperado, o erro apresentado é de
integridade, uma vez que este departamento não existe na tabela Depto (ORA-02291: restrição de integridade
(DESENV.SYS_C00xxxxx) violada - chave-pai não localizada).
Nossa última etapa é cancelar esta alteração. Para tal, devemos pressionar o botão Remover Registro (X em vermelho)
ou a opção Remover do menu Gravar.
Encerraremos, agora, a execução desta aplicação e no Form Builder faremos um último teste antes de fechar a
aplicação: no Navegador, posicione o mouse sobre o nó Pacotes Embutidos (Built-In Packages) e tentemos executar.
Podemos executar a aplicação desta forma?
O botão de execução fica desabilitado porque o objeto que detém o foco não é um aplicativo. Posicione o cursor,
agora, sobre um nó da sua aplicação EX01 (pode ser um nó vazio, como por exemplo Grupos de Registros – Record
Groups). Observe que o botão de executar ficou habilitado, pois o foco está posicionado sobre uma parte da
aplicação, e esta é executável.
Concluímos, então, que o Form Builder é sensível ao objeto em que está posicionado. Suas ações, como por
exemplo Salvar, Executar, etc., sempre se referem ao objeto em foco.
Feche esta aplicação para montarmos o Exercício 7.2 (no menu Arquivo – File, escolha a opção Fechar – Close).
7.02) Crie uma aplicação com o nome de EX02 baseada na tabela Func. Selecione as colunas cd_mat, nm_func,
cd_depto, dt_nasc, nr_cargo e in_sexo.
Crie uma nova canvas do tipo Guia. Defina os prompts adequados para cada coluna.
O formato do Layout deve ser Tabular, com a apresentação de cinco registros.
A distância entre os registros deve ser 15. O título do quadro deve ser Funcs. Não inclua barra de rolagem.
A tempo de execução:
♦ Faça uma consulta de todos os registros.
♦ Faça navegação com as opções de rolagem para frente e para trás do menu Gravar (Record). Qual o resultado?
♦ Navegue até o último registro. Use a tecla Seta para Baixo.
♦ Retorne até o registro de matrícula 150.
♦ Crie dois novos registros nesta posição da tela e salve.
♦ Remova o registro de matrícula 100.
♦ Tente salvar a alteração. O que acontece? Qual o erro enviado pelo database?
♦ Cancele esta exclusão. O que acontece?
Para criar uma nova aplicação use a opção Novo (New) do menu Arquivo (File). Basta que o foco esteja sobre o nó
Forms. Você pode optar por usar a ferramenta (botão) Criar (Create) que tem o mesmo efeito ou, ainda, usar o
botão Novo (New) da barra de ferramentas.
Para que o Assistente seja acionado, selecione o nó Blocos de Dados (Data Blocks), use a ferramenta Criar (Create)
e escolha a opção que aciona o Assistente de Bloco de Dados (Data Block Wizard).
Nesta aplicação, usaremos uma Canvas do tipo Tab.
O diálogo referente à Canvas deve ser preenchido da seguinte forma: no campo Canvas selecione a opção (Novo
Canvas), no campo Tipo selecione a opção Guia e no campo Página de Guia selecione a opção (Nova Página de Tab).
O resultado da montagem de tela deste exercício está apresentado na Figura-resposta 7.02A a seguir. Compare com o seu.
Na figura-resposta fizemos uma leitura completa, isto é, pressionamos apenas o botão para Executar Consulta
(Execute Query) sem qualquer restrição anterior.
Quando realizamos a navegação usando as opções de rolagem para frente e para trás, observamos que, se na
primeira página visualizamos cinco registros novos, quando executamos a rolagem para frente, o último registro
desta página se torna o primeiro e quatro novos registros são apresentados. O último da página anterior sempre
passa a ser o primeiro da próxima página. Por este motivo, se a quantidade de registros na tela é inferior a três não
verificamos diferença entre a operação de rolagem e a navegação simples para o próximo registro.
O próximo teste é a navegação com a tecla Seta para Baixo e o retorno com a tecla Seta para Cima, onde ocorre a
navegação unitária num sentido ou no outro.
A seguir posicionamos o cursor no registro de matrícula 150 e pressionamos o botão Inserir Registro (Add Record)
da barra de ferramentas para a inclusão de dois novos registros, seguida da salva.
Nosso próximo passo é uma tentativa de remoção do registro de matrícula 100. Ocorre, porém, um erro indicando que
existem registros subordinados (filho) ao registro de matrícula 100 (para visualização da mensagem de erro, escolha a
opção Ajuda da barra de menu, opção Erro de Exibição). Isto porque, como sabemos, em nosso modelo de dados a
tabela de Funcionários possui um relacionamento de Gerência com a tabela de Departamentos. Sendo assim, o funcionário
de matrícula 100 é gerente de um departamento e, portanto, em função deste relacionamento não pode ser removido.
Para que pudéssemos cancelar a tentativa de exclusão, deveríamos selecionar o registro com erro e removê-lo da lista de
pendências. Isto não é possível, porque o registro não aparece na lista de registros do bloco. Porém, se tentarmos sair da
aplicação Entrar, Executar Consulta ou Limpar o Bloco, o Forms Runtime apresentará um diálogo indagando se desejamos
efetivar as modificações. Quando pressionarmos o botão Não (No), estaremos cancelando a tentativa de exclusão.
Encerremos a execução da aplicação. Em seguida, efetuaremos uma salva e o fechamento do fonte.
7.03) Abra a aplicação do exercício anterior e salve-a com o nome de EX03.
Acrescente um bloco para a tabela Depto com as colunas cd_depto, cd_gerente e nm_depto na mesma canvas da
tabela Func, mas em outra Tab.
Desmarcar a opção de junção automática dos blocos de dados.
Defina os prompts adequados para cada coluna. O formato do layout deve ser Form com a apresentação de
quatro registros.
O título do quadro deve ser Departamento. Apresente uma barra de rolagem.
A tempo de execução:
♦ Qual a primeira pasta apresentada? Por quê?
♦ Navegue para a pasta de departamentos.
Na confecção do layout, escolhemos a mesma Canvas do bloco anterior, porém solicitamos que seja anexada uma
nova página Tab, ou seja, o campo Página de Guia deve ser preenchido com (Nova Página Tab).
O resultado da nova pasta (Tab) está presente na Figura-resposta 7.03A.
Executemos a aplicação. Você observou que a primeira pasta (Tab) apresentada foi a de funcionários? Isto ocorreu
porque no Navegador o bloco Func está na frente do bloco Depto.
Clique na pasta de Departamento (no meu caso Page5). Pressione o botão Executar Consulta. O que aconteceu? As
linhas consultadas foram as de funcionário e não de departamento. A pasta de funcionário foi apresentada
novamente. Isto ocorreu porque o foco (de novo!) está posicionado sobre o item cd_mat (primeiro do bloco Func).
Experimente navegar para a pasta Departamento e posicionar o cursor sobre o item cd_depto. Quando solicitamos
nova consulta, esta ocorre no bloco departamento, pois já modificamos o foco.
Nossa próxima tarefa é encerrar esta aplicação, retornar ao Form Builder e arrastar com o mouse o bloco Depto
para a frente do bloco Func. Clique sobre o ícone para conseguir arrastar qualquer objeto.
Quando executamos a aplicação novamente, a pasta apresentada passa a ser a de Departamento, pois o foco está
sobre o item cd_depto.
Como última etapa deste exercício, testaremos o vínculo de um bloco com o outro. Para tal faremos uma consulta
geral em Departamento (obtivemos nove departamentos). Posicionaremos o cursor sobre o departamento D11,
navegaremos para a pasta de Funcionários, posicionaremos o cursor sobre o item cd_mat e acionaremos uma
consulta geral (Executar Consulta).
O resultado é que são mostrados registros de todos os departamentos, sem vinculação alguma com o registro
selecionado em Departamento. Não existe vínculo na aplicação, porém o modelo de dados implementado con-
tinua valendo no banco de dados.
Para comprovar, tentemos remover o departamento D11. É possível? Não, pois recebemos o mesmo erro ocorrido
anteriormente, indicando que existem registros-filho que impedem a exclusão.
No nosso caso pretendemos utilizar o relacionamento através do banco de dados. Desta forma, marcaremos a
opção para junção automática dos blocos de dados e pressionaremos o botão Criar Relacionamento para que o
Form Builder verifique em nível de banco de dados quais os relacionamentos existentes entre a tabela para a qual
está sendo criado um bloco e as tabelas dos demais blocos já existentes. Caso a opção de junção automática não
esteja marcada quando pressionarmos o botão Criar Relacionamento, o Form Builder apresentará um novo diálogo
para que informemos se a ligação será feita através de uma cláusula de união (entre os blocos) ou através de algum
item REF (apenas para objetos). Neste caso deveremos indicar a ligação manualmente.
No nosso caso o Form Builder mostra uma janela em que são apresentados os relacionamentos existentes no banco
de dados para que façamos a escolha daquele que desejamos representar. No momento, só encontraremos um
relacionamento e, portanto, selecionaremos aquele apresentado.
Quando aceitarmos este diálogo, a tela de relacionamentos aparecerá preenchida da seguinte forma:
♦ No campo Blocos de Dados Mestre aparecerá o nome Depto.
♦ No campo Condição de Junção aparecerá o texto: Func.cd_depto = Depto.cd_depto
A canvas gerada conterá na parte superior os dois registros de departamento e na parte inferior os cinco registros de
funcionário. Após a confecção da aplicação, passemos às atualizações.
Nossa primeira questão se refere à consulta, e portanto devemos posicionar o cursor no item cd_depto e pressionar
o botão Executar Consulta (Execute Query). Você observará que todos os departamentos foram consultados, porém
no bloco de funcionários estão apresentados apenas aqueles pertencentes ao departamento selecionado (em foco).
Quando navegamos de um departamento para outro, automaticamente, a lista de funcionários apresentada se
modifica para que somente os funcionários do departamento em foco sejam mostrados.
Quando tentamos remover um departamento para o qual existem funcionários ocorre um erro. Observe que não
se trata de um erro de banco de dados. O erro ocorre antes que o registro seja retirado do Buffer; é um erro dado
pelo próprio Forms em função do relacionamento.
Alteramos o cargo de um dos funcionários apresentados. Ao tentarmos navegar para outro departamento, aparece
a mensagem “Você deseja salvar as alterações efetuadas?”. Isto ocorre porque, quando mudamos de registro em
Departamento, o Forms Runtime tem de limpar o bloco de funcionários para preenchê-lo com as linhas dos
funcionários pertencentes ao novo departamento. Quando ele tenta limpar o bloco de funcionário, percebe que
existem modificações não efetivadas e apresenta a mensagem.
Para realizarmos o teste da inclusão, faremos uma operação de Limpar Tudo para que não existam dados nem em
funcionário e nem em Departamento. A seguir, incluiremos uma linha em Funcionário e realizaremos a operação
de salva. Esta operação ocorre sem falhas.
Todo este comportamento é especificado pelo objeto de relacionamento. Esse objeto está subordinado ao bloco-
mestre da relação (no nosso caso, Depto), em um nó chamado Relações (Relations). Verifique no Navegador.
Faremos um estudo mais detalhado nas propriedades de uma relação. Ao modificarmos estas propriedades estaremos
alterando a forma da aplicação Executar.
7.05) Crie uma aplicação com o nome de EX05 baseada na tabela Func. Selecione as colunas cd_mat, nm_func,
cd_depto, in_sexo, vl_sal. Marque a opção Impor Integridade de Dados (Enforce Data Integrity).
Crie uma nova canvas do tipo Conteúdo (Content). Defina os prompts adequados para cada coluna.
Neste exercício testaremos a marcação da opção Impor Integridade de Dados (Enforce Data Integrity) e suas
conseqüências na aplicação gerada. Essa opção garante que as críticas de integridade presentes na base de dados
também sejam validadas no ambiente cliente.
Não acompanharemos mais a criação da aplicação. Se você ainda tiver dúvidas, refaça os exercícios anteriores até
que as mesmas estejam completamente sanadas.
Nosso primeiro teste será preencher a coluna Sexo com um valor diferente de F e M.
Observe que a mensagem apresentada no rodapé da tela (When-Validate-Item trigger failed on field – Func.In_Sexo)
indica que esta ação é inválida. Qualquer valor diferente de F, M e Null causará esta mensagem de erro tão logo
ocorra a navegação; portanto, preencha e navegue para causar o erro.
Como próximo teste tentaremos remover o registro de matrícula 150. A mensagem recebida (“Não é possível
deletar o registro-mestre quando existem registros de detalhe compatíveis”) indica que a ação não pode ser realizada.
Observe que o registro de matrícula 150 não foi removido, a mensagem ocorreu antes de ele ser incluído na lista de
linhas a serem removidas do banco de dados e, portanto, antes que o comando Delete fosse enviado para o banco
de dados. Não há necessidade de cancelamento desta ação, pois ela não ocorreu de fato.
Tentaremos, agora, alterar o código do departamento para X11.
A mensagem (“O valor da chave estrangeira não existe na tabela da chave primária”) nos mostra que esta operação
não é possível. O Forms Runtime impediu que a navegação procedesse. O cursor ficou preso no campo de
departamento para que fizéssemos o acerto do valor. Isto significa que essa validação está ocorrendo antes de o
registro ser enviado ao banco de dados.
7.06) Crie uma aplicação de nome EX06 baseada nas tabelas Func e Depto, com as seguintes características:
♦ Para a tabela Func as colunas cd_mat, cd_depto, nm_func, vl_sal, nr_cargo e in_sexo devem ser selecionadas.
♦ Para a tabela Depto as colunas cd_depto, nm_depto e cd_gerente devem ser selecionadas.
♦ Não estabelecer relacionamento.
♦ Tanto Depto quanto Func devem ser apresentadas em formato Form com 1 (um) registro cada um.
♦ Ambas devem ser apresentadas na mesma canvas. Definir barra de rolagem para ambos os blocos.
♦ Os dados de Funcionário devem estar ordenados por cargo e nome do funcionário.
♦ Os dados de Departamento devem estar ordenados por nome do departamento.
♦ Na última coluna de Funcionário, deve ser feita a navegação para Departamento.
♦ Na última coluna de Departamento, no entanto, deve ser feita a navegação para o próximo registro de Departamento.
♦ O bloco Departamento somente poderá realizar consultas.
♦ Já o bloco Funcionário poderá realizar consultas, exclusões e alterações, mas não poderá efetuar inclusões.
♦ Deve ser permitida ao usuário navegação com o uso de Block Menu.
Após a construção básica dos blocos realizada com o Assistente de Bloco de Dados (Data Block Wizard), deveremos
alterar algumas propriedades para garantir as demais especificações.
Para garantir a ordenação dos dados de Func, devemos preencher a propriedade Order By presente no grupo Database
com o texto: Order By nr_cargo, nm_func. O mesmo deve ser feito para nome do departamento no bloco Depto, ou
seja, preenchimento da propriedade com o texto: Order By nm_depto (a expressão Order By não é necessária).
No grupo Navegação (Navigation), devemos associar ao bloco Func o valor Alterar Bloco de Dados (Change Block)
para a propriedade Estilo de Navegação (Navigation Style); para o bloco Depto, essa propriedade deve receber o
valor Alterar Registro (Change Record).
Para garantirmos que o bloco Depto somente realize consultas, devemos inibir as propriedades Inserção Permitida
(Insert Allowed), Atualização Permitida (Update Allowed) e Exclusão Permitida (Delete Allowed), deixando habilitado
(Sim) apenas em Consulta Permitida (Query Allowed). Essas propriedades estão incluídas no grupo Database.
Para o bloco Func, devemos impedir apenas a inclusão de novos funcionários usando Não para a propriedade
Inserção Permitida (Insert Allowed).
Como último quesito deste exercício, devemos adicionar um texto para a propriedade Descrição do Bloco de
Dados (Data Block Description) e habilitar a propriedade Listado no Menu Bloco de Dados (Listed in Block Menu)
de ambos os blocos.
Se você ainda não o fez, teste as requisições feitas por este exercício.
A tempo de execução, quando acionamos a tecla F5 (Block Menu), é apresentado um diálogo contendo a lista de
blocos de dados com o texto que preenchemos na propriedade Descrição do Bloco de Dados. Confira!
7.07) Crie uma aplicação de nome EX07 baseada na tabela Func com as seguintes características:
♦ As colunas cd_mat, cd_depto, nm_func, vl_sal e nr_cargo devem ser selecionadas.
♦ O formato de apresentação deve ser Tabular com seis registros.
♦ Devem ser especificados 12 registros na área de buffer.
♦ A pesquisa no banco de dados deve ser feita de seis em seis registros.
♦ Somente os registros com cargo superior a 18 devem ser apresentados no resultado.
Neste exercício, após a utilização do Assistente de Bloco de Dados (Data Block Wizard), poucas foram as modificações
realizadas nas propriedades.
Inicialmente, alteramos a propriedade Número de Registros Armazenados no Buffer (Number of Records Buffered)
para garantir que no mínimo 12 registros fossem armazenados no Buffer. Em seguida, modificamos a propriedade
Tamanho do Array de Consulta (Query Array Size) para garantir que o acesso ao banco de dados (Fetch) trouxesse
seis registros de cada vez.
Para garantir que somente os cargos maiores de 18 fossem lidos por esta aplicação, tivemos de incluir uma cláusula
Where (propriedade do bloco Func) em nosso bloco com o texto Where nr_cargo > 18 (a palavra-chave Where não
é necessária).
7.08) Crie uma aplicação de nome EX08 baseada na tabela Func com as seguintes características:
♦ As colunas cd_mat, nm_func e nr_cargo devem ser selecionadas.
♦ O formato de apresentação deve ser Tabular com seis registros.
♦ Altere a orientação para horizontal.
♦ Altere a quantidade de registros apresentados para quatro.
♦ Consulte todos os registros antes que o usuário obtenha a primeira linha.
♦ Estabeleça um número máximo de 15 registros por consulta total.
♦ Inclua, agora, uma barra de rolagem para este bloco.
♦ Crie um bloco de controle com um único item e apresente-o na mesma canvas do bloco Func.
Nossa primeira etapa, como sempre, é utilizar o Assistente para a construção básica do bloco. Como resultado,
teremos a criação de uma canvas contendo seis registros, sendo cada um deles composto das colunas cd_mat,
nm_func e nr_cargo envolvidos por um retângulo (Quadro – Frame).
Para garantirmos que as modificações de orientação e quantidade de registros sejam mantidas, nosso próximo
passo é remover o Quadro (Frame) criado automaticamente pelo Assistente. Posteriormente saberemos por que
esta atitude agora é útil.
A propriedade Orientação do Registro (Record Orientation) do grupo deve ser alterada para Horizontal a fim de
obedecer ao solicitado, assim como a propriedade Número de Registros Exibidos (Number of Records Displayed)
deve ser alterada para 4. Ambas as propriedades se acham presentes no grupo Registros (Records).
Para garantir que sejam consultadas todas as linhas antes de o usuário obter a primeira, devemos marcar a propriedade
Consultar Todos os Registros (Query All Records) do grupo Registros (Records). Para que esta pesquisa não demore
indefinidamente, limitaremos a 15 registros a quantidade total de linhas obtidas usando a propriedade Máximo de
Registros Extraídos (Maximum Records Fetched) do grupo Database. Se houver mais de 15 registros na tabela, a
consulta será abortada em 15.
Para a inclusão da barra de rolagem, devemos expandir o grupo Barra de Rolagem e indicar que desejamos apresentar
uma barra de rolagem para o bloco através da propriedade Mostrar Barra de Rolagem (Show Scroll Bar). Escolhi
incluí-la horizontalmente, indicando o valor Horizontal para a propriedade Orientação da Barra de Rolagem (Scroll
Bar Orientation). Para que ela ficasse visível, só faltava a definição do nome da Canvas onde esta barra irá aparecer,
o que é preenchido na propriedade Canvas da Barra de Rolagem (Scroll Bar Canvas).
Nosso último passo é incluir um novo Bloco (sem o auxílio do Assistente) e, neste bloco, criar um item. Para esse
item devemos especificar uma canvas a fim de que ele também fique visível.
Para verificarmos o que aconteceu com a tela, devemos usar o editor de Layout. Pressione a tecla F2 e com o mouse
clique e arraste os itens para posições mais adequadas.
Veja o resultado de uma execução na Figura-resposta 7.08A.
Execute agora esta aplicação e verifique que em uma consulta total apenas 15 registros são trazidos. Navegue para
o último registro. Não ocorre outra tentativa de leitura. São mantidos apenas os primeiros 15 registros obtidos.
7.09) Crie uma aplicação de nome EX9 com as seguintes características:
♦ No SQL*Plus, crie uma view que estabeleça um join entre as tabelas Func e Depto e inclua as colunas cd_mat,
nm_func, cd_depto, vl_sal, nm_depto, cd_gerente e que veja apenas os funcionários que não são gerentes.
♦ Crie um bloco nesta aplicação baseado nesta view. Garanta que somente consultas sejam permitidas.
♦ Crie um bloco baseado na tabela Depto, mas que obtenha simultaneamente os gastos totais de cada departamento
(total de salário). Garanta que somente consultas sejam realizadas. Não utilize View.
Para este exercício, o nosso primeiro passo será criar a view no banco de dados, de acordo com a Listagem-resposta 7.09A.
Listagem-resposta 7.09A
SQL> CREATE VIEW NAO_GERENTE
2 AS SELECT F.CD_MAT, F.NM_FUNC, F.CD_DEPTO, F.VL_SAL,
3 D.NM_DEPTO, D.CD_GERENTE
4 FROM FUNC F, DEPTO D
5 WHERE F.CD_DEPTO = D.CD_DEPTO
6 AND F.CD_MAT <> D.CD_GERENTE;
View criada.
Em seguida, devemos usar o Assistente de Bloco de Dados (Data Block Wizard) para criar um bloco baseado nesta
view em vez de numa tabela. Como etapa seguinte devemos desabilitar as propriedades Inserção Permitida (Insert
Allowed), Atualização Permitida (Update Allowed) e Exclusão Permitida (Delete Allowed) para esse bloco.
Para desenvolver a segunda parte do programa, devemos criar normalmente o bloco a partir da tabela Depto,
selecionando as colunas cd_depto, nm_depto, cd_gerente e cd_depto_ctb.
O próximo passo é modificar o valor da propriedade Tipo de Origem de Dados de Consulta (Query Data Source
Type) para indicar que os dados serão obtidos a partir de um comando Select a ser definido. O valor dessa propriedade
deve ser Consulta da cláusula From (Sub-query).
O comando Select a ser usado como origem dos dados deve ser incluído na propriedade Nome de Origem de Dados
de Consulta (Query Data Source Name) com o seguinte texto:
Listagem-resposta 7.09B
SELECT D.CD_DEPTO, D.NM_DEPTO, D.CD_GERENTE, D.CD_DEPTO_CTB,
SUM (F.VL_SAL) SAL_TOTAL
FROM FUNC F, DEPTO D
WHERE F.CD_DEPTO = D.CD_DEPTO
GROUP BY D.CD_DEPTO, D.NM_DEPTO, D.CD_GERENTE, D.CD_DEPTO_CTB
Observe, no entanto, que existem cinco colunas selecionadas neste SQL Select, e portanto o nosso bloco deve
conter cinco colunas. Sendo assim, vá ao Navegador e inclua uma nova coluna neste bloco com o nome de
Sal_Total (o mesmo nome utilizado na sub-query). Altere as propriedades Tipo de Dado (Data Type) do grupo
Dados (Data) para numérico e Canvas do grupo Físico (Physical) para o nome da Canvas.
As propriedades Inserção Permitida (Insert Allowed), Atualização Permitida (Update Allowed) e Exclusão Permitida
(Delete Allowed) devem ser desabilitadas para esse bloco.
Como última restrição, a coluna cd_depto deve ter a propriedade Chave Primária (Primary Key) marcada com Sim
(Yes). Isto é necessário quando usamos consulta da cláusula From. Teste!
7.10) Crie uma aplicação de nome EX10 baseada em um pacote com as seguintes características:
♦ Um tipo registro (RLer) com todas as colunas da tabela Func, acrescido de uma coluna de tipo Rowid.
♦ Um tipo registro (Rlock) com apenas uma coluna de tipo Rowid.
♦ Uma variável cursor baseada no registro RLer.
♦ Um tipo tabela baseado no registro Rler.
♦ Um tipo tabela baseado no registro Rlock.
♦ Uma procedure para inclusão que receba como parâmetro o tipo tabela do registro Rler.
♦ Uma procedure para exclusão que receba como parâmetro o tipo tabela do registro Rlock.
♦ Uma procedure para bloqueio que receba como parâmetro o tipo tabela do registro Rlock.
♦ Uma procedure para leitura que receba como parâmetro o código da matrícula (opcional), o código do
departamento (opcional) e que retorne o tipo cursor do registro Rler.
Uma vez que esta forma de trabalho é a mais complexa, façamos passo a passo todas as etapas.
Como primeiro passo devemos criar um pacote no banco de dados com as especificações dos tipos e das rotinas definidas.
Listagem-resposta 7.10A
SQL> CREATE OR REPLACE PACKAGE PFORMS IS
2 TYPE RLER IS RECORD (CD_MAT FUNC.CD_MAT%TYPE,
3 NM_FUNC FUNC.NM_FUNC%TYPE,
4 NM_SOBRENOME FUNC.NM_SOBRENOME%TYPE,
5 CD_DEPTO FUNC.CD_DEPTO%TYPE,
6 NR_RAMAL FUNC.NR_RAMAL%TYPE,
7 DT_ADM FUNC.DT_ADM%TYPE,
8 NR_CARGO FUNC.NR_CARGO%TYPE,
9 NR_GIT FUNC.NR_GIT%TYPE,
10 IN_SEXO FUNC.IN_SEXO%TYPE,
11 DT_NASC FUNC.DT_NASC%TYPE,
12 VL_SAL FUNC.VL_SAL%TYPE,
13 ENDERECO ROWID);
14 TYPE RLOCK IS RECORD (ENDERECO ROWID);
15 TYPE CFUNC IS REF CURSOR RETURN RLER;
16 TYPE TFUNC IS TABLE OF RLOCK INDEX BY BINARY_INTEGER;
17 TYPE TLER IS TABLE OF RLER INDEX BY BINARY_INTEGER;
18 PROCEDURE INCLUI (PTAB IN OUT TLER);
19 PROCEDURE EXCLUI (PTAB IN OUT TFUNC);
20 PROCEDURE BLOQUEIA (PTAB IN OUT TFUNC);
21 PROCEDURE CONSULTA (PCD_MAT IN NUMBER := NULL,
22 PCD_DEPTO IN VARCHAR2:= NULL,
23 PTAB IN OUT CFUNC);
24 END;
25 /
A Listagem-resposta 7.10A nos mostra a parte de especificação do pacote com os tipos solicitados acima. Observe
que o tipo Rler corresponde a todas as colunas da tabela Func, acrescido do Rowid. O objetivo de obtenção do
Rowid é a possibilidade de bloqueio e exclusão utilizando diretamente o endereço da linha.
Listagem-resposta 7.10B
SQL> CREATE OR REPLACE PACKAGE BODY PFORMS IS
2 PROCEDURE INCLUI (PTAB IN OUT TLER) IS
3 I NUMBER := 1;
4 BEGIN
5 WHILE PTAB.EXISTS (I) LOOP
6 INSERT INTO FUNC (CD_MAT, NM_FUNC, NM_SOBRENOME,
7 CD_DEPTO, NR_RAMAL, DT_ADM, NR_CARGO,
8 NR_GIT, IN_SEXO, DT_NASC, VL_SAL) VALUES
9 (PTAB (I).CD_MAT, PTAB (I).NM_FUNC, PTAB (I).NM_SOBRENOME,
10 PTAB (I).CD_DEPTO, PTAB (I).NR_RAMAL, PTAB (I).DT_ADM,
11 PTAB (I).NR_CARGO, PTAB (I).NR_GIT, PTAB (I).IN_SEXO,
12 PTAB (I).DT_NASC, PTAB (I).VL_SAL);
13 I := I + 1;
14 END LOOP;
15 END INCLUI;
16 PROCEDURE EXCLUI (PTAB IN OUT TFUNC) IS
17 I NUMBER := 1;
18 BEGIN
19 WHILE PTAB.EXISTS (I) LOOP
20 DELETE FROM FUNC
21 WHERE ROWID = PTAB (I).ENDERECO;
22 I := I + 1;
23 END LOOP;
24 END EXCLUI;
25 PROCEDURE BLOQUEIA (PTAB IN OUT TFUNC) IS
26 I NUMBER := 1;
27 DUMMY NUMBER;
28 BEGIN
29 WHILE PTAB.EXISTS (I) LOOP
30 SELECT 1 INTO DUMMY FROM FUNC
31 WHERE ROWID = PTAB (I).ENDERECO FOR UPDATE;
32 I := I + 1;
33 END LOOP;
34 END BLOQUEIA;
35 PROCEDURE CONSULTA (PCD_MAT IN NUMBER := NULL,
36 PCD_DEPTO IN VARCHAR2:= NULL,
37 PTAB IN OUT CFUNC) IS
38 BEGIN
39 OPEN PTAB FOR SELECT CD_MAT, NM_FUNC, NM_SOBRENOME,
40 CD_DEPTO, NR_RAMAL, DT_ADM, NR_CARGO,
41 NR_GIT, IN_SEXO, DT_NASC, VL_SAL, ROWID
42 FROM FUNC
43 WHERE CD_MAT = NVL (PCD_MAT, CD_MAT)
44 AND CD_DEPTO = NVL (PCD_DEPTO, CD_DEPTO);
45 END CONSULTA;
46 END;
47 /
A Listagem-resposta 7.10B nos mostra a rotina de consulta, que pode receber dois parâmetros opcionais e abre o
cursor para as linhas selecionadas de acordo com o parâmetro. Esse cursor é retornado ao programa que executou
esta procedure. Já a procedure de exclusão se baseia apenas no endereço de cada uma das linhas recebidas como
parâmetro. A rotina de bloqueio também é baseada no rowid e a de inclusão, baseada nas colunas da tabela Func.
Se você não ficou muito seguro quanto a estas informações, simplesmente preencha-as e confira depois da
geração do bloco.
Passemos à próxima rotina. Na próxima tela, devemos informar qual a nossa rotina de inclusão de dados.
O preenchimento deste diálogo será feito da seguinte forma:
♦ Campo Procedimento será preenchido com Pforms.Inclui.
♦ Pressionar o botão Renovar.
♦ A tabela referente aos argumentos precisa da nossa intervenção apenas para a coluna Valor, a qual será preenchida
com Bfunc para o parâmetro Ptab.
Desta vez, desejamos que todos os itens do bloco que está sendo criado sejam transferidos para o parâmetro, uma
vez que se trata de uma rotina de inclusão. O nome do bloco ainda não foi dado pelo Form Builder, por isso eu
arbitrei que se chamará Bfunc. Quando o bloco tiver sido criado com o nome XXX, alteraremos seu nome para
Bfunc. Na verdade a informação do nome do bloco não é indispensável, pois o próprio Form Builder passa como
parâmetro o nome do bloco na ausência de outra informação (é o default).
Se ocorrer alguma mensagem de erro durante o preenchimento destas telas, não se assuste. Caso você dê OK e os
campos apareçam preenchidos, então está tudo bem.
A próxima tela solicitada é de atualização (alteração). Não forneceremos, pule.
Na exclusão, observe que a única coluna encontrada foi Endereço, pois somente precisaremos do Rowid da linha
para excluí-la. Para este parâmetro, portanto, deve ser informado o nome do item que corresponde ao Rowid. Para
facilitar a ligação, dei o mesmo nome tanto no registro Rler quanto no registro Rlock, ou seja, Endereço.
A última tela que devemos preencher é relativa à rotina que fará o bloqueio (Lock). Seu preenchimento é similar ao
da exclusão.
As demais telas dizem respeito ao layout. Escolhi formato Form com um único registro. Você pode escolher o que
desejar; isto não afeta o resultado.
Não acabamos, ainda. Nosso próximo passo é alterar o nome do bloco para Bfunc.
Em seguida, devemos fazer um pequeno ajuste. Uma coluna do tipo Rowid não é válida no ambiente cliente; por
este motivo, a coluna foi criada com o tipo Varchar2 (até aí nenhum problema), porém seu tamanho ficou com
zero. Para acertar este problema, devemos abrir a tela de propriedades do item Endereço, no grupo Dados (Data) e
alterar a propriedade Tamanho Máximo (Maximum Length) de 0 para 30.
Abra também a tela de propriedades do bloco e expanda o grupo Banco de Dados (Database). Selecione a propriedade
Colunas de Origem de Dados de Consulta (Query Data Source Columns). No diálogo apresentado, a coluna Endereço
também aparece com zero e deve ser alterado para 30.
A Figura-resposta 7.10A nos mostra onde deve ser feita a alteração.
Crie uma nova canvas do tipo Conteúdo (Content). Defina os prompts adequados para cada coluna.
O formato do Layout deve ser Form, com a apresentação de 1 (um) registro. O título do quadro deve ser Funcionários.
Apresente uma barra de rolagem.
As seguintes características devem ser anexadas a esta aplicação básica:
♦ O item in_sexo deve ser do tipo radio group, para os valores F, M e Null.
♦ O item nr_cargo deve ser do tipo List Item para os valores (48 – analista júnior, 49 – analista pleno, 50 – analista
sênior, 51 – dba, 52 – analista de dados, 53 – suporte de software, 54 – suporte de hardware, 55 – coordenador de
projeto, 56 – gerente de sistema, 57 – instrutor, 58 – gerente de suporte, 59 – gerente de treinamento, 60 –
diretor). O usuário poderá informar outros valores não presentes na lista, inclusive Null.
♦ O item Matrícula deve ser de preenchimento obrigatório.
♦ A consulta só pode ser feita pelos campos Cargo e Departamento.
♦ A tempo de consulta, o campo Departamento deve ter seu tamanho ampliado para que seja possível a pesquisa
por strings do tipo >= A00.
♦ A consulta pelo campo Departamento pode ser feita com letras maiúsculas ou minúsculas indiferentemente.
♦ Não são admitidos funcionários com menos de 18 anos ou com mais de 60 anos.
♦ Quando cada campo adquirir o foco, deve ser apresentada uma explicação sobre o preenchimento na linha de mensagem.
♦ Quando o mouse for passado sobre cada campo, deve ser apresentado o nome do item.
♦ A data de nascimento deve utilizar um formato que obrigue o usuário a digitar toda a máscara.
Iniciaremos a montagem desta aplicação com o Assistente de Bloco de Dados. Selecionaremos as colunas especificadas
da tabela Func e escolheremos a canvas do tipo Content. Porém, quando vamos especificar quais itens devem ser
apresentados na canvas, já aproveitamos para determinar que a coluna In_Sexo seja do tipo Grupo de Opções
(Radio Group) e que a coluna Nr_Cargo seja do tipo Caixa de Combinação (Combo Box). Aumentaremos o tamanho
da coluna Nr_Cargo para 90 a fim de que fique visível o texto da lista.
Nossa primeira tarefa é incluir os botões de opção. No Navegador, incluiremos três botões com os nomes de Fem,
Masc e Nulo. Preencheremos as propriedades de Etiqueta (Label) e Valor (Value), da seguinte forma:
♦ Para o Botão Fem a Etiqueta será Feminino e o valor F.
♦ Para o Botão Masc a Etiqueta será Masculino e o valor M.
♦ Para o Botão Nulo a Etiqueta será Não Definido e o valor não será preenchido (ou seja, Null).
O segundo passo é a montagem da lista referente ao cargo. No grupo Funcional, devemos obter a propriedade
Elementos da Lista (List Elements) a fim de preencher com os valores fornecidos. Acrescentei aos valores digitados
um elemento “Indefinido” sem valor (Null), conforme solicitado.
Nossa próxima etapa é atribuir à propriedade Obrigatório (Required), do grupo Dados, o valor Sim (True) para o
item cd_mat. Em seguida, devemos desabilitar a propriedade Consulta Permitida (Query Allowed) do grupo Banco
de Dados (Database), para os itens nm_func, cd_mat, in_sexo e dt_nasc.
Como etapa seguinte, devemos definir um valor para a propriedade Tamanho da Consulta (Query Length) do
grupo Banco de Dados, relativamente ao item cd_depto. No nosso caso, 10 é suficiente.
A seguir, ainda no grupo Banco de Dados (Database) deste mesmo item (cd_depto), devemos habilitar a propriedade
Consulta Insensível a Maiúsculas/Minúsculas (Case Insensitive Query).
O teste de intervalo de datas deve ser feito via programação para que os valores sejam mutáveis de acordo com a
data vigente. Temporariamente, trabalharemos com valores fixos. Preenchemos, portanto, a propriedade Mínimo
Valor Permitido (Lowest Allowed Value) com o valor 01/01/1939 e a propriedade Máximo Valor Permitido (High-
est Allowed Value) com o valor 01/01/1981.
A explicação de cada campo foi digitada na propriedade Dica (Hint), pertencente ao grupo Ajuda. Todos os itens
receberam esta informação. A propriedade Exibir Dica Automaticamente (Display Hint Automatically) deve estar
habilitada para que a propriedade Dica (Hint) tenha efeito.
O nome do item foi preenchido na propriedade Dica da Ferramenta (Tooltip) deste mesmo grupo Ajuda (Help).
Todos os itens receberam esta informação.
Para garantir que a data de nascimento seja totalmente digitada, usamos uma máscara com o formato FXDD/MM/
YYYY. O modificador FX exige o tamanho exato.
7.12) Crie uma aplicação de nome EX12 baseada na tabela Proj. Selecione as colunas cd_proj, cd_depto, nm_proj,
cd_resp, qt_eqp, dt_ini, dt_fim.
Crie uma nova canvas do tipo Conteúdo (Content). Defina os prompts adequados para cada coluna.
O formato do Layout deve ser Form, com a apresentação de dois registros. O título do quadro deve ser Projetos.
Apresente uma barra de rolagem.
As seguintes características devem ser anexadas a esta aplicação básica:
♦ O nome do projeto deve ser estendido para que possa ocupar mais de uma linha. Acrescente uma barra de
rolagem para facilitar a navegação neste item. A quebra da linha deve ser feita somente em palavra inteira.
♦ Criar um bloco de controle que contenha uma coluna que some a quantidade total de pessoas na equipe de
projetos selecionados.
♦ O código do projeto deve ser armazenado sempre em letras maiúsculas, assim como o código do departamento.
♦ O campo Equipe deve ter seu alinhamento pela direita.
♦ Todos os itens desta aplicação devem ter fonte Arial com tamanho 8.
♦ Todos os prompts devem ser definidos em vermelho.
♦ As datas de início e de fim do projeto somente devem ser modificadas se não estiverem preenchidas (Null), caso
contrário não devem ser alteradas. O usuário deve, obrigatoriamente, digitar toda a máscara.
♦ Quando o mouse for passado sobre cada campo, deve ser apresentado o nome do item.
♦ A data de início do projeto, se preenchida, deve ser maior que a data atual.
♦ O campo Código do projeto é de preenchimento obrigatório, assim como o código do departamento, o nome
do projeto e o responsável.
Iniciamos a montagem, mais uma vez, usando o Assistente de Bloco de Dados. Aproveitaremos a montagem do
layout para alterar o valor da altura da coluna nm_proj para 37 e sua largura para 100, a fim de atender ao requisito
para ocupar mais de uma linha.
Para que haja a quebra de linha, devemos, ainda, habilitar a propriedade Várias Linhas (Multi-Line) e determinar
o Estilo de Sobreposição (Wrap Style). Foi solicitado que a quebra de linha seja feita considerando a palavra inteira;
sendo assim, o valor desta propriedade (Wrap Style) deve ser Palavra (Word).
Com a tela pronta, criamos um bloco de controle pelo Navegador e incluímos um item (Texto). Nesse item
modificamos as propriedades Nome (Name) para Total, Tipo de Dado (Data Type) para Numérico (Number),
respectivamente dos grupos Geral (General) e Dados (Data). No grupo Cálculo (Calculation) modificamos as
propriedades Modo de Cálculo (Calculation Mode) para Sumário (Summary), Função Sumária (Summary Func-
tion) para soma (sum), Bloco Sumariado (Summarized Block) para Proj e Item Sumariado (Summarized Function)
para qt_eqp. Ainda no item tivemos de torná-lo visível na canvas. Sendo assim, no grupo Físico (Physical) alteramos
a propriedade Canvas para Canvas2.
Para que o cálculo possa ser feito, o Bloco que contém o item de cálculo deve ter a propriedade Registro Simples
(Single Record) habilitada e o Bloco que contém a coluna a ser sumariada deve ter a propriedade Consultar Todos
os Registros (Query All Records) ou a propriedade Pré-Calcular Sumários (Precompute Summaries) habilitada,
pertencentes respectivamente aos grupos Registros e Banco de Dados Avançado. A escolha de Consular Todos os
Registros significa que o Form Builder antes de apresentar a primeira linha para o usuário deverá trazer todas as
informações selecionadas para o ambiente cliente, viabilizando, desta forma, o cálculo desejado. Ao escolhermos
Pré-Calcular Sumários indicamos que o Form Builder deve montar um comando de consulta anterior à seleção das
linhas (porém com o mesmo critério) a fim de realizar o cálculo desejado. Escolhemos a segunda opção.
Para que o projeto fique sempre em maiúsculas, usamos a propriedade Restrição a Maiúsculas/Minúsculas (Case
Restriction), do grupo Funcional, com o valor Superior (Upper).
No grupo Cor do Prompt, alteramos a propriedade Cor de Fundo do Prompt (Prompt Background Color) para o valor Red.
Para garantir a modificação de um item somente se seu valor for Null, devemos habilitar a propriedade Atualizar
Somente se Null (Update Only If Null) do grupo Banco de Dados (Database).
Preenchemos, também, a propriedade Dica da Ferramenta (grupo Ajuda – Help) de cada item.
Na data de início, escolhemos como valor mínimo a variável de sistema $$DBDATE$$.
A obrigatoriedade é definida no grupo Dados, propriedade Obrigatório (Required).
O formato do Layout deve ser Form, com a apresentação de 1 (um) registro em cada pasta. Escolha o título de cada
Quadro. Apresente uma barra de rolagem apenas para a pasta de Depto.
Os quatro itens apenas consultados foram bloqueados de formas diferentes: para salário transformamos seu tipo
em Item de Exibição (Display Item); para admissão, alteramos a propriedade Ativado (Enabled) para Não (False),
para sobrenome alteramos a propriedade Somente Consulta (Query Only) para Sim (True) e para Sexo alteramos as
propriedades Inclusão Permitida (Insert Allowed) e Alteração Permitida (Update Allowed) para Não (False).
O bloco Funcionário deve ter a propriedade Inclusão Permitida (Insert Allowed) desabilitada.
Para estabelecermos a cópia, a propriedade Copiar Valor a Partir do Item (Copy value from Item) recebeu o valor
depto.cd_depto.
Para alinhamento dos campos numéricos utilizamos a propriedade Justificação (Justification) com o valor Direita (Right).
No grupo Cor alteramos a propriedade Cor de Fundo (a primeira) para Blue (nos itens de Funcionário) e Green (nos
itens de Departamento).
A navegação automática é garantida pela propriedade Salto Automático (Automatic Skip).
O próximo passo deve ser a inclusão dos três novos itens, todos do tipo Caixa de Seleção (Check Box). Não se
esqueça de dar os valores, quando assinalado e quando não assinalado; a apresentação, quando outros valores
forem informados, a canvas e pasta tab em que estes itens serão apresentados. Não são itens do banco de dados.
Nossa última etapa é a propriedade Estilo de Navegação (Navigation Style), que deve ser preenchida com o valor
Alterar Bloco de Dados (Change Block).
7.14) Criar uma aplicação de nome EX14 baseada na tabela PRJATV. Todas as colunas devem ser apresentadas.
Devem ser trazidos para a mesma canvas, também, o nome da atividade e o nome do projeto. Estabeleça um
relacionamento com a tabela PRJATV através da cláusula Where.
♦ Torne invisível a coluna cd_ativ da tabela Ativ e a coluna cd_proj da tabela Proj.
♦ Os itens cd_ativ e cd_proj da tabela PRJATV devem ser de preenchimento obrigatório.
♦ As consultas só podem ser feitas pelos campos cd_ativ e cd_proj.
♦ A tempo de consulta, o campo cd_ativ deve ter seu tamanho ampliado para que seja possível a pesquisa por
strings do tipo >= 80.
♦ Todos os itens dessa aplicação devem ter fonte Arial com tamanho 8.
♦ Todos os prompts devem ser definidos em vermelho.
♦ As datas devem possuir máscara.
♦ Deve-se garantir que, quando um campo for totalmente preenchido, a navegação para o próximo campo seja automática.
♦ Quando cada campo adquirir o foco, deve ser apresentada uma explicação sobre o preenchimento na linha de mensagem.
♦ Deve-se apresentar a quantidade de dias do projeto.
♦ A data de início do projeto deve ter como valor default o dia atual.
♦ Os itens desta aplicação não devem ser apresentados em formato de terceira dimensão.
A montagem dos três blocos é normal, sendo que não apresentamos na Canvas as colunas cd_proj e cd_ativ já a
tempo de montagem da tela. Em seguida, alteramos a cláusula Where do bloco Ativ para que sejam listadas somente
as atividades cujo código seja igual ao código da atividade do bloco PrjAtv. O mesmo deve ser feito para o bloco
Proj com código do projeto.
A obrigatoriedade de preenchimento é dada pela propriedade Obrigatório (Required) do grupo Dados (Data).
Para que a consulta somente se dê pelos códigos, devemos alterar a propriedade Consulta Permitida (Query Al-
lowed) do grupo Banco de Dados para Não (False), para as datas de início e fim de atividade do projeto.
A próxima questão é resolvida pela propriedade Tamanho da Consulta (Query Length) do grupo Banco de Dados.
Estimamos em 10 seu tamanho final.
Para a próxima questão, alteramos as propriedades Nome da Fonte (Fonte Name) e Tamanho da Fonte (Font Size)
do grupo Fonte.
Para os prompts, utilizamos o grupo Cor do Prompt e alteramos a propriedade Cor de Fundo (Background Color).
A máscara das datas está presente no grupo Dados (Data) e a propriedade é Máscara de Formato (Format Mask)
preenchida com fxdd/mm/rrrr.
A navegação automática é garantida pela propriedade Salto Automático (Automatic Skip) do grupo Funcional (Functional).
A explicação na linha de mensagem deve ser preenchida na propriedade Dica (Hint) e a propriedade Exibir Dica
Automaticamente (Display Hint Automatically) deve estar habilitada. Ambas do grupo Ajuda.
Para cálculo da quantidade de dias do projeto, criamos um bloco de controle cuja propriedade Registro Simples
(Single Record) do Grupo Registros foi preenchida com Sim (Yes).
Incluímos um item de texto neste bloco. Alteramos seu nome para Cálculo (grupo Geral), seu tipo de dado para
numérico (grupo Dados) e no grupo cálculo alteramos a propriedade Modo de Cálculo (Calculation Mode) para
Formula e a propriedade Fórmula para o valor Trunc (:prjatv.dt_fim - :prjatv.dt_ini). Sua visibilidade deve ser
assegurada com o preenchimento da propriedade Canvas (grupo Físico – Physical). Deve-se indicar adicionalmente
que este bloco não é de dados, através da propriedade Bloco de Dados do Banco de Dados (Database Data Block).
O valor inicial da data de início do projeto é preenchido na propriedade Valor Inicial do grupo Dados com o texto
$$dbdate$$ (data do banco de dados) ou $$date$$ (data do sistema operacional corrente).
Para que a parte gráfica dos itens perca o aspecto tridimensional, preenchemos a propriedade Bevel (do grupo
Físico – Physical) com Nenhum (None).
O aspecto não ficou dos mais bonitos, mas vale como teste.
7.15) Criar uma aplicação de nome EX15 baseada na tabela Func, contendo os campos cd_mat, nm_func, nr_cargo e vl_sal.
O formato do bloco deve ser tabular com dez registros na canvas.
♦ Deve ser acrescentado um item nessa canvas (sem repetição) para que o usuário preencha com uma senha
válida no intervalo 123456 a 234567. Essa senha não deve ser visível.
♦ O nome do funcionário deve ser digitado sempre em maiúsculas.
♦ A matrícula é de preenchimento obrigatório.
♦ Retire o quadro dessa aplicação.
♦ Deve-se incluir uma coluna cd_depto manualmente e sem repetição que garanta que toda pesquisa seja feita
apenas para o departamento informado.
♦ Deve-se apresentar sempre o total de salários de cada departamento.
A montagem da canvas através do Assistente não traz novidades.
Para a criação do campo de Senha preferimos a utilização de um bloco de controle, para o qual alteramos a
propriedade Bloco de Dados do Banco de Dados (Database Data Block) para Não (False). O item Senha, criado, foi
alterado para tipo de dado numérico (grupo Dados – Data); mínimo e máximo valor permitido (Lowest Allowed
Value e Highest Allowed Value) para os valores determinados; ocultar dados (Conceal Data) para Sim (Yes). Não se
esqueça de tornar este item visível na canvas.
Para que o nome do funcionário seja digitado sempre em maiúsculas, devemos alterar a propriedade Restrição a
Maiúsculas/Minúsculas (Case Restriction) para Superior (Upper).
Para retirarmos o quadro da aplicação, podemos, no Navegador, expandir o nó Canvas e remover o objeto Frame
ou acionar o editor de Layout (F2), selecionar o quadro e removê-lo.
A inclusão da coluna cd_depto pode ser feita no Navegador. Podemos incluí-la no bloco Func sendo ou não coluna
do banco de dados. Seu tipo de dado (Data Type) deve ser caracter com tamanho máximo (Maximum Length) de
3. Sua presença deve ser garantida na tela (propriedade Canvas). A propriedade Número de Itens Exibidos (Number
of Items Displayed) deve receber o valor 1.
Para que a navegação só ocorra se este item estiver preenchido, devemos alterar a cláusula Where do bloco para o
texto: cd_depto = : func.cd_depto.
Como última tarefa, devemos criar mais um item no bloco Controle, cujo nome Total fique visível na canvas e seja
do tipo numérico. O grupo Cálculo deve ser preenchido da seguinte forma: Modo de Cálculo com Sumário, Função
Sumária igual a Soma, Bloco Sumariado igual a Func e Item Sumariado igual a vl_sal.
O bloco de controle deve ter a propriedade Registro Simples (Single Record) preenchida com Sim (Yes) e o bloco
Func deve ter a propriedade Pré-Calcular Sumários (Precompute Summaries) preenchida também com Sim (Yes).
Para facilitar o processo de navegação, o bloco de controle foi passado para a frente do bloco Func. No bloco Func
o primeiro item a receber o foco é cd_depto. Sendo assim, quando o bloco entrar no modo de Entrar Consulta, a
coluna cd_depto é logo preenchida.
Alterei, ainda, o tipo de item de Total para Item de Exibição, não correndo o risco de ser alterado. Foi impedida,
também, a consulta por outras colunas diferente de cd_depto (Consulta Permitida – Query Allowed).
Observe no resultado que os prompts dos campos criados manualmente também foram preenchidos. Verifique o
grupo Prompt e faça o mesmo.
7.16) Crie uma aplicação de nome EX16 baseada na aplicação EX11. Inclua a seguinte funcionalidade:
♦ O título da janela deverá ser EX16.
♦ Não é permitido o redimensionamento da janela a tempo de execução, nem maximização e minimização.
♦ O usuário também não poderá fechar a aplicação através da janela.
♦ Incluir uma barra de rolagem horizontal na janela.
♦ Dimensione a canvas com 180 X 180.
♦ Dimensione a janela com 190 (X) por 182 (Y).
♦ Altere o posicionamento da janela para: 70 (X), 20 (Y).
A funcionalidade incluída neste exercício diz respeito às propriedades da janela e da canvas. Iniciaremos as
modificações pelas propriedades da janela.
No grupo Funcional encontramos diversas propriedades a serem alteradas.
Alteramos as propriedades Título (Title), Fechamento Permitido (Close Allowed), Redimensionamento Permitido
(Resize Allowed), Maximização Permitida (Maximize Allowed), Minimização Permitida (Minimize Allowed).
No grupo Físico (Physical) da janela, alteramos as propriedades Posição X (X Position) para 70, Posição Y (Y
Position) para 20, Largura (Width) para 190, Altura (Height) para 182 e Mostrar Barra de Rolagem Horizontal
(Show Horizontal Scroll Bar) para Sim (Yes).
Nosso último passo é dimensionar a canvas. Portanto, no grupo Físico (Physical) da canvas alteramos as propriedades
Largura (Width) para 180 e Altura (Height) para 180.
Agora, é só testar. Observe na execução que podemos movimentar a janela livremente, porém os sinais indicadores
de dimensionamento que aparecem próximo à borda da janela não ficam visíveis. Os ícones de maximização e
minimização não aparecem e uma barra de rolagem aparece na parte inferior da janela, porém desabilitada, uma
vez que toda a canvas está visível na janela.
7.17) Crie uma aplicação de nome EX17 baseada na aplicação EX12. Inclua a seguinte funcionalidade:
♦ O título da janela deverá ser EX17.
♦ Não é permitido o redimensionamento da janela a tempo de execução, somente maximização e minimização.
♦ Devem ser especificados um ícone para quando a janela for minimizada e um texto para esta situação.
♦ Esta janela deve ser apresentada em estilo diálogo.
♦ Defina cor para a canvas.
♦ O usuário não poderá movimentar esta janela.
♦ Determine seu posicionamento centralmente na tela do usuário.
Neste caso, novamente, iniciaremos pelas propriedades relativas à janela.
No grupo Funcional, alteramos as propriedades Título (Title) para EX17, Redimensionamento Permitido (Resize
Allowed) para Não (No), Maximização Permitida (Maximize Allowed) para Sim (Yes), Minimização Permitida (Mini-
mize Allowed) para Sim (Yes), Estilo da Janela (Window Style) para Caixa de Diálogo (Dialog), Título Minimizado
(Minimized Title) para EX17 e Nome do Arquivo de Ícones (Icon Filename) para macro (a especificação de ícone é
feita apenas com o nome do arquivo, sem extensão e sem diretório).
Se você executar a aplicação neste momento verificará que o ícone não foi encontrado, porque o Form Builder e o
Forms Runtime procuram por arquivos com a extensão ICO e com o nome especificado na propriedade que
estejam presentes em um dos diretórios informados na variável de ambiente UI_ICON do registrador do Windows.
Para que nossa aplicação fique com a funcionalidade desejada, clique no botão Iniciar da barra de aplicações do
Windows e escolha a opção Executar; preencha o campo Abrir da caixa de diálogo Executar com o texto REGEDIT.
Quando o diálogo do registrador aparecer, expanda o nó HKEY_LOCAL_MACHINE e a seguir expanda o nó SOFT-
WARE e a pasta Oracle também.
Quando você encontrar a pasta Home (relativa à instalação do Oracle Forms), clique sobre ela. Do lado direito da janela
serão mostradas diversas variáveis de ambiente. Navegaremos deste lado do diálogo procurando pela variável UI_ICON
(a lista está em ordem alfabética). Provavelmente você não encontrará esta variável, e portanto teremos de criá-la.
Clique sobre o menu Editar e marque, no submenu Novo, a opção Valor da Seqüência; observe a Figura-resposta 7.17A.
Será criada uma nova variável com o nome de Novo Valor #1. Você estará em modo de edição e poderá trocar o
nome da variável para UI_ICON. Se você deu Enter inadvertidamente, mantenha essa variável selecionada, retorne
ao menu Editar e marque a opção Renomear para que você retorne ao modo de edição.
Para que possamos associar um diretório a esta variável, devemos efetuar um clique duplo sobre o ícone da variável
ou apenas deixá-la selecionada, e no menu Editar escolher a opção Modificar.
O diálogo Editar Seqüência será apresentado e poderemos preencher com o diretório onde se encontra o ícone que
desejamos apresentar. Se desejarmos incluir um novo diretório em uma lista já existente (ou um segundo diretório
nesta), preencha um ponto-e-vírgula após o último diretório existente e inclua seu novo diretório após o ponto-e-
vírgula. Não precisamos escrever em letras maiúsculas.
Após todo este trabalho, podemos fechar o regedit e retornar à nossa aplicação. Ao executarmos novamente a
aplicação, o ícone já aparecerá conforme o planejado.
Nosso próximo passo é determinar uma cor para a canvas. No grupo Cor, preenchemos a propriedade Cor de
Fundo (Background Color), a segunda de cima para baixo, com o valor DarkYellow. Experimente outras cores.
Para definir um posicionamento central, retornamos às propriedades da janela e estabelecemos no grupo Físico
(Physical) da janela as propriedades Posição X (X Position) para 70, Posição Y (Y Position) para 70, Largura (Width)
para 345 e Altura (Height) para 200.
Execute e teste esta aplicação.
7.18) Crie uma aplicação de nome EX18 baseado na aplicação EX13. Inclua a seguinte funcionalidade:
♦ O título da janela deverá ser EX18.
♦ Não é permitido o redimensionamento da janela a tempo de execução nem minimização, apenas maximização.
♦ Dê títulos adequados a cada pasta.
♦ Dê cores diferenciadas a cada uma das pastas.
♦ Dê dimensões adequadas à canvas.
♦ Altere o estilo das pastas para arredondado.
♦ Coloque as orelhas das pastas do lado esquerdo.
♦ O usuário não poderá fechar a aplicação através da janela.
♦ Incluir uma barra de rolagem horizontal na janela.
♦ O usuário não poderá movimentar esta janela.
A funcionalidade referente à janela já estudamos nos exercícios anteriores e você já deve saber onde efetuar as
modificações (em caso de dúvida, verifique os Exercícios 7.16 e 7.17).
Na pasta Page3, trocaremos a propriedade Etiqueta (Label) para Departamento e a propriedade Cor de Fundo
(background color), a segunda de cima para baixo, com o valor r100g88b88.
Na pasta Page5, trocaremos a propriedade Etiqueta (Label) para Funcionário e a propriedade Cor de Fundo (back-
ground color), a segunda de cima para baixo, com o valor r25g88b75.
Teste sua aplicação.
7.19) Crie uma aplicação de nome EX19 baseado na aplicação EX14. Inclua a seguinte funcionalidade:
♦ O título da janela deverá ser EX19.
♦ Inclua uma barra de ferramentas vertical.
♦ Crie um bloco de controle de nome Controle.
♦ Inclua neste bloco seis botões com os nomes próximo, anterior, primeiro, último, rolar_acima, rolar_abaixo,
que devem ser apresentados na barra de rolagem vertical.
♦ Todos os botões devem apresentar ícones e indicadores das ações a serem efetuadas.
♦ Não é permitido o fechamento pela janela.
Nesta aplicação deveremos incluir uma canvas que funcione como uma barra de ferramentas vertical.
Antes de seguirmos, altere as propriedades referentes à janela, as quais você já conhece.
No Navegador, incluiremos uma nova canvas e alteraremos algumas de suas propriedades.
No grupo Geral, alteraremos as propriedades Nome (Name) para Vertical e Tipo de Canvas (Canvas Type) para
Barra de Ferramentas Vertical (Vertical ToolBar). Se o texto na janela de propriedades não estiver visível, aumente
a largura da janela até que toda a propriedade seja apresentada.
No grupo Físico (Physical) alteraremos sua Largura (Width) para 38.
A seguir, criaremos um novo bloco de nome Controle, cuja propriedade Bloco de Dados do Banco de Dados receba
o valor Não (False).
Neste bloco incluiremos seis itens cujo tipo será botão (tecla – pushbutton). Os nomes estão especificados no
exercício. Todos devem ter a propriedade Icônico (Iconic) preenchida com Sim (True). Escolha um ícone adequado
para cada um (seguem as mesmas regras referentes a ícones vistas no Exercício 7.17).
Para indicar a ação a ser efetuada, preencha a propriedade Dica da Ferramenta com os mesmos nomes dos botões.
No grupo Físico (Physical) dimensionaremos os botões com 30 x 30 (largura e altura). O posicionamento X de
todos eles será 4. O posicionamento Y será seqüencialmente 5, 35, 65, 95, 125 e 155.
Para que as duas canvas sejam apresentadas juntas na mesma janela, devemos retornar às propriedades da Janela e,
no grupo Funcional, preencher a propriedade Canvas da Barra de Ferramentas Vertical (Vertical Toolbar Canvas)
com o nome da nossa canvas, ou seja, Vertical.
Teste o resultado executando sua aplicação.
7.20) Crie uma aplicação de nome EX20 baseado na aplicação EX15. Inclua a seguinte funcionalidade:
♦ O título da janela deverá ser EX20.
♦ Inclua uma barra de ferramentas vertical.
♦ Inclua uma barra de ferramentas horizontal.
♦ Inclua no bloco Controle seis botões com os nomes próximo, anterior, primeiro, último, rolar_acima, rolar_abaixo,
que devem ser apresentados na barra de ferramentas vertical.
♦ Inclua no bloco de Controle seis botões com os nomes: salvar, sair, consultar, incluir, remover e limpar, que
devem ser apresentados na barra de ferramentas horizontal.
♦ Todos os botões devem apresentar ícones e indicadores das ações a serem efetuadas.
♦ Dê cores diferenciadas a cada uma das canvas.
♦ O usuário poderá minimizar e maximizar a janela desta aplicação, porém não poderá redimensionar, fechar ou
movimentá-la.
♦ Devem ser especificados ícone e título para a janela minimizada.
Este exercício é semelhante aos anteriores, com a intenção de reforçarmos a localização das propriedades.
Repetiremos as mesmas etapas, tanto para a barra de ferramentas vertical quanto para a horizontal. Todos os
botões devem ficar no mesmo bloco.
Verifique, nas aplicações anteriores, a utilização de cada propriedade e confira o resultado com o da Figura-resposta 7.20A.
Para que os botões fiquem com fundo cinza, preencha a propriedade Cor de Fundo (Background Color), a segunda
de cima para baixo, com o valor Gray.
No desenvolvimento desta aplicação utilizei o mesmo ícone para indicação de todas as ações. Isto torna a aplicação um pouco confusa. Se você
possuir outros ícones em seu micro, é preferível que identifique as ações com botões mais compatíveis.
Num ambiente real de produção, você copiará todos os ícones para um diretório comum e, em seguida, preencherá a variável de ambiente UI-
Icon com o diretório onde se encontram estes arquivos.
7.21) Crie uma aplicação de nome EX21 a partir da aplicação EX16. Inclua a seguinte funcionalidade:
♦ Estabelecer uma distância entre a linha do quadro e cada objeto de 5 pontos, tanto na vertical quanto na horizontal.
♦ A distância interna entre os objetos deve ser de 3.
♦ No máximo devem ser colocados três objetos em cada linha.
♦ O título do quadro deve ser posicionado no centro do quadro (horizontalmente).
♦ A distância entre os prompts dos objetos e os próprios objetos deve ser de 5 pontos.
♦ Altere o título do quadro usando o editor de Layout.
♦ Todos os prompts dos itens devem ser vermelhos.
♦ Coloque os objetos com cor de fundo amarela.
♦ Altere o tipo da letra dos objetos para Arial com tamanho 9.
Solução:
A cor dos prompts foi atribuída com o uso da barra de ferramentas vertical do editor de layout. Para a letra dos
objetos, selecionamos todos os itens de texto simultaneamente e no menu Formato utilizamos a opção Fonte.
A cor dos objetos também foi atribuída com o uso da barra de ferramentas vertical do editor de layout.
A Figura-resposta 7.21A nos mostra apenas a janela da aplicação durante uma execução.
7.22) Crie uma aplicação de nome EX22 a partir da aplicação EX17. Inclua a seguinte funcionalidade:
♦ Ajustar o tamanho do quadro aos objetos.
♦ Alinhar o prompt pela parte inferior do objeto.
♦ Deslocar o prompt lateralmente em relação ao objeto em 5 pontos.
♦ Alinhar o título do quadro pela direita com um distanciamento da vertical de 15 pontos.
♦ Separar o título da linha que envolve o quadro em 8 pontos.
♦ Alterar o tamanho e a cor da canvas pelo editor de Layout.
♦ Alterar a cor de fundo dos objetos.
♦ Aumentar o tamanho de todos os objetos horizontalmente.
♦ Trocar a cor da letra de todos os objetos.
♦ Construir dois retângulos em torno de grupos de objetos desenhados e colocar essa linha em terceira dimensão
usando duas opções diferentes.
Comece a construção, sempre que tiver quadro na aplicação, pelas propriedades do Quadro. Em seguida, altere o
tamanho do quadro verticalmente ou horizontalmente para que ele arrume os objetos de formas diferentes até
que você encontre aquela que mais o agrade. Só neste momento faça alterações manuais. Você poderá alterar a
propriedade Atualizar Layout (Update Layout) para Manualmente a fim de impedir alterações indesejáveis caso
haja necessidade de modificar o tamanho do quadro.
Iniciaremos, então, alterando as propriedades ShrinkWrap (ShrinkWrap) para Sim (Yes) a fim de que o tamanho do
quadro fique sempre ajustado (próximo) aos objetos; Alinhamento do Prompt ao Topo (Top Prompt Alignment)
para Inferior (Bottom), a fim de alinhar o prompt pela parte inferior do objeto; se a propriedade Deslocamento do
Prompt ao Topo (Top Prompt Offset) não estiver com zero, alteraremos para zero a fim de garantir o alinhamento
inferior. O deslocamento horizontal do prompt em relação ao objeto é fornecido pela propriedade Deslocamento
Inicial do Prompt (Start Prompt Offset) e seu valor deve ser de 5 pontos.
Para o título do quadro usaremos as propriedades Alinhamento do Título do Quadro (Frame Title Alignment) pela
Direita (Right); Deslocamento do Título do Quadro (Frame Title Offset) com o valor 15 para que o texto se afaste
da lateral direita em 15 pontos e, finalmente, Espaçamento do Título do Quadro (Frame Title Spacing), com o valor
8 para que seja dada uma distância entre o texto e a linha do quadro.
Para alterarmos o estilo do layout e a quantidade de registros apresentada, usaremos as propriedades Estilo de Layout
(Layout Style) e Número de Registros Exibidos (Number of Records Displayed) presentes dentro das propriedades do
quadro. Quando efetuamos esta modificação, automaticamente as propriedades do bloco são alteradas.
As demais ações devem ser feitas diretamente no editor de Layout.
7.24) Crie uma aplicação de nome EX24 a partir da aplicação EX19. Inclua a seguinte funcionalidade:
♦ Remover os quadros relativos a atividade e projeto e deixar somente o de projeto-atividade.
♦ Impedir que o quadro afete o bloco de dados.
♦ Colocar a cor de fundo de todos os itens igual à cor da canvas.
A definição de cor de fundo e o tamanho dos objetos é realizada diretamente no editor de Layout.
Para a distância entre os registros e o prompt, selecione todos os itens deste bloco no navegador e altere simultaneamente
as propriedades Distância Entre Registros (Distance Between Records) do grupo Registros (Records) para 10 e Estilo de
Exibição do Prompt (Prompt Display Style) do grupo Prompt para Primeiro Registro (First Record).
Para a inclusão do Prompt para o item Dias, basta que preenchamos a propriedade Prompt (Prompt). Para igualar
seu deslocamento com o dos demais itens, devemos preencher a propriedade Deslocamento de Conexão do Prompt
(Prompt Attachment Offset) com 5.
Selecione horizontalmente todos os elementos de um registro e estabeleça alinhamento horizontal Distribuir e
vertical Nenhum (repita para todos os registros).
Selecione verticalmente todos os elementos de uma mesma coluna e estabeleça alinhamento vertical Pilha e hori-
zontal Nenhum.
7.25) Crie uma aplicação de nome EX25 a partir da aplicação EX20. Inclua a seguinte funcionalidade:
♦ Somente a coluna Matrícula deve ser apresentada com repetição.
♦ Incluir as demais colunas da tabela Func.
♦ Colocar uma coluna Depto no bloco de controle e efetuar a pesquisa relativa a departamento por essa coluna.
♦ Ajustar a navegação de acordo com a tela.
♦ Colocar letra Arial tamanho 8 para todos os itens e definir itens e prompts em vermelho.
♦ Ajustar o layout para que fique semelhante ao da Figura-resposta 7.25A.
Inicialmente, no navegador incluiremos um item de nome depto no bloco de controle e alteraremos as propriedades
de tipo de dado para caracter e de tamanho para 3. Em seguida, alteraremos a cláusula Where do bloco Func para
que a pesquisa às linhas de departamento seja feita utilizando este item e não mais cd_depto.
Nosso próximo passo será incluir manualmente os itens de funcionário não presentes nesta aplicação: nr_ramal,
nm_sobrenome, dt_adm, dt_nasc, in_sexo, nr_git. Após a inclusão, devemos modificar as propriedades tipo de dado
e tamanho para que estes itens tenham as mesmas características da coluna correspondente no banco de dados.
A alteração de fonte, cor de letra, inclusão de boilerplates gráficos e ajustes diversos de posicionamento são todos
efetuados usando-se o editor de Layout.
Após termos definido o aspecto da tela, devemos retornar ao Navegador e movimentar os itens de tal forma que a
seqüência deles no Navegador defina a seqüência de navegação durante a execução da aplicação.
A partir deste tópico, além de estudarmos os triggers, começaremos a utilizar nos exercícios as rotinas disponibilizadas
pelo Form Builder para realizar diversas ações. Você conhecerá muitas dessas rotinas, porém no nó Pacotes Embutidos
(Extensões Standard) existem muito mais rotinas. Na Parte III: Referência você encontrará um capítulo contendo
todas estas rotinas organizadas por tipo de uso. O objetivo é simplesmente dar alguma facilidade na hora de definir
qual a rotina a usar; no entanto, a consulta à Ajuda do Form Builder é indispensável para que você saiba quais os
parâmetros possíveis e a capacidade da rotina.
Você encontrará, ainda, neste material um tópico que trata especificamente deste nó Pacotes Embutidos, porém
nosso estudo das rotinas já começa agora.
7.26) Crie uma aplicação de nome EX26 baseada na aplicação EX25, incluindo a seguinte funcionalidade:
♦ Formatar os campos de data com dd/mm/rrrr.
♦ Os campos de data são de preenchimento obrigatório e sempre com tamanho máximo.
♦ Formatar o campo de salário com L999G999G999D99.
♦ Adicione o código-padrão para os botões.
♦ Verificar a tempo de alteração ou inclusão se o salário informado está dentro da tabela de cargos e salários a seguir:
a) Para cargos até 46 (inclusive), o salário deve variar de 500 a 1.500 (inclusive).
b) Para cargos de 47 a 52 (inclusive), o salário deve variar de 1.501 a 2.000 (inclusive).
c) Para cargos de 53 a 55 (inclusive), o salário deve variar de 2.001 a 2.500 (inclusive).
d) Para cargos de 56 a 58 (inclusive), o salário deve variar de 2.501 a 3.000 (inclusive).
e) Para cargos de 59 a 60 (inclusive), o salário deve variar de 3.001 a 3.500 (inclusive).
f) Para cargos de 61 a 62 (inclusive), o salário deve variar de 3.501 a 4.000 (inclusive).
g) Para cargos de 63 (inclusive) em diante, o salário deve variar de 4.501 a 10.000 (inclusive).
Caso haja alguma incorreção, causar uma falha e enviar mensagem adequada.
♦ A janela da aplicação e a janela do Forms Runtime devem aparecer maximizadas.
♦ Garanta o preenchimento de salário, nome e sobrenome.
♦ Garanta que a data de nascimento somente aceite valores acima de 1940.
Passaremos, agora, a relacionar os passos para a customização desta aplicação.
Nossa primeira etapa é preencher a propriedade Máscara de Formatação (Format Mask) dos itens dt_nasc e dt_adm
com o valor DD/MM/RRRR. Essa propriedade está presente do grupo Data.
Ainda no mesmo grupo encontramos as propriedades Obrigatório (Required) e Tamanho Fixo (Fixed Size), que
devem ser habilitadas para cumprimento da terceira etapa.
O campo Salário também terá preenchida a propriedade Máscara de Formatação (Format Mask), agora com o valor
L999G999G999D99.
Para acionamento dos botões, devemos criar um gatilho (trigger) do tipo When-Button-Pressed para cada um deles
contendo o seguinte código-padrão:
♦ Próximo = Next_Record;
♦ Anterior = Previous_Record;
♦ Primeiro = First_Record;
♦ Último = como não existe código para navegação direta para o último registro, devemos montar uma lógica que
navegue registro a registro para baixo até que seja atingido o último. A variável de sistema (será visto no próximo
tópico) System.Last_Record indica se atingimos ou não o último botão. Veja o código criado na Listagem-
resposta 7.26A.
Listagem-resposta 7.26A
LOOP
NEXT_RECORD;
IF :SYSTEM.LAST_RECORD = 'TRUE' THEN
EXIT;
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
MESSAGE ('Navegação inválida');
Rolar_Acima = Scroll_Up;
Rolar_Abaixo = Scroll_Down;
Salvar = Commit_Form;
Sair = Exit_Form;
Consultar = Execute_Query;
Incluir = Create_Record;
Remover = Delete_Record;
Limpar = Clear_Record;
Alguns destes botões (por exemplo, Inserir, Limpar, Remover, Consultar) necessitam de que o foco não se mova do
lugar quando o botão for acionado, ou seja, não devemos permitir que haja navegação para o botão quando o
usuário clicá-lo. Caso contrário, como o botão está pendurado no bloco de controle e não no bloco Func, o Forms
Runtime tentará executar a ação solicitada para o bloco de controle e receberá um erro que será repassado para o
usuário (“Esta ação não pode ser executada aqui”). Sendo assim, marcaremos as propriedades Navegável com
Teclado (Keyboard Navigable) e Navegação do Mouse (Mouse Navigate) com Não (False).
Para validação, temos, como sabemos, dois triggers: When-Validate-Item e When-Validate-Record. Uma vez que
desejamos a comparação do valor de dois itens e, ainda, queremos impedir a navegação (causar uma falha), devemos
criar a crítica num trigger When-Validate-Record (em nível de bloco), conforme a Listagem-resposta 7.26B (trecho).
Listagem-resposta 7.26B
IF :FUNC.NR_CARGO <= 46 THEN
IF :FUNC.VL_SAL NOT BETWEEN 500 AND 1500 THEN
MESSAGE ('Salário deve estar entre 500 e 1500 para este cargo');
RAISE FORM_TRIGGER_FAILURE;
ELSE
GOTO FIM;
END IF;
END IF;
IF :FUNC.NR_CARGO BETWEEN 47 AND 52 THEN
IF :FUNC.VL_SAL NOT BETWEEN 1501 AND 2000 THEN
MESSAGE ('Salário deve estar entre 1501 e 2000 para este cargo');
RAISE FORM_TRIGGER_FAILURE;
ELSE
GOTO FIM;
END IF;
END IF;
IF :FUNC.NR_CARGO BETWEEN 53 AND 55 THEN
IF :FUNC.VL_SAL NOT BETWEEN 2001 AND 2500 THEN
MESSAGE ('Salário deve estar entre 2001 e 2500 para este cargo');
RAISE FORM_TRIGGER_FAILURE;
ELSE
GOTO FIM;
END IF;
END IF;
IF :FUNC.NR_CARGO BETWEEN 56 AND 58 THEN
IF :FUNC.VL_SAL NOT BETWEEN 2501 AND 3000 THEN
MESSAGE ('Salário deve estar entre 2501 e 3000 para este cargo');
RAISE FORM_TRIGGER_FAILURE;
ELSE
GOTO FIM;
END IF;
END IF;
IF :FUNC.NR_CARGO BETWEEN 59 AND 60 THEN
IF :FUNC.VL_SAL NOT BETWEEN 3001 AND 3500 THEN
MESSAGE ('Salário deve estar entre 3001 e 3500 para este cargo');
RAISE FORM_TRIGGER_FAILURE;
ELSE
GOTO FIM;
END IF;
END IF;
IF :FUNC.NR_CARGO BETWEEN 61 AND 62 THEN
IF :FUNC.VL_SAL NOT BETWEEN 3501 AND 4000 THEN
MESSAGE ('Salário deve estar entre 3501 e 4000 para este cargo');
RAISE FORM_TRIGGER_FAILURE;
ELSE
GOTO FIM;
END IF;
END IF;
IF :FUNC.NR_CARGO >= 63 THEN
A próxima etapa é garantir fazer com que a janela do Forms Runtime e a janela da própria aplicação sejam
maximizadas quando a aplicação iniciar a execução.
Escolhemos o gatilho Pre-Form para definir o código. Usaremos a rotina Set_Window_Property a fim de alterar a
propriedade Window_State das duas janelas e passá-las para o estado maximizado. Observe na Listagem-resposta
7.26C que informamos como parâmetro Janela1 correspondendo ao nome da janela da nossa aplicação (expanda
o nó Janelas – Windows e verifique o nome). Para a janela do Forms Runtime, utilizamos o mneumônico
Forms_Mdi_Window (verifique no arquivo de Ajuda).
Listagem-resposta 7.26C
SET_WINDOW_PROPERTY ('JANELA1', WINDOW_STATE, MAXIMIZE);
SET_WINDOW_PROPERTY (FORMS_MDI_WINDOW, WINDOW_STATE, MAXIMIZE);
Para garantirmos o preenchimento de nome, sobrenome e salário, basta que habilitemos a propriedade Obrigatório
(Required) no grupo Dados (Data).
A última crítica determina que a data de nascimento deve ser maior que 1940. Neste caso, basta que preenchamos
a propriedade Mínimo Valor Permitido (Lowest Allowed Value) do grupo Dados (Data) com o valor 01/01/1940
para que o próprio Forms Runtime se encarregue da crítica.
7.27) Crie uma aplicação de nome EX27 baseada na aplicação EX26, incluindo a seguinte funcionalidade:
♦ Traga a coluna nm_foto coluna para a sua aplicação.
♦ Inclua essa coluna na canvas imediatamente abaixo de um item do tipo imagem, criado no bloco Func, mas não
pertencente ao banco de dados.
♦ A tempo de execução, o campo nm_foto deverá ser preenchido com o caminho e nome de arquivos do tipo BMP
presentes em seu disco. Quando a coluna for preenchida, a imagem correspondente deverá ser trazida para a tela.
♦ Crie uma canvas do tipo stack e preencha essa canvas com um boilerplate que especifique como deve ser feito
o preenchimento dessa tela.
♦ Esta canvas deverá ser apresentada quando o usuário pressionar a tecla Help. Quinze segundos depois, esta tela
deve ser escondida novamente.
♦ A janela da aplicação não pode ser fechada.
♦ A janela da aplicação não pode ser minimizada.
♦ Anexar o símbolo da empresa na barra de ferramentas.
Como primeiro passo devemos salvar a aplicação com o nome de EX27. A inclusão das novas colunas requer:
a) Criação de dois novos itens no bloco Func.
b) O item nm_foto deve ter tipo caracter e tamanho 200, ser coluna do banco de dados e visível na canvas2.
c) O item foto deve ser do tipo imagem, não ser coluna do banco de dados e visível na canvas2.
A próxima etapa é gráfica e será apresentada ao fim de toda a montagem.
Para trazer a imagem para a tela, devemos criar um trigger, que pode ser When-Validate-Item ou Post-Text-Item.
Escolhi When-Validate-Item para que a leitura ocorra a tempo de validação.
Listagem-resposta 7.27B
READ_IMAGE_FILE (:FUNC.NM_FOTO, NULL, 'FUNC.FOTO');
IF NOT FORM_SUCCESS THEN
MESSAGE ('NOME DE FOTO INVÁLIDA');
END IF;
Na Listagem-resposta 7.27B apresentamos a rotina Read_Image_File que realiza a leitura do arquivo. No primeiro
parâmetro informamos o nome do arquivo (no nosso caso, este nome está armazenado dentro do item nm_foto,
por este motivo preenchemos com :nm_foto, ou seja, o conteúdo do item). No segundo parâmetro informamos o
tipo do arquivo a ser lido; considerei que não sabemos ou que podem ser arquivos de tipos diferentes, deixando
que o Forms Runtime descubra o tipo do arquivo pela extensão. No terceiro parâmetro devemos informar o nome
do item do tipo imagem que receberá a foto (por este motivo informamos o nome entre aspas).
A criação da canvas é feita no Navegador com a ferramenta Criar (Create). Em seguida, abrimos a tela de propriedades
e alteramos seu tipo para Empilhado (Stack). A seguir, navegamos para o Editor de Layout e diminuímos seu
tamanho para que fique como uma barra. Então incluímos um boilerplate de texto contendo uma informação
para o preenchimento da tela.
Para termos visualização e posicionarmos a canvas no local em que ela deve aparecer, navegamos para a canvas2,
acionamos no menu Visualizar (View) a opção Views Sobrepostas (Stacked Views). No diálogo apresentado estarão
listadas todas as canvas do tipo Stack. Selecionaremos nossa canvas e clicaremos o botão OK. Retornaremos então
à canvas2 com a visualização simultânea da canvas ST_Func (canvas do tipo Stack) na mesma tela. Poderemos,
então, arrastá-la para a posição desejada. Para realizar este movimento, a canvas ST_Func deve estar selecionada e
você deve clicar exatamente em um dos quadradinhos indicativos de seleção para arrastá-la (ou usar o teclado com
Shift+Seta para baixo ou para cima).
Se você não conseguir selecionar a canvas, retorne ao Layout dela (sozinha), tire a visibilidade do ViewPort (Show
View) e selecione a canvas. Retorne, então, à canvas2 e a canvas ST_Func aparecerá selecionada.
A apresentação da canvas deve ser realizada pelo trigger Key-Help (em nível de aplicação), como solicitado.
Listagem-resposta 7.27C
DECLARE
TEMPO TIMER;
BEGIN
TEMPO := CREATE_TIMER ('TIMER_TEMPO', 15000, NO_REPEAT);
SHOW_VIEW ('ST_FUNC');
END;
Para controle de tempo, criaremos um objeto Timer. O nome deste objeto será Timer_Tempo. Os parâmetros para
a rotina Create_Timer são: o nome do timer a ser criado, o tempo em que ele será considerado expirado (em
milissegundos) e uma indicação de recontagem de tempo ou não. Quando preenchemos o terceiro parâmetro com
No_Repeat, indicamos que quando o tempo expirar o timer pode ser destruído, pois não será utilizado novamente.
Para executarmos uma ação quando o tempo expirar, devemos criar um trigger When-Timer-Expired em nível de
aplicação para solicitar que a view seja escondida.
Listagem-resposta 7.27D
HIDE_VIEW ('ST_FUNC');
Para que a canvas ST_Func não seja apresentada por default, devemos alterar sua propriedade Visível (Visible) para
Não (False) a fim de que ela só apareça quando acionada.
Os dois tópicos seguintes você já sabe onde deve alterar.
Para anexarmos uma imagem qualquer em nossa aplicação, devemos navegar para o Layout desejado (escolhi a
canvas Horizontal) e usar no submenu Importar (Import) do menu Arquivo (File) a opção Imagem (Image). Quando
a imagem for carregada, podemos arrastá-la e dimensioná-la para o posicionamento adequado.
7.28) Crie uma aplicação de nome EX28 baseada na aplicação EX27, incluindo a seguinte funcionalidade:
♦ Inclua uma nova canvas do tipo conteúdo para a manutenção na tabela Departamento (utilize o Assistente para
efetuar essa inclusão). O nome do Departamento pode ocupar mais de uma linha.
♦ Inclua uma nova canvas do tipo conteúdo para a manutenção na tabela Projetos (utilize o Assistente para
efetuar esta inclusão). O nome do Projeto pode ocupar mais de uma linha.
♦ Nomeie as canvas de acordo com o bloco que contêm: Cfunc, Cdepto e Cproj.
♦ Deve ser criada uma canvas stack para cada uma destas novas canvas de conteúdo contendo, respectivamente,
informações sobre o preenchimento de dados em departamento e projetos.
♦ Incluir um botão na barra de ferramentas vertical que estabeleça a navegação entre os blocos. Quando estivermos
posicionados em funcionário, ocorrerá a navegação para departamento. Quando estivermos posicionados em
departamento, ocorrerá a navegação para projetos, e quando estivermos posicionados em projetos, ocorrerá a
navegação para funcionário. A ajuda do botão deverá indicar para onde ocorrerá a navegação.
♦ Quando houver navegação para cada um dos blocos, a janela da aplicação deverá indicar o nome do bloco correspondente.
♦ Somente poderemos efetuar consulta pelas colunas nr_cargo e departamento (do bloco de controle). A atualização
poderá ser efetuada para todas as colunas, sendo que Matrícula poderá ser incluída, mas não alterada.
♦ Altere as características dos itens, de acordo com as especificações a seguir:
a) O item in_sexo deve ser do tipo radio group, para os valores F, M e Null.
b) O item nr_cargo deve ser do tipo List Item para os valores (48 – analista júnior, 49 – analista pleno, 50 –
analista sênior, 51 – dba, 52 – analista de dados, 53 – suporte de software, 54 – suporte de hardware, 55 –
coordenador de projeto, 56 – gerente de sistema, 57 – instrutor, 58 – gerente de suporte, 59 – gerente de
treinamento, 60 – diretor). O usuário poderá informar outros valores não presentes na lista, inclusive Null.
c) A coluna nr_git deve corresponder a uma lista com os seguintes valores (12 – primeiro grau incompleto, 13 –
primeiro grau completo, 14 – segundo grau incompleto, 15 – segundo grau completo, 16 – superior incompleto,
Listagem-resposta 7.28A
IF :CONTROLE.BLOCO = 'FUNCIONARIO' THEN
:CONTROLE.BLOCO := 'DEPARTAMENTO';
SET_ITEM_PROPERTY ('CONTROLE.NAVEGA', TOOLTIP_TEXT, 'Projeto');
GO_BLOCK ('DEPTO');
ELSIF :CONTROLE.BLOCO = 'DEPARTAMENTO' THEN
:CONTROLE.BLOCO := 'PROJETO';
SET_ITEM_PROPERTY ('CONTROLE.NAVEGA', TOOLTIP_TEXT, 'Funcionário');
GO_BLOCK ('PROJ');
ELSE
:CONTROLE.BLOCO := 'FUNCIONARIO';
SET_ITEM_PROPERTY ('CONTROLE.NAVEGA', TOOLTIP_TEXT, 'Departamento');
GO_BLOCK ('FUNC');
END IF;
Quando ocorre a troca de bloco, alteramos o valor da variável de controle para o nome do próximo bloco e
alteramos o texto da propriedade Dica da Ferramenta do botão Navega. A rotina Set_Item_Property permite que, a
tempo de execução, alteremos algumas das propriedades dos itens.
Para que esta variável tenha um valor inicial, no trigger Pre-Form (já existente), preencha-a com o valor Funcionário,
que é o primeiro bloco visível na aplicação.
Nossa próxima tarefa é alterar o título da janela. Utilizaremos mais uma vez a rotina Set_Window_Property, agora
para a propriedade Title. Veja a Figura-resposta 7.28B.
Listagem-resposta 7.28B
SET_WINDOW_PROPERTY (FORMS_MDI_WINDOW, TITLE, :CONTROLE.BLOCO);
Escolhemos o gatilho When-New-Block-Instance em nível de Form, ou seja, todas as vezes que houver uma mudança
de bloco provocada ou não pelo botão, ocorrerá a execução deste trigger. Sendo assim, basta que façamos uma
atribuição do conteúdo da variável Bloco para o título da janela. Você vai observar que alteramos o título da janela
da aplicação Forms Runtime. Se você preferir modificar o nome da janela da sua aplicação, deve passar como
primeiro parâmetro da rotina o nome da sua janela (‘Janela1’, no caso do exemplo).
Voltamos às propriedades. Para que não seja possível a consulta pelos demais campos, devemos desabilitar a
propriedade Consulta Permitida (Query Allowed) de todos os itens e habilitá-la apenas para nr_cargo, uma vez que
o código do departamento do bloco de controle não é item do banco de dados.
As outras três ações já realizamos várias vezes para o preenchimento de listas e do grupo de opções. Você só não
deve esquecer de preencher a propriedade Mapeamento de Outros Valores (Mapping of Other Values) a fim de
determinar uma ação quando o usuário informar um valor não presente na lista.
A última tarefa é efetuar uma crítica relativa à coluna grau de instrução.
Listagem-resposta 7.28C
IF :FUNC.NR_GIT < 16 THEN
MESSAGE ('Grau de Instrução Inválido');
RAISE FORM_TRIGGER_FAILURE;
END IF;
A Listagem-resposta 7.28C nos apresenta a crítica anexada, porém ainda incompleta, pois a solicitação era de que
a tempo de inclusão esta crítica fosse realizada. Para tal deveríamos saber o estado do registro, que também é
fornecido por variáveis de ambiente; portanto, o término deste item ficará para outro exercício.
7.29) Crie uma aplicação de nome EX29 baseada na aplicação EX28, incluindo a seguinte funcionalidade:
♦ Inclua uma coluna para cálculo da gratificação por tempo de serviço, que deverá utilizar a fórmula: (tempo de
serviço / 3) multiplicado por 1/5 do salário para todos os funcionários que tiverem mais de dois anos de casa.
♦ Inclua um item do tipo check box que poderá ser marcado pelo usuário. Quando isto acontecer, o salário do
funcionário deverá ser acrescido de 5% a tempo de alteração.
♦ Garanta que o código do projeto siga o padrão de duas letras e quatro números.
♦ Não são admitidos funcionários menores de 21 anos do sexo feminino e 18 anos do sexo masculino.
♦ Não são admitidos funcionários com mais de 60 anos.
♦ A data inicial do projeto deverá ser igual ou superior à data do dia do cadastramento e inferior à data final.
♦ O usuário somente poderá utilizar as teclas Ajuda, Próximo Item, Item Anterior. As demais teclas deverão ser
desabilitadas com mensagem adequada.
♦ Se o código do departamento (do bloco de controle) não for preenchido, deverá ser feita a consulta de todas as
linhas da tabela Func.
♦ Quando o botão Consultar for acionado, navegue para um item do bloco atual.
Após criarmos a nova aplicação de nome EX29 baseada em EX28, criaremos uma coluna no próprio bloco de
funcionário (poderia ser em controle também) contendo a seguinte fórmula:
Trunc ( ( ( (sysdate - :func.dt_nasc)/365.25)/3) * (:func.vl_sal/5),2)
Essa fórmula deve ser inserida no grupo Cálculo (Calculation). A propriedade Modo de Cálculo (Calculation Mode)
deve ser preenchida com a indicação de fórmula e a propriedade Fórmula (Formula) com a fórmula descrita.
Além destas propriedades não devemos nos esquecer de definir esta coluna como numérica (grupo Dados – Data),
não pertencente ao banco de dados e desativada (só leitura).
A seguir, criamos uma nova coluna no bloco Func novamente, do tipo Caixa de Seleção, chamado Premio, que não
pertence ao banco de dados e cujos valores válidos são ‘S’ e ‘N’ (são valores de livre escolha). Para garantir que em
uma mesma execução o salário não será atualizado duas vezes, a ação de aumento do salário foi incluída num
trigger de Pre-Update do bloco Func. Temos, porém, um pequeno problema. Um trigger transacional só é ativado
se o Forms Runtime acusar uma alteração no registro. Como o item Premio não pertence ao banco de dados,
quando alteramos seu valor ele passa por uma validação; porém o estado do registro não é alterado (não é necessária
nenhuma alteração para o banco de dados). A fim de forçar esta ação, criamos um trigger de validação para Premio
que atribui o valor de salário a ele mesmo, causando, então, a modificação no estado do registro (isto também
poderia ser feito através da rotina Set_Record_Property).
Listagem-resposta 7.29A
:FUNC.VL_SAL := :FUNC.VL_SAL;
Para garantirmos a crítica de código do projeto, basta que a máscara do campo seja AA9999.
A crítica de idade foi anexada ao trigger When-Validate-Record do bloco Func.
Listagem-resposta 7.29B
<<FIM>>
IF :FUNC.IN_SEXO = 'F' OR
:FUNC.IN_SEXO IS NULL THEN
IF (SYSDATE - :FUNC.DT_NASC) / 365.25 < 21 THEN
MESSAGE ('Deve ter mais de 21 anos');
RAISE FORM_TRIGGER_FAILURE;
END IF;
ELSE
IF (SYSDATE - :FUNC.DT_NASC) / 365.25 < 18 THEN
MESSAGE ('Deve ter mais de 18 anos');
RAISE FORM_TRIGGER_FAILURE;
END IF;
END IF;
Listagem-resposta 7.29C
IF (SYSDATE - :FUNC.DT_NASC)/ 365.25 > 60 THEN
MESSAGE ('Não é permitido maior de 60 anos');
RAISE FORM_TRIGGER_FAILURE;
END IF;
Para crítica de data do projeto utilizamos as propriedades valor mínimo e valor máximo. Sendo o mínimo igual a
$$DBDATE$$ e o máximo igual a :proj.dt_fim.
Para controlar o teclado, utilizamos os triggers a seguir com os respectivos comandos:
♦ Key-Next-Item – Next_Item;
♦ Key-Prev-item – Previous_Item;
♦ Key-Others – Message (‘Tecla Inválida’);
Para que a restrição da consulta fique variável, devemos retirar o preenchimento da cláusula Where em nível de
propriedade e incluir um trigger Pre-Query que altere dinamicamente a cláusula Where de acordo com o valor
preenchido em :controle.depto. Veja a Listagem-resposta 7.29D.
Listagem-resposta 7.29D
IF :CONTROLE.DEPTO IS NULL THEN
SET_BLOCK_PROPERTY ('FUNC', DEFAULT_WHERE, '');
ELSE
SET_BLOCK_PROPERTY ('FUNC', DEFAULT_WHERE,
'WHERE CD_DEPTO = '''||:CONTROLE.DEPTO||'''');
END IF;
A propriedade Default_Where do bloco permite a alteração dinâmica da cláusula Where a ser aplicada à Query.
Para evitarmos a navegação para o bloco Func cada vez que preenchemos o código do departamento, faremos a
navegação automática no botão Consultar (trigger When-Button-Pressed), conforme a Listagem-resposta 7.29E.
Listagem-resposta 7.29E
GO_ITEM ('FUNC.CD_MAT');
EXECUTE_QUERY;
Esta ação não está completa, pois, se navegarmos para outro bloco, o desvio será feito para o bloco Func, o que não
desejamos, porém isto ainda depende de sabermos em que bloco estamos. Se você quiser, faça o controle através
daquela variável Bloco criada no bloco Controle. Isto será reavaliado no tópico de Variáveis.
7.30) Crie uma aplicação de nome EX30 baseado na aplicação EX29, com a seguinte funcionalidade:
♦ Impeça que a pergunta “Você deseja salvar as alterações efetuadas?” seja apresentada para o usuário.
♦ A partir da aplicação atual, acione outra das aplicações que você fez anteriormente utilizando um botão na
barra de ferramentas vertical. Essa outra aplicação deverá ser acionada em outra sessão do mesmo usuário.
♦ Se o campo nm_foto estiver preenchido, a tempo de leitura a foto já deverá ser carregada.
♦ Todo projeto deve ter departamento e responsável.
♦ O responsável deve ser funcionário do mesmo departamento.
♦ Todas as mensagens devem ser apresentadas na linha de mensagem, inclusive as mensagens recebidas do banco
de dados. Neste caso, deve ser mostrada também a sintaxe causadora do erro.
♦ Crie um botão na barra de ferramentas horizontal que apresente as teclas disponíveis para os usuários.
A princípio, esta parece ser uma tarefa árdua, ou seja, controlar todos os pontos em que a mensagem “Você deseja
salvar ....” pode aparecer. Na aplicação atual, porém, esta atividade não será tão difícil, portanto recapitulemos. A
mensagem aparece quando:
♦ O usuário sai da aplicação sem salvar – Os modos de saída da nossa aplicação estão restritos ao botão Sair porque
as teclas que permitem a saída foram bloqueadas (When-Others) e a janela não pode ser fechada, e portanto o
único ponto de controle com relação a esta situação é o botão Sair (ponto um).
♦ O usuário limpa o bloco – Esta ação não está disponibilizada diretamente para o usuário (não existe tecla
disponível e nem botão).
♦ O usuário efetua um Entrar Consulta – Esta ação não está disponibilizada na aplicação (não existe tecla disponível
e nem botão).
♦ O usuário efetua um Executar Consulta – Esta ação está presente através do botão Consultar (ponto dois).
♦ O usuário efetua um Clear Form (Limpar Tudo) – Esta ação não está disponibilizada na aplicação (não existe
tecla disponível e nem botão).
Você já observou que as ações de seu menu-padrão não estão mais funcionando? Teste! Isto ocorre porque o menu-
padrão não é construído com as funções-padrão diretamente e sim com a função Do_Key (<ação>) que simula as
ações de teclado. Como desabilitamos diversas ações de teclado, o menu deixou de funcionar.
Resta-nos então decidir o que fazer em um destes dois pontos quando descobrirmos que existem modificações
realizadas. Consideraremos que, se o usuário pretende sair ou realizar uma nova consulta, ele está desistindo das
ações realizadas até agora. Poderíamos perguntar-lhe também, mas gostaria de analisar os parâmetros das rotinas
de sair e de execução da consulta. Você pode decidir outra coisa quando descobrir as possibilidades.
Listagem-resposta 7.30A
EXIT_FORM (no_commit);
A Listagem-resposta 7.30A (When-Button-Pressed do botão Sair) mostra a rotina Exit_Form recebendo um parâmetro.
Existem quatro possibilidades de parâmetro para essa rotina: Ask_Commit (que é a opção default e que apresenta
a mensagem indesejada atualmente), Do_Commit (executa um Commit_Form antes de encerrar), No_Commit
(efetua todo o processo de validação, mas não atualiza o banco de dados) e No_Validate (não executa a fase de
validação e não atualiza o banco de dados).
Listagem-resposta 7.30B
GO_ITEM ('FUNC.CD_MAT');
CLEAR_BLOCK (NO_VALIDATE);
EXECUTE_QUERY;
A Listagem-resposta 7.30B nos mostra a operação realizada pela ação de consulta (botão Consultar). Como a rotina
Execute_Query não possui os parâmetros que desejávamos e a limpeza do bloco é necessária, executamos um Clear_Block
indicando a ação a ser realizada. Nas duas situações registradas não ocorre mais a pergunta para o operador.
Nosso próximo passo é acionar uma outra aplicação em uma sessão diferente da atual.
Listagem-resposta 7.30C
OPEN_FORM ('EX29', ACTIVATE, SESSION, SHARE_LIBRARY_DATA);
Na Listagem-resposta 7.30C (botão Aplicar) resolvemos este problema usando a rotina Open_Form, cujos
parâmetros indicam:
♦ O nome da aplicação a ser executada.
♦ Se a nova aplicação é ativada imediatamente ou não. Podemos navegar de uma para outra através do menu Window.
♦ Se deve ou não (No_Session) ser aberta uma nova sessão, isto é, uma nova conexão com o banco de dados.
♦ Se devemos ou não (No_Share_Library_Data) compartilhar as bibliotecas entre aplicações, isto é, se duas aplicações
que invocam uma mesma biblioteca (Library) devem ou não compartilhar a cópia desta biblioteca em memória
no ambiente cliente. Esta opção pode resguardar memória no ambiente cliente.
O próximo passo é apresentar o conteúdo da foto a tempo de leitura; portanto devemos criar o trigger Post_Query
para o bloco Func. Já sabemos que este trigger será acionado uma vez para cada linha retornada do banco de dados
(bem dentro das nossa necessidades). Veja a Listagem-resposta 7.30D.
Listagem-resposta 7.30D
IF :FUNC.NM_FOTO IS NOT NULL THEN
READ_IMAGE_FILE (:FUNC.NM_FOTO, NULL, 'FUNC.FOTO');
IF NOT FORM_SUCCESS THEN
MESSAGE ('NOME DE FOTO INVÁLIDA');
END IF;
END IF;
No próximo passo você já sabe o que fazer: alterar a propriedade Obrigatório (Required) dos itens.
Já garantir que o responsável trabalhe no departamento que coordena o projeto requer PL/SQL.
Listagem-resposta 7.30E
DECLARE
DEP VARCHAR2 (3);
BEGIN
SELECT CD_DEPTO INTO DEP
FROM FUNC WHERE CD_MAT = :PROJ.CD_RESP;
IF DEP IS NULL OR
:PROJ.CD_DEPTO <> DEP THEN
MESSAGE ('Este coordenador não pertence ao '||
'Departamento Responsável');
RAISE FORM_TRIGGER_FAILURE;
END IF;
END;
Criamos um gatilho When-Validate-Record em nível de bloco para Proj e preenchemos conforme a Listagem-
resposta 7.30E.
Para as mensagens de erro utilizamos o trigger On_Error, que por começar com ON já sabemos que substitui a
funcionalidade default; portanto, devemos incluir tanto a apresentação das mensagens do Forms Runtime quanto
as mensagens do banco de dados, incluindo a apresentação da tela de erro. Verifique a Listagem-resposta 7.30F.
Listagem-resposta 7.30F
MESSAGE (ERROR_TYPE||TO_CHAR (ERROR_CODE)||': '||ERROR_TEXT);
IF DBMS_ERROR_CODE <> 0 THEN
MESSAGE (DBMS_ERROR_TEXT);
DISPLAY_ERROR;
END IF;
Nossa última tarefa é a apresentação das teclas, que é facilmente resolvida com a execução da rotina Show_Keys
em um botão recém-criado de nome Keys.
Neste tópico abandonaremos, temporariamente, a aplicação que temos incrementado até agora. Trabalharemos
apenas com as características dos relacionamentos mestre-detalhe.
7.31) Crie uma nova aplicação de nome EX31. As seguintes tabelas devem ser apresentadas numa mesma canvas:
♦ Departamento: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Funcionário: formato Tabular, todas as colunas, oito registros por tela.
As seguintes características devem ser configuradas para esta aplicação:
♦ O bloco de funcionário deve ser construído em uma canvas do tipo Empilhado (Stack) com uma barra de
rolagem de tal forma que parte dos dados fique visível na canvas principal. Para visualização das demais
informações, o usuário deverá se utilizar da barra de rolagem. A canvas fica visível todo o tempo sobre a canvas
de Conteúdo (Content) onde foi construído Departamento.
♦ O relacionamento entre os blocos deve ser do tipo Departamento (pai), Funcionário (Filho).
♦ Não deve ser possível excluir um registro em um pai quando houver registros nos respectivos filhos.
♦ Não deve ser possível uma pesquisa em um filho se não houver registro alocado no pai correspondente.
♦ Tão logo o registro-pai seja trazido, o(s) registro(s)-filho deve(m) ser trazido(s) imediatamente.
A Figura-resposta 7.31A nos apresenta o esquema do relacionamento.
O resultado apresenta uma canvas do tipo empilhado (Stack) sobreposta na canvas de conteúdo onde se acha o
bloco Departamento.
♦ Por fim, as propriedades Diferido (Deferred) e Consulta Automática (Automatic Query) são responsáveis pela
coordenação de leitura. Quando Diferido recebe o valor Não indica que a leitura não deve ser adiada, ou seja,
tão logo seja realizada no bloco Mestre, o detalhe deverá imediatamente receber os dados. Neste caso, o valor de
Consulta Automática é ignorado.
7.32) Crie uma nova aplicação de nome EX32. As seguintes tabelas devem ser apresentadas numa mesma canvas:
♦ Departamento: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Projeto: formato Tabular, todas as colunas três registros por tela.
♦ Projeto Atividade: formato Tabular, todas as colunas cinco registros por tela.
As seguintes características devem ser configuradas para esta aplicação:
♦ O relacionamento entre os blocos deve ser do tipo Departamento (avô), Projeto (pai) e Projeto-Atividade (filho).
♦ Não será permitida a remoção de Departamento se existirem projetos; no entanto, a remoção de projeto poderá
ser efetuada desde que todos os registros de Projeto-Atividade sejam removidos também.
♦ Deve ser possível uma pesquisa em um filho mesmo que não haja registro alocado no pai correspondente.
♦ Tão logo o registro de Departamento seja trazido o(s) registro(s)-filho deve(m) ser trazido(s) imediatamente.
Porém, somente devem ser consultados os registros de Projeto Atividade quando o usuário estabelecer a navegação
para este bloco.
A Figura-resposta 7.32A nos apresenta o esquema do relacionamento.
Iniciaremos pelo Assistente criando os três blocos e estabelecendo os relacionamentos-padrão. Os três blocos devem
ser criados na mesma tela para facilitar a visualização dos testes.
Você observará no Navegador que existem dois objetos de relacionamento: um controla a ligação de Departamento
com Projeto e outro controla a ligação de Projeto com Projeto Atividade. Lembre-se de que o objeto Relação é
sempre encontrado no bloco Mestre do relacionamento.
As demais características são informadas diretamente nas propriedades da relação, ou seja:
♦ A propriedade Excluir Comportamento do Registro (Delete Record Behavior) deve receber o valor Não-Isolado
(Non-Isolated) para o relacionamento de Departamento com Projeto e Em Cascata (Cascading) para o
relacionamento de Projeto com Projeto-Atividade.
♦ Já a propriedade Impedir Operações sem Mestre (Prevent Masterless Operation) deve receber o valor Não (False)
em ambas as ligações.
♦ Por fim, as propriedades Diferido (Deferred) e Consulta Automática (Automatic Query) são responsáveis pela
coordenação de leitura. Para a ligação de Departamento com Projeto, Diferido deve receber Não (consulta
imediata e automática). Para a ligação de Projeto com Projeto-Atividade, Diferido deve receber Sim e Consulta
Automática também deve receber Sim, pois a consulta será automática quando o usuário navegar para o bloco.
7.33) Crie uma nova aplicação de nome EX33. As seguintes tabelas devem ser apresentadas numa mesma canvas:
♦ Funcionário: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Departamento: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Projeto: formato Tabular, todas as colunas, três registros por tela.
As seguintes características devem ser configuradas para esta aplicação:
♦ O relacionamento entre os blocos deve ser do tipo Funcionário (pai), Departamento (filho), Projeto (filho).
Ambos pendurados em Departamento.
♦ Deve ser possível a remoção de funcionário, mesmo que haja departamentos e projetos.
♦ Deve ser possível uma pesquisa em um filho mesmo que não haja registro alocado no pai.
♦ Tão logo o registro de Funcionário seja trazido, o(s) registro(s)-filho deve(m) ser esvaziado(s), porém a pesquisa
nos filhos deve ser comandada manualmente.
A Figura-resposta 7.33A nos apresenta o esquema do relacionamento.
Quando estivermos utilizando o Assistente, a tempo do relacionamento de Projeto serão apresentadas duas
possibilidades de relação. Devemos escolher aquela associada a Func, pois a ligação desejada é entre Func e Proj e
entre Func e Depto.
Neste exercício os dois objetos Relação (Relation) estão pendurados em Func, pois este bloco é o mestre das duas ligações.
As demais características são informadas diretamente nas propriedades da relação, ou seja:
♦ A propriedade Excluir Comportamento do Registro (Delete Record Behavior) deve receber o Em Cascata (Cas-
cading) para ambos os relacionamentos. No nosso caso específico, esta ação não funcionará, pois existem dois
relacionamentos entre Func e Depto, ou seja, o departamento não pode ser removido uma vez que existam
funcionários pertencentes a ele. Outro problema é que Projeto deve ser removido antes de Departamento, pois
também é “filho” de departamento.
♦ A propriedade Impedir Operações sem Mestre (Prevent Masterless Operation) deve receber o valor Não (False)
em ambas as ligações.
♦ Por fim, as propriedades Diferido (Deferred) e Consulta Automática (Automatic Query) são responsáveis pela
coordenação de leitura. Diferido deve receber Sim e Consulta Automática Não em ambas as relações.
7.34) Crie uma nova aplicação de nome EX34. As seguintes tabelas devem ser apresentadas numa mesma canvas:
♦ Projeto: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Atividade: formato Form, todas as colunas, 1 (um) registro por tela.
♦ Projeto Atividade: formato Tabular, todas as colunas, oito registros por tela.
Quando você vier a usar o Assistente para a montagem dos relacionamentos, selecione os blocos na seguinte
ordem: bloco Projeto (Mestre), bloco Atividade (Mestre) e, por último, o bloco Projeto-Atividade.
Para a montagem dos relacionamentos, para o bloco Projeto Atividade será mostrada uma lista com dois
relacionamentos: um com projeto e outro com atividade. Selecione o de projeto e dê OK, mas não clique no botão
Próximo. Clique no botão Definir Relacionamento novamente e selecione a ligação com atividade. Só então con-
tinue o processo. Serão criados dois objetos Relação (Relation). Um entre Projeto e Projeto Atividade e outro de
Atividade com Projeto Atividade.
Com as demais propriedades você já sabe o que fazer. Teste o resultado. A leitura de Projeto-Atividade só ocorre
com os dois registros-mestre selecionados. Verifique!
7.35) Crie uma nova aplicação de nome EX35 baseada na aplicação EX32. As seguintes características devem ser
configuradas para esta aplicação:
♦ Não será permitida a remoção de Departamento se existirem projetos.
♦ Não será permitida a remoção de Projeto se existirem registros em Projeto Atividade.
♦ Não deve ser possível uma pesquisa em um filho se não houver registro alocado no pai correspondente.
♦ Tão logo o registro de Departamento seja trazido o(s) registro(s) filhos devem ser trazido(s) imediatamente.
Porém somente devem ser consultados os registros de Projeto Atividade quando o usuário estabelecer a navegação
para este bloco.
♦ Quando um projeto for trazido do banco de dados, deve ser trazido simultaneamente o nome do coordenador
do projeto.
♦ Quando uma atividade for trazida ou alterada, deve ser apresentada a sigla da nova atividade.
Neste exercício partimos de uma aplicação que possuía os relacionamentos definidos. No entanto, alteramos as
propriedades dos relacionamentos para que atendessem às especificações. Esta parte você já utilizou bastante nos
exercícios anteriores. A novidade deste exercício é que foi solicitada a apresentação do nome do responsável pelo
projeto e a sigla da atividade.
Para tal criamos dois itens não pertencentes ao banco de dados: um no bloco Projeto, chamado Nm_Coordenador,
o outro no bloco Prjatv, chamado Sg_Atividade.
Para que fosse possível o ajuste destas informações na canvas, os itens nm_proj e nm_coordenador foram diminuídos
lateralmente e aumentados verticalmente, além de terem a propriedade Várias Linhas (Multi-Line) habilitada. Veja
a tela resultante na Figura-resposta 7.35A.
O próximo passo é garantir que a tempo de leitura seja obtido o nome de cada coordenador. Por este motivo
criamos um trigger Post-Query (nível bloco) que obtenha o nome do funcionário que seja coordenador, ou seja,
semelhante ao cd_resp.
Listagem-resposta 7.35A
SELECT NM_FUNC INTO :NM_COORDENADOR
FROM FUNC
WHERE CD_MAT = :CD_RESP;
Listagem-resposta 7.35B
SELECT NM_SIGLA INTO :SG_ATIVIDADE
FROM ATIV
WHERE CD_ATIV = :CD_ATIV;
Para garantir que quando o usuário modificar a atividade sua sigla seja alterada também, repetimos esta ação num
trigger When-Validate-Item associado ao item cd_ativ.
7.36) Construa uma aplicação de nome EX36 baseada na aplicação EX30. Acrescente a seguinte funcionalidade:
♦ Corrija os pontos da aplicação 30 em que não foram usadas variáveis de ambiente:
a) Tecla Ajuda – Contexto de bloco.
b) Navegação entre os blocos.
c) Nome do bloco atual.
d) Crítica de grau de instrução só na inclusão.
e) Quando o botão Consultar for acionado, navegue para um item do bloco atual.
♦ Crie um botão na barra de ferramentas horizontal que apresente o último comando Select montado na aplicação.
♦ Crie uma função chamada Idade que receba como parâmetro uma data e retorne a idade.
♦ Crie uma função chamada Letras que receba como parâmetro um texto e retorne a quantidade de letras no texto.
Nossa primeira etapa é substituir a utilização do item Bloco por um controle mais efetivo das situações.
Como primeira situação, desejamos que a tecla Ajuda possa ser utilizada em qualquer tela e que apresente a canvas
do tipo Empilhado (Stack) mais adequada.
Listagem-resposta 7.36A
DECLARE
TEMPO TIMER;
NM_CANVAS VARCHAR2 (30);
BEGIN
NM_CANVAS := GET_ITEM_PROPERTY (:SYSTEM.CURSOR_ITEM, ITEM_CANVAS);
IF NM_CANVAS = 'CFUNC' THEN
TEMPO := CREATE_TIMER ('TIMER_FUNC', 15000, NO_REPEAT);
SHOW_VIEW ('ST_FUNC');
ELSIF NM_CANVAS = 'CDEPTO' THEN
TEMPO := CREATE_TIMER ('TIMER_DEPTO', 15000, NO_REPEAT);
SHOW_VIEW ('ST_DEPTO');
ELSIF NM_CANVAS = 'CPROJ' THEN
TEMPO := CREATE_TIMER ('TIMER_PROJ', 15000, NO_REPEAT);
SHOW_VIEW ('ST_PROJ');
END IF;
END;
Na Listagem-resposta 7.36A apresentamos uma solução para o problema (trigger Key-Help em nível de Form).
Inicialmente, obtemos o nome da canvas em que o item que detém o foco (System.Cursor_Item) está pendurado.
Esta opção foi adotada em função de termos mais de um bloco (Controle) na mesma canvas e, ainda, utilizaremos
este mesmo bloco para incluir itens em outras canvas. Deste modo não seria suficiente obtermos o nome do bloco
atual, precisávamos de uma informação que identificasse, sem dúvida, o posicionamento atual; portanto, adotamos
o nome da canvas. Em seguida, criamos um timer com nome específico para cada canvas e acionamos o texto de
ajuda correspondente.
Listagem-resposta 7.36B
DECLARE
NM_TIMER VARCHAR2 (30);
BEGIN
NM_TIMER := GET_APPLICATION_PROPERTY (TIMER_NAME);
IF NM_TIMER = 'TIMER_FUNC' THEN
HIDE_VIEW ('ST_FUNC');
ELSIF NM_TIMER = 'TIMER_DEPTO' THEN
HIDE_VIEW ('ST_DEPTO');
ELSIF NM_TIMER = 'TIMER_PROJ' THEN
HIDE_VIEW ('ST_PROJ');
END IF;
END;
Em seguida corrigimos o trigger When-Timer-Expired para que escondesse a canvas de ajuda que tenha sido acionada.
A rotina Get_Application_Property recebendo como parâmetro Timer_Name indica o nome do controle de tempo
que expirou. Desta forma pudemos esconder a canvas adequada.
A navegação entre os blocos está apresentada na Listagem-resposta 7.36C. No trigger When-Button-Pressed do
botão Navega utilizamos o mesmo estratagema de obter o nome da canvas. O restante já havia sido feito. Após este
acerto, podemos remover o item Bloco do bloco de controle.
Listagem-resposta 7.36C
DECLARE
NM_CANVAS VARCHAR2 (30);
BEGIN
NM_CANVAS := GET_ITEM_PROPERTY (:SYSTEM.CURSOR_ITEM, ITEM_CANVAS);
Para que a crítica seja realizada apenas na inclusão devemos controlar o estado do registro, como podemos verificar
na Listagem-resposta 7.36D.
Para efetuar a navegação para o bloco correto, mais uma vez adotamos obter o nome da canvas atual. Esta ação está
montada na Listagem-resposta 7.36E.
A próxima solicitação é a apresentação do último comando Select executado. Isto é resolvido através da variável de
ambiente System.Last_Query; basta que a utilizemos em um comando message.
Pede-se, agora, a criação de uma rotina que receba como parâmetro uma data e calcule a idade relativa.
Nossa última tarefa é criar uma rotina que receba como parâmetro um texto e determine a quantidade de letras
que o mesmo contém.
7.37) Construa uma aplicação de nome EX37 baseada na aplicação EX36. Acrescente a seguinte funcionalidade:
♦ Acione as rotinas Idade e Letras na leitura ou na alteração dos valores de data de nascimento, nome, sobrenome,
nome do departamento ou nome do projeto.
♦ Criar um parâmetro que indique em que horário o programa atual poderá ser executado.
a) Se o parâmetro receber A, indica período diurno (entre 8 e 18 horas).
b) Se o parâmetro receber B, indica período vespertino (entre 14 e 20 horas).
c) Se o parâmetro receber C, indica período noturno (entre 18 e 20 horas).
d) Qualquer outro valor impede a execução do programa.
Se o programa for acionado fora de seu horário, deve encerrar com mensagem adequada.
♦ Garantir que os campos alfanuméricos sejam fornecidos em letras maiúsculas (todos os blocos).
♦ Altere a forma de apresentação da foto do funcionário. Aumente-a proporcionalmente ao tamanho do desenho
do item.
Para realizarmos o primeiro passo, precisamos incluir quatro novos itens na aplicação: dois na canvas de funcionário,
um na de departamento e um na de projeto. Todos os itens são numéricos, não-pertencentes ao banco de dados e
não-ativados (só leitura). Sua localização pode ocorrer no bloco de controle ou no bloco de dados da tela. O
posicionamento do item modifica o tipo de rotina que devemos preparar.
Em primeiro lugar devemos acionar as rotinas na validação individual de cada item para garantir que, quando
houver uma modificação no valor, imediatamente seja feita a verificação. Exemplificamos com a validação de
nome do projeto na Listagem-resposta 7.37A.
A contabilização da idade e letras a tempo de leitura depende da localização do item que receberá o valor. Se o item
for incluído no bloco de dados correspondente, podemos acionar as rotinas no trigger de Post-Query. Se o item for
incluído no bloco de controle (que não tem sincronismo com o bloco de dados e, no nosso caso, é do tipo Registro
Simples – Single Record), devemos acionar as rotinas na trigger de When-New_Record_instance de tal forma que,
quando o usuário navegar para frente ou para trás no bloco de dados, o item seja calculado novamente.
Para efeito de teste criamos a idade e a quantidade de letras para nome do funcionário e nome do projeto no bloco
de controle e a quantidade de letras para departamento no bloco Depto. Teste as duas formas de trabalho.
Para garantir que todos os itens alfanuméricos sejam informados com letras maiúsculas, basta que alteremos a
propriedade Restrição a Maiúsculas/Minúsculas (Case Restriction) para Superior (Upper).
A última ação diz respeito ao item imagem. Para efeito de teste, alteramos:
♦ Mostrar Paleta (Show Palette) para Sim (Yes).
♦ Estilo de Dimensionamento (Sizing Style) para Ajustar (Adjust).
Dê uma lida nas propriedades do grupo funcional de um item do tipo imagem. A Figura-resposta 7.37A apresenta
a versão atual da aplicação.
Como última tarefa, devemos criar um parâmetro (veja o nó Parâmetros) do tipo caracter com tamanho 1 (escolha
um valor inicial para teste). No trigger de Pre-Form, fazemos a crítica relativa ao horário.
7.38) Construa uma aplicação de nome EX38 baseada na aplicação EX37. Acrescente a seguinte funcionalidade:
♦ Criar um botão na barra de ferramentas horizontal que acione a aplicação EX37 passando como parâmetro o
período de execução.
♦ Quando for lido um funcionário que seja gerente, impeça que seu salário seja alterado modificando as
características do item na canvas.
♦ Na tela de funcionário, se o usuário passar o mouse sobre o código do departamento, o nome deste deve ser
apresentado em um item flutuante (semelhante ao Dica da Ferramenta) próximo ao campo.
♦ Utilizar a rotina Letras para validação de nome e sobrenome, impedindo que a soma das duas informações
ultrapasse 20 caracteres.
Nossa primeira tarefa é simples: devemos criar um botão na barra de ferramentas para acionamento de outra aplicação.
Podemos utilizar três rotinas para efetuar a chamada da outra aplicação Call_Form (a segunda aplicação é acionada e
a primeira permanece ativa, porém, inacessível até que se feche a segunda aplicação), New_Form (a segunda aplicação
é acionada e a primeira é encerrada), Open_Form (a segunda aplicação pode ser acionada em uma sessão diferente da
primeira aplicação. Neste caso, a primeira aplicação fica ativa e acessível a qualquer momento).
Na Listagem-resposta 7.38A escolhemos chamar a segunda aplicação com Call_Form. Uma vez que esta aplicação
deve receber um ou mais parâmetros, devemos criar uma lista de parâmetros para efetuar esta passagem. A rotina
Create_Parameter_Lista criou uma lista de nome LEX37 e adicionou a esta lista o parâmetro Horário (nome do
parâmetro na aplicação chamada) com o valor ‘A’.
Quando acionamos a chamada da rotina Call_Form, indicamos o nome da lista. Entre no arquivo de Ajuda do
Form Builder e verifique o que significam os demais parâmetros informados na chamada.
Após a utilização da lista de parâmetros, devemos destruí-la para que não ocupe memória desnecessariamente.
Nosso próximo passo será apresentar o nome do departamento. Devemos cumprir diversas etapas para a realização desta
ação. Inicialmente, devemos ler e armazenar o nome do departamento a cada funcionário que for lido do banco de dados.
Com este objetivo montamos uma lógica que leia o nome do departamento dentro de uma área (Pacote.Texto) que
possa ser consultada da próxima vez que executarmos este trigger, ou seja, em um item ou em uma variável de
pacote (escolhemos criar um pacote de nome Pacote e dentro dele duas variáveis de controle depto_ant e texto). Se
o código do departamento for igual ao anterior, não precisamos realizar a leitura novamente, pois a informação já
está armazenada na variável de pacote Texto.
GER_ANT NUMBER := 0;
TEXTO VARCHAR2 (300);
END;
Para armazenamento, criamos um item no bloco de departamento chamado nm_depto (não é item do bloco de
dados). Com esta rotina preenchemos o nome do departamento para cada linha de funcionário. Desta forma é
possível a navegação para a frente e para trás, pois o nome está preservado.
Para apresentação da informação criamos um item no bloco Controle chamado nome_depto, que é um item
apenas de visualização. Preenchemos sua propriedade Visível (Visible) com Não (No) para que ele ficasse
temporariamente invisível. No entanto, estabelecemos seu posicionamento e tamanho na canvas de Cfunc. Outra
propriedade importante a ser preenchida chama-se Finalizado (Rendered), seu valor deve ser preenchido com Não
(No) para que quando este objeto se torne visível ele não seja recoberto pelos objetos próximos.
Para tornar o item visível, alteramos sua propriedade a tempo de execução. Sendo assim, usamos os triggers When-
Mouse_Enter para tornar o item visível, e When-Mouse-Leave para torná-lo invisível novamente.
Se você executar sua aplicação neste ponto é possível que venha a receber alguns erros de crítica relativo a cargo e
salário. Isto pode acontecer porque criamos um novo item no bloco de funcionário (nm_depto), que mesmo não
sendo um item do banco de dados, teve seu valor alterado, fazendo com que o registro precisasse de validação e,
conseqüentemente, acionando o trigger When-Validate-Record. Observe que o estado do registro não foi alterado,
ele continua com o estado de Query, porém necessitando de validação.
Para contornar esta situação, incluímos no trigger When-Validate-Record um teste, como mostrado na Listagem-
resposta 7.38E, com a finalidade de pular as críticas quando o registro está na situação de Query.
Nosso próximo passo será impedir a atualização do salário do gerente. Este controle pode ser feito de duas formas
diferentes: podemos trocar a propriedade Updateable da instância, para indicarmos que naquele registro o item
vl_sal não pode ser alterado, como mostrado na Listagem-resposta 7.38F.
Listagem-resposta 7.38F
IF :FUNC.GERENTE IS NOT NULL THEN
IF :FUNC.CD_MAT = :FUNC.GERENTE THEN
SET_ITEM_INSTANCE_PROPERTY ('FUNC.VL_SAL', UPDATEABLE,
CURRENT_RECORD, PROPERTY_FALSE);
END IF;
END IF;
A segunda forma de controle é, a cada linha lida, armazenar o código do gerente, e quando houver navegação para
um novo registro compararmos esta informação com a matrícula e alterarmos a propriedade Enabled do item.
Como já temos pronta a rotina de leitura do nome do departamento, acrescentamos um novo item no bloco de
funcionário chamado Gerente e, ao efetuarmos a leitura do nome do departamento, obtemos também o código do
gerente. Veja a Listagem-resposta 7.38B. Mostramos na Listagem-resposta 7.38G a seguir a alteração da propriedade
Enabled feita no trigger When-New-Record-Instance.
ELSE
SET_ITEM_PROPERTY ('FUNC.VL_SAL', ENABLED, PROPERTY_TRUE);
END IF;
A última tarefa requer apenas a utilização da rotina letras, que foi acrescida no fim do trigger When-Validate-Record.
7.39) Construa uma aplicação de nome EX39 baseada na aplicação EX38. Acrescente a seguinte funcionalidade:
♦ Crie uma procedure na base de dados de nome Qtsexo que receba como parâmetro um determinado departamento
e retorne a quantidade de funcionários de cada sexo do departamento informado.
♦ Acione a rotina Qtsexo quando um departamento for escolhido (na canvas de Funcionário) e quando cada
departamento for lido na canvas de Departamento.
♦ A cada 30 minutos a aplicação deve verificar se a hora atual ainda está dentro dos limites de tempo autorizados
para esta aplicação.
Neste exercício nosso primeiro teste é a criação da rotina na base de dados. Veja a Listagem-resposta 7.39A.
Listagem-resposta 7.39A
PROCEDURE QTSEXO (PDEPTO IN VARCHAR2,
QTFEM OUT NUMBER, QTMASC OUT NUMBER) IS
BEGIN
SELECT FEM, MAS INTO QTFEM, QTMASC
FROM (SELECT COUNT (*) FEM FROM FUNC
WHERE IN_SEXO = 'F' AND CD_DEPTO = PDEPTO) F,
(SELECT COUNT (*) MAS FROM FUNC
WHERE IN_SEXO = 'M' AND CD_DEPTO = PDEPTO) M;
END;
Para fazer esta criação, basta que você selecione o nó Unidades de Programas Armazenadas (Stored Program Units)
subordinado ao usuário Desenv no nó Objetos do Banco de Dados (Database Objects).
Para utilização da rotina, criamos dois itens no bloco de controle SexoF e SexoM para receberem os valores calculados.
Incluímos, então, um trigger When-Validate-Item para o item Depto do bloco de controle.
Observe que, para acionarmos a rotina QtSexo, criamos duas variáveis locais ao bloco de PL/SQL e quando obtivemos
o valor atribuímos ao item. Um item não deve ser passado como parâmetro para uma rotina armazenada no banco
de dados (ocorre erro na execução).
A próxima etapa requer que verifiquemos a hora atual a cada 30 minutos. Uma vez que repetiremos a mesma
crítica já desenvolvida no Pre-Form, preferimos criar uma função.
A função deve ser acionada no Pre-Form a cada 30 minutos. Desta forma, criamos uma variável de tempo permanente
no pacote.
Na rotina de Pre-Form inicializamos esta variável com a indicação de que esta verificação se faça a cada 30 minutos
ou 1.800.000 milissegundos.
Finalmente, no trigger When-Timer-Expired devemos verificar se este Timer específico foi acionado e fazer as
validações necessárias.
7.40) Construa uma aplicação de nome EX40 baseada na aplicação EX39. Acrescente a seguinte funcionalidade:
♦ Crie três indicadores (caixa de seleção) que permitam ao usuário estabelecer a ordenação da consulta por:
departamento, nome do funcionário e/ou salário (podem ser aceitos todos os três, dois ou um item marcado). A
ordem será depto (primária), nome (secundária) e salário (terciária).
♦ Crie um botão nesta aplicação para acionar o relatório de nome REP17 (será testado no próximo capítulo) que
receba como parâmetro um código de departamento.
♦ Crie uma trigger na base de dados de nome Csal que impeça que o salário dos funcionários seja diminuído.
Como primeiro passo, criamos os três itens do tipo Caixa de Seleção (Check Box) para indicação da ordenação.
A seguir incluímos no trigger de Pre-Query a modificação da propriedade Order By do bloco a tempo de execução.
Observe que nos utilizamos daquela variável Texto existente no package Pacote (não precisamos declarar uma
nova variável, pois ela tem existência por toda a aplicação). Atribuímos como valor inicial para esta variável o
texto “Order By” (nove posições). Não se esqueça de esvaziar a variável ao término do uso.
A solicitação seguinte tem o objetivo de acionar um outro relatório de nome Rep17.
O processo é o mesmo de quando acionamos uma outra aplicação com parâmetro. A diferença está na rotina
necessária para executarmos o relatório, chamada Run_Product. Essa rotina executa tanto um relatório quanto um
módulo do Oracle Graphics.
Como último passo, devemos criar o trigger na base de dados; portanto, retorne ao nó Objetos do Banco de Dados
(Database Objects), expanda o nó do usuário Desenv, expanda o nó das tabelas (Tables) e expanda o nó da tabela
Func. Crie um objeto no nó Triggers (Figura-resposta 7.40A).
7.41) Construa uma aplicação de nome EX41 baseada na aplicação EX40. Acrescente a seguinte funcionalidade:
♦ Crie uma rotina que recebe um texto e mostre este texto em uma janela de Alerta que possua um único botão.
♦ Todas as mensagens enviadas pelo programa (as messages) devem ser substituídas por mensagens apresentadas
pelo Alerta.
♦ Todas as mensagens de erro ou aviso fornecidas pelo Forms Runtime devem ser apresentadas na janela do Alerta.
Criamos, inicialmente, um objeto Alerta de nome Aviso contendo um único botão. Em seguida, criamos uma
unidade de programa chamada Mens.
Para substituir as chamadas à Message por chamadas à Mens, utilize a opção Localizar/Substituir PL/SQL do menu Programa.
A Listagem-resposta 7.41B mostra a inclusão do trigger On-Message para garantir que as mensagens do sistema
também sejam fornecidas pelo alerta. O trigger On-Error já se encontrava presente na aplicação e a chamada à
rotina Message foi substituída por Mens.
7.42) Construa uma aplicação de nome EX42 baseada na aplicação EX41. Acrescente a seguinte funcionalidade:
♦ Crie um editor com letra Courier New, tamanho 8, azul, quebra de linha em fronteira de palavra e que contenha
uma barra de rolagem vertical.
♦ Crie um botão na barra de ferramentas horizontal que acione o editor apenas para os itens: nm_depto, nm_foto
e nm_proj.
♦ Para os demais itens é vedada a utilização de editor.
♦ Para o item nm_proj deve ser acionado o bloco de notas (do Windows) no lugar do editor interno.
♦ O editor deve ser posicionado exatamente sobre o item em edição, exceto no caso de nm_foto, quando o editor
deve ser posicionado sobre o item vl_sal.
Como primeiro passo, temos a criação do Editor com as características especificadas. Essas características podem
ser atribuídas às propriedades do objeto criado.
Listagem-resposta 7.42A
IF :SYSTEM.CURSOR_ITEM IN ('FUNC.NM_FOTO', 'DEPTO.NM_DEPTO',
'PROJ.NM_PROJ') THEN
EDIT_TEXTITEM;
END IF;
Para que o editor possa ser acionado pela rotina Edit_textitem, devemos indicá-lo nas propriedades do item, uma
vez que esta rotina não recebe como parâmetro o nome do editor.
Neste conjunto de propriedades (nó Editor) podemos informar o nome do editor ou Sytem_Editor para que seja
acionado o editor do sistema (no nosso caso o bloco de notas) e as coordenadas de apresentação do editor. Para
calcular estas coordenadas, obtenha as coordenadas do objeto sobre o qual o editor será apresentado e acrescente
a largura da barra de ferramentas vertical (coordenada X) ou a largura da barra de ferramentas horizontal + largura
do menu (coordenada Y).
7.43) Construa uma aplicação de nome EX43 baseada na aplicação EX42. Acrescente a seguinte funcionalidade:
♦ Especificar os seguintes atributos visuais:
a) av_prompt – letra vermelha, Arial, tamanho 8.
b) av_editor – letra azul, Courier New, tamanho 8.
c) av_item_atu – letra preta, Arial, tamanho 8, cor de fundo branca.
d) av_item_cons – letra cinza, tipo Courier New, tamanho 8, cor de fundo branca.
e) av_item_atu_corr – cor de fundo cinza.
f) av_item_mod – cor de fundo vermelha.
g) av_item_inc – cor de fundo azul.
h) av_item_check – letra vermelha, Arial, tamanho 8.
i) av_item_radio – letra vermelha, Arial, tamanho 8.
♦ Aplique os atributos visuais da seguinte forma:
a) Para os prompts de todos os itens – av_prompt
b) Para o editor – av_editor
c) Para os itens atualizáveis – av_item_atu
d) Para os itens somente consultados – av_item_cons
e) Para os itens com ocorrência, aplicável ao registro corrente – av_item_atu_corr
f) Para os itens-chave cujo registro tenha sido modificado (só na instância modificada) – av_item_mod
g) Para os itens-chave cujo registro tenha sido incluído (só na instância modificada) – av_item_inc
h) Para os radio groups – av_item_radio
i) Para os check box – av_item_check
A criação dos objetos atributos visuais é feita no nó Atributos Visuais (Visual Attributes).
Após a criação, fazemos a atribuição estática dos valores para cada item. Teste antes de prosseguir. O que não ficar
de acordo com as expectativas deve ser corrigido individualmente.
Para que somente a instância do registro corrente seja alterada, devemos modificar por programação seus atributos,
como apresentado no trecho de código (parte do trigger) da Listagem-resposta 7.43A.
7.44) Construa uma aplicação de nome EX44 baseada na aplicação EX43. Acrescente a seguinte funcionalidade:
♦ Criar um botão Ajuda na barra de ferramentas horizontal. Ao primeiro toque, deve ser mostrado na área de mensagem
um texto de ajuda sobre o item que detém o foco. No segundo toque, deve ser mostrada na área de mensagem a
canvas de ajuda referente ao bloco corrente. Como esta ação é um pouco trabalhosa, teste apenas para três itens.
♦ Retire o uso da tecla Ajuda; utilize apenas o botão.
Nesta aplicação, inicialmente incluiremos três itens do tipo Item de Texto (não ativado) e os posicionaremos
exatamente sobre a área de mensagem em cada uma das canvas. Esses itens devem ter cor de fundo cinza ou não
ter cor de fundo. As propriedades indicativas de múltiplas linhas e tamanho devem ser habilitadas e alteradas para
300 respectivamente.
Em seguida devemos incluir o botão na barra de ferramentas horizontal com o seguinte trigger: When-Button-
Pressed (Listagem-resposta 7.44A).
Observe que criamos um item no pacote chamado Vez (inicializado com zero). Se o valor deste item for zero, é
montada dinamicamente uma mensagem de acordo com o item. Se o valor do item for um, executamos as ações
previstas para a tecla de Ajuda.
Criamos, ainda, em nível de bloco (em todos os três blocos de dados) um trigger When-New-Item-Instance para
que, quando o usuário navegar para um outro item, a variável vez retorne a zero e os textos sejam inicializados.
Listagem-resposta 7.44B
PACOTE.VEZ := 0;
:CONTROLE.TXT_FUNC := NULL;
:CONTROLE.TXT_DEPTO := NULL;
:CONTROLE.TXT_PROJ := NULL;
7.45) Construa uma aplicação de nome EX45 baseada na aplicação EX44. Acrescente a seguinte funcionalidade:
♦ Crie um record group estático com as seguintes colunas: nm_item (30 caracteres), tx_ajuda (300 caracteres).
♦ Preencha o record group anterior com o nome de dez itens da sua aplicação juntamente com dez mensagens de ajuda.
♦ Faça uma função que receba como parâmetro o nome do item e o pesquise no record group anterior, retornando
a mensagem correspondente ou ‘Não encontrada mensagem de ajuda’.
♦ Substitua o teste presente no botão de ajuda pelo uso da rotina.
Nosso primeiro passo neste exercício é criar o Record Group do tipo estático.
7.46) Construa uma aplicação de nome EX46 baseada na aplicação EX45. Acrescente a seguinte funcionalidade:
♦ Crie uma rotina para preencher um record group dinâmico que contenha o menor e o maior valor salarial de
cada cargo.
♦ Utilize esse record group para estabelecer a crítica de cargo x salário.
♦ Utilize esse record group para apresentar na área de mensagem a faixa salarial válida quando o usuário passar o
mouse sobre o código do cargo.
Nosso primeiro passo nesta aplicação é a criação do Record Group dinâmico. Incluímos a criação deste objeto no
trigger Pre-Form; no entanto criamos no package Pacote um conjunto de variáveis a fim de armazenar os
identificadores referentes ao grupo criado. Nesta primeira listagem-resposta (7.46A), são mostradas as variáveis
criadas para dar suporte à criação do grupo.
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_SUP,1,1500);
SET_GROUP_CHAR_CELL (PACOTE.RGC_MENS,1,'Valor fora do intervalo 500 - 1500');
— Linha 2 —
ADD_GROUP_ROW (PACOTE.RG_CARGO, 2);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_INF, 2, 47);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_SUP, 2, 52);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_INF, 2, 1501);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_SUP,2,2000);
SET_GROUP_CHAR_CELL (PACOTE.RGC_MENS,2,'Valor fora do intervalo 1501 - 2000');
— Linha 3 —
ADD_GROUP_ROW (PACOTE.RG_CARGO, 3);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_INF, 3, 53);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_SUP, 3, 55);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_INF, 3, 2001);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_SUP,3,2500);
SET_GROUP_CHAR_CELL (PACOTE.RGC_MENS,3,'Valor fora do intervalo 2001 - 2500');
— Linha 4 —
ADD_GROUP_ROW (PACOTE.RG_CARGO, 4);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_INF, 4, 56);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_SUP, 4, 58);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_INF, 4, 2501);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_SUP,4,3000);
SET_GROUP_CHAR_CELL (PACOTE.RGC_MENS,4,'Valor fora do intervalo 2501 - 3000');
— Linha 5 —
ADD_GROUP_ROW (PACOTE.RG_CARGO, 5);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_INF, 5, 59);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_SUP, 5, 60);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_INF, 5, 3001);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_SUP,5,3500);
SET_GROUP_CHAR_CELL (PACOTE.RGC_MENS,5,'Valor fora do intervalo 3001 - 3500');
— Linha 6 —
ADD_GROUP_ROW (PACOTE.RG_CARGO, 6);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_INF, 6, 61);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_SUP, 6, 62);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_INF, 6, 3501);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_SUP,6,4000);
SET_GROUP_CHAR_CELL (PACOTE.RGC_MENS,6,'Valor fora do intervalo 3501 - 4000');
— Linha 7 —
ADD_GROUP_ROW (PACOTE.RG_CARGO, 7);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_INF, 7, 63);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_SUP, 7, 99);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_INF, 7, 4001);
SET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_SUP,7,10000);
SET_GROUP_CHAR_CELL (PACOTE.RGC_MENS,7,'Valor fora do intervalo 4001 - 10000');
Esta criação e este preenchimento são apresentados na Listagem-resposta 7.46B. Inicialmente, criamos o grupo,
em seguida, cada uma das colunas e posteriormente preenchemos cada uma das linhas com o intervalo de cargos,
o intervalo de salários e a mensagem de erro a ser apresentada.
Para que uma mensagem seja apresentada próxima ao item nr_cargo, devemos criar um item do tipo Item de
Exibição (Display Item) com tamanho de 120 bytes, presente na canvas Cfunc, alinhado próximo ao item, sem
bevel, com a propriedade Finalizado (Rendered) desabilitada (Não), amarelo claro, com letras cinza, invisível.
A atribuição a este item deve ser feita no trigger When-Mouse-Enter do item nr_cargo. Devemos também torná-lo
visível neste momento. Quando o mouse sair de cima do item devemos limpar o item e torná-lo invisível de novo.
Listagem-resposta 7.46C
DECLARE
ISAL NUMBER;
SSAL NUMBER;
BEGIN
:CONTROLE.MSG_CARGO := '';
FOR I IN 1..7 LOOP
IF GET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_INF, I) <= :FUNC.NR_CARGO AND
GET_GROUP_NUMBER_CELL (PACOTE.RGC_CD_CARGO_SUP, I) >= :FUNC.NR_CARGO THEN
ISAL := GET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_INF, I);
SSAL := GET_GROUP_NUMBER_CELL (PACOTE.RGC_VL_SUP, I);
:CONTROLE.MSG_CARGO := 'Intervalo salarial válido entre '||
isal||' e '||ssal;
EXIT;
END IF;
END LOOP;
SET_ITEM_PROPERTY ('CONTROLE.MSG_CARGO', VISIBLE, PROPERTY_TRUE);
END;
Observe que é feito um controle para que a lista somente seja preenchida a cada 10 minutos, a fim de diminuir o
tráfego na rede.
Quando a Lista é apresentada ao usuário e este faz uma escolha, devemos atribuir ao item da canvas correspondente
o valor presente no item controle.cd_depto.
Neste caso utilizamos a rotina Copy. Essa rotina recebe como primeiro parâmetro o valor a ser atribuído e o item
para o qual o valor deve ser informado. O nome do item está contido na variável de sistema Cursor_Item, sendo
por este motivo utilizado.
7.48) Construa uma aplicação de nome EX48 baseada na aplicação EX47. Acrescente a seguinte funcionalidade:
♦ Crie um record group estático contendo uma coluna de data.
♦ Este record group deverá ser preenchido dinamicamente da seguinte forma:
a) O dia será sempre 10.
b) A partir da data atual, obter um mês para trás e seis meses para frente.
c) Incluir a data atual.
Listagem-resposta 7.48A
DECLARE
RETORNO NUMBER;
BEGIN
RETORNO := POPULATE_GROUP_WITH_QUERY ('RG_DATA',
'SELECT ADD_MONTHS (TRUNC (SYSDATE, ''MM'') + 9, '||
'ROWNUM - 2) FROM DEPTO WHERE ROWNUM < 9');
END;
Na Listagem-resposta 7.48A encontramos uma forma de preencher as oito linhas de data com todas as
especificações pedidas.
Listagem-resposta 7.48B
DECLARE
LISTA BOOLEAN;
RETORNO NUMBER;
BEGIN
IF :SYSTEM.CURSOR_ITEM = 'FUNC.DT_ADM' THEN
LISTA := SHOW_LOV;
GOTO FIM;
ELSIF PACOTE.LOV_TIMER IS NULL THEN
RETORNO := POPULATE_GROUP ('RG_DEPTO');
IF RETORNO = 0 THEN
PACOTE.LOV_TIMER := SYSDATE;
END IF;
ELSIF (SYSDATE - PACOTE.LOV_TIMER) > 10/1440 THEN
RETORNO := POPULATE_GROUP ('RG_DEPTO');
IF RETORNO = 0 THEN
PACOTE.LOV_TIMER := SYSDATE;
END IF;
END IF;
LISTA := SHOW_LOV;
IF LISTA THEN
COPY (:CONTROLE.CD_DEPTO, :SYSTEM.CURSOR_ITEM);
END IF;
<<FIM>>
NULL;
END;
Quando efetuamos uma consulta neste bloco, automaticamente a tela de depuração é reapresentada para a execução
do passo-a-passo.
Listagem-resposta 7.50A
IF :SYSTEM.CURSOR_ITEM = 'FUNC.CD_MAT' THEN
DEBUG.SUSPEND;
END IF;
A Listagem-resposta 7.50A mostra esta forma de interrupção. Poderíamos também usar a variável de exception
Break, porém, neste caso, deveríamos causar a exceção: Raise Debug.Break (o efeito é o mesmo).
7.52) Crie uma aplicação que estabeleça o cadastramento de Departamentos, os quais devem ser apresentados
como uma árvore hierárquica. Deve ser possível a inclusão e alteração de departamentos utilizando esta estrutura.
♦ Para o botão Incluir – quando o usuário apertar o botão Incluir já deve ter, previamente, selecionado um nó-pai.
Este botão incluirá um elemento filho neste nó selecionado com label *** (3 asteriscos) e valor nulo. Simultaneamente
deve ser incluída uma linha no vetor de controle indicando que deve ser feita uma inclusão no banco de dados.
♦ Para o botão Alterar – quando o usuário pressionar o botão Alterar já deverá, previamente, ter selecionado um
nó. Os dados preenchidos na tela serão incorporados a este nó para posterior atualização do banco de dados.
A aplicação desenvolvida não estabeleceu critérios rígidos de crítica. Certamente, você poderá sofisticar
tremendamente o exemplo que veremos a seguir. Nosso intuito é apenas o de testar o pacote Ftree juntamente
com o item do tipo Árvore Hierárquica.
Inicialmente criamos uma aplicação vazia contendo um bloco de nome Htree contendo um único item de nome
Adepto e tipo Árvore Hierárquica. Esta árvore será preenchida inicialmente através do comando select apresentado
na Listagem-resposta 7.52A, apresentada a seguir.
Listagem-resposta 7.52A
SELECT DECODE(LEVEL, 1, 1, 2, 1, 3, 0), LEVEL,
UPPER(CD_DEPTO), '', UPPER(NM_DEPTO)
FROM DEPTO
CONNECT BY PRIOR CD_DEPTO=CD_DEPTO_CTB
START WITH CD_DEPTO = 'A00'
Em seguida limitamos as teclas disponibilizadas para o usuário, e desta forma criamos as triggers Key-Next-Item
(com a chamada à rotina Next_Item), Key-Exit (com a chamada à rotina Exit_Form) e Key-Others (com o texto
Null; impedindo o uso de qualquer outra tecla).
Para que os dados do item selecionado fossem incorporados à tela, usamos uma trigger When-Tree-Node-Selected
subordinada ao item Adepto, com o texto apresentado na Listagem-resposta 7.52C.
Em nossa canvas acrescentamos três botões: Incluir, Alterar e Salvar. Para o botão Incluir adicionamos o seguinte código:
A rotina Add_Tree_Node recebe como parâmetro o nome do item, um nó (informamos o nó-pai), a indicação do
tipo de nó (Parent_Offset indica que o nó informado deve ser o pai do nó a ser criado. Poderíamos informar
também Sibling_Offset, indicando que o nó informado seria irmão, ou seja, com o mesmo nível do nó a ser
criado), posicionamento do nó no grupo (escolhemos Last_Child), o estado do nó após a inclusão (decidimos que
o nó deveria ser mostrado contraído) e os valores de Label, ícone e Valor para o nó a ser criado.
Após a inclusão do nó na árvore, adicionamos uma linha no vetor declarado no Package Pacote contendo a ação
a ser realizada no banco de dados e o endereço do nó.
A seguir veremos o conteúdo do botão Alterar.
Iniciamos esta lógica verificando se este nó já se acha presente no vetor. Caso isto seja verdade não temos necessidade
de incluir uma segunda indicação. Se este nó não houver sido modificado ainda, devemos incluir a solicitação de
modificação no vetor (para controle). Em seguida, alteramos as propriedades do nó para que refletissem os valores
preenchidos pelo usuário. Observe que o nó selecionado, representado pela variável Pacote.Nó é utilizado como
referência de atualização (não há crítica).
As variáveis utilizadas no programa foram incluídas em uma especificação de pacote chamada Pacote, de tal forma que
ficassem visíveis em toda a aplicação e pudessem ser utilizadas sem restrições. Listamos, a seguir, o conteúdo deste package:
Para que o array Vetor fosse sempre inicializado, na trigger Pre-form removemos todo o seu conteúdo.
Finalmente, quando o usuário pressiona o botão Salvar, simulamos um processo transacional do Oracle. Percorremos
o Vetor e para cada linha encontrada enviamos o comando Insert ou Update para o banco de dados. Para forçar a
atualização executamos um Commit_Form. Nossa última etapa é limpar novamente o vetor para que não façamos
as atualizações duas vezes.
Listagem-resposta 7.52H
DECLARE
WCD_DEPTO DEPTO.CD_DEPTO%TYPE;
WNM_DEPTO DEPTO.NM_DEPTO%TYPE;
WCD_DEPTO_CTB DEPTO.CD_DEPTO_CTB%TYPE;
NO_PAI FTREE.NODE;
BEGIN
FOR I IN 1..PACOTE.INX LOOP
WCD_DEPTO := FTREE.GET_TREE_NODE_PROPERTY ('ADEPTO', PACOTE.VETOR(I).NÓ,
FTREE.NODE_LABEL);
WNM_DEPTO := FTREE.GET_TREE_NODE_PROPERTY ('ADEPTO', PACOTE.VETOR(I).NÓ,
FTREE.NODE_VALUE);
NO_PAI := FTREE.GET_TREE_NODE_PARENT('ADEPTO', PACOTE.VETOR(I).NÓ);
WCD_DEPTO_CTB := FTREE.GET_TREE_NODE_PROPERTY ('ADEPTO', NO_PAI,
FTREE.NODE_LABEL);
IF PACOTE.VETOR(I).IND_STATUS = 'I' THEN
INSERT INTO DEPTO (CD_DEPTO, NM_DEPTO, CD_DEPTO_CTB)
VALUES (WCD_DEPTO, WNM_DEPTO, WCD_DEPTO_CTB);
ELSIF PACOTE.VETOR(I).IND_STATUS = 'A' THEN
UPDATE DEPTO
SET NM_DEPTO = WNM_DEPTO,
CD_DEPTO_CTB = WCD_DEPTO_CTB
WHERE CD_DEPTO = WCD_DEPTO;
END IF;
END LOOP;
END;
COMMIT_FORM;
PACOTE.INX := 0;
PACOTE.VETOR.DELETE;
PACOTE.NÓ := NULL;
Observe que até mesmo o código do departamento contábil pode ser preenchido no banco de dados, pois podemos obter
o nó-pai relativamente ao nó incluído ou alterado e determinar o código do departamento na propriedade Node_Label.
Muitas críticas poderiam ser acrescidas a este programa garantindo, por exemplo, que o código do departamento
não pudesse ser preenchido em uma alteração, ou que um registro com código de departamento 3 asteriscos não
fosse incluído no banco de dados. A sofisticação é sua. Divirta-se !
7.53) Construa uma aplicação de nome EX53 baseada na aplicação EX48. Acrescente a seguinte funcionalidade:
Listagem-resposta 7.53A
PACKAGE PLOCAL IS
ARQ TEXT_IO.FILE_TYPE;
ACAO VARCHAR2 (1);
PROCEDURE ABRE;
PROCEDURE GRAVA;
PROCEDURE FECHA;
END;
Listagem-resposta 7.53B
PACKAGE BODY PLOCAL IS
PROCEDURE ABRE IS
BEGIN
ARQ := TEXT_IO.FOPEN ('C:\TESTE\LOG'||
TO_CHAR (SYSDATE, 'DDMMYYYY')||'.TXT','A');
END ABRE;
PROCEDURE GRAVA IS
BEGIN
TEXT_IO.PUT_LINE (ARQ, ACAO||' '||RPAD (USER,10)||' '||
LPAD (:CD_MAT,3)||' '||RPAD (:NM_FUNC||' '||:NM_SOBRENOME, 24)||
' '||LPAD (:VL_SAL,11)||' '||
TO_CHAR (:DT_NASC, 'DD/MM/YYYY')||' '||:FUNC.CD_DEPTO);
END;
PROCEDURE FECHA IS
BEGIN
TEXT_IO.FCLOSE (ARQ);
END;
END;
Após cada ação de atualização gravamos as linhas, portanto, nos triggers Post-Update, Post-Insert e Post-Delete. A
Listagem-resposta 7.53D apresenta o Post-Update.
A última etapa é o fechamento do arquivo, que somente ocorrerá quando todas as linhas forem gravadas, portanto
no trigger Post-Forms-Commit ou Post-Database_Commit. Escolhemos utilizar o Post-Forms-Commit, apresentado
na Listagem-resposta 7.53E.
Listagem-resposta 7.53E
PLOCAL.FECHA;
7.54) Construa uma aplicação de nome EX54 baseada na aplicação EX53. Acrescente a seguinte funcionalidade:
♦ Criar um avaliador de tempo que inicie a marcação quando houver o início do processo transacional e contabilize
o tempo de execução deste processo.
♦ Apresente o tempo decorrido em um alerta.
♦ Altere o símbolo do ícone (para ampulheta) enquanto este processo estiver em andamento.
Neste exercício trabalharemos com o pacote Ora_Prof, responsável pela contabilização de tempo decorrido e útil
quando desejamos controlar a performance de uma determinada ação.
Criaremos, então, o controlador de tempo no início da aplicação (Pre-Form) com o comando
Ora_Prof.Create_Timer (‘transacao’).
Quando iniciamos o processo transacional, damos início à contabilização e, simultaneamente, alteramos o formato
do ícone do cursor.
7.55) Construa uma aplicação de nome EX55 baseada na aplicação EX54. Acrescente a seguinte funcionalidade:
♦ Altere as máscaras de edição dos campos de data de acordo com o ambiente em que atue o programa:
a) Americano – data= fxdd-mon-yyyy
b) Brasileiro – data = fxdd/mm/rrrr
Nesta aplicação usaremos o pacote Ora_Nls. Podemos obter qualquer informação que desejemos do ambiente
relativamente ao National Language Support. Nessa aplicação obteremos o nome da linguagem e de acordo com
esta informação alteraremos a formatação da máscara de edição dos campos dt_adm e dt_nasc.
7.56) Construa uma aplicação de nome EX56 baseada na aplicação EX55. Acrescente a seguinte funcionalidade:
♦ Verifique se a variável de ambiente COM_SESSAO está com o valor True ou False.
♦ Caso esteja com TRUE, o comando OPEN_FORM do botão aplicação deve ser do tipo SESSION.
♦ Caso esteja com FALSE, o comando OPEN_FORM do botão aplicação deve ser do tipo NO_SESSION.
Neste exercício utilizaremos o pacote Tool_Env que nos permitirá obter informação a respeito de qualquer variável
do ambiente subordinada ao grupo Oracle. Por esse motivo, em vez de lidarmos com uma das variáveis de ambiente
já conhecidas do Oracle, criaremos nossa própria variável (subordinada ao mesmo nó). Desta forma execute o
Regedit, expanda o nó Hkey_Local_Machine e em seguida os nós Software e Oracle. Pressione o mouse sobre o nó
Homex (referente à sua instalação) para que na área à direita sejam mostradas as variáveis de ambiente do Oracle.
Use, agora, o menu Editar, submenu Novo, opção Valor da Seqüência e crie a variável COM_SESSAO e preencha-a
com o valor TRUE. Retornaremos ao Forms para utilizar esta variável. Observe a Listagem-resposta 7.56A.
7.57) Construa uma aplicação de nome EX57 contendo o bloco de funcionário, com as colunas cd_mat, nm_func,
nm_sobrenome, nr_cargo, vl_sal e in_sexo.
♦ Monte uma carta no Word relativa ao aumento de salário dos funcionários, com o seguinte layout:
Figura-resposta 7.57A
♦ Salve esta carta com o nome do funcionário precedido do código do departamento e seguido da data e hora
atuais no diretório cartas.
Neste exercício faremos, através de um conjunto de rotinas do Form Builder, acesso ao Word. Nosso objetivo é
abrir o Word, criar um documento, preencher o documento, salvar o documento e fechá-lo.
Para realizar estas tarefas deveríamos conhecer objetos, coleções, propriedades e métodos do Word para que pudéssemos
estabelecer a comunicação corretamente. Porém, muito provavelmente, estas operações que desenvolveremos aqui
não são operações do dia-a-dia de um analista Oracle Forms, e portanto são ações que fazemos com pouca freqüência.
Neste caso, encurtaremos o caminho e escolheremos métodos mais práticos de ação.
Nossa primeira tarefa será criar uma macro no Word que realize exatamente as mesmas operações que nós desejamos
comandar; desta forma saberemos quais os passos e em que ordem deveremos realizá-las.
Como segunda tarefa estudaremos como pesquisar no arquivo Vbawrd8.hlp para entender o objeto a ser usado,
que parâmetro usar quando tivermos de acionar um método, etc.
Finalmente, conheceremos as rotinas do Form Builder capazes de estabelecer a comunicação.
Iniciaremos, então, abrindo o Word. No menu Ferramentas, devemos selecionar o submenu Macro e a opção
Gravar Nova Macro. O diálogo da Figura-resposta 7.57B permite que determinemos um nome para a macro além
de estabelecer o local de armazenamento.
Em seguida, realizaremos exatamente os passos que desejamos reproduzir, ou seja, abrir um novo documento,
digitar os textos especificados, salvar o documento em um determinado diretório e fechar o documento.
Quando estas tarefas estiverem concluídas, devemos interromper a gravação da macro. Isto pode ser feito através
da pequena janela que aparece na tela durante a gravação ou podemos retornar ao menu Ferramentas, submenu
Macro, opção Parar Gravação a fim de encerrar o procedimento de gravação.
Para obtermos os comandos a serem executados devemos, agora, retornar ao menu Ferramentas, submenu Macro,
opção Editor do Visual Basic.
Quando a janela for aberta, selecione o menu Exibir, opção Explorer de Projeto, para que a janela tome o aspecto
apresentado na Figura-resposta 7.57C.
Nesta janela existem nós. Um deles tem o nome de Normal (quando você determinou o local onde seria gravada a
macro, se você tiver escolhido Normal.dot, expanda o nó Normal. Se você determinou que a macro fosse gravada sob
o nome do documento atual, expanda o nó correspondente ao documento atual, e assim por diante); expanda-o.
Sob este nó você encontrará um outro nó de nome Módulos e subordinado a ele um objeto de nome NewMacros
(é este objeto que estamos procurando). Dê um clique duplo neste objeto para que seja mostrada a macro que você
acabou de gerar em uma janela próxima. Veja a Figura-resposta 7.57D.
Nosso objetivo será reproduzir, na aplicação Form, exatamente os passos definidos nesta macro. Você pode mandar
imprimi-la, copiar o texto para outro arquivo, etc. O importante é guardar os passos a serem executados. Com isto
encerramos a primeira etapa de nosso estudo.
Nossa segunda etapa é um estudo do arquivo Vbawrd8.hlp (este arquivo é fornecido pela Microsoft juntamente
com o Office). Nesse arquivo encontramos a estrutura de objetos do Word.
Abra-o, clique sobre o botão Tópicos da Ajuda e, na pasta Índice, digite Application. Existem dois itens subordinados
a Application: Objeto e Propriedade. Escolha o nó Objeto.
O objeto Application corresponde ao próprio Word, ou seja, é a aplicação Word. É a raiz de todos os objetos.
Observe na Figura-resposta 7.57E que, na parte superior da janela, encontramos quatro botões: Consulte também,
Propriedades, Métodos e Eventos.
Um objeto é um elemento complexo composto de propriedades, métodos e eventos. Não vamos estudar este
assunto profundamente; no entanto, devemos ter alguma noção do que nos espera.
Um método corresponde a uma ação, ou seja, uma rotina que realiza alguma ação sobre o objeto ao qual está associado.
Uma propriedade corresponde a uma característica deste objeto. A propriedade é subdividida em três tipos:
propriedades escalares (ou simples), coleções e objetos.
Uma propriedade simples é aquela que possui um valor diretamente armazenado e que afeta de alguma forma o
objeto. Já uma coleção é como um array composto por diversos objetos (que por sua vez possui propriedades,
métodos e eventos). O terceiro tipo de propriedade é aquele que aponta para um outro objeto (que por sua vez
possui propriedades, métodos e eventos).
Você achou complicado? À primeira vista parece, mas observe o esquema da Figura-resposta 7.57F.
Toda vez que encontrarmos um objeto, já sabemos que ele pode possuir outras propriedades, métodos e eventos.
Quando encontramos uma coleção significa que devemos escolher um dos objetos da coleção (talvez usando um
método que aponte para um deles) para alterar suas propriedades ou invocar seus métodos, e assim por diante. As
ações se repetem sempre da mesma forma.
O último componente de um objeto é o evento. Quando determinadas ações são executadas sobre os objetos, eles
podem perceber ou receber indicação daquela ação. Isto é um evento, ou seja, a capacidade de um objeto perceber
a ocorrência de uma ação externa. Podemos dar tratamento à ocorrência de um evento, ou seja, quando um objeto
percebe a ocorrência de um evento podemos determinar que ações serão realizadas.
Estas noções apresentam, grosso modo, o que precisamos saber para realizar uma pesquisa neste arquivo (Vbawrd8)
e conseguir executar a tarefa proposta.
Nossa próxima etapa é conseguir definir todos os passos desejados usando o Form Builder.
Na aplicação desejada, devemos usar o Assistente para criar um bloco de funcionário contendo pelo menos as
colunas cd_mat, nm_func, nm_sobrenome, nr_cargo, vl_sal e in_sexo (formato Form com 1 [um] registro).
Neste bloco gerado devemos anexar a coluna nr_cargo_ant (semelhante a nr_cargo, porém não pertencente ao
banco de dados) e vl_sal_ant (semelhante a vl_sal, porém não pertencente ao banco de dados). Devemos criar,
também, um trigger de Post-Query que atribua aos itens nr_cargo_ant e vl_sal_ant o valor lido do banco de dados.
Devemos anexar também um botão que executará toda a ação. Não há necessidade de acrescentar qualquer crítica.
Vamos nos ater à montagem do exemplo. Apresentaremos, a seguir, cada passo do exemplo com três informações:
a ação definida na macro, a ação definida no Form Builder, uma pequena explicação.
♦ Abrir o Word.
A primeira etapa não aparece na macro porque o Word já está aberto quando a geramos.
A Listagem-resposta 7.57A mostra os passos para a abertura do Word. Usar a rotina Create_OleObj. Para esta
função passamos como parâmetro o nome do aplicativo que desejamos abrir. Ela retorna um objeto (raiz) que
representa o aplicativo aberto. Deve ser atribuído a uma variável do tipo Oleobj. Como sabemos que o objeto-raiz
do Word se chama Application, criei nossa variável com o nome de App. Toda vez que a usarmos estaremos
modificando características da aplicação como um todo.
Com a execução deste comando o Word entra em execução, porém não fica visível (não aparece na tela). É desta
forma que você vai usar se estiver querendo gerar uma carta sem que seu usuário tenha acesso a ela. No nosso caso
achei mais interessante que pudéssemos acompanhar a montagem da carta, e por este motivo foi necessário tornar
o Word visível. Portanto, precisei modificar o valor da propriedade Visible do objeto Application (por curiosidade,
retorne ao Vbawrd8 e verifique se para o objeto Application você encontra esta propriedade).
Quando desejamos modificar ou obter ou acionar um método ou propriedade, devemos primeiro obter o código
correspondente a esta propriedade ou método. A função Get_Ole_MemberId recebe como parâmetro o objeto ao
qual a propriedade ou método pertence (por isso usamos App) e a propriedade ou método que desejamos usar.
Retorna o número correspondente a ele (observe que Membro é do tipo Number).
A rotina Set_Ole altera o valor de uma propriedade. Recebe como parâmetro o objeto ao qual a propriedade
pertence (App), o código da propriedade (Membro), o valor da propriedade (‘True’) e o tipo da propriedade (Vt_Bstr
– string). O último parâmetro é uma constante interna do Form Builder (pesquise na ajuda da função Set_Ole para
verificar os valores válidos).
♦ Abrir um documento vazio.
Listagem-resposta 7.57B
— Obtendo a coleção Documents —
MEMBRO := GET_OLE_MEMBERID(APP, 'DOCUMENTS');
DOCS := GET_OLE_OBJ (APP, MEMBRO);
— Invocando o Método Add: passo1 - argumentos —
INIT_OLEARGS(1);
ADD_OLEARG('C:\ARQUIVOS DE PROGRAMAS\MICROSOFT OFFICE\MODELOS\NORMAL.DOT', VT_BSTR);
— Invocando o Método Add: passo2 - acionando —
MEMBRO := GET_OLE_MEMBERID(DOCS, 'ADD');
CALL_OLE(DOCS, MEMBRO);
A Listagem-resposta 7.57B mostra a primeira ação da macro: criar um documento vazio a partir do arquivo
Normal.dot. Observe que foi utilizado o método Add que pertence à coleção Documents.
Devemos, então, descobrir a que objeto a coleção Documents está associada. Se você pesquisar no arquivo Vbawrd8
descobrirá que a coleção Documents está subordinada diretamente ao objeto Application.
Neste caso, em nossa aplicação devemos: obter a coleção Documents, criar uma lista de argumentos com o nome
do Normal.dot e acionar o método Add da coleção.
A rotina Init_OleArgs inicializa uma área de memória que será passada como argumento. O parâmetro indica
quantos argumentos serão transferidos a tempo de Call_Ole. No nosso caso passaremos um único parâmetro que
corresponde ao nome de um modelo (Normal.dot).
Em seguida, obtemos o código correspondente ao método Add (da coleção Documents) e acionamos o método.
♦ Gravar um texto no documento
Listagem-resposta 7.57C
— Obtendo o objeto Selection —
MEMBRO := GET_OLE_MEMBERID(APP, 'SELECTION');
OBJSEL := GET_OLE_OBJ (APP, MEMBRO);
— Invocando o Método TypeText: passo1 - argumentos —
INIT_OLEARGS(1);
ADD_OLEARG('Rio de Janeiro, '||
TO_CHAR(SYSDATE, 'dd/mm/yyyy')||'.', VT_BSTR);
— Invocando o Método TypeText: passo2 - acionando —
MTEXTO := GET_OLE_MEMBERID(OBJSEL, 'TYPETEXT');
CALL_OLE(OBJSEL, MTEXTO);
O próximo comando encontrado em nossa macro aciona o método TypeText, porém de um objeto chamado
Selection. Para descobrirmos a que este objeto está subordinado, retornemos ao Vbawrd8.
Ao efetuarmos a pesquisa, descobriremos que Selection é uma propriedade que retorna um único objeto e que pertence ao
objeto Application. Por este motivo definimos uma outra variável (ObjSel) de tipo OleObj para “apontar” para este objeto.
Listagem-resposta 7.57D
— Invocando o Método TypeParagraph —
INIT_OLEARGS(0);
MPARAG := GET_OLE_MEMBERID(OBJSEL, 'TYPEPARAGRAPH');
CALL_OLE(OBJSEL, MPARAG);
CALL_OLE(OBJSEL, MPARAG);
CALL_OLE (OBJSEL, MPARAG);
O método TypeParagraph não recebe parâmetros e é subordinado ao próprio objeto Selection. Sendo assim, a ação
correspondente no Form Builder ficou fácil: inicializamos a área de memória indicando tamanho 0 (isto é obrigatório,
pois caso contrário você receberá erro), pois não temos argumentos a serem enviados, e em seguida acionamos o
método três vezes pois desejamos duas linhas em branco.
♦ Criando as demais linhas de texto.
Estas duas últimas operações se repetem para todos os textos da carta.
Listagem-resposta 7.57E
— Invocando o Método TypeText: passo1 - argumentos —
INIT_OLEARGS(1);
IF :IN_SEXO = 'M' THEN
TEXTO := 'Caro Sr. ';
ELSIF :IN_SEXO = 'F' THEN
TEXTO := 'Cara Sra. ';
ELSE
TEXTO := 'Caro(a) Sr(a). ';
END IF;
ADD_OLEARG (TEXTO||INITCAP(:NM_FUNC)||' '||
INITCAP(:NM_SOBRENOME)||',', VT_BSTR);
— Invocando o Método TypeText: passo2 - acionando —
MTEXTO := GET_OLE_MEMBERID(OBJSEL, 'TYPETEXT');
CALL_OLE(OBJSEL, MTEXTO);
— Invocando o Método TypeParagraph —
INIT_OLEARGS(0);
CALL_OLE(OBJSEL, MPARAG);
CALL_OLE(OBJSEL, MPARAG);
CALL_OLE(OBJSEL, MPARAG);
— Invocando o Método TypeText: passo1 - argumentos —
INIT_OLEARGS(1);
ADD_OLEARG('Confira as alterações ocorridas em seus dados funcionais a partir de '||
TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE,'MM'),1), 'DD/MM/YYYY')||'.', VT_BSTR);
— Invocando o Método TypeText: passo2 - acionando —
MTEXTO := GET_OLE_MEMBERID(OBJSEL, 'TYPETEXT');
CALL_OLE(OBJSEL, MTEXTO);
— Invocando o Método TypeParagraph —
INIT_OLEARGS(0);
CALL_OLE(OBJSEL, MPARAG);
CALL_OLE(OBJSEL, MPARAG);
CALL_OLE(OBJSEL, MPARAG);
— Invocando o Método TypeText: passo1 - argumentos —
INIT_OLEARGS(1);
ADD_OLEARG(' '||RPAD('Cargo Anterior ', 17)||'= '
||:NR_CARGO_ANT, VT_BSTR);
— Invocando o Método TypeText: passo2 - acionando —
MTEXTO := GET_OLE_MEMBERID(OBJSEL, 'TYPETEXT');
CALL_OLE(OBJSEL, MTEXTO);
— Invocando o Método TypeParagraph —
INIT_OLEARGS(0);
CALL_OLE(OBJSEL, MPARAG);
— Invocando o Método TypeText: passo1 - argumentos —
INIT_OLEARGS(1);
ADD_OLEARG(' '||RPAD('Cargo Atual ', 17)||'= '
||:NR_CARGO, VT_BSTR);
— Invocando o Método TypeText: passo2 - acionando —
MTEXTO := GET_OLE_MEMBERID(OBJSEL, 'TYPETEXT');
CALL_OLE(OBJSEL, MTEXTO);
— Invocando o Método TypeParagraph —
INIT_OLEARGS(0);
CALL_OLE(OBJSEL, MPARAG);
— Invocando o Método TypeText: passo1 - argumentos —
INIT_OLEARGS(1);
ADD_OLEARG(' '||RPAD('Salário Anterior ', 17)||'= '
||TO_CHAR(:VL_SAL_ANT, 'L999G999D99'), VT_BSTR);
— Invocando o Método TypeText: passo2 - acionando —
MTEXTO := GET_OLE_MEMBERID(OBJSEL, 'TYPETEXT');
CALL_OLE(OBJSEL, MTEXTO);
Por este motivo, a Listagem-resposta 7.57E mostra os trechos de código do PL/SQL inserido na aplicação. Se você
seguir todas as linhas da carta, conseguirá montá-la sem dificuldades.
♦ Identificando o diretório para armazenamento.
Listagem-resposta 7.57F
— Invocando o Método ChangeFileOpenDirectory: passo1 - argumentos —
INIT_OLEARGS(1);
ADD_OLEARG('C:\cartas\', VT_BSTR);
— Invocando o Método ChangeFileOpenDirectory: passo2 - acionando —
MEMBRO := GET_OLE_MEMBERID(APP, 'ChangeFileOpenDirectory');
CALL_OLE (APP, MEMBRO);
Voltamos, portanto, ao Form Builder, obtemos o código correspondente a esse método, construímos a área de
argumentos e acionamos o método, como mostrado na Figura-resposta 7.57F.
♦ Salvar o arquivo.
Listagem-resposta 7.57G
— Obtendo a propriedade ActiveDocument —
MEMBRO := GET_OLE_MEMBERID(APP, 'ACTIVEDOCUMENT');
DOCS := GET_OLE_OBJ (APP, MEMBRO);
— Invocando o Método SaveAs: passo1 - argumentos —
INIT_OLEARGS(1);
ADD_OLEARG(LOWER(:CD_DEPTO||:NM_FUNC||
TO_CHAR(SYSDATE,'YYYYMMDDHH24MI')), VT_BSTR);
— Invocando o Método SaveAs: passo2 - acionando —
MEMBRO := GET_OLE_MEMBERID(DOCS, 'SaveAs');
CALL_OLE (DOCS, MEMBRO);
Na macro foi acionado o método SaveAs pertencente a ActiveDocument (representa o documento ativo, em uso).
Devemos procurar a que objeto pertence esse novo elemento. Descobrimos, então, que ActiveDocument é uma
propriedade que retorna um objeto Document relativo ao documento ativo.
Com esta informação podemos obter esse objeto, seu método SaveAs e acioná-lo.
Se você tiver a curiosidade de pesquisar o método SaveAs, verificará que ele recebe diversos parâmetros; no entanto,
somente o nome do arquivo é obrigatório.
♦ Fechar o arquivo.
Listagem-resposta 7.57H
— Invocando o Método Close —
INIT_OLEARGS(0);
MEMBRO := GET_OLE_MEMBERID(DOCS, 'Close');
CALL_OLE(DOCS, MEMBRO);
END;
A última etapa é o fechamento do arquivo. Utilizamos o método Close do objeto Document (visto anteriormente).
♦ Conclusão.
Você observou que os passos são bastante repetitivos. Se você tiver tempo e interesse, leia um pouco mais sobre objetos
e navegue neste arquivo Vbawrd8 para obter maiores informações sobre os objetos do Word. É muito interessante!
Se você precisa de informações mais imediatas, siga os passos que apresentamos aqui: gerar a macro e seguir cada uma
das etapas registradas nela. Você encontrará todos os objetos relativos ao Word no arquivo fornecido pela Microsoft.
Imagine, porém, que você deseja trabalhar com Excel (e não com Word). O caminho é o mesmo. A diferença é o
arquivo de Ajuda da Microsoft; neste caso, se chama Vbaxl8.hlp. Boa sorte!
7.58) Criar uma aplicação de nome EX58 baseada na aplicação EX56. Acrescente a seguinte funcionalidade:
♦ Retirar a janela de mensagens.
♦ Adiar a verificação de obrigatoriedade de preenchimento para quando a validação do registro ocorrer.
♦ Garantir a leitura de diversas linhas a cada acesso ao banco de dados.
♦ Estabelecer a leitura simultânea de seis linhas de cada vez para as tabelas Func e Proj e de todas as linhas para Depto.
Em relação às solicitações deste exercício, a única que produz efeito visual é a retirada da janela de console (local
onde são apresentadas as mensagens produzidas pela rotina Message). Esta ação é conseguida ao associarmos Null
à propriedade Janela Console (Console Window) do módulo EX58.
A segunda solicitação é o adiamento da crítica de obrigatoriedade de preenchimento. Isto também é obtido através
de uma propriedade do módulo EX58. Corresponde à propriedade Diferir Imposição Obrigatória (Defer Required
Enforcement), à qual devemos atribuir Sim (Yes).
As demais solicitações trarão ganho de performance, pois a leitura será feita a cada seis linhas. Para que esta ação
tenha efeito, devemos marcar a opção Processamento de Array (Array Processing) na opção Preferências (Prefer-
ences) do menu Ferramentas (Tools).
Em seguida, devemos preencher com 6 a propriedade Tamanho do Array de Consulta (Query Array Size) para os
blocos Func e Proj. Já para o bloco Depto usaremos a propriedade Consultar Todos os Registros (Query All Records)
com o valor Sim (Yes).
7.59) Criar uma aplicação de nome EX59 baseada na aplicação EX58. Acrescente a seguinte funcionalidade:
♦ Gerar estatísticas e verificar o resultado (testar e em seguida desmarcar).
♦ Testar a aplicação somente para consulta (testar e em seguida desmarcar).
♦ Garantir que seja possível ao Form Builder abrir cursores independentes para cada uma das operações.
Na pasta Geral (General) encontramos as preferências: Salvar Antes de Desenvolver (Save Before Building) e
Desenvolver Antes de Executar (Build Before Running).
Quando encerramos a aplicação, recebemos a mensagem FRM41602: Total de cursores que usaram XXX provocada
pela opção de estatística.
Além dessa informação, essa opção gera um arquivo com o nome Ora<número do PID>.trc onde encontraremos
todos os comandos Selects executados pela aplicação durante o período em que esta ficou ativa. Esse arquivo deve
ser entregue ao seu DBA para que ele avalie se os comandos estão construídos adequadamente. Esse arquivo (se
você instalou o Personal Oracle) está presente no diretório Oracle\Admin\<sid>\Udump. No caso do exemplo, o
nome do arquivo é Ora29259.trc.
7.60) Criar uma aplicação de nome EX60 baseada na aplicação EX59. Acrescente a seguinte funcionalidade:
♦ Determinar um tempo máximo de consulta.
♦ Determinar uma quantidade máxima de linhas para consulta.
♦ Associar uma barra de ferramentas horizontal à janela da aplicação.
♦ Associar uma barra de ferramentas vertical à janela da aplicação.
♦ Quando ocorrer um erro de banco de dados, soar um alarme sonoro.
As quatro primeiras solicitações estão associadas às propriedades do módulo EX60.
As propriedades Tempo Máximo Para Consulta (Maximum Query Time) e Máximo de Registros Extraídos (Maxi-
mum Records Fetched) são aplicáveis somente se a propriedade Consultar Todos os Registros (Query All Records)
estiver marcada (no nosso caso, isto ocorre para o bloco Depto). Como a quantidade de linhas é muito pequena,
não conseguiremos bloquear por tempo, somente por quantidade de registros.
As propriedades Canvas da Barra de Ferramentas Horizontal (Form Horizontal ToolBar Canvas) e Canvas da Barra
de Ferramentas Vertical (Form Vertical ToolBar Canvas) associam a canvas correspondente como barra de ferramentas
da janela MDI.
Nossa última tarefa é associar um alarme sonoro em caso de erro.
A rotina Bell é encarregada desta tarefa, porém somente quando há um sincronismo entre o Forms Runtime e a tela.
7.61) Criar uma aplicação de nome EX61 baseada na aplicação EX60. Acrescente a seguinte funcionalidade:
♦ Criar duas novas cores em sua paleta de cores.
♦ Exporte a paleta de cores com o nome de pteste.pal.
♦ Execute a aplicação em modo silencioso e cause um erro de banco de dados (incluir um funcionário já existente,
por exemplo).
Para editarmos a paleta de cores, devemos: alterar o modo das cores para Editável (menu Preferências) e salvá-lo,
fechar o Form Builder, abrir o Form Builder com uma aplicação nova (vazia, sem canvas) e, finalmente, acionar o
editor de Layout (F2). No menu Formato, Opções de Layout, encontraremos a Paleta de Cores.
No nosso exercício, incluímos duas novas cores a que chamamos de violeta e terra, respectivamente. Após aceitarmos
este diálogo da paleta de cores, ainda com o editor de Layout aberto, devemos utilizar a opção Exportar Paleta de
Cores do menu Arquivo.
Quando for mostrado o diálogo da Figura-resposta 7.61, preencheremos o nome do arquivo da paleta de cores.
Para utilizarmos esta paleta de cores na aplicação EX61, devemos: fechar a aplicação atual, abrir a aplicação EX61,
abrir uma canvas (acionar o editor de Layout), e no menu Arquivo selecionar a opção Importar Paleta de Cores.
Quando o diálogo correspondente for apresentado, pesquisar e selecionar a paleta criada anteriormente. Retornar
às preferências e colocar o modo das cores como Somente Leitura – Compartilhável. Agora, selecione um objeto
qualquer e abra a paleta de cores (no editor de Layout). Você verá surgir as cores incluídas por você.
A última ação deste exercício é executar a aplicação em modo silencioso. Esta opção também está nas Preferências
(pasta Runtime). Marque a opção desejada, salve e execute a aplicação causando um erro.
7.62) Criar uma aplicação de nome ExTemp, baseada na aplicação EX61, contendo apenas as seguintes informações:
♦ Todos os atributos visuais.
♦ Todos os editores.
♦ Todos os alertas.
♦ Retirar os parâmetros.
♦ O bloco de controle somente com os botões, exceto Ajuda, Lob, Depto e Navega.
♦ As triggers On-Message, On_Error, Pre-Form e Key-*.
♦ As canvas de botões com os respectivos botões.
♦ A janela Janela1.
♦ Manter a unidade de programa Mens.
♦ Retirar do Pre-Form a montagem do Record Group.
♦ Criar uma classe de propriedades Texto com as seguintes características:
a) Salto automático
b) Todas as letras maiúsculas
c) Prompt justificado à esquerda
d) Deslocamento da conexão do prompt 5.
♦ Compile esta aplicação corrigindo os erros de sintaxe encontrados (em função de objetos ausentes).
O objetivo deste exercício é criarmos uma aplicação-esqueleto contendo os principais padrões da instalação.
Escolhemos alguns objetos com este objetivo.
Devemos retirar todos os erros de sintaxe causados pela utilização de objetos inexistentes na aplicação.
Este esqueleto não deve ser utilizado diretamente. Quando houver a criação de uma nova aplicação, partiremos
deste arquivo.
Podemos, em uma instalação, criar vários tipos diferentes de esqueletos (Templates) característicos de tipos de
programas (consulta, atualização, etc.) ou que incorporem padrões de layout diferentes.
O objetivo do esqueleto é aumentar a produtividade e estabelecer uma forma segura e prática de estabelecermos padrões.
Com mais este exemplo, você terá condições de escolher a melhor forma de trabalhas em sua instalação.
Podemos manter este diálogo aberto e arrastar de uma aplicação aberta os objetos desejados para a biblioteca de
objetos na pasta programada.
Como última etapa devemos marcar as Smart Classes. Para tal, basta que selecionemos o objeto desejado na Object
Library e selecionar a opção SmartClass do menu Objeto do Form Builder.
7.65) Crie uma aplicação de nome Ex65 contendo um bloco de funcionário e todos os campos. Obtenha os seguintes
objetos da biblioteca de objetos Bib64:
♦ Utilize os atributos visuais.
♦ Utilize a classe Texto para todos os itens do tipo Text Item.
♦ Associe o editor Edtexto ao item nm_foto.
Na aplicação EX65 iniciaremos criando o bloco Func através do Assistente. Podemos obter os objetos da biblioteca
de maneiras diferentes:
♦ Remova a janela Janela1 da aplicação EX65. Arraste a janela Janela1 da biblioteca de objetos. Faça uma cópia.
♦ Associe a classe Texto aos itens diretamente a partir da biblioteca de objetos. Para tal, selecione um dos itens e
abra a propriedade Divisão em Subclasses (Subclass Information). Selecione o módulo Bib64 e o botão de opção
Classe de Propriedades, em seguida selecione a classe Texto (ver Figura-resposta 7.65A).
♦ Crie um alerta no nó Alertas. Em seguida, com o botão direito do mouse escolha a opção Classes Inteligentes
(Smart Classes) e marque “Aviso”.
♦ Repita esta operação para a unidade de programa Mens.
Compile e verifique se algum objeto não foi trazido. Traga-o e execute a aplicação.
Obtemos o mesmo tipo de resultado que aquele conseguido através do Template.
São duas formas diferentes de padronização e reutilização de código. Faça outros testes e escolha aquela mais
adequada à sua instalação.
7.66) Criar uma biblioteca de PL/SQL de nome BPL66 que contenha as seguintes rotinas:
♦ Rotina (Dv_Matr) para calcular o dv da matrícula do funcionário (noves fora).
♦ Rotina (Intervalo) para determinar o intervalo de anos entre duas datas recebidas como parâmetro.
♦ Rotina (Abono) para calcular o abono salarial (trimestral) de acordo com o número de anos de casa. A rotina
deve receber como parâmetro o tempo de serviço e o salário.
♦ Menos de um ano de casa – Não recebe abono.
♦ De um a menos de três anos de casa – Recebe 3% de abono.
♦ De três a menos de seis anos de casa – Recebe 10% de abono.
♦ Mais de seis anos de casa – Recebe 15% de abono.
Para a criação de uma biblioteca de rotinas PL/SQL, devemos simplesmente usar o botão Criar (Create) sobre o nó
Bibliotecas PL/SQL. Como passos seguintes devemos criar as três rotinas, compilar a biblioteca e, como última
etapa, salvá-la com o nome adequado.
END IF;
END LOOP;
RETURN VAL_DV;
END;
Observe que as três rotinas foram criadas sem qualquer referência a objetos da aplicação. São totalmente
independentes. Se fizermos qualquer referência direta a objetos da aplicação, receberemos erro de sintaxe uma vez
que a biblioteca não tem nenhuma ligação direta com a aplicação.
A melhor forma de trabalharmos com Bibliotecas é mantendo a independência, ou seja, fazendo toda a passagem
de informação como parâmetro.
Se desejarmos (indispensavelmente) fazer acesso a um item, devemos usar as rotinas Name-In (obter o valor) e
Copy (para alterar o valor do item). Quando em execução, a biblioteca tem acesso à área de memória onde se
encontram as variáveis da aplicação. Durante o desenvolvimento, não. Por este motivo recebemos erro de sintaxe.
7.67) Criar uma aplicação de nome EX67 baseada na aplicação EX60. Anexe a biblioteca Bpl66.
♦ Acionar a rotina Dv_Matr quando for feita a inclusão do funcionário (criar um item do tipo exibição).
♦ Acionar a rotina Abono quando a linha for obtida do banco de dados (criar um item do tipo exibição).
♦ Para acionar a rotina Abono, obtenha o tempo de serviço através da rotina Intervalo.
Nosso primeiro passo neste exercício será efetuar a anexação da biblioteca. Isto é feito no nó Bibliotecas Anexadas
(Attached Libraries). Quando selecionarmos o nó e pressionarmos o botão Criar, será mostrado o diálogo da Figura-
resposta 7.67A para que informemos o nome da biblioteca e sua localização.
Ao pressionarmos o botão OK, um diálogo será mostrado nos questionando sobre a manutenção ou não do caminho.
De um modo geral, é conveniente retirar o caminho uma vez que a instalação deste programa em ambiente de
produção certamente estabelecerá novos diretórios para as bibliotecas, executáveis, ícones, etc.
Com esta etapa pronta, podemos acionar as rotinas. Para tal, criamos dois itens, que não pertencem ao banco de
dados, no bloco Func. O preenchimento do DV só é feito a tempo de inclusão de linha; por este motivo utilizamos
um trigger When-validate-Item, porém o cálculo só é acionado quando o estado do registro é New. O cálculo do
abono foi adicionado ao trigger Post-Query.
Listagem-resposta 7.67A
:FUNC.ABONO := ABONO (INTERVALO (SYSDATE, :DT_ADM), :VL_SAL);
A Figura-resposta 7.68A nos mostra a primeira fase, ou seja, a montagem inicial da hierarquia de menus.
A seguir preencheremos o menu Cadastros da seguinte forma: EX65 e EX64 com Call_Form, EX63 e EX61 com
New_Form, EX60 e EX30 com Open_Form em outra sessão e, finalmente, EX31 com New_Form na mesma sessão.
De todos estes aplicativos, apenas o EX65 possui parâmetro e, portanto, sua chamada ficou mais complexa.
A chamada dos demais é mais simples, pois não temos de criar a lista de parâmetros.
A chamada dos relatórios somente será testada no próximo capítulo. Neste momento, criaremos uma chamada
semelhante àquela feita no botão da aplicação, com a diferença de que não podemos fazer referência direta do
item Func.cd_depto. Por este motivo, utilizamos Name-In. Veja a Listagem-resposta 7.68C.
No próximo submenu temos os radios Mostrar ou Retirar Ajuda. O radio Retirar Ajuda deve ser o primeiro da lista
pois ele aparecerá como se houvesse sido marcado.
Utilizamos a mesma lógica do botão Ajuda da aplicação. O temporizador, no entanto, não é necessário (poderia ser
omitido) uma vez que existe uma outra opção que retira a mensagem.
No trigger do radio Retirar Ajuda podemos apenas usar a rotina Hide_View para as três canvas.
Ao item de menu separador não associamos nenhuma lógica.
No próximo menu incluímos apenas itens mágicos: Copiar, Recortar e Colar, que não possuem qualquer comando
associado a eles (Nulo).
O item Window, da mesma forma, é um item mágico sem subitens ou comandos.
Com esta aplicação compilada (Arquivo -> Administração -> Compilar Arquivo), podemos associá-la à aplicação
EX68 criada. A associação é feita nas propriedades da aplicação. Informe o nome do arquivo de menu MN68.MMX
e o nome do menu principal (no meu caso Principal).
Com esta associação feita, podemos testar a aplicação e verificar o que acontece quando acionamos uma aplicação
com Call_Form, New_Form, Open_Form na mesma sessão e Open_Form em sessões diferentes.
Verifique antes de cada chamada quais as janelas abertas (utilize o menu Window) para realizar este acompanhamento.
Observe também que as aplicações 68, 64, 63, 61 e 60 utilizam as barras de ferramentas associadas à janela MDI; já
as aplicações 65, 30 e 31 não têm esta utilização. Verifique o que ocorre.
7.69) Crie uma aplicação de nome EX69 baseada na aplicação EX68 contendo:
Um Pop-up Menu possui as mesmas características de um Menu (relativamente às suas propriedades), porém tem
visibilidade de todos os itens criados na aplicação uma vez que está incorporado ao aplicativo. A Listagem-resposta
7.69A mostra a ação de Mostrar Ajuda no Popup semelhante àquela do botão Ajuda da barra de ferramentas
(fazendo menção aos itens da aplicação).
A Listagem-resposta 7.69B apresenta a troca de menu a tempo de execução. Nesta rotina, podemos informar a
forma de apresentação do menu (Pull_Down, Bar ou Full_Screen) e o nome do submenu principal. Experimente
informar apenas o nome do menu sem os demais parâmetros e veja a diferença.
7.70) Faça uma aplicação, de nome EX70, que estabeleça o cadastramento de funcionários (use a tabela TB_Func).
Na tela de cadastramento devem ser apresentados simultaneamente o nome do gerente e o nome do departamento
do funcionário. Use uma lov para que estas informações sejam selecionadas. Gere, simultaneamente, um arquivo
que demonstre todas as ações realizadas pelos usuários e que seja auxiliar no processo de depuração.
A resolução deste exercício pode ser feita, praticamente, toda pelo Assistente de Bloco.
Iniciamos definindo as colunas a serem obtidas da tabela TB_Func: todas as colunas escalares e a coluna nm_depto
(obtida a partir da referência cd_depto).
Seguimos estabelecendo a lov a partir de cd_depto (Tb_Depto), formato Form com 1 registro e barra de rolagem.
Para que o usuário não tenha a falsa impressão de que poderá alterar o nome do departamento, tornamos o campo
referenciado como campo apenas de consulta (Item de Exibição).
Como o Assistente gera a lov automaticamente, não tivemos necessidade de realizar esta etapa, porém o campo
default de acionamento da lov tornou-se item de exibição e, portanto, não recebe o foco.
Para contornar esta situação, associamos a lov (trocamos seu nome para L_Depto) à coluna cd_mat e, adicionalmente,
criamos um botão que pudesse acionar a lov quando o usuário tivesse interesse, desta forma, a lov pode ser
acionada pelo botão ou pelo teclado quando o foco estiver sobre a coluna cd_mat. O texto adicionado à trigger
When-Button-Pressed deste botão é apresentado pela Listagem-resposta 7.70A.
Listagem-resposta 7.70A
IF NOT SHOW_LOV('L_DEPTO', 300, 120) THEN
RAISE FORM_TRIGGER_FAILURE;
END IF;
Quando concluímos os testes de inclusão, exclusão e alteração, criamos um ícone no Windows com o comando
apresentado na Listagem-resposta 7.70B a seguir.
Listagem-resposta 7.70B
C:\ORAWIN95\BIN\IFRUN60.EXE MODULE=EX70.FMX USERID=DESENV/DESENV@DESENV
RECORD=COLLECT LOG=EX70.LOG
A partir do arquivo gerado poderemos acompanhar as ações realizadas pelo usuário até que ocorra a homologação
da aplicação.
Com este exercício encerramos, por enquanto, os testes com o Form Builder. A seguir, iniciaremos nosso estudo
com o Report Builder. Mais tarde retornaremos ao Form Builder para estabelecer a chamada a um Report.
Capítulo 8
O REPORT BUILDER R6I
Neste capítulo, estudaremos a ferramenta de desenvolvimento Report Builder 6i que faz parte do pacote de
ferramentas para desenvolvimento chamado Reports Developer 6i. Iniciaremos nosso estudo conhecendo um
pouco sobre o pacote. Logo depois, serão dadas informações gerais sobre a ferramenta ora em estudo e, em seguida,
trabalharemos com a ferramenta em diversos exemplos e exercícios.
Para o desenvolvimento e entendimento adequado deste capítulo, o leitor já deve estar muito bem familiarizado
com a linguagem SQL e a linguagem PL/SQL previamente estudadas. Nos itens referentes a pré-requisitos indicaremos
apenas os requisitos necessários ao tópico em estudo, considerando o conhecimento prévio de SQL e PL/SQL satisfeito.
SOBRE O PACOTE
O Reports Developer corresponde a um conjunto de ferramentas usadas para a construção de relatórios que,
dinamicamente, recuperam, formatam e distribuem informações armazenadas no banco de dados. Com este pacote
tanto podemos publicar relatórios na Web ou em um ambiente de três camadas quanto gerar relatórios em ambiente
cliente-servidor. As ferramentas agregadas nos dão uma grande flexibilidade na construção e gerenciamento dos relatórios.
O Report Builder 6i é a principal ferramenta deste ambiente, pois é a ferramenta para desenvolvimento dos relatórios
e obtenção das informações de uma base de dados Oracle.
Para apoiar o Report Builder 6i, as seguintes ferramentas fazem parte do pacote Reports Developer:
♦ Procedure Builder – É a ferramenta que nos auxilia no desenvolvimento de programas PL/SQL, tanto no ambiente
cliente (em bibliotecas de programas compartilhadas por aplicações Report), quanto no ambiente servidor (criação de
procedures, functions, packages e database triggers), permitindo uma depuração passo a passo das aplicações criadas.
♦ Graphics Builder – É a ferramenta que permite que visualizemos os dados do banco de dados de forma gráfica.
Os produtos gerados por essa ferramenta podem ser utilizados em aplicações Reports.
♦ Project Builder – Esta é uma ferramenta integradora e organizadora, permitindo que associemos as diversas
aplicações que componham um projeto de desenvolvimento em uma hierarquia manipulável. Projetos são
associações de arquivos com as ferramentas usadas para editá-los. Esses arquivos podem ser de qualquer tipo:
form, report, display (gráficos), módulos de 3GL, documentação e scripts de teste. O grupamento e visualização
de todos os componentes de um projeto é apenas uma das vantagens. A ferramenta permite também ações
coletivas, como por exemplo uma compilação.
♦ Query Builder – É uma ferramenta auxiliar na construção de consultas ao banco de dados. Possui uma interface
gráfica e intuitiva que nos permite rápida e facilmente a montagem de queries para a recuperação de informações.
♦ Schema Builder – Esta ferramenta nos auxilia na criação, cópia, modificação e remoção de objetos (e
relacionamentos) do banco de dados.
♦ Translation Builder – Esta é uma ferramenta para suporte e gerenciamento no processo de conversão de aplicações
Oracle para uma das linguagens suportadas. Suporta a conversão de arquivos do tipo .fmb, .ogd, .rdf, .res e .msg.
O pacote Reports Developer contém ferramentas que abrangem todas as áreas necessárias ao desenvolvimento de aplicações
(gráficos, queries, manutenção do banco de dados, tradução), e, ainda, uma ferramenta para controle do ambiente.
Neste livro, o objeto de nosso estudo será o Report Builder 6i.
SOBRE A FERRAMENTA
Ao desenvolvermos um relatório, em qualquer ferramenta, claramente identificamos duas áreas principais de
trabalho: a parte de obtenção dos dados e a parte de especificação do layout. A ferramenta que estudaremos a
seguir possui estas duas áreas ou estes dois conceitos bastante definidos, o que nos facilitará o estudo.
Da mesma forma que o Form Builder, o Report Builder não é uma ferramenta isolada; é composta de diversos
executáveis com finalidades diversas. Destacaremos aqueles que mais afetam o nosso estudo:
♦ RWBLD60 – Report Builder – Este é o aplicativo para desenvolvimento e compilação individual de um relatório.
Gera arquivos de quatro categorias: RDF/REP (fonte e executável Report), SQL (fonte de uma consulta externa),
PLL (PL/SQL Library) e TDF (Template). O fonte também pode ser armazenado em formato XML.
♦ RWRUN60 – Report Runtime – Este é o aplicativo para execução dos relatórios desenvolvidos (Reports e Librar-
ies PL/SQL). Existem duas versões deste aplicativo: uma para usuários que estejam executando seus relatórios a
partir de máquinas character-mode (por exemplo VT220) e outra para usuários que estejam executando seus
relatórios a partir de máquinas bit-mapped (por exemplo um ambiente Windows). Em ambos os casos podemos
executar tanto relatórios character-mode quanto relatórios bit-mapped. O único fator limitante é o periférico de
saída (por exemplo, não podemos executar um relatório bit-mapped para a tela de um VT220).
♦ RWCON60 – Report Convert – Este aplicativo permite a conversão da forma de armazenamento (fonte de
relatório armazenado no banco de dados para fonte, template ou executável de relatório em disco; fonte no
disco para fonte armazenado no banco de dados. Os fontes tanto podem ser de relatórios quanto de bibliotecas).
Durante este processo o Convert poderá efetuar a compilação das rotinas de PL/SQL como parte do processo de
conversão (por exemplo quando tentamos criar um .rep ou quando usamos um .rex como origem ou quando
usamos um fonte gerado em outra plataforma).
♦ RWRBE60 – Report Background Engine – Este aplicativo aguarda por qualquer linha de comando para a execução
de relatórios. Quando recebe uma linha de comando ele coloca o relatório em uma fila. Isto ocorre,
automaticamente, quando um Forms ou Graphics usa a rotina RUN_PRODUCT ou de um Reports usamos
SRW.RUN_REPORT. A submissão de relatório para o Report Background Engine também pode ser feita através
do utilitário RWISV60 (em substituição ao Reports Runtime, pois é mais leve. Sua linha de argumentos é igual à
do Reports Runtime). O Report Background Engine somente é utilizado em ambientes cliente-servidor, ou seja,
quando o relatório é executado localmente. Para a submissão em um ambiente de três camadas ou Internet,
devemos usar o RWCLI60 para enviar o relatório para o Reports Server.
Durante este capítulo trataremos da construção, compilação e teste de relatórios. Desta forma, trabalharemos,
basicamente, com o Report Builder e o Report Runtime. No Capítulo 9, onde estudaremos o ambiente de três
camadas ou o uso do produto para Internet, estaremos analisando outros executáveis associados a este ambiente.
SOBRE O ESTUDO
Neste capítulo desenvolveremos o estudo com exemplos passo a passo. Os capítulos da parte Referências conterão
a lista de propriedades, de rotinas predefinidas, de triggers, etc. Faremos um estudo similar àquele desenvolvido
para a ferramenta Form Builder.
METODOLOGIA
♦ Apresentação e descrição dos diálogos apresentados pela ferramenta e forma de preenchimento.
TÉCNICA
♦ Criação de pequenos programas seguindo os diálogos apresentados.
CONCEITOS INICIAIS
A ferramenta Report Builder é capaz de construir quatro tipos de módulos diferentes:
♦ Report – Que consiste do relatório em si, contendo áreas para obtenção dos dados, definição do layout, parâmetros,
etc. O fonte de um módulo Report possui a extensão RDF e o executável REP. Alternativamente podemos gerar
o fonte de um relatório com extensão .XML (nesta extensão as especificações de layout não são arquivadas,
somente a estrutura do relatório).
♦ Consulta SQL Externa – Que consiste de um comando de SQL Select armazenado externamente ao relatório e
que pode ser utilizado como fonte de obtenção de dados para mais de um relatório. O arquivo contendo este
comando possui a extensão SQL.
♦ PL/SQL Library – Que consiste de um conjunto de programas PL/SQL que podem ser compartilhados por diversas
aplicações Report (ou Form) que executam no ambiente. O fonte de um módulo PL/SQL Library possui a extensão
PLL e o executável PLX.
♦ Gabarito – Que consiste de um conjunto de especificações, principalmente relativas ao layout, que são
incorporadas ao relatório que estivermos preparando. Pode conter especificação para diferentes tipos de layouts
de relatório. Possui a extensão .TDF.
Durante este capítulo, trataremos de cada um destes módulos individualmente a fim de analisarmos suas
características e usos.
A primeira tela apresentada contém um conjunto de opções para iniciarmos a construção dos relatórios sob o
grupo Projetando e um outro conjunto de opções de apresentação da ferramenta sob o grupo Fixando na memória.
Antes de construirmos nosso primeiro relatório, veremos como navegar dentro da ferramenta. Por este motivo
escolheremos a opção “Criar um novo relatório manualmente”.
♦ Relatórios (Reports) – Subordinado a este nó estará o módulo de Reports que viermos a desenvolver. Na Figura
8.02 aparece uma aplicação de nome “Module1”. Observe que o nó Relatórios está preenchido com o símbolo
( - ), indicando que o nó está expandido. O nó do módulo “Module1” está preenchido com o símbolo ( + ),
indicando que o nó está contraído, ou seja, existem elementos subordinados a este nó que não estão visíveis.
♦ Gabaritos – Subordinado a este nó estará o módulo de Gabarito (Template) que viermos a desenvolver. Na Figura
8.02 não existe nenhum módulo aberto, portanto o nó está vazio. Não há nenhum símbolo preenchendo o nó.
♦ Consultas SQL Externas – Subordinado a este nó incluiremos comandos de SQL Select armazenados em arquivos.
Esses comandos Select podem ser compartilhados por diversos relatórios, caracterizando uma origem de dados
e diversos layouts. Não incluímos ainda nenhum módulo subordinado a este nó.
♦ Bibliotecas PL/SQL – Subordinado a este nó estará o módulo Library de PL/SQL que viermos a desenvolver. Na
Figura 8.02 também não existe nenhum módulo aberto, portanto o nó está vazio.
♦ Ações de Depuração e Stack – Nestes nós não serão cadastrados módulos. Serão incluídas ações temporárias,
criadas para efeito de depuração.
♦ Pacotes Embutidos – Subordinado a este nó existem diversos pacotes (packages) contendo uma variedade de
rotinas que poderemos utilizar no desenvolvimento da aplicação. Observe que este nó está contraído ( + ).
♦ Objetos do Banco de Dados – Subordinado a este nó serão visualizados os diversos objetos do banco de dados a
que o usuário ao qual estamos conectados tem acesso. Atualmente o nó está vazio, pois não estabelecemos,
ainda, conexão com o banco.
A seguir veremos as diversas ações que podemos realizar no Navegador de Objetos. Se você já estudou o Form
Builder, não encontrará diferenças nas ações Expandir ou Contrair, porém verifique as ações Criar ou Deletar.
EXPANDIR OU CONTRAIR
Para expandir um nó ou contraí-lo, basta que pressionemos o mouse sobre o símbolo ( + ) para expandi-lo ou sobre
o símbolo ( - ) para contraí-lo.
A Figura 8.04 apresenta os botões que realizam as ações de expansão e contração na barra de ferramentas.
Como teste, utilize o botão de Expandir Tudo sobre o nó Pacotes Embutidos. Você verificará que a expansão se dará
em todos os nós subordinados ao nó principal. Todos serão expandidos simultaneamente. A ação inversa é obtida
com o botão Contrair Tudo.
CRIAR OU DELETAR
Diferentemente do Form Builder, no Report Builder nem todos os objetos podem ser criados no Navegador. Para
determinados objetos, devemos utilizar o editor adequado para manipulação do objeto.
Quando o objeto puder ser criado pelo Navegador, o botão Criar (presente na barra de ferramentas) ficará habilitado.
Caso contrário, ficará desabilitado.
Na Figura 8.05 mostramos os botões Criar e Deletar em ambas as situações: habilitados e desabilitados.
Para realizarmos esta ação basta que selecionemos o nó ou um objeto do mesmo tipo daquele que desejamos criar
e pressionemos o botão Criar.
Como teste, selecione o nó Consultas SQL Externas (corresponde a um elemento do tipo SQL) e pressione o botão
Criar. Você observará que será criado um novo módulo de nome “Module2”.
Outra forma de realizar a mesma operação é realizarmos um clique duplo sobre o nó em que desejamos criar um
elemento. Teste sobre o nó Parâmetros de Usuário (subordinado ao nó Modelo de Dados do relatório).
Com estes testes verificamos que podemos manipular com mais de um módulo ao mesmo tempo usando a
ferramenta, uma vez que criamos “Module1” e “Module2”. Isto se aplica a todos os nós principais (Reports, Gabaritos,
SQL Externas e Libraries). Porém, enquanto não tivermos prática no desenvolvimento de aplicações com esta
ferramenta, trabalharemos com um módulo por vez.
Para removermos um elemento, devemos selecioná-lo e pressionar a ferramenta Deletar ou pressionar o botão Del
do teclado.
Na Figura 8.06 apresentamos os dois botões ligados à execução da aplicação e o botão associado ao envio de mensagem.
Quando pressionamos um dos dois botões de execução, acionamos o Report Runtime para execução da aplicação
corrente. A diferença entre eles é que o botão Executar apresenta a saída no vídeo por default e o botão Imprimir
apresenta a saída na impressora por default.
Para que o relatório seja enviado por e-mail devemos executá-lo e, em seguida, pressionar o botão Mensagem a fim
de transmitir o resultado da execução para outro usuário (via e-mail).
Em plataformas Windows, a técnica para envio de e-mail é o Microsoft Messaging Application Programming
Interface (MAPI). Os relatórios bitmap são atachados com formato PostScript, enquanto que os relatórios charac-
ter-mode são atachados como textos ASCII.
Para que esta opção funcione precisamos ter a aplicação MAPI client instalada em nosso sistema operacional.
ABRIR E SALVAR
Este último conjunto de botões realiza ações sobre os módulos.
A ação se dá de acordo com o elemento que tivermos selecionado no momento. Por exemplo, se tivermos selecionado
um módulo Report ou qualquer elemento subordinado a ele e pressionarmos o botão Salvar, efetuaremos a salva
do módulo corrente, e se pressionarmos o botão Abrir serão apresentados outros arquivos com extensão RDF
(Report) para que façamos a escolha daquele que desejamos abrir.
Como exemplo, vamos salvar o módulo atual.
Uma vez que o Report Builder pode ser salvo tanto no banco de dados quanto no disco e é a primeira vez que
salvamos este módulo, o Report Builder apresenta um diálogo para que indiquemos o meio de armazenamento.
Quando optamos por disco, o Report Builder apresenta um novo diálogo para que determinemos o diretório onde
efetuaremos a salva e o nome desejado para o módulo.
A partir do momento que definirmos o diretório e o nome do módulo, o Report Builder não mais apresentará este
diálogo nas próximas vezes que pressionarmos o botão Salvar.
Como teste, salve o módulo ativo com o nome de Teste. Observe após a salva que no navegador o nome do
módulo foi alterado para Teste.
LOCALIZAR
Podemos usar o pesquisador do Navegador para encontrar elementos e nós dentro do Navegador. Para iniciarmos
uma busca devemos digitar a string que desejamos procurar no campo Localizar, que fica posicionado no canto
superior direito da janela do Navegador. A cada caracter que digitamos, o Report Builder movimenta o cursor para
o próximo elemento com o qual as letras digitadas sejam compatíveis.
Por exemplo, selecionemos o módulo Teste. Ao posicionarmos o cursor sobre o campo Localizar e digitarmos a letra
“A”, o Report Builder posicionará o cursor sobre o nó After Parameter Form (nó subordinado a Gatilhos de Relatório).
Quando necessário, podemos utilizar as duas lanternas posicionadas ao lado do campo Localizar para efetuar uma
busca para frente ou para trás.
NAVEGANDO NA HIERARQUIA
Da lado esquerdo da janela do Navegador existe um campo que apresenta o nome do elemento atualmente
selecionado. Ao abrirmos a lista desse campo, verificaremos que ele contém todos os ancestrais hierarquicamente
superiores em relação ao objeto selecionado. Ele apresenta a árvore de subordinação do elemento selecionado.
Podemos selecionar qualquer elemento dessa hierarquia, bastando que façamos a seleção do elemento desejado,
clicando o mouse sobre o nome do elemento na lista.
Esta árvore pode ser curta, apresentando apenas o nó selecionado e o nome do módulo ou mais longa, indicando
os vários “frames” e “repeating frames”, se o objeto selecionado pertencer ao layout.
PAINÉIS DO NAVEGADOR
Podemos dividir o navegador em múltiplos painéis horizontal ou verticalmente. Para tal, devemos pressionar e
arrastar o mouse sobre o ponto de divisão horizontal ou vertical mostrado na Figura 8.08.
Só é possível dividi-lo num sentido (vertical ou horizontal) de cada vez. Podemos realizar múltiplas subdivisões,
desde que num mesmo sentido.
Observe na Figura 8.09 que algumas letras da palavra “parame” estão selecionadas e parte da palavra foi removida.
Veja o nome completo do nó no campo referente à hierarquia (canto superior esquerdo da janela do Navegador).
Para efetivarmos a modificação, basta pressionarmos o mouse sobre qualquer outro nó para que seja encerrado o
estado de digitação. Se desejarmos desistir devemos pressionar a tecla Esc para encerrar, desfazendo as modificações.
ESTILO DO RELATÓRIO
A primeira tela apresentada aparece na Figura 8.10.
Neste diálogo são apresentadas diversas opções de estilo para o relatório. Como teste, sem pressionar o botão
próximo, marque uma opção de cada vez e observe no painel à esquerda um exemplo do estilo de relatório
correspondente. Durante nosso estudo teremos oportunidade de testar todos os estilos. Iniciemos, então, com o
estilo Tabular. No campo Título podemos preencher um texto (livre) que será usado para título do relatório gerado
(preencha com Primeiro Teste). Em seguida, pressione o botão Próximo.
O segundo diálogo determina se criaremos uma Instrução de SQL ou uma Consulta Express (o que significa que
estaremos obtendo informações de um Express Server). Neste livro não utilizaremos um Express Server (apesar de,
posteriormente, fazermos alguns comentários sobre o diálogo específico); portanto, escolha Instrução de SQL.
O terceiro diálogo, referente aos dados (observe os botões abaixo do campo Instrução de Consulta), nos possibilita
três opções:
♦ Podemos digitar o comando Select que contenha os dados desejados no espaço Instrução de Consulta.
♦ Podemos acionar o Query Builder para a construção passo a passo do comando SQL ao pressionarmos o botão
Query Builder.
♦ Podemos desenvolver este relatório a partir de uma consulta previamente armazenada em um arquivo .SQL
existente no disco. Esta opção utiliza a opção Importar Consulta SQL (External Query).
Se não houvéssemos, até este ponto, estabelecido conexão com o banco de dados, poderíamos pressionar o botão
Conectar para que o diálogo apropriado fosse apresentado.
A Figura 8.11 nos mostra o primeiro diálogo apresentado pelo Query Builder. Neste diálogo devemos indicar de
que objetos desejamos obter dados.
Na parte superior do diálogo, devemos indicar se os objetos de onde virão os dados são: Tabelas (Tables), Views, Snapshots,
Sinônimos (Synonyms) ou uma combinação de tipos diferentes (podemos marcar mais de uma opção simultaneamente).
Na parte central, é apresentada uma lista com três opções: Desenv (que é o usuário ao qual estabelecemos conexão),
<Local> (ou o banco de dados ao qual você estiver conectado) e Bancos de Dados (Databases).
Se os objetos pertencerem ao usuário Desenv, eles serão apresentados na caixa de diálogo inferior.
Se desejarmos obter dados de objetos pertencentes a outros usuários do banco local (ou atual), devemos escolher a
opção <Local> (ou o banco de dados ao qual você estiver conectado). Neste caso, a caixa de diálogo inferior
apresentará a lista de usuários e você poderá selecionar aquele que interessa.
A opção Bancos de Dados, quando selecionada, mostrará a lista de objetos Database Links presentes no banco de
dados atual, que permitirão a conexão com outros bancos (não exploraremos esta opção neste material).
A tela apresentada corresponde ao diálogo principal do Query Builder. Observe que aparecem em cinza os dois
relacionamentos existentes entre as tabelas selecionadas.
Este diálogo principal se subdivide em duas áreas:
♦ Do lado direito se encontra a área de objetos selecionados.
♦ Do lado esquerdo se encontra a área de restrições da consulta.
Além das áreas, esta janela apresenta uma barra de ferramentas superior com todas as ações disponíveis no Query
Builder. Testaremos as funções e utilizaremos os botões da barra passo a passo.
Até este momento, apesar de termos selecionado as tabelas Func e Depto, ainda não estabelecemos quais colunas
farão parte desta consulta.
♦ Efetuar um clique duplo sobre a coluna, apresentada no desenho (lado direito do painel) ou um clique simples
sobre o quadrado (caixa de seleção) à esquerda do nome da coluna.
♦ Pressionar o botão Seqüência de Coluna da barra de ferramentas (destacado na Figura 8.12).
Selecionaremos via clique duplo a coluna nm_depto da tabela Depto.
Concentremos nossa atenção na imagem da tabela Depto apresentada na Figura 8.12. Nesta imagem, encontramos:
♦ Do lado direito a indicação do tipo de coluna: Alfanumérica (símbolo A), Numérica (símbolo contendo os
números 7, 8 e 9), Data (símbolo contendo o número 31).
♦ Do lado esquerdo o indicador (checado ou não checado) de coluna selecionada (clique duplo sobre uma das
colunas para que este indicador apareça checado).
♦ Do lado direito da coluna cd_depto_ctb aparece uma seta curva, indicando que essa coluna representa um auto-
relacionamento na tabela (sabemos que cd_depto_ctb possui relacionamento com a coluna cd_depto).
♦ Do lado direito do nome do objeto (no caso Depto) aparece um símbolo indicando que se trata de uma tabela (T).
♦ Do lado esquerdo do nome do objeto aparece o indicador (checado ou não checado) para tabela.
Pressionaremos a seguir o botão Seqüência de Coluna (destacado na barra de ferramentas na Figura 8.12) para
escolher as colunas cd_mat e nr_cargo.
A Figura 8.13 nos mostra o diálogo para escolha das colunas que serão incluídas na cláusula Select do comando.
Do lado esquerdo aparecem as colunas disponíveis. Observe que as colunas que possuem o mesmo nome nas duas
tabelas já aparecem prefixadas com o nome do owner (usuário) e do objeto. As demais aparecem prefixadas apenas
com o nome da tabela.
Para incluirmos uma coluna no comando Select, devemos selecioná-la no lado esquerdo e pressionar o botão Copiar.
Se quisermos retirar uma coluna da lista, devemos selecioná-la no lado direito e pressionar o botão Remover.
Se desejarmos que o comando Select seja apresentado em uma determinada ordem, devemos selecionar as colunas
na ordem desejada.
As duas colunas a serem selecionadas usando este diálogo são cd_mat e nr_cargo.
Neste diálogo existem, ainda, dois botões para auxílio na montagem da expressão:
♦ Colar Coluna – Se clicarmos neste botão será apresentada a lista das colunas para seleção; basta você selecionar
a coluna da lista e OK.
♦ Colar Func – Se clicarmos neste botão será apresenta a lista de funções de SQL que poderemos utilizar na
expressão montada.
Para efeito de teste, escreveremos então quatro expressões:
♦ Concatenação de nome e sobrenome, já explicada acima.
♦ Formatação de data de nascimento, ou seja, to_char(dt_nasc, ‘dd/mm/yyyy’).
♦ Formatação de data de admissão, ou seja, to_char(dt_adm, ‘dd/mm/yyyy’).
♦ Formatação de sexo, ou seja, decode (in_sexo, ‘F’, ‘Feminino’, ‘M’, ‘Masculino’, ‘Indeterminado’).
Para criarmos uma nova coluna sem sair deste diálogo, devemos pressionar o botão Definir. Portanto, mãos à obra.
O resultado destas quatro novas colunas está apresentado no diálogo da Figura 8.14.
Quando você fechar este diálogo observará que as quatro colunas foram acrescentadas à lista de colunas da tabela Func
(com um indicador de função do lado direito), porém não apresentam o símbolo indicativo de que estão selecionadas.
Faça um clique simples sobre a caixa de seleção correspondente de cada uma delas (passando para o estado “checado”).
Para cada “coluna definida” marcada, a coluna original, presente na expressão, também será considerada selecionada.
Antes de prosseguir, verifique novamente o comando Select montado.
Selecionamos, então, a coluna dt_nasc e pressionamos o botão Copia. Para determinar que a ordenação seja
descendente, selecionamos a coluna dt_nasc do lado direito do diálogo e marcamos a opção Descendente. Em
seguida dê OK e verifique o comando SQL.
Portanto, pressione o botão Rename Table (passe o mouse lentamente sobre a barra de ferramentas para que o
nome do botão seja apresentado).
Quando você abrir este diálogo, na janela superior aparecerá o nome da tabela para a qual você definirá o alias. Na
parte inferior do diálogo você deve escrever DP (para Depto), pressionar o botão Definir. Em seguida, selecione a
tabela Func e escolha como alias “FC”. Na parte central aparecerá o alias escolhido para cada uma das tabelas. Dê OK.
Antes de seguir, verifique novamente o comando Select. Ficou melhor, não?
Observe que na barra de ferramentas, do lado direito, diversos botões foram habilitados. Esses botões serão utilizados
para a montagem da restrição.
Nosso objetivo é incluir duas restrições:
♦ cd_mat > 20
♦ DP.cd_depto = ‘D11’
Como primeiro passo usaremos o botão Colar Coluna, da barra de ferramentas, para obter a coluna cd_mat. Em
seguida, escreveremos > 20 na linha de texto.
Para incluir a segunda restrição, pressionaremos a tecla Enter e uma nova caixa de restrição será aberta.
Como próximo passo selecionaremos a coluna cd_depto (pressione o botão Colar Coluna) e digitaremos o restante
da restrição. Quando clicarmos novamente na primeira restrição, o operador AND será acrescido (automaticamente)
para ligar as duas condições. O resultado é apresentado na Figura 8.15.
Se você desejar alterar o operador AND pelo OR ou acrescentar NOT, selecione o retângulo onde aparece o AND e
pressione o botão desejado na barra de ferramentas. Para cada teste, verifique o que aconteceu com a cláusula
Where do comando Select.
Durante os exercícios deste tópico, trabalharemos variações de montagem que nos possibilitem utilizar os demais
botões do Query Builder.
Por ora aceitaremos o diálogo. Clique OK.
Neste momento, retornaremos ao Assistente de Relatórios para prosseguir na montagem de nosso primeiro relatório.
Vamos retirar a condição de relacionamento que liga o gerente à sua matrícula para que a quantidade de linhas do
resultado seja maior.
A Listagem 8.01 nos mostra a cláusula Where resultante. Pressione o botão OK. Havendo alguma incorreção,
modifique o comando SQL adequadamente.
Siga para a próxima pasta (Campos).
CAMPOS (FIELDS)
Neste diálogo determinaremos, dentre as colunas lidas pelo comando Select, quais as que serão apresentadas no relatório.
Quando navegamos para esse diálogo, todas as colunas aparecem no campo Campos Disponíveis. Ao pressionarmos
o botão (>>) passaremos para o campo da direita (Campos Exibidos – Displayed Fields), todas as colunas apresentadas.
Se quisermos omitir alguma coluna, devemos selecioná-la e devolvê-la para o campo Campos Disponíveis (Avail-
able Fields) usando o botão (<).
No nosso caso, todas as colunas devem ser selecionadas. Seguiremos para a próxima etapa.
TOTAIS (TOTALS)
Neste diálogo estabeleceremos campos de sumário relativos às colunas selecionadas.
Escolheremos alguns totais para efeito de teste. Ao selecionarmos uma coluna do lado esquerdo um conjunto de
botões será habilitado, de acordo com o tipo (data, numérico, char, etc.) da coluna.
ETIQUETAS (LABELS)
Neste diálogo escolheremos os títulos das colunas do relatório.
Fizemos algumas alterações, não apenas nos títulos, como também na largura de determinadas colunas. Verifique
na Figura 8.16.
Navegue para o próximo diálogo.
GABARITO (TEMPLATE)
Neste diálogo veremos que o Report Builder oferece um conjunto de gabaritos predefinidos que poderemos usar e
customizar, de acordo com os padrões de nossa instalação.
Neste primeiro exemplo não utilizaremos um Gabarito (escolha, portanto, o botão de opção “Não há Gabarito”e,
em seguida, Encerrar), para que possamos analisar exatamente o resultado da montagem sem qualquer interferência.
Nos exercícios, no entanto, experimentaremos todas as opções.
Quando você aceitar este diálogo, estará encerrando a montagem do relatório. Automaticamente, entrará em
execução o Previsualizador Ativo (Live Previewer) que nos mostrará o resultado da execução do relatório.
EXERCÍCIOS
Neste primeiro tópico estudaremos como usar o Assistente de Relatórios, o resultado fornecido pelos diversos tipos
de layout, os templates disponíveis e, adicionalmente, o Query Builder para a construção dos comandos de SQL.
Sendo assim, em todos os exercícios você deve se utilizar do Assistente e do Query Builder.
Figura-resposta 8.6
COMPONENTES DE UM RELATÓRIO
Agora que já montamos diversos relatórios usando o Assistente, estudaremos em detalhes as diversas partes de que
se compõe um relatório.
Comentamos anteriormente que um relatório (desenvolvido em qualquer linguagem) sempre possui duas áreas
principais de trabalho: dados (com ou sem parâmetros) e layout.
O Report Builder possui estas áreas bem definidas, o que nos facilitará o estudo.
Fechemos, então, o relatório anterior e criemos um novo; porém, escolha a opção de criar um relatório manualmente
do menu principal ou use a opção Relatório (ctrl + N) do menu Arquivo (File), submenu Novo (New). Salve esse
relatório vazio com o nome de Data_Model1.
Observe novamente o Navegador de Objetos (verifique a Figura 8.03).
Nele, você encontra quatro ícones principais:
♦ Previsualizador Ativo (Live Previewer) – Este ícone acionará a execução do relatório para avaliação (Preview).
♦ Modelo de Dados (Data Model) – Onde desenvolveremos a parte de dados do relatório.
♦ Layout Model (Layout Model) – Onde desenvolveremos a parte de layout do relatório.
♦ Form de Parâmetros (Parameter Form) – Onde desenvolveremos a tela para solicitação dos parâmetros do relatório.
A PALETA DE FERRAMENTAS
Observe que a paleta de ferramentas à esquerda possui dez botões (passe o mouse vagarosamente sobre esses
botões para que seus nomes sejam apresentados):
♦ Selecionar (Select) – Quando este botão está pressionado, podemos selecionar qualquer objeto do diagrama.
♦ Ampliar (Magnify) – Este botão tem a finalidade de efetuar as operações de ampliação e redução.
♦ Consultar (Query) – Com este botão criaremos um objeto para especificação dos dados a serem selecionados.
Em um relatório podemos criar um ou mais objetos deste tipo.
♦ Consulta de Cursor de Ref. (PL/SQL Tool) – Esta funcionalidade é semelhante ao uso de um bloco baseado em
procedimento do Form Builder, ou seja, poderemos criar uma rotina que retorne um cursor e nosso relatório
seja baseado neste resultado.Em um relatório podemos criar um ou mais objetos deste tipo.
♦ Express Query – Na construção de um relatório poderemos escolher entre construir uma Express Query ou uma
SQL Query. No caso de Express Query, é apresentado um diálogo no qual podemos definir o banco de dados,
dimensões, etc, neste caso faremos conexão com um servidor Express.
♦ Coluna de Resumo (Summary Column) – Esta ferramenta cria colunas de sumário a serem anexadas ao relatório.
Essas colunas não estão presentes no banco de dados. São geradas a tempo de execução, baseando-se nos dados
obtidos do banco de dados pela consulta.
♦ Coluna de Fórmula (Formula Column) – Esta ferramenta cria colunas de fórmula a serem anexadas ao relatório.
Essas colunas não estão presentes no banco de dados. São definidas pelo usuário e geradas a tempo de execução,
baseando-se nos dados obtidos do banco de dados pela consulta.
♦ Coluna de Espaço Reservado (PlaceHolder Column) – Com esta ferramenta criamos uma coluna de trabalho, que
funciona como uma variável do relatório e pode ser utilizada dentro de gatilhos ou fórmulas para recepção de valores.
♦ Produto Híbrido (Cross Product) – Com esta ferramenta criaremos um relatório matricial.
♦ Ligação de Dados (Data Link) – Com esta ferramenta poderemos estabelecer uma ligação entre dois objetos Query.
A BARRA DE FERRAMENTAS
A barra de ferramentas superior possui os seguintes botões:
♦ Previsualizador Ativo (Live Previewer) – Aciona o Preview. Só possível após a montagem do layout.
♦ Modelo de Layout (Layout Model) – Aciona o Editor de Layout para que possamos modificar, criar ou apenas
visualizar o layout gerado.
♦ Form de Parâmetros (Parameter Form) – Aciona o Editor da Tela de Parâmetros para que possamos modificar,
criar ou apenas visualizar a tela de parâmetros gerada.
♦ Abrir (Open) – Abre um novo relatório.
♦ Salvar (Save) – Salva o relatório atual.
♦ Executar (Run) – Executa o relatório atual.
♦ Imprimir (Print) – Executa o relatório atual, direcionando-o para a impressora default do sistema.
♦ Limpar (Clear) – Remove o objeto atualmente selecionado.
♦ Ampliar (Zoom In) – Aumenta o nível de zoom.
♦ Reduzir (Zoom Out) – Reduz o nível de zoom.
♦ Assistente de Relatórios (Report Wizard) – Aciona o Assistente de Relatórios.
♦ Ajuda (Help) – Aciona o arquivo de ajuda para esta tela.
A BARRA DE STATUS
A Barra de Status informa o nível de zoom e a posição relativa do mouse dentro da área de desenho (tanto na
horizontal quanto na vertical).
Se você desejar, acione o Query Builder para construir o comando Select definido na Listagem 8.02.
CONSULTA (QUERY)
A consulta é a parte superior do desenho mostrado na Figura 8.17, onde encontramos o título Q_1.
Selecione a consulta e abra a tela de propriedades (use o botão direito do mouse ou a opção Paleta de Ferramentas
do menu Ferramentas ou F4 ou um clique duplo).
A paleta de propriedades apresentada possui apenas três propriedades de interesse para nós neste momento:
♦ Arquivo de Origem de Consulta Externa (External Query Source File) – Nesta propriedade determinamos o
nome de um arquivo em disco (extensão SQL) que contenha um comando de SQL Select a ser usado para
obtenção dos dados.
♦ Instrução de Consulta SQL (SQL Query Statement) – Esta propriedade contém o texto do comando SQL Select
atualmente associado a este objeto.
♦ Máximo de Linhas a Obter (Maximum Rows to Fetch) – Neste parâmetro podemos limitar a quantidade de
linhas trazidas pela consulta. Isto é especialmente útil quando a base de dados é muito extensa e desejamos
apenas testar a execução do relatório.
Em função de muitas referências dentro do Report Builder se fazerem por nome, alteraremos o nome de cada um
dos objetos que vierem a ser criados. No caso da Query, trocaremos seu nome para Qfunc (para tal, clique sobre a
propriedade Nome e altere o texto presente (Q_1) para Qfunc).
O segundo objeto de estudo é o grupo.
GRUPO (GROUP)
Para o grupo daremos a identificação de G_Detalhe. Selecione-o e obtenha a paleta de propriedades e altere seu nome.
A única propriedade a ser analisada, no momento, para o objeto é o Tipo de Filtro (Filter Type) que determinará ou
não uma condição de filtragem para as linhas selecionadas no banco de dados.
Quando determinado Nenhum (None), indicamos que todas as linhas selecionadas pela Query serão utilizadas no relatório.
Se desejarmos que apenas as N primeiras linhas sejam utilizadas, devemos escolher o valor Primeira (First) para
esta propriedade. Quando efetuamos esta escolha, uma nova propriedade é apresentada – Número de Registros
(Number of Records), onde definiremos qual o valor de N, ou seja, a quantidade de linhas iniciais da consulta a
serem utilizadas no relatório.
Se desejarmos que apenas as N últimas linhas sejam utilizadas, devemos escolher o valor Última (Last) para esta
propriedade. Quando efetuamos esta escolha, a propriedade Número de Registros (Number of Records) é apresentada
novamente para que possamos definir o valor de N, ou seja, a quantidade de linhas finais da consulta a serem
utilizadas no relatório.
Finalmente, o último valor válido para esta propriedade é PL/SQL. Nesta situação, é acrescida a propriedade Filtro
PL/SQL(PL/SQL Filter). Nesta opção deveremos escrever um texto de PL/SQL indicando se a linha lida deve ou não
ser incorporada ao relatório.
Não podemos, de forma alguma, esquecer de retornar um valor desta função (caso contrário, receberemos erro de execução).
Copie o texto de PL/SQL para sua aplicação, compile e feche o editor de PL/SQL.
Quando você retornar ao Editor, observará que imediatamente acima do grupo existe um desenho (uma bolinha
verde) identificador de filtro no grupo. Este ícone mudou de cor, indicando que esse grupo possui um filtro associado.
♦ Valor se Nulo (Value If Null) – Nesta propriedade especificamos o valor a ser apresentado no relatório se o
conteúdo desta coluna em determinada linha for Null. No nosso caso preencheremos com três hífens (---).
♦ Ordem de Quebra (Break Order) – Esta propriedade só possui interesse quando estamos trabalhando um grupo
de quebra (será visto mais adiante). No caso de um grupo simples, como é o nosso caso, esta propriedade não
tem efeito. Indicará se esta coluna deve ser apresentada em ordem ascendente ou descendente.
♦ Ler do Arquivo (Read from File) – Nesta propriedade indicaremos se o texto contido nesta coluna, na verdade,
contém um nome de arquivo que deve ser lido e apresentado no relatório no lugar do texto da coluna. Neste
primeiro exemplo, trabalharemos com Não nessa propriedade.
CRIANDO UM LAYOUT
Para a criação de um Layout que nos possibilite a impressão do relatório, acionaremos o Assistente de Relatórios
(Report Wizard), cujas pastas já conhecemos.
Verificaremos que:
♦ Na pasta Estilo, escolheremos o estilo Formato de Form.
♦ Na pasta Dados, a query já está preenchida.
♦ Na pasta Campos, as colunas não foram transferidas para exibição, o que devemos fazer agora.
♦ Não preencheremos a pasta Totais.
♦ Modificaremos os nomes dos títulos das colunas a gosto.
♦ Não usaremos Gabarito (só nos exercícios).
Ao encerrarmos o Assistente, o relatório será executado. Devemos observar as seguintes características da execução:
♦ De que departamentos foram selecionadas as linhas?
Foram selecionadas linhas do departamento D11 e D21, conforme o filtro especificado.
♦ Houve algum departamento vazio?
Não, porque o comando no filtro somente autoriza departamentos que comecem com ‘D’.
♦ O relatório está ordenado por alguma coluna?
Não. Embora a especificação Ordem de Quebra esteja preenchida com Ascendente para todas as colunas deste
grupo, a ordenação não ocorre porque esta propriedade só é aplicável ao grupo de quebra.
♦ Quantos registros foram apresentados por página?
Apenas um registro é apresentado por página quando o estilo do relatório é Formato de Form (ou formulário).
Salve o relatório atual para que possamos fazer um novo teste.
Retorne ao Editor (clique duplo no ícone correspondente no Navegador ou F2 ou a opção Editor de Relatório do
menu Ferramentas – Tools).
Desejamos, agora, que nosso relatório grupe os dados relativos ao mesmo departamento. Para tal, devemos indicar
para o Report Builder que usaremos a coluna cd_depto para identificar a quebra. Antes, porém, observemos que o
nome do grupo foi modificado. Quando acionamos o assistente de relatório, ele modifica o nome do grupo (não
modifica o da Query).
Nosso primeiro passo será criar um grupo de quebra. Para realizar esta ação, clique sobre a coluna cd_depto e, sem
soltar o botão do mouse, arraste-a para cima, para fora do grupo.
A Figura 8.18 nos mostra o resultado da ação realizada anteriormente. Este desenho indica que os dados serão apresentados
em ordem de departamento e, quando houver uma alteração no departamento, será realizada uma ação de quebra.
Neste caso, a propriedade Ordem de Quebra (Break Order) tem efeito para a coluna cd_depto. Criaremos o layout do
relatório e executaremos para ver o resultado. Teste posteriormente para ordenação Descendente e verifique o resultado.
A propriedade Ordem de Quebra (Break Order) só é utilizada pelo Report Builder em um grupo de quebra. ela indica acoluna ou as colunas de
quebra e a ordem com que os dados devem ser apresentados.
Acione o Assistente de Relatórios (Reports Wizard) e escolha como estilo Agrupar à Esquerda. As demais pastas
você já tem condições de escolher sozinho. Observe o aparecimento da pasta Grupos (Groups), que nos mostra
quais as colunas presentes em cada um dos grupos de quebra (no nosso caso, só temos uma).
Ao encerrarmos o Assistente, o relatório será executado. Devemos observar as seguintes características da execução:
♦ Por que todos os códigos de departamento foram apresentados?
Isto ocorreu porque o filtro está posicionado no bloco-detalhe; sendo assim, a linha é obtida do banco de dados, é
montada a informação do grupo de quebra e, na hora de montar a informação do grupo detalhe, ocorre a filtragem.
♦ Por que não foram apresentadas linhas para os outros departamentos?
Justamente por causa do filtro. Para contornar esta situação, isto é, para que não sejam mostrados nem mesmo os
códigos de departamento, devemos colocar o filtro no grupo de quebra. Para tal, retorne ao Editor, selecione o filtro
do grupo detalhe e copie o texto da função (só o texto entre o Begin e o End). Remova o filtro, clicando no botão
Delete da janela do editor de PL/SQL. Na paleta de propriedades, defina que o Tipo de Filtro (Filter Type) é Nenhum
(None). A seguir, abra a tela de propriedades do grupo de quebra, troque o tipo de filtro para PL/SQL, pressione o
botão da propriedade associada e, quando o editor de PL/SQL for acionado, cole o texto do filtro no local adequado.
Na Figura 8.19 apresentamos o resultado esperado.
Observe que os demais departamentos não são mais apresentados e todas as linhas de cada departamento aparecem
seguidas umas em relação às outras.
Salve esta aplicação. Iniciaremos uma outra usando um novo objeto, o Link.
RELACIONANDO DADOS
Neste exemplo criaremos um Link para relacionar duas queries.
Feche o relatório anterior. Abra um novo e salve-o com o nome de Data_Model3. Navegue para o Modelo de Dados
(clique duplo no ícone correspondente no Navegador ou F2 ou a opção Editor de Relatórios do menu Ferramentas).
Use a ferramenta SQL Consultar (Query) para criar o comando SQL Select apresentado na Listagem 8.04.
Crie uma segunda query com o comando de SQL Select apresentado na Listagem 8.05.
Observe na Figura 8.20 que os grupos receberam, automaticamente, o nome do primeiro campo selecionado na
Query precedido de “Q_”. Uma vez que o Report Builder não trabalha com qualificação (como ocorria com o Form
Builder em relação a item e bloco), quando incluímos em Queries distintas colunas com o mesmo nome, o próprio
Report trata de fazer a substituição dos nomes iguais, acrescentando um número seqüencial à coluna duplicata. O
mesmo ocorre para o nome do grupo.
Iniciaremos nossos testes montando um layout para estes dados e executando o relatório.
Acione, portanto, o Assistente de Relatórios (Report Wizard). Na pasta Estilo, escolha Tabular. Na pasta Grupos,
escolha Vertical para ambos. Observe que os grupos não estão relacionados, são independentes. Na pasta Campos,
selecione todos. Aumente o tamanho do nome do departamento para 40. Não anexe gabarito.
Execute a aplicação. Observe que todas as linhas de Departamento foram apresentadas primeiro com o layout
Tabular, seguidas de todas as linhas de Funcionário, também apresentadas no formato Tabular.
Não existe nenhuma ligação entre os dados das duas queries. A ordem de apresentação dos grupos foi definida em
função da ordem das queries no Editor. A query mais à esquerda foi definida primeiro no Layout Model e a query
mais à direita foi definida em seguida.
Se você desejar fazer um teste a mais, retorne ao Modelo de Dados e troque a ordem dos objetos. Arraste-os,
trocando-os de lugar, ou seja, coloque a Query de Funcionário mais à esquerda e a de Departamento mais à direita.
Em seguida remova o layout criado (este passo é indispensável). Para tal, entre no menu Exibir (View) e escolha
Modelo de Layout (Layout Model). Quando o layout for apresentado, escolha a opção Selecionar Todos (Select All)
do menu Editar (Edit). Em seguida, use a tecla Delete para que todos os objetos sejam removidos. Acione o Assistente
novamente, preencha as pastas adequadamente e execute o relatório.
Nesta situação todos os funcionários são apresentados primeiro. Em seguida, todos os departamentos.
Prossigamos, então, retornando ao Modelo de Dados.
Desejamos, agora, que os dados se relacionem, ou seja, que para cada departamento sejam apresentados os
funcionários correspondentes.
A ferramenta Ligação de Dados (Data Link) permite a montagem desta ligação de três formas:
♦ De Query para Query – Devemos clicar inicialmente na ferramenta Ligação de Dados (Data Link), em seguida na
query-pai e, sem soltar o botão do mouse, arrastá-lo até a query-filha. O Report Builder pesquisará no banco de
dados os relacionamentos existentes entre as duas tabelas envolvidas e estabelecerá a ligação baseado no que for
encontrado no banco de dados.
♦ De Grupo para Grupo – Devemos clicar inicialmente na ferramenta Ligação de Dados (Data Link), em seguida
no grupo-pai e, sem soltar o botão do mouse, arrastá-lo até o grupo-filho. Neste caso, o Report Builder estabelecerá
a ligação apenas em relação ao grupo, independente das colunas presentes em cada um deles. Para cada linha do
grupo-pai, todas as linhas do grupo-filho serão associadas.
♦ De Coluna para Coluna – Devemos clicar inicialmente na ferramenta Ligação de Dados (Data Link), em seguida
na coluna-pai e, sem soltar o botão do mouse, arrastá-lo até a coluna-filha (esta operação deve ser repetida para
todas as colunas que se relacionarem entre as duas queries – chave composta). O Report Builder agirá, agora, em
relação às colunas envolvidas. Cada vez que a coluna da query-pai mudar de valor, um novo conjunto de linhas
na query-filha será selecionado.
Neste primeiro exemplo, devemos relacionar os dois conjuntos através das queries; portanto clique na ferramenta
Ligação de Dados (Data Link), em seguida na query Q_Depto e, sem soltar o botão esquerdo do mouse, arraste-o
até a query Q_Func. O resultado obtido está na Figura 8.21. Se seu desenho não ficou igual, verifique se a query
Q_Depto está mais à esquerda. Se não estiver, basta mover os objetos de posição.
Acionaremos, a seguir, o Assistente. Escolheremos estilo Agrupar Acima (Group Above). As demais pastas não
precisam ser preenchidas, pois já o estão. Observe a diferença de resultado na execução deste relatório.
Salve este relatório e abra um novo. Testaremos, agora, a criação de uma query baseada em um Cursor.
VARIÁVEL CURSOR
Na paleta de ferramentas do Modelo de Dados podemos observar um botão (além daquele associado à Query) chamado
Consulta de Cursor de Ref. Este botão dará origem a uma query também, porém recebida de uma variável cursor.
Esta funcionalidade é semelhante ao uso de um bloco baseado em procedimento do Form Builder, ou seja, poderemos
criar uma rotina que retorne um cursor e nosso relatório seja baseado neste resultado.
Para analisarmos esta questão, criaremos um relatório vazio (Data_Model4) e definiremos uma especificação de
pacote no banco de dados, conforme apresentado na Listagem 8.06.
Com esta definição criamos o tipo cursor e especificamos o tipo de retorno associado aos cursores deste tipo.
Em seguida, no Modelo de Dados criaremos uma consulta baseada em cursor. Quando soltarmos o mouse sobre a
área gráfica do editor, será acionado o editor de PL/SQL para que façamos o preenchimento da função apresentada.
Definimos um pequeno exemplo, apresentado pela Listagem 8.07 a seguir.
Quando compilarmos e fecharmos esta função o Data Model assumirá o aspecto apresentado pela Figura 8.22, o
que nos permitirá a montagem do layout normalmente.
Use o Assistente de Relatórios para a montagem do Layout, execute-o e veja o resultado.
O manuseio desta coluna de ordenação é feita com a ferramenta Sort. Esta coluna é visível no modelo de dados e
no navegador, porém não é visível através dos Assistentes (de Dados e do Relatório), nem no Layout ou no
Previsualizador Ativo.
Uma vez que não estamos estudando o Oracle Express, interromperemos a seqüência de análise deste desenvolvimento.
Ficamos, apenas, com a informação de que o Report Builder é capaz de desenvolver relatórios para o produto
Oracle Express, certamente conhecido dos desenvolvedores para Data Warehouse.
Nosso próximo passo será a realização dos exercícios do tópico para que possamos testar outras características do
Modelo de Dados.
EXERCÍCIOS
Neste tópico estaremos focando o Editor do Modelo de Dados, e portanto criaremos os grupos, os relacionamentos
entre queries manualmente. Só o layout deve ser criado com o uso do Assistente.
♦ Colunas Nome e Sobrenome concatenadas, matrícula, data de admissão (formatada), salário (formatado) e foto
do funcionário da tabela Func.
♦ Colunas Nome do Departamento da tabela Depto.
♦ O relacionamento entre as tabelas deve ser feito com o uso de um Join pelo código do gerente.
♦ Utilize o layout Form.
♦ Fornecer nomes adequados para os títulos de coluna.
♦ Utilizar o gabarito Corporate1 Landscape.
8.10) Criar um relatório de nome REP10 com as seguintes características:
♦ Todas as colunas da tabela Func e da tabela Depto.
♦ O relacionamento entre as tabelas deve ser feito com o uso de um link pela coluna cd_depto.
♦ Estabeleça uma restrição para que sejam fornecidos apenas os funcionários com salário maior que R$ 2.000,00.
♦ Formato Agrupar Acima.
♦ Fornecer nomes adequados para os títulos de coluna.
♦ Utilizar o gabarito Confidential Background Landscape.
SUMÁRIOS
Um sumário é um cálculo executado em relação a diversas linhas de uma única coluna. Por exemplo, um somatório
de salários, uma média salarial, um total de gastos, etc.
O Report Builder oferece um conjunto de funções que nos possibilitam criar diversas operações de sumarização.
Como sempre, estudaremos este assunto através de um exemplo. Abra, portanto, o exemplo Data_Model2 e salve-
o com o nome de Data_Model5.
Abra o Modelo de Dados e observe que nesse exemplo temos um grupo de quebra contendo o código do
departamento e um grupo de detalhe contendo a matrícula, o nome e o salário do funcionário.
Por outro lado, se incluirmos uma coluna qualquer no grupo de detalhe, ela será impressa cada vez que as colunas
Matrícula, Nome e Salário forem impressas.
Antes de prosseguirmos nosso estudo com os sumários, façamos um teste. Alteremos o comando de SQL Select
para que inclua dois valores constantes: ‘quebra’, apelidado de GQ e ‘detalhe’, apelidado de GD.
Para tal, efetue um clique duplo na Query; na pasta de propriedades apresentada, selecione a propriedade Instrução
de Consulta SQL (SQL Query Statement) e modifique manualmente o comando Select.
Observe o resultado na Listagem 8.08. Dê OK e retorne ao modelo de dados. Arraste a coluna GQ para o grupo Quebra.
O resultado deve ser similar ao da Figura 8.24. Como detalhe adicional, observe que a coluna GQ está marcada
com uma seta do lado esquerdo. Isto significa que, se seu valor for diferente, ela estará determinando a quebra.
Neste nosso caso, isto não vai acontecer, pois seu valor será igual em todas as linhas.
A indicação de coluna de quebra (seta do lado esquerdo) somente tem utilidade no grupo de quebra. No grupo de detalhe esta informação é ignorada.
Entre, agora, no Assistente, gere um novo layout (agrupar à esquerda) e execute este relatório. O que você concluiu?
Na nossa execução, a coluna GQ (‘quebra’) foi impressa duas vezes, enquanto a coluna GD (‘detalhe’) foi impressa
diversas vezes (quinze, no meu caso). Isto ocorre em função da freqüência de impressão.
Se você tiver entendido este conceito, não terá dificuldades de determinar o posicionamento das colunas de sumário
que definiremos a seguir.
O primeiro passo para criarmos uma coluna de sumário é determinar sua freqüência de impressão; portanto, de
acordo com o tipo de sumário definido a seguir, determine seu posicionamento no diagrama. Confira o resultado
na Figura 8.25 (mas tente fazer sozinho). Utilize o botão Coluna de Resumo (Summary Column) presente na paleta
de ferramentas do Modelo de Dados (Data Model).
♦ Total de salários por departamento (Tot_Sal_Dep) – somente deverá ser impresso uma vez para cada departamento.
♦ Quantidade de funcionários por departamento (Qtd_Fun_Dep) – somente deverá ser impresso uma vez para
cada departamento.
♦ Média salarial por departamento (Avg_Sal_Dep) – somente deverá ser impresso uma vez para cada departamento.
♦ Total de salários da empresa (Tot_Sal_Emp) – somente deverá ser impresso uma vez para todo o relatório.
♦ Quantidade de funcionários da empresa (Qtd_Fun_Emp) – somente deverá ser impresso uma vez para todo o relatório.
♦ Maior salário da empresa (Max_Sal_Emp) – somente deverá ser impresso uma vez para todo o relatório.
♦ Percentual de cada salário em relação ao departamento (Pct_Sal_Dep) – deverá ser impresso uma vez para cada funcionário.
♦ Percentual de cada salário em relação à empresa (Pct_Sal_Emp) – deverá ser impresso uma vez para cada funcionário.
♦ Acumulado de cada salário em relação ao departamento (Acm_Sal_Dep) – deverá ser impresso uma vez para
cada funcionário.
♦ Acumulado de cada salário em relação à empresa (Acm_Sal_Emp) – deverá ser impresso uma vez para cada funcionário.
Observe que os totais relativos à empresa não ficam posicionados dentro dos grupos uma vez que sua freqüência
de impressão é única ao final de todo o relatório.
Os percentuais, apesar de serem calculados em relação ao departamento e à empresa, devem ser impressos com a
mesma freqüência de impressão do registro de funcionário uma vez que cada salário terá um valor de percentual
diferente em relação à empresa e em relação ao departamento.
Os acumulados correspondem a totais em que visualmente acompanhamos a soma, isto é, cada vez que um novo
salário é acrescentado visualizamos o resultado do acumulado. Por este motivo, o acumulado de salários em relação
ao departamento foi apresentado na freqüência do funcionário. O acumulado em relação à empresa poderia ser
feito em relação ao funcionário ou em relação ao departamento. Eu escolhi manter no nível de funcionário.
Apenas nos totais da empresa (Total e Quantidade) poderíamos utilizar como origem (source) os sumários de
departamento ou a coluna vl_sal (o resultado é o mesmo). A diferença se dá na freqüência com que a operação de
soma será calculada: a cada linha ou apenas na quebra. Se pudermos utilizar como origem (source) uma coluna
que tenha uma freqüência de impressão menor, a operação será feita menos vezes e, portanto, haverá algum
ganho de performance. Por enquanto não se preocupe com performance. O entendimento é agora mais importante.
Usaremos, neste exemplo, vl_sal como origem para todos os sumários.
♦ Percentual de cada salário em relação à empresa (Pct_Sal_Emp). Função: % do Total (% of Total). Zerar a cada
funcionário: no grupo G_cd_mat.
♦ Acumulado de cada salário em relação ao departamento (Acm_Sal_Dep). Função: Soma (Sum). Zerar no grupo
G_cd_depto.
♦ Acumulado de cada salário em relação à empresa (Acm_Sal_Emp). Função: Soma (Sum). Zerar no fim do
relatório: Report.
Observe que no nosso exemplo criamos um Percentual de cada salário em relação ao departamento (Pct_Sal_Dep),
porém até agora não informamos ao Report Builder que a sumarização deveria ser feita em relação ao departamento,
ou seja, em relação ao total de salários do departamento.
Esta informação é dada através da propriedade Computar (Compute At).
No nosso caso, teríamos:
♦ Percentual de cada salário em relação ao departamento (Pct_Sal_Dep). Função: % do Total (% of Total). Zerar a
cada funcionário: no grupo G_cd_mat. Computar: no grupo G_cd_depto.
♦ Percentual de cada salário em relação à empresa (Pct_Sal_Emp). Função: % do Total (% of Total). Zerar a cada
funcionário: no grupo G_cd_mat. Computar: Report.
Nosso próximo passo será acionar o assistente (com layout Agrupar Acima) e executar este relatório.
Vamos verificar se existem funcionários sem salários na base de dados (se não houver, inclua alguns para que você
verifique o que ocorre no resultado).
Apesar de termos forçado esta situação, não houve problemas com o cálculo dos somatórios, dos percentuais, da
média, dos totais por departamento. Isto ocorre porque, como sabemos de nosso estudo no SQL, as linhas com
Null não participam das funções de grupo.
No entanto, esta situação causa um erro relativamente aos totais de quantidade. O resultado dos sumários
“Quantidade de funcionários por departamento” e “Quantidade de funcionários da empresa” está incorreto. Como
utilizamos uma coluna que admite Null como origem (source), os funcionários sem salário não foram computados
na quantidade de funcionários.
Para corrigir esta situação, a melhor coluna a ser utilizada como origem (Source) da quantidade de funcionários
(em ambos os níveis) é a coluna cd_mat, que por ser PK está preenchida em todas as linhas.
FÓRMULAS
Uma fórmula é um cálculo que envolve uma ou mais colunas de um mesmo registro. Uma fórmula corresponde a uma
função de PL/SQL que retorna um valor. Desta forma, uma variável do tipo fórmula retornará o resultado do cálculo.
Suponhamos, então, para a montagem de nosso exemplo que desejássemos calcular as seguinte informações:
♦ FGTS para cada funcionário (Fgts_Func).
♦ INSS para cada funcionário (Inss_Func).
♦ Ticket-alimentação para cada funcionário (Ticket_Func).
♦ Projeto em que o funcionário está alocado (Proj_Func).
♦ Projetos do Departamento (Proj_Depto).
Para não confundirmos com o exemplo anterior, criaremos um novo relatório Data_Model6, partindo da mesma
Query do Data_Model5, porém sem os sumários anteriores.
Como regra para utilização das colunas selecionadas na fórmula, temos que:
♦ Podemos mencionar qualquer coluna que esteja na mesma freqüência de impressão.
♦ Podemos mencionar qualquer coluna que esteja em uma freqüência de impressão menor, ou seja, de um grupo
acima daquele onde se encontra a fórmula.
No nosso caso temos que:
♦ Se a fórmula foi criada no nível de Funcionário, poderá mencionar as colunas presentes no próprio nível de
Funcionário ou no nível da quebra (Departamento) ou no nível do relatório (fora dos grupos).
♦ Se a fórmula foi criada no nível de Departamento, poderá mencionar as colunas presentes no próprio nível de
Departamento ou no nível do relatório (fora dos grupos).
As fórmulas a serem utilizadas são:
♦ FGTS para cada funcionário (Fgts_Func). Numérico. Tamanho: 7,2. Fórmula: 0.1 * :vl_sal.
♦ INSS para cada funcionário (Inss_Func). Numérico. Tamanho: 7,2. Fórmula: 0.08 * :vl_sal.
Ticket-alimentação para cada funcionário (Ticket_Func). Numérico. Tamanho: 7,2. Fórmula: dia_útil* 5.00.
♦ Projeto em que o funcionário está alocado (Proj_Func). Alfanumérico. Tamanho: 6. Fórmula: obter o projeto
que tenha um responsável com a matrícula mais próxima da matrícula do funcionário e no mesmo departamento.
return cod_projeto;
end if;
end;
♦ Projetos do Departamento (Proj_Depto). Alfanumérico. Tamanho: 40. Fórmula: obter todos os códigos de projeto
desse departamento.
EXERCÍCIOS
Neste grupo de exercícios trabalharemos com os sumários e fórmulas; portanto, não devemos utilizar o Assistente
para a montagem destas colunas no Modelo de Dados.
8.11) Criar um relatório de nome REP11 com as seguintes características (utilize o Assistente para a montagem dos totais):
♦ Todas as colunas da tabela Func.
♦ Crie os seguintes sumários:
a) Total de funcionários.
b) Total de salários.
c) Média salarial.
d) Maior cargo.
e) Menor grau de instrução.
♦ Formato Tabular.
♦ Gabarito Confidential Background.
8.12) Criar um relatório de nome REP12 semelhante ao REP11, porém sem a utilização do Assistente de Relatório:
♦ Todas as colunas da tabela Func.
♦ Crie os seguintes sumários:
a) Total de funcionários.
b) Total de salários.
c) Média salarial.
d) Maior cargo.
e) Menor grau de instrução.
♦ Utilize o formato Tabular.
♦ Utilize o gabarito Cyan Grid.
8.13) Criar um relatório de nome REP13 com as seguintes características (não utilize o Assistente na montagem dos sumários):
♦ Todas as colunas da tabela Func e da tabela Depto.
♦ O relacionamento entre as tabelas deve ser feito com o uso de um join pela coluna cd_depto.
♦ Crie os seguintes sumários:
a) Total de funcionários por departamento.
b) Total de funcionários geral.
c) Total de salários por departamento.
d) Total de salários geral.
e) Média salarial por departamento.
f) Percentual do salário do funcionário em relação do departamento.
g) Percentual do salário do funcionário em relação à empresa.
h) Percentual do total salarial do departamento em relação à empresa.
i) Maior cargo por departamento.
j) Maior cargo da empresa.
k) Menor grau de instrução por departamento.
l) Menor grau de instrução da empresa.
♦ Formato Agrupar Acima.
♦ Gabarito Corporate 2.
8.14) Criar um relatório de nome REP14 com as seguintes características (não utilize o Assistente na montagem dos sumários):
♦ Selecione as colunas cd_mat, nm_func, vl_sal e cd_depto da tabela Func e as colunas cd_depto e nm_depto da
tabela Depto.
♦ O relacionamento entre as tabelas deve ser feito com o uso de um link pela coluna cd_depto.
♦ Crie as seguintes fórmulas:
CONCEITUAÇÃO
Neste tópico trataremos de dois assuntos relacionados: dos parâmetros e da tela de parâmetros.
Os parâmetros são variáveis para as quais associamos valores a tempo de execução, isto é, são “Containers” de
dados. Por este motivo estão subordinados ao Modelo de Dados.
Observe, no Navegador de Objetos (Object Navigator), que existem dois nós associados a parâmetros: Parâmetros
de Sistema (System Parameters) e Parâmetros de Usuário (User Parameters).
PARÂMETROS DE SISTEMA
Os parâmetros de sistema são variáveis predefinidas associadas a todas as aplicações de relatório.
Estão associados a ações específicas, que conheceremos a seguir:
BACKGROUND
Este parâmetro indica se o relatório deve ser executado em background. O valor Yes não é suportado pelo Report
Builder (usando o Preview), apenas pelo Runtime.
Os valores válidos são: Yes ou No (default).
COPIES
Este parâmetro determina o número de cópias do relatório. Será ignorado se o destino não for impressora.
Os valores válidos variam de 1 a 9.999.
O valor default é 1.
CURRENCY
Este parâmetro determina o símbolo a ser usado como símbolo financeiro para formatos numéricos.
O valor default para este parâmetro é dado pela NLS em uso.
DECIMAL
Este parâmetro determina o símbolo a ser usado como caracter decimal para formatos numéricos.
O valor default para este parâmetro é dado pela NLS em uso.
DESFORMAT
Este parâmetro possui dois significados diferentes:
♦ Em ambientes BitMap, especifica o driver da impressora a ser usado quando o destino (DesType) é arquivo.
♦ Em ambientes Caracter, especifica as características da impressora cujo nome é dado pelo parâmetro DesName.
Esse parâmetro é ignorado se o destino for vídeo.
Alguns dos valores válidos são: hpl, hplwide, dec, decwide, decland, dec180, deflt, wide, pdf, html, htmlcss, htmlcssie,
rtf, xml, delimited.
Quando escolhemos como formato PDF, estamos indicando que o arquivo gerado poderá ser lido por um software
similar ao Adobe Acrobat Reader. As características do arquivo serão determinadas pelo driver de impressora
atualmente selecionado. Deve existir um driver de impressora configurado e selecionado na estação para que seja
possível a geração do arquivo.
Quando escolhemos HTML, estamos indicando que o arquivo gerado poderá ser lido por um browser que seja
compatível com o formato HTML 3.0 (por exemplo, Netscape 2.2).
Quando escolhemos HTMLCSS, estamos indicando que o arquivo gerado poderá ser lido por um browser que seja
compatível com o formato HTML 3.0 que suporte Cascading Style Sheets. Já o valor HTMLCSSIE indica que o
relatório incluirá Style Sheets que podem ser lidos pelo Microsoft Internet Explorer 3.x, especificamente.
O valor RTF formata o arquivo de saída de tal forma que possa ser lido por um processador de texto (como o
Microsoft Word).
Quando escolhemos XML indicamos que o relatório de saída será um documento XML. Este relatório pode ser
aberto e lido por um browser que suporte XML ou por uma aplicação qualquer que suporte esta extensão.
Finalmente, DELIMITED indica que a saída do relatório poderá ser lida por um utilitário “spreadsheet” como por
exemplo o Microsoft Excel.
O valor default para este parâmetro é obtido da propriedade valor inicial. Se não houver valor inicial ou for dflt, o driver
da impressora atualmente selecionado é usado. Se não houver uma impressora selecionada, PostScript é o default.
DESNAME
Neste parâmetro informamos o nome do arquivo, nome da impressora, email ID (ou lista de distribuição) para
onde o relatório será enviado.
Este parâmetro será ignorado se o destino for vídeo.
Se o destino for Preview, o Report Builder se utiliza desse parâmetro para determinar o tipo de fonte a ser usado
para apresentação do resultado.
Se o destino for arquivo e este parâmetro estiver vazio, o nome default para o arquivo gerado será <nome do relatório>.lis.
DESTYPE
Este parâmetro determina o destino do relatório em execução.
Os valores válidos são: screen, file, printer, preview, sysout ou mail.
O valor Screen direciona a saída para o Previewer, assim como o valor Preview. A opção Preview gerará a formatação
como PostScript.
A opção Sysout não é válida para execução pelo Report Builder. Somente podemos usá-la com o Runtime quando
o parâmetro Batch (da linha de comando do Runtime) receber o valor Yes.
MODE
Indica se o relatório terá formato gráfico (BitMap) ou formato caracter (character mode). Se no ambiente Windows
especificarmos Mode=Character, será acionado o driver ASCII para que seja produzida uma saída compatível.
Os valores válidos para este parâmetro são: Bitmap, Character ou Default.
O valor Default (que é o default) indica que o modo do relatório deve ser compatível com o executável em uso.
ORIENTATION
Este parâmetro determina a direção de impressão das páginas do relatório.
O valor Default (que é o default) indica que a direção de impressão será determinada pela orientação que estiver
especificada para a impressora.
PRINTJOB
Este parâmetro determina se deve ou não ser apresentado o diálogo de Print Job antes da execução do relatório.
Esse diálogo permite que o usuário imprima parte do relatório, determine a impressora, número de cópias, etc.
Os valores válidos para esse parâmetro são: Yes (default) e No.
THOUSANDS
Este parâmetro determina o símbolo a ser usado como separador de milhar para formatos numéricos.
O valor default para esse parâmetro é dado pela NLS em uso.
Durante os exercícios deste tópico, utilizaremos os parâmetros predefinidos para verificar as diferenças de resultado.
PARÂMETROS DE USUÁRIO
Os parâmetros de usuário são variáveis criadas na aplicação que podem ser utilizadas em qualquer ponto do relatório.
Seu uso mais comum é a restrição de linhas a serem selecionadas por alguma das queries definidas no relatório.
Existem duas formas de referenciarmos os parâmetros na aplicação: Bind e Lexical.
Estudaremos, inicialmente, a forma Bind.
BIND REFERENCE
Uma referência do tipo Bind é usada para substituição de um valor em uma expressão SQL ou PL/SQL. É muito comum
sua utilização nas cláusulas Select, Where, Group By, Order By, Having, Connect By e Start With da query do relatório.
Esse tipo de referência não pode ser usado na cláusula From ou em substituição a palavras reservadas. Sua utilização
é feita com os dois-pontos precedendo o nome do parâmetro na cláusula escolhida.
Façamos um teste para melhor entendimento.
Salve seu módulo Data_Model6 como Data_Model7, retire todas as variáveis de fórmula e qualquer filtro de grupo
que ainda reste na aplicação. Em seguida, salve-a.
Abra a query da aplicação e inclua a cláusula Where apresentada na Listagem 8.14.
Quando clicarmos no botão OK, a mensagem apresentada na Figura 8.28 será mostrada, indicando que o Report
Builder criou o parâmetro mencionado na sintaxe da Query QFunc.
Ao retornarmos para o Navegador, veremos que foi adicionado um parâmetro no nó Parâmetros de Usuário
(User Parameters).
A criação automática do parâmetro não nos exime da tarefa de verificar as características do parâmetro gerado;
portanto, dê um clique duplo (ou use o botão direito do mouse) para obter a tela de propriedades desta variável.
Observe que o tipo do parâmetro é caracter e o tamanho é 40. Apesar de o tipo ser compatível com o tipo da coluna
cd_depto, o tamanho foi determinado de forma independente do comprimento da coluna. Alteremos seu tamanho
para 3 e faremos nossa primeira execução para descobrir onde o parâmetro é solicitado.
A tela de parâmetros apresentada na Figura 8.29 é construída automaticamente pelo Report Builder quando execu-
ta um relatório que possui parâmetros e não encontra a tela de parâmetros correspondente.
LISTA DE VALORES
Suponhamos, agora, que nosso usuário, além de poder escrever o valor do parâmetro, poderá selecionar o valor de
uma lista predefinida.
Para tal, retornemos às propriedades do parâmetro e selecionemos a propriedade Lista de Valores (List of Values).
O diálogo da Figura 8.30 mostra que podemos montar os valores para a lista de duas formas: fornecendo valores estáticos
(static values) ou fornecendo um comando Select (Select Statement) que obtenha os valores do banco de dados.
Preencheremos o campo Valor (Value) com o texto D11 e, em seguida, pressionaremos o botão Adicionar >>(Add>>).
Repetiremos esta operação para os valores D21, E21, E11 e A00.
No canto superior esquerdo encontramos um check box com o texto: Restringir Lista a Valores Predeterminados
(Restrict List to Predetermined Values). Isto significa que a tempo de execução o usuário não poderá digitar outro
valor, somente escolher um dos valores da lista. Como este não é o nosso desejo, desmarcaremos essa opção.
Para encerrar, clique em OK e execute a aplicação.
Escolha um dos parâmetros e veja o resultado. Em seguida, execute novamente e preencha o parâmetro com B01
e veja o resultado.
Retornemos, então, à propriedade Lista de Valores (List of Values), com a intenção de apresentar para o usuário
não mais o código do departamento, mas sim o nome do departamento. Neste caso, escolheremos uma lista de
valores baseada na Instrução Select.
No diálogo apresentado, preencheremos o campo Instrução de Consulta de SQL com o texto da Listagem 8.15.
Observe que no comando Select definido incluímos duas colunas: cd_depto e nm_depto.
A primeira coluna definida no comando Select é sempre atribuída ao parâmetro. Desta forma, se o usuário escolher
a terceira linha da lista de valores, o código do departamento desta linha será atribuído ao parâmetro P_Depto,
mesmo que esse código não fique visível.
No canto superior direito deste diálogo temos dois check boxes que nos indicam:
♦ Restringir Lista a Valores Predeterminados (Restrict List to Predetermined Values) – Quando marcamos esta
opção, o usuário somente poderá selecionar um dos valores da lista. Não poderá efetuar nenhuma digitação.
♦ Ocultar Primeira Coluna (Hide First Column) – Quando marcamos esta opção, indicamos que na lista de valores
apresentada não será mostrado o valor da primeira coluna. Desta forma, o usuário verá o nome do departamento,
porém estaremos obtendo para o parâmetro o código do departamento.
Façamos, a seguir, a execução da aplicação com estas (ambas) condições marcadas e vejamos o resultado na Figura 8.31.
Inicialmente, verifique que não podemos digitar no campo P_Depto, somente escolher um valor da lista. Também
não temos visibilidade do código. Outra questão é que a largura da lista não é suficiente para que todo o texto do
parâmetro seja apresentado.
As duas primeiras situações foram provocadas por nós através das opções Restringir Lista a Valores Predeterminados
(Restrict List to Predetermined Values) e Ocultar Primeira Coluna (Hide First Column). A outra situação foi provocada
pelo fato de o Report Builder construir a tela de parâmetro automaticamente. Só poderemos contornar esta situação
quando pudermos construir nossa própria tela, o que será visto ainda neste tópico.
LEXICAL REFERENCE
Outra forma de fazermos referência a um parâmetro dentro do comando SQL Select é chamada de léxica, porque
podemos alterar o texto do comando Select a ser enviado para o banco de dados.
Suponhamos, então, que desejássemos que a ordenação da consulta fosse feita ora por matrícula, ora por nome e
ora por salário, de acordo com um parâmetro informado.
Para realizar este teste, salve sua aplicação com o nome de Data_Model8.
Usaremos um parâmetro com o nome de P_Order, do tipo caracter e com comprimento de 40 bytes. Você poderá
criá-lo pelo Navegador ou se utilizar do mesmo estratagema anterior, isto é, mencioná-lo no comando Select da
Query e deixar que o Report Builder crie-o automaticamente para você.
No caso de uma referência léxica, a sintaxe a ser utilizada no comando Select é diferente daquela usada na referência
Bind. Veja a Listagem 8.16.
Neste caso, estamos informando ao Report Builder que haverá uma alteração na sintaxe do comando Select a ser
enviado para o banco de dados.
Para que o usuário possa decidir qual a melhor ordem para o resultado, criaremos uma lista estática com os valores:
matrícula, nome e salário.
Quando você selecionar a propriedade Gatilho de Validação (Validation Trigger), será acionado o editor de PL/
SQL, contendo uma função boleana. Como esse gatilho é de validação, isto significa que poderíamos efetuar uma
crítica no valor do parâmetro recebido e desejar que o usuário voltasse a digitá-lo. Por este motivo o gatilho é
boleano. Se a informação digitada pelo usuário estiver correta, devemos retornar True, caso contrário, False, o que
fará com que a tela de parâmetros seja apresentada novamente para as devidas correções.
O texto que escrevemos não necessita deste recurso, porque o usuário não tem a possibilidade de informar um
valor inválido. Portanto, digite o texto e execute a aplicação.
Selecione a opção Criador de Form de Parâmetros (Parameter Report Builder) no menu Ferramentas (Tools).
Ele apresentará o diálogo da Figura 8.33.
Na lista apresentada, estão presentes todos os parâmetros existentes na aplicação, sejam parâmetros de usuário ou
parâmetros de sistema.
Se clicarmos sobre o nome do parâmetro, um retângulo em volta do nome ficará em preto (veja o parâmetro
P_Depto na Figura 8.33), indicando que esse parâmetro será selecionado e montado na tela gerada.
Ao lado de cada parâmetro, aparece um campo (Etiqueta – Label) em que podemos definir um texto que será
colocado lateralmente ao parâmetro na execução.
No nosso caso, selecionaremos os parâmetros DesType e P_Depto. Para o parâmetro P_Depto preencheremos a
coluna Etiqueta (Label) com o texto Departamento.
Ainda temos, neste mesmo diálogo, possibilidade de escrever três outros textos aplicáveis à tela como um todo:
Título (Title), Linha de Dicas (Hint Line) e Linha de Status (Status Line).
Preencheremos com os seguintes textos:
♦ Título (Title) – Parâmetros do Relatório.
♦ Linha de Dicas (Hint Line) – Preencha adequadamente.
♦ Linha de Status (Status Line) – O preenchimento é obrigatório.
Quando você clicar em OK, será acionado o Editor da Tela de Parâmetros.
Se você já estudou o Form Builder, não terá dificuldades em alterar a tela de parâmetros gerada, pois o editor é
semelhante ao editor de Layout do Form Builder. Se você ainda não estudou o Form Builder, em breve veremos o
editor de Layout do Report Builder, que permitirá a você fazer as modificações que faremos a seguir.
Faremos algumas poucas modificações no layout, a fim, principalmente, de visualizarmos integralmente o texto
do parâmetro.
♦ Aumente o tamanho da caixa de texto dos dois parâmetros apresentados.
♦ Troque a cor do texto “Parâmetros do Relatório” para vermelho e tipo de letra Arial, tamanho 12, negrito.
♦ Sublinhe o texto “Preencha adequadamente”.
♦ Coloque em branco o texto “O preenchimento é obrigatório”.
O resultado não ficou mais agradável?
Quando usamos o editor da tela de parâmetros, aparece uma linha preta do lado direito da tela. Essa linha é
indicadora do tamanho da tela. Em breve veremos como alterá-lo. Neste momento, estamos limitados ao tamanho
definido atualmente.
EXERCÍCIOS
Neste grupo de exercícios estaremos focando os parâmetros; portanto, se você desejar, pode se utilizar do Assistente.
METODOLOGIA
♦ Apresentação de alguns dos objetos de layout que permitirão a construção de layouts complexos.
TÉCNICA
♦ Análise de uso dos diferentes objetos, exemplos e exercícios.
INTRODUÇÃO
Neste tópico, começaremos a estudar como o Report Builder formata o layout de nossos relatórios. Nosso objetivo
principal é o entendimento que nos possibilitará interferir no resultado gerado.
Para o acompanhamento passo a passo, iniciaremos montando um relatório, porém sem a definição do layout, ou
seja, sem o auxílio do Assistente (Wizard).
Para este fim, criaremos um novo relatório ainda sem nome. Abriremos o editor do Modelo de Dados, criaremos
uma Query (com a ferramenta adequada), o que causará o aparecimento do diálogo Instrução de Consulta de SQL.
Preencheremos este diálogo com o comando Select apresentado acima e clicaremos em OK. O Modelo de Dados
será novamente apresentado já com o objeto gráfico (da consulta) montado.
Para completar, retorne ao Navegador e salve o relatório indicando o nome de Layout1.
Criemos, agora, dentro deste quadrado, quatro fields, ou seja, clique na ferramenta Campo (Field) e crie um
retângulo dentro do retângulo relativo ao Repeating Frame. Repita esta operação quatro vezes. O resultado até
agora está presente na Figura 8.34.
Para que o relatório fique pronto para a execução, falta apenas fazermos a associação entre cada um dos elementos
e o objeto do Modelo de Dados correspondente. Portanto, usaremos a tela de propriedades de cada um dos objetos
do Layout para estabelecer esta associação.
Abra a tela de propriedades do Repeating Frame; estudaremos, inicialmente, apenas algumas das propriedades:
♦ Origem (Source) – Esta propriedade determina qual o grupo do Modelo de Dados que corresponde a esse Repeat-
ing Frame.
♦ Direção de Impressão (Print Direction) – Nesta propriedade determinamos de que forma esse Repeating Frame
se desenvolverá ao longo da página.
♦ Máximo de Registros por Página (Maximum Records per Page) – Nesta propriedade definimos o número máximo
de Repeating Frames por página, ou seja, o número máximo de registros deste grupo em uma determinada
página do relatório.
♦ Espaçamento Horiz. Entre Quadros (Inter-Frame Horizontal) – Nesta propriedade definimos o espaço a ser
preservado entre um Repeating Frame e outro no sentido horizontal.
♦ Espaçamento Vert. Entre Quadros (Inter-Frame Vertical) – Nesta propriedade definimos o espaço a ser preservado
entre um Repeating Frame e outro no sentido vertical.
Devemos, portanto, preencher a propriedade Origem com o nome do grupo G_CD_MAT.
Repetiremos esta ação para os campos (Fields), com o objetivo de também definir qual a coluna correspondente ao campo.
♦ F_1 – cd_mat
♦ F_2 – nm_func
♦ F_3 – cd_depto
♦ F_4 – vl_sal
A execução do relatório apresenta o aspecto da Figura 8.35.
Observe que o Repeating Frame é impresso também. Os objetos contidos dentro dele a tempo de definição são
formatados cada vez que ele é formatado. Ele é o controle.
Como teste, vamos determinar que o número máximo de registros por página é três (propriedade do Repeating
Frame). Retorne ao Layout, altere esta propriedade e execute novamente o relatório.
Como resultado, temos que apenas três Repeating Frames foram impressos em cada uma das páginas e,
conseqüentemente, apenas três linhas da tabela Func foram apresentadas.
Retornemos novamente ao layout e alteremos a propriedade Direção de Impressão (Print Direction). Esta também
é uma propriedade do Repeating Frame. Observe que essa propriedade possui quatro opções: Vertical (Down),
Horizontal (Across), Vertical/Horizontal (Down/Across) e Horizontal/Vertical (Across/Down).
Para que essa propriedade possa apresentar um resultado compreensível, seu Repeating Frame deve ter um tamanho
horizontal suficiente para que ao menos dois sejam impressos horizontalmente. No caso do meu desenho, o
Repeating Frame possui um tamanho um pouco maior que 3 polegadas de largura. Como a minha página está com
disponibilidade de até 7,5 polegadas, cabem duas impressões no sentido horizontal. Verifique o seu desenho antes
de fazer este teste. Caso seja necessário, diminua o tamanho dos campos e do Repeating Frame e aproxime o
desenho da margem esquerda superior do relatório.
No caso do exemplo desenvolvido até agora, podemos alterar essa propriedade para o valor Vertical/Horizontal
(Down/Across). Isto significa que o Repeating Frame será impresso inicialmente no sentido vertical; quando a
página acabar, será iniciada a impressão na segunda coluna da mesma página e assim por diante. Antes de iniciarmos
a execução, devemos retirar a restrição referente ao número de registros por página.
Observe o resultado deste teste. Veja o desenvolvimento da impressão: matrículas 10, 20, 30, 50, 60, 70, 90, 100,
110, 130 (impressas verticalmente na primeira coluna). Com o fim da página (no sentido vertical), ocorre o re-
torno para a impressão da segunda coluna: matrículas 150, 170, 200, etc., até o fim da página no sentido vertical.
Novamente, é feita uma tentativa de montagem de uma próxima coluna, que não cabe mais nesta página (no
sentido horizontal). Sendo assim, ocorre a mudança de página.
A quantidade de matrículas impressa verticalmente na página depende da altura do Repeating Frame. Quanto maior, menos matrículas aparecerão
em uma coluna.
Um novo teste para que essa propriedade fique bem clara para nós. Alteremos novamente a propriedade Direção
de Impressão (Print Direction). Vamos escolher desta vez o valor Horizontal/Vertical (Across/Down).
Observe agora a diferença de resultado. No sentido horizontal, temos as matrículas 10 e 20. Como acabou a página
(no sentido horizontal), foi necessária a criação de uma segunda linha com as matrículas 30 e 50. Mais uma vez
acabou a página horizontalmente e uma nova linha (vertical) foi adicionada, e assim por diante, até que a página
tenha se completado.
A Figura 8.36 apresenta a imagem dos Repeating Frames para as quatro opções de desenvolvimento de impressão.
As setas presentes na borda do objeto indicam exatamente como se desenvolverá a impressão do objeto.
Nosso último teste com este objeto será aumentarmos o espacejamento entre os Repeating Frames a tempo de impressão.
Usando na direção de impressão o valor horizontal/vertical, preenchemos o valor da propriedade Espaçamento
Horizontal Entre Quadros (Inter-Frame Horizontal) com 0.1 (polegadas), e na propriedade Espaçamento Vertical
Entre Quadros (Inter-Frame Vertical) o valor 0.6 (polegadas).
Na execução obtemos como resultado a impressão dos Repeating Frames com um intervalo entre eles tanto na
horizontal como na vertical.
CAMPOS (FIELDS)
Você observou que o tamanho do desenho que fazemos determina o tamanho do objeto a tempo de impressão e
que as características que definimos para os objetos são refletidas na impressão.
Para entendermos como o Report Builder monta os objetos no Layout, diminuiremos o tamanho vertical dos
campos (fields), atribuiremos máscara para os campos numéricos e trabalharemos com cor.
Inicialmente, diminuiremos verticalmente o tamanho dos campos e aproximaremos as bordas do Repeating Frame.
Observe que na Figura 8.37 diminuímos verticalmente o tamanho dos objetos do quadro e aumentamos
horizontalmente o tamanho do campo F_4 (salário). Isto será necessário para que possamos atribuir a esse objeto
uma máscara (propriedade máscara de formato – format mask), que será LNNNGNN0D00 ou L999G990D00.
O valor para formato N no Report Builder corresponde ao valor para formato 9 do Form Builder e do PL/SQL.
Antes da execução, vamos atribuir nomes adequados aos campos para que possamos identificá-los com mais
facilidade. Associe, portanto, o nome do objeto do Modelo de Dados a que corresponde incluindo um F na frente,
ficando desta forma F_cd_mat, F_cd_depto, e assim por diante. No Layout, os campos agora serão apresentados
com o nome que atribuímos, ficando, portanto, mais fácil de identificarmos o resultado.
Para que tenhamos um resultado mais coerente, retire o espaçamento que definimos tanto horizontalmente quanto
verticalmente para os Repeating Frames. Execute o relatório e verifique o resultado até aqui.
Para que este resultado fique com mais aspecto de relatório, devemos retirar a cor dos objetos. Sendo assim, selecione
o objeto e utilize na barra de ferramentas vertical o botão Cor de Linha (Line Color). No quadro de cores apresentado,
escolha a opção Nenhuma Linha (No Line). Da mesma forma, selecione cada objeto (inclusive o Repeating Frame) e,
com o botão Cor de Preenchimento (Fill Color), escolha a opção Nenhum Preenchimento (No Fill).
Na Figura 8.38 vemos o resultado desta ação no Layout. Execute a aplicação e veja o que acontece na impressão. Se
você desejar que o intervalo entre as linhas seja ainda menor, deverá diminuir ainda mais o tamanho do campo e
o espaço entre o campo e o quadro.
BOILERPLATES
Nosso próximo objeto de estudo é o boilerplate, ou seja, um objeto que só é apresentado no Layout e tem a
finalidade de permitir a montagem gráfica do relatório. Temos dois tipos de boilerplates: os gráficos e os de texto.
Os boilerplates gráficos permitirão que desenhemos linhas, retângulos, curvas, e outros objetos de desenho.
Poderemos até montar um relatório tipo pré-impresso, com linhas, campos, etc., só que gerado pelo Report Builder.
O boilerplate de texto permitirá que coloquemos títulos, identificadores de campos, enfim, informações de texto
fixas nas páginas do relatório.
Iniciaremos nossos testes utilizando o mesmo relatório que trabalhamos até então.
Em nosso primeiro teste, incluiremos títulos para as colunas. Sendo assim, aumentaremos o tamanho dos Repeat-
ing Frames e incluiremos títulos imediatamente acima do objeto. Veja a Figura 8.39.
Como era de se esperar, o título foi impresso para cada uma das linhas. Isto ocorre porque incluímos o título
dentro do Repeating Frame. Coloquemos, agora, o título do lado de fora para analisarmos as diferenças.
Remova o título da parte de dentro e o crie novamente do lado de fora ou arraste-o para fora do Repeating Frame.
Para que esta operação tenha sucesso, o ícone do cadeado (na barra de ferramentas) deve estar aberto. Veja o
resultado na Figura 8.40.
Ao executarmos este relatório, verificaremos que, embora o Repeating Frame tenha se repetido na horizontal, o
boilerplate foi impresso uma única vez sobre o primeiro grupo de registros. Se desejarmos que ele também apareça
sobre a segunda coluna, devemos desenhá-lo novamente na posição desejada.
Na Figura 8.41 apresentamos esta situação. Tente montar este layout e verifique o resultado na execução.
CAMADAS DE IMPRESSÃO
O Editor de Layout é composto de diversas camadas de impressão. Cada vez que desenhamos um objeto ele é
incluído em uma diferente camada. Não temos dois objetos presentes na mesma camada.
A Figura 8.42 nos mostra o que acontece quando desenhamos cada um dos objetos no layout. Cada objeto pertence
a uma camada diferente. Para que um objeto seja considerado contido em outro, ele não só deve estar dentro dos
limites do outro como também deve estar em uma camada acima do outro.
Veja o field F_cd_mat na figura frontal (abaixo); ele está contido nos limites de R_1. Na figura em perspectiva
(superior), este campo F_cd_mat está à frente de R_1. Neste caso podemos dizer que ele está contido em R_1.
Façamos um teste em nossa aplicação. Como primeiro passo removeremos o Repeating Frame criado (R_1).
Vamos colorir (usando o botão Cor de Preenchimento – Fill Color), agora, os campos de amarelo.
No próximo passo criaremos um Repeating Frame em torno dos campos (pinte-o de verde).
Você observará que o Repeating Frame ficou na frente de todos os campos. Sendo assim, os campos não estão
contidos nesse Repeating Frame.
Para testarmos o erro que ocorre a tempo de execução, associe o Repeating Frame ao Grupo (preencha a propriedade
Origem – Source) e execute a aplicação.
O erro recebido indica que a coluna F_cd_mat está com uma freqüência de impressão inferior ao seu grupo. Isto
quer dizer que existem mais linhas com cd_mat do que a quantidade de linhas a serem impressas. Está sobrando
matrícula. Como o campo F_cd_mat não está contido no Repeating Frame R_1, ele só será impresso uma vez; no
entanto, existem diversos registros com matrículas a serem impressas, o que causa o erro REP1213: O campo
‘F_cd_mat’ referencia a coluna ‘CD_MAT’ a uma freqüência abaixo de seu grupo.
Para corrigirmos esta situação, devemos posicionar o Repeating Frame R_1 atrás dos demais objetos. Selecione-o e
utilize a opção Mover para Trás (Move Backward) ou F8, do menu Organizar (Arrange) para que você vá movendo
o Repeating Frame para trás passo a passo. Você perceberá que o objeto F_vl_sal será o primeiro a aparecer, em
seguida o objeto F_cd_depto e assim por diante. Como cada um está em uma camada diferente, cada vez que o
Repeating Frame navega uma camada para trás, um objeto aparece.
Se você desejar, pode enviar o Repeating Frame para trás de todos em um único comando, com a opção Enviar Para
Trás (Send to Back) ou F6, do menu Organizar (Arrange).
Após a arrumação verificamos no resultado que o Repeating Frame ficou atrás de todos os itens. A execução é bem-
sucedida nesta situação.
FREQÜÊNCIA DE IMPRESSÃO
Um bom entendimento de Freqüência de Impressão nos garantirá uma execução sempre bem-sucedida do relatório,
pois este é um dos pontos mais importantes de nosso estudo.
Já verificamos que existe uma ligação bastante significativa entre as camadas de um relatório e a freqüência de
impressão. Aprofundaremos um pouco mais nosso estudo neste sentido.
A Figura 8.43 nos mostra nosso relatório contendo os objetos R_1 (Repeating Frame), F_cd_mat (Field) e dois
outros objetos chamados de Corpo (Body) e Margem (Margin). Esses últimos são objetos internos do Report Builder
e estão presentes em todos os relatórios.
Quando um relatório é executado, o Report Builder executa os seguintes passos:
♦ Monta todos os objetos que estiverem diretamente pendurados na Margem.
♦ Monta todos os objetos que estiverem pendurados diretamente no Corpo.
No nosso caso, o único objeto pendurado diretamente no corpo é o Repeating Frame R_1. Sendo assim, ele monta
o primeiro registro (G_CD_MAT) relativo a R_1. Como existem objetos pendurados em R_1, ele monta os objetos
pendurados em R_1.
Mas existem mais registros a serem impressos; sendo assim, ele monta o próximo registro (G_CD_MAT) relativo a
R_1. Como existem objetos pendurados em R_1, ele monta esses objetos.
Este último parágrafo se repete enquanto houver registros referentes ao grupo G_CD_MAT.
Observe, então, que o objeto R_1, a tempo de execução, acontece mais de uma vez, isto é, existe mais de um objeto
R_1 na impressão, tantos quantos forem os registros G_CD_MAT.
Concluímos, então, que, para uma determinada página de relatório, o Report Builder imprime:
♦ Uma vez todos os objetos que estiverem pendurados na margem.
♦ Uma vez todos os objetos que estiverem pendurados no corpo.
♦ Se o objeto for do tipo Repeating Frame, ele será gerado tantas vezes quantas couberem na página ou de acordo
com os limites que tivermos estabelecido (por exemplo, número máximo de registros por página).
Nosso próximo teste será analisar a freqüência de impressão dos boilerplates que adicionamos como cabeçalho de
coluna no relatório.
Para que nosso relatório ocupe mais de uma página, alteremos a direção de impressão do Repeating Frame para
Vertical (Down) e executemos novamente nosso relatório.
Quando o relatório for executado, poderemos observar que nos será apresentada a impressão da primeira página (campo
Página, na barra de ferramentas superior, preenchido com 1). Navegue para a segunda página usando a ferramenta
Página Seguinte (Next Page), presente na barra de ferramentas horizontal ao lado (esquerdo) do campo Página.
Você observará que o boilerplate não apareceu na segunda página. Por quê?
Selecione um dos boilerplates e abra sua tela de propriedade. Analisemos o grupo Layout Avançado (Advanced Layout).
As propriedades Impressão de Objeto Ativada e Impressão de Base Ativada são as responsáveis por este resultado.
♦ Impressão de Base Ativada (Base Printing On) – Nesta propriedade indicamos qual é o objeto que comandará a
impressão do objeto atual. Temos duas opções neste caso: o objeto no qual o atual está contido (objeto de
encerramento – enclosing object) ou o objeto no qual ele está ancorado (objeto de ancoragem – anchoring object).
♦ Impressão de Objeto Ativada (Print Object On) – Nesta propriedade definimos com que freqüência o objeto
atual será impresso em relação ao objeto no qual ele está pendurado (contido ou ancorado). Os valores válidos
para esta propriedade são:
a) Todas as Páginas (All) – Esta opção indica que o objeto atual deve ser montado em todas as páginas em que o
objeto no qual ele está pendurado for impresso.
b) Tudo, Exceto a Primeira Página (All But First) – Esta opção indica que o objeto atual deve ser montado em
todas as páginas em que o objeto no qual ele está pendurado for impresso, exceto na primeira página.
c) Tudo, Exceto a Última Página (All But Last) – Esta opção indica que o objeto atual deve ser montado em todas
as páginas em que o objeto no qual ele está pendurado for impresso, exceto na última.
d) Default – Esta opção indica que o Report Builder deverá determinar a freqüência de impressão mais adequada
para o objeto.
e) Primeira Página (First) – Esta opção indica que o objeto atual deve ser montado apenas na primeira página
em que o objeto no qual ele está pendurado for impresso.
f) Última Página (Last) – Esta opção indica que o objeto atual deve ser montado apenas na última página em
que o objeto no qual ele está pendurado for impresso.
Nosso boilerplate, portanto, está pendurado no objeto Corpo, sua freqüência de impressão está preenchida com First
(Primeira Página). Sendo assim, ele será impresso apenas na primeira página em que o objeto Corpo for impresso.
Alteremos, então, sua freqüência para Todas as Páginas (All) em todos os quatro boilerplates.
No resultado obtido na execução do relatório, veremos que os textos foram montados na segunda página do
relatório, como desejávamos.
Antes de estudarmos outro aspecto do Report Builder, vamos verificar o valor das propriedades estudadas para os
Fields F_cd_mat, F_nm_func, etc. Este grupo de propriedades Layout Avançado (Advanced Layout) existe para
todos os objetos do Layout.
Você descobrirá que a propriedade Impressão de Objeto Ativada (Print Object On) também está preenchida com
Primeira Página (First). Como é que esse objeto é impresso, então, tantas vezes?
O objeto no qual ele está contido é um Repeating Frame, e, sendo assim, quem é impresso diversas vezes em uma
determinada página é o Repeating Frame. Portanto, os objetos que estão dentro dele somente precisam ser impressos
uma vez (First) a cada vez que o Repeating Frame for impresso. Entendeu agora?
Este assunto ainda não acabou. Continuaremos a estudá-lo juntamente com outros assuntos.
ELASTICIDADE
Montaremos, agora, um relatório com um nível de quebra. Salve o relatório atual com o nome de Layout2 e
retorne ao Editor do Modelo de Dados.
Criaremos um grupo de quebra contendo a coluna cd_depto. Clique sobre ela e arraste-a para fora e para cima do
grupo G_CD_MAT.
Como resultado, temos um grupo G_CD_MAT contendo três colunas (cd_mat, nm_func e vl_sal), um grupo G_CD_DEPTO
contendo uma coluna (cd_depto). Este resultado deve ser reproduzido no Layout, conforme a Figura 8.44.
Definimos um novo Repeating Frame, associamos o grupo G_CD_DEPTO e enviamos este Repeating Frame para
trás. O Field F_cd_depto saiu do Repeating Frame R_1 e ficou pendurado apenas no Repeating Frame R_2, da
mesma forma que no Modelo de Dados ele saiu do grupo G_CD_MAT e ingressou no grupo G_CD_DEPTO.
Na Figura 8.45, escolhemos propositalmente a página 21 da execução, pois é uma das poucas páginas em que
encontramos mais de uma impressão dos objetos. Analisemos, então, o que temos aqui.
A página exata do seu relatório poderá variar de acordo com os tamanhos especificados para os fields e repeating frames. Encontre a página em
que aparece a única linha do departamento E01 e você encontrará a mesma situação apresentada na Figura 8.45.
Se você consultar sua base de dados, verificará que o funcionário Joaquim está alocado no departamento D21. O
único funcionário do departamento E01 é o João (matrícula 50) e que a Eliane é um dos funcionários do departamento
E11. O que observamos, então, é que nessa página cada um dos registros pertence a departamentos diferentes, ou
seja, formatamos o Repeating Frame R_2 três vezes (são 3 R_2 presentes nessa página). Ao navegarmos para a página
22, veremos a presença solitária do funcionário João (matrícula 290), que também pertence ao departamento E11 (o
mesmo da Eliane). Por que, então, este funcionário não foi impresso na mesma página da Eliane?
Retorne ao seu layout e dê uma boa olhada em seu desenho. Você sabe que o Repeating Frame R_1 será impresso
diversas vezes (uma para cada registro). Quando ele estava sozinho diretamente pendurado no Corpo, era impresso
tantas vezes quantas coubessem em uma página. Agora ele está pendurado no Repeating Frame R_2. Logo, ele está
sendo impresso tantas vezes quantas cabem no Repeating Frame R_2. Como fizemos um desenho muito pequeno, só
cabe uma impressão. Sendo assim, o Report Builder quebra a página, pois não consegue montar uma segunda impressão.
Podemos resolver este problema de duas formas:
Na primeira, esticaremos o Repeating Frame R_2 verticalmente até o fim do Corpo.
Figura 8.46 – Layout com Repeating Frame esticado até o final do Corpo
♦ Fixo (Fixed) – Esta opção indica que o objeto não se expande, e desta forma seu conteúdo será impresso apenas
no espaço destinado a ele. Para Fields numéricos, quando o conteúdo não cabe, aparecem *** (asteriscos) indicando
que não foi possível a impressão do conteúdo. Para alfanuméricos, o texto é apresentado até a borda do objeto,
sendo cortado neste ponto. Para Repeating Frames, o Report Builder toma outra atitude, quebrando de página
e tentando continuar a impressão em uma próxima página.
♦ Expandir (Expand) – Esta opção indica que o objeto é expansível, ou seja, se o conteúdo for maior que o
desenho, o objeto crescerá para acomodar todo o conteúdo. Se, ao contrário, o conteúdo for menor que o
desenho, no mínimo o espaço do desenho será ocupado pelo objeto.
♦ Contrato (Contract) – Esta opção indica que o objeto é contrátil: se o conteúdo for maior que o desenho, somente
será utilizado o espaço do desenho, ou seja, terá comportamento similar ao fixo. Se, ao contrário, o conteúdo for
menor que o desenho, o espaço ocupado pelo objeto será apenas o suficiente para a impressão de seu conteúdo.
♦ Variável (Variable) – Esta opção indica que o objeto é variável, ou seja, se o conteúdo for maior que o desenho,
o objeto crescerá para acomodar todo o conteúdo. Se, ao contrário, o conteúdo for menor que o desenho, o
espaço ocupado pelo objeto será apenas o suficiente para a impressão de seu conteúdo.
No nosso caso, desejamos que o Repeating Frame R_2 cresça no sentido vertical; portanto, o tornaremos expansível
(ou variável) no sentido vertical. Execute o relatório e verifique o resultado.
A Figura 8.47 nos mostra o resultado gráfico de modificarmos a elasticidade no sentido vertical para o Repeating
Frame R_2. Para cada uma das opções um indicador é adicionado ao Repeating Frame.
Nosso teste, porém, ainda não acabou. Analisaremos apenas mais uma situação antes dos exercícios.
Limite a quantidade de registros do Repeating Frame R_1 (o de dentro) a três por página. Execute novamente seu relatório.
A Figura 8.48 nos apresenta a página 1 do relatório. Antes de chegarmos aos exercícios, façamos um teste adicional.
Modifique a propriedade Máximo de Registros por Página do repeating frame R_1 (o de dentro) para 3, execute-o
e navegue para a segunda página do relatório.
O registro de matrícula 1 pertence ao departamento A00; no entanto, o código do departamento não foi impresso
nessa página. Por quê?
Voltamos à freqüência de impressão. O Repeating Frame R_2 foi formatado na primeira página para o departamento
A00. Quando ocorreu a mudança de página (por causa do limite que impusemos), o que foi impresso na segunda
página foi a continuação do Repeating Frame R_2, ainda do departamento A00. Como a freqüência de impressão
do objeto F_cd_depto é Primeira Página (First), ele não foi impresso na segunda.
Quando mudamos de departamento, podemos dizer que também mudamos de Repeating Frame; é um outro
Repeating Frame R_2 que está sendo impresso (uma outra instância deste objeto), e por isso, quando este “novo”
objeto é impresso, o código do departamento é formatado, pois é a primeira impressão desse objeto (é a primeira
página para esse objeto).
Nos exercícios você vai se deparar com diversas situações semelhantes. Estude para realizá-los com facilidade.
EXERCÍCIOS
Nos exercícios deste tópico estaremos estudando os objetos de Layout. Criaremos, também, uma query que possa
ser utilizada nos exemplos. A utilização do Assistente para a geração do Layout será minimizada.
8.20) Crie uma query externa que apresente numa mesma linha o nome, sobrenome (concatenados), o cargo, o
salário, matrícula e data de admissão do funcionário; o código e nome do departamento; o nome e sobrenome
(concatenados) e ramal do gerente. Salve essa query com o nome Q20.
8.21) Crie um relatório com o nome de REP21 baseado na query externa Q20. O relatório deve ter formato tabular.
8.22) Crie um relatório com o nome de REP22 baseado na query externa Q20. O relatório deve ter uma quebra
contendo os dados do gerente e do departamento.
8.23) Crie um relatório com o nome de REP23 baseado na query externa Q20. O relatório deve conter a seguinte carta:
Figura-resposta 8.23
8.24) Crie um relatório com o nome de REP24 baseado na query externa Q20. O relatório deve ter quebra por
gerente (primeiro nível) e por departamento (segundo nível). Devem ser apresentados os seguintes sumários:
♦ Soma salarial por departamento.
WORKSPACE
É a área de janela do Layout, ou seja, a área disponível para desenho. Seu tamanho é independente do tamanho
atual da janela, isto é, o Workspace pode ser maior ou menor que a área da janela.
Quando o Workspace é maior que a janela, podemos rolar a janela para ver outras partes do Workspace.
O tamanho dessa área de desenho é definido dentro das propriedades do relatório atual, ou seja, nas propriedades
do módulo relatório que estamos trabalhando (o Layout2). Esta definição será vista quando estudarmos as
propriedades específicas do módulo.
RÉGUAS (RULERS)
Uma régua horizontal (em cima) e uma vertical (lateral esquerda). Essa régua pode ser apresentada em unidades
diferentes (ex.: centímetros, caracteres, pés, etc.), de acordo com a unidade em vigor no relatório.
GUIAS
Podem ser selecionadas guias (tracejadas) horizontais e verticais para referência. Para selecionarmos uma guia,
basta que posicionemos o mouse sobre uma das réguas, o pressionemos e arrastemos até a posição desejada para
apresentação da guia.
GRID
Existe uma grade dentro do Workspace para auxílio no posicionamento de objetos. Se desejarmos visualizar esta
grade, devemos usar o menu Exibir (View), opção Grade (Grid). Aparecem uns pontinhos na área de desenho com
um determinado espacejamento vertical e horizontal.
Podemos alterar a quantidade de pontos se utilizarmos a opção Réguas (Rulers) do submenu Opções de Layout
(Layout Options) do Menu Formatar (Format).
Nesse diálogo, podemos alterar a unidade de apresentação das réguas, a quantidade de linhas de grade (de quantos
em quantos pontos da unidade escolhida será definida uma grade – grid) e a quantidade de pontos dentro da grade
para alinhamento (se usarmos a opção de alinhamento pela grade).
Por exemplo: suponhamos que tenhamos definido que a grade será impressa a cada polegada. Se definirmos que a
quantidade de pontos de alinhamento é cinco, na verdade estaremos dizendo que a grade será criada a cada 0.2 polegadas,
porém somente será mostrada visualmente a cada 1 polegada. Desta forma, para efeito de alinhamento, existirão cinco
linhas de grade por polegada, o que permitirá que um determinado objeto seja posicionado em 0.2, 0.4, 0.6, etc.
Visualmente, no entanto, o objeto não estará sobre uma das linhas de grade (que só ocorrem a cada polegada).
AS BARRAS DE FERRAMENTAS
Ao olharmos para a tela do Layout Editor, observamos a presença de duas barras de Ferramentas Superiores e uma
Vertical, na lateral esquerda. Começaremos nosso estudo por elas.
Quando pressionamos cada um destes botões, fechamos o editor atual e abrimos um outro associado a outra parte
do Report Builder, respectivamente: execução, modelo de dados, layout e tela para recepção dos parâmetros.
O próximo conjunto já é nosso conhecido, pois é o mesmo que se encontra no Navegador de Objetos: Abrir (abrir
um relatório existente), Salvar (gravar/salvar o relatório atual), Executar (executar o relatório atual direcionando-
o para o Previsualizador Ativo), Imprimir (executar o relatório atual direcionando-o para a impressora default do
sistema), Recortar/Copiar/Colar (estas ações recortam, copiam ou colam objetos no layout).
Os dois próximos botões ampliam ou reduzem o nível de detalhamento do Layout, ou seja, o nível de zoom. Seus
nomes são, respectivamente: Ampliar (Magnify) e Reduzir (Reduce). Essas ferramentas são muito úteis quando
estamos desenhando e precisamos colocar os objetos muito próximos uns dos outros sem que se sobreponham.
A seguir, encontramos os botões Inserir Data e Hora (Insert Date and Time) e Inserir Número de Página (Insert Page
Number). Esses botões incluem em nosso relatório Fields que têm como origem objetos internos do Report Builder,
ou seja, Data Atual e Número de Página. Uma vez que esses objetos são incluídos na margem e não no Corpo,
estudaremos seu uso mais tarde.
Os próximos três botões acionam os três Assistentes (Wizards) disponibilizados pelo Report Builder: Assistente de
Relatórios, Assistente de Gráfico (esse assistente aciona o Oracle Graphics para o desenvolvimento de um gráfico
com os dados oriundos do modelo de dados; não será visto neste material) e Assistente de Web (esse assistente nos
auxilia a gerar um relatório direcionado para Web – em formato HTML – ou um relatório em formato PDF).
Testaremos esta opção posteriormente neste material.
Os quatro botões a seguir permitem a navegação para as quatro partes constitutivas de um relatório, ou seja, a
margem (Margin), o corpo (Body), o cabeçalho (Header) e o trailer (Trailer). Esses botões requerem um estudo mais
específico e voltaremos a eles em seguida.
O último botão da barra de ferramentas superior aciona a Ajuda do Editor.
Coloque os boilerplates Mat e Depto em negrito, os boilerplates Mat, Nome e Salário em itálico e os fields sublinhados.
O grupo de botões a seguir realiza alinhamento interno dos objetos de layout, ou seja, o conteúdo de um determinado
objeto pode ser alinhado à esquerda, centralizado ou direita. Como teste, alinharemos os campos F_vl_sal e Fcd_mat
pela direita, o campo F_cd_depto pelo centro e o campo F_nm_func pela esquerda.
Os próximos cinco botões modificam a propriedade Máscara de Formato (Format Mask) do field selecionado a fim
de incluir indicação de moeda, percentual, vírgulas, adicionar ou retirar casas decimais. Selecione um field, por
exemplo, F_vl_sal; clique em um destes botões, acione a tela de propriedades e veja o que foi colocado como
máscara para o objeto.
O próximo botão tem a finalidade de ativar ou desativar o Modo de Restrição (Confine Mode). Isto significa que,
se o cadeado (ícone do botão) estiver fechado, não conseguimos arrastar um determinado objeto para fora do
objeto que o contém. Quando o cadeado está aberto, esta operação é possível. A ação de arrastar um determinado
objeto não troca o objeto de layer (ou seja, de camada). Experimente clicar e arrastar o objeto F_vl_sal de dentro do
Repeating Frame R_1 com o cadeado fechado. Abra o cadeado e tente novamente.
O penúltimo botão dessa barra de ferramentas tem a finalidade de ativar ou desativar o Modo Flex (Flex Mode).
Isto significa que, quando arrastamos um objeto e o encostamos na borda do objeto que o contém, este cresce.
Imagine que desejássemos incluir, agora, uma nova coluna em nosso relatório, por exemplo, o cargo do funcionário.
Além de alterarmos a query para incluir a nova coluna, devemos incluí-lo no Layout, dentro do Repeating Frame
R_1. Sendo assim, devemos aumentar o Repeating Frame R_2 (onde R_1 está contido), aumentar o Repeating
Frame R_1 e estabelecer o posicionamento do Field no local desejado. Se ativarmos o modo Flex, poderemos,
simplesmente, arrastar o Field F_vl_sal para a direita, a fim de que os dois Repeating Frames cresçam simultaneamente
(experimente!). Quando o tamanho for aquele desejado, desativamos o modo Flex e movimentamos o field F_vl_sal
para a posição desejada.
O último botão desta barra tem a finalidade de selecionar o objeto-pai do objeto que tivermos selecionado atualmente.
Aparentemente, esta opção é pouco útil, pois podemos selecionar diretamente o objeto-pai. Lembre-se, porém, que
num relatório real teremos dezenas de Fields, diversos Repeating Frames e todos bastante próximos uns dos outros.
Às vezes fica muito difícil saber onde um determinado objeto está contido. Esta opção é bastante valiosa. Quando
você estiver trabalhando com o Report Builder no desenvolvimento de um relatório real, saberá por quê.
♦ Selecionar (Select) – Seleciona um objeto ou grupo de objetos. Basta que efetuemos um clique sobre o objeto desejado.
♦ Seleção de Quadro (Frame Select) – Quando selecionamos esta ferramenta e clicamos sobre um objeto, faz com
que esse objeto e todos que estiverem contidos dentro dele sejam selecionados simultaneamente. Útil para
Quadros de Repetição (Repeating Frames) e Quadros (Frames).
♦ Girar (Rotate) – Gira os objetos (gráficos, itens não podem ser rodados). Para girarmos um elemento devemos
selecioná-lo, clicar na ferramenta e, com o mouse, pressionar um dos indicadores de tamanho (presentes nos
cantos do objeto) e, sem soltar o botão esquerdo do mouse, rodar.
♦ Reformar (Reshape) – Permite que se modifique um objeto (gráfico) selecionado (por exemplo, ângulo de um arco).
Para efetuarmos um teste com esta ferramenta, devemos criar um objeto do tipo Arco; selecione-o na paleta de ferramentas
e faça um arco. Com esse objeto selecionado, pressione o botão Reformar. Você perceberá que apenas dois pontos ficam
indicados no elemento. Utilize o mouse para arrastar um destes pontos e modificar o ângulo do arco.
♦ Ampliar (Magnify) – Aumenta ou reduz a apresentação do Layout (fator - 2x), isto é, zoom. Para obtermos este
efeito, devemos clicar sobre o botão e em seguida sobre o Layout. O efeito inverso é obtido com os mesmos
movimentos, porém a tecla Ctrl (ou Shift) deve estar pressionada simultaneamente.
O segundo grupo de botões é composto de ferramentas gráficas, ou seja, ferramentas para a criação de elementos
gráficos, também chamados de boilerplates gráficos. Neste grupo se encontram as ferramentas:
A informação de cor de cada objeto é armazenada com um índice para localização de cor na paleta. Se alterarmos a paleta, como conseqüência
teremos a modificação involuntária da cor do objeto.
CRIANDO OBJETOS
Para criarmos um novo objeto, devemos cumprir os seguintes passos:
♦ Na paleta de ferramentas, selecionar a ferramenta para o tipo de objeto que desejamos criar.
♦ Posicionar o cursor na área de desenho onde desejamos que o canto esquerdo superior do objeto seja posicionado.
♦ Pressionar e arrastar o mouse até o desenho atingir o tamanho desejado.
MOVER OBJETOS
Para mover um objeto, usamos o mouse. Esta opção irá alterar o posicionamento do objeto na área de desenho e,
possivelmente, sua freqüência de impressão, se for retirado de dentro do objeto onde está contido atualmente.
REDIMENSIONANDO UM OBJETO
O redimensionamento individual de um objeto também é feito com o mouse. Basta que cliquemos sobre o objeto
para que sejam mostrados pequenos quadrados sobre a borda do objeto. Para modificar seu tamanho, devemos
clicar sobre um destes quadrados e arrastar o mouse na direção desejada: para aumentar, em direção à parte externa
do objeto, e para diminuir, em direção à parte interna do objeto.
Neste diálogo, poderemos dimensionar os objetos selecionados pelo maior, pelo menor, pela média ou atribuir um
valor específico, tanto em relação à largura quanto em relação à altura.
Este valor pode ser fornecido nas unidades: polegadas, centímetros, pontos ou caracteres.
Posteriormente, podemos reutilizar as opções definidas sem necessidade de reabrir o diálogo usando a opção
Repetir Dimensionamento (Repeat Sizing) do mesmo menu Organizar (Arrange).
ALINHANDO OBJETOS
O alinhamento pode ser feito em relação à grade (grid) ou um objeto em relação ao outro. Para tal, devemos
escolher a opção Alinhar Objetos (Align Objects) no menu Organizar (Arrange).
As opções de alinhamento dependem da direção horizontal ou vertical.
Horizontalmente temos: esquerda, direita, centralizado, distribuir (espaços entre objetos horizontalmente iguais)
e pilha (objetos colados lateralmente uns nos outros).
Verticalmente temos: por cima, por baixo, centralizado, distribuir (espaços entre objetos verticalmente iguais) e
pilha (objetos colados lateralmente uns nos outros).
O alinhamento também pode ser repetido com a opção Repetir Alinhamento (Repeat Alignment) do menu
Organizar (Arrange).
BOILERPLATE GRÁFICO
Para adicionarmos um boilerplate gráfico a uma Canvas, usamos as ferramentas adequadas da paleta de ferramentas.
O modo de criação é semelhante ao visto anteriormente para Boilerplate de Texto, Items, etc.
ATRIBUINDO FONTE
Para modificarmos a fonte de um elemento qualquer, devemos selecioná-lo e escolher a opção Fonte (Font) no
menu Formato.
Neste diálogo, podemos determinar a fonte, estilo de letra, tamanho e efeitos para o item ou boilerplate selecionado.
Observe que algumas dessas opções se acham presentes na Barra de Ferramentas Horizontal Inferior.
MODIFICANDO A LINHA
Ainda no menu Formato (Format), encontramos cinco opções para customização de linha:
♦ Largura da Linha (Line Width) – Apresenta um conjunto de opções de espessuras de linha.
♦ Bevel (Bevel) – Apresenta um conjunto de opções de relevo para linha.
♦ Borda – Apresenta a possibilidade de apresentarmos ou escondermos qualquer um dos quatro lados da borda de
um elemento.
♦ Traço (Dash) – Apresenta um conjunto de tipos de linhas (tracejado, pontilhado, contínua, etc.).
♦ Seta(Arrow) – Apresenta opções para inclusão de setas nas linhas.
ALINHAMENTO E ESPACEJAMENTO
O alinhamento e espacejamento dos textos dos itens podem ser feitos com as opções Espacejamento de Texto
(Spacing) e Justificar (Alignment).
O espacejamento diz respeito ao espaço interno entre linhas de um objeto. Facilmente visível quando um boilerplate
de texto ocupa mais de uma linha.
A justificação está relacionada ao alinhamento horizontal do conteúdo dentro de um determinado objeto. Esta
opção também se encontra presente na barra de ferramentas horizontal (Estilo).
OPERAÇÕES
As seguintes operações podem ser feitas com objetos (fields e boilerplates):
♦ Movimentação – Pode ser feita diretamente com o cursor.
♦ Redimensionamento – Pode ser feito diretamente com o cursor.
♦ Recorte – Após a seleção, devemos escolher a opção Recortar (Cut) ou Copiar (Copy) do menu Editar (Edit).
♦ Colagem – Selecionar a opção Colar (Paste) do menu Editar (Edit).
♦ Exclusão – Usar a opção Limpar (Clear) do menu Editar (Edit) ou apertar a tecla Delete.
♦ Duplicação – Após a seleção, usar a opção Duplicar (Duplicate) do menu Editar (Edit).
GRUPANDO OBJETOS
No menu Organizar (Arrange) encontramos as opções:
♦ Agrupar (Group)/Desagrupar (Ungroup) – Estas opções permitem que montemos ou desmontemos um
grupamento formado de dois ou mais objetos.
O grupamento é um auxílio que o Report Builder proporciona para que, após o desenho (Layout) do relatório,
esses objetos possam sempre ter o mesmo posicionamento perante outros objetos, ou seja, quando movemos um
objeto, movemos, na verdade, o grupo, ficando o objeto em si com o mesmo tamanho e alinhamento anteriores.
Quando grupamos objetos, o Report Builder os tratará como se fossem um único objeto.
♦ Agrupar Operações (Group Operations) – São operações realizadas sobre grupamentos, tais como:
a) Selecionar Pai (Select Parent) – Marca o grupo-pai, ou seja, o envoltório.
b) Selecionar Filhos (Select Children) – Marca todos os objetos pertencentes ao grupo.
c) Adicionar ao Grupo (Add To Group) – Adiciona um objeto ao grupo.
d) Remover do Grupo (Remove From Group) – Retira um objeto do grupo.
Para manter compatibilidade com as versões anteriores, ainda encontramos quatro botões na barra de ferramentas
horizontal superior, que permitem a navegação para cada uma das partes do relatório, porém estas partes mudaram
tremendamente de significado.
O Report Builder 6i nos possibilita a definição de múltiplos layouts definidos no mesmo relatório, cada um dos
quais com formatação própria de saída, layout de página e orientação diferenciados.
Nosso relatório possui três seções independentes (Seção Cabeçalho, Seção Principal e Seção de Trailer), cada uma
das quais com Corpo e Margem.
♦ Cabeçalho (Header) – Primeira seção a ser impressa se houver sido criado um layout para ela.
♦ Principal (Main) – Seção principal (botão selecionado na Figura 8.56). Normalmente desenvolvemos o relatório
usando esta seção.
♦ Trailer – Última seção do relatório, somente impressa se houver sido criado um layout para ela.
♦ Margem (Margin) – Corresponde à área de margem de cada uma das partes do relatório. A navegação ocorrerá
para a margem da seção correspondente.
O editor de layout só apresenta uma parte do relatório de cada vez. Quando escolhemos a trailer, cabeçalho ou
principal, estamos definindo qual delas desejamos que esteja ativa para desenharmos.
Obs.: A maioria dos desenhos é feita na seção principal do relatório.
Usando o Layout2, no Navegador, expanda o nó Layout Model. Você observará a presença de três seções Cabeçalho,
Principal e Trailer. Aparentemente não encontramos diferença com relação à versão anterior; no entanto, façamos
a expansão de uma destas seções (por exemplo Seção Cabeçalho) e encontraremos dois nós: Corpo e Margem.
Podemos criar diferentes layouts em cada uma das seções com objetos vindos das mesmas queries ou de queries
diferentes do Data Model. São áreas independentes. Em versões futuras da ferramenta, há a previsão de adição ou
remoção de seções.
Por default, o Assistente de Relatório desenvolve o layout na seção Principal; no entanto, podemos utilizar o
próprio Assistente para o desenvolvimento de layouts nas outras seções, bastando que no Editor de Layout façamos
a navegação para a seção desejada.
Adicionaremos, então, um novo layout ao relatório Layout 2 para entendermos este uso. Façamos a navegação
para a Seção Cabeçalho e recorramos ao Assistente de Relatório, escolhendo relatório com formato Agrupar à
Esquerda, gabarito Corporate 1 e título Seção de Cabeçalho.
Execute, em seguida, este relatório e observe os dois resultados produzidos.
A Figura 8.57 nos mostra como as diversas partes do relatório são montadas.
Inicialmente é montado o relatório cujo layout foi desenvolvido na seção cabeçalho. No nosso caso usamos uma
única query para as duas seções. Poderíamos, no entanto, ter criado uma query totalmente diferente a ser
desenvolvida nesta seção. Em seguida é montado o relatório cujo layout foi desenvolvido na seção Principal.
Observe que em todas as seções existe uma área de margem e uma área de corpo. Desta forma, quando está sendo
desenvolvida a seção Cabeçalho, para cada página é feita a montagem da margem e em seguida do corpo. Essa
dupla é formatada tantas vezes quantas forem necessárias para o desenvolvimento de todos os Repeating Frames e
Fields definidos. Observe no desenho da Figura 8.57 que a margem não está ao redor do corpo, corresponde, na
verdade, a uma camada (layer) montada antes do corpo. O corpo é montado sobre essa margem.
Podemos utilizar a margem para a montagem de objetos que se repetirão em todas as páginas, como por exemplo
uma marca d’água para o papel, numeração de página, título do relatório, data, etc.
Podemos diminuir o tamanho do corpo para que ele fique menor que as bordas da margem, de forma que possamos
desenhar objetos na margem que não sejam recobertos pelo corpo.
Na Figura 8.58 visualizamos a margem e o corpo. Na margem definimos diversos objetos que serão impressos em
todas as páginas, independente do que estiver sendo desenvolvido no corpo. O objeto triângulo criado no centro da
margem funciona como uma marca d’água, ou seja, os objetos presentes no corpo são formatados por cima dele.
Os demais objetos definidos na margem aparecem em todas as páginas sem sobreposição, pois diminuímos o
tamanho do corpo para que ficasse menor que a margem, sobrando uma borda em torno de todo o corpo para
definição de objetos constantes.
Como exemplificação de margem e corpo e, simultaneamente, testando campos de paginação e de data, navegaremos
para a margem do relatório (da seção Principal, por exemplo).
Observamos que, quando navegamos para a margem, continuamos a visualizar o corpo, porém não conseguimos
selecionar nenhum dos objetos pertencentes a ele (tente!). A linha escura que aparece em torno dos objetos do
corpo corresponde aos limites de desenvolvimento dos objetos do corpo. Você pode movimentá-los (clique o
mouse sobre a linha preta e arraste-a) ou alterar seu dimensionamento. Quando clicar o mouse sobre a linha preta,
alguns quadradinhos brancos aparecerão nos cantos e no meio da linha, permitindo seu dimensionamento. Teste!
O objeto criado é um field associado (origem) ao objeto interno Data Atual (Current Date). Abra a tela de propriedades
e verifique.
INSERIR NUMERAÇÃO
Ao criarmos um objeto de paginação (ferramenta Inserir Número de página – Insert Page Number), o diálogo
presente na Figura 8.60 nos permite definir apenas o posicionamento da numeração.
Observe que o tipo de objeto é diferente do anterior. Neste caso, foi criado um boilerplate que faz referência aos
objetos internos &<PageNumber> (Número da Página) e &<TotalPages> (Total de Páginas). Esta forma de montagem
é prática, pois podemos alinhar com mais facilidade o texto com o valor da quantidade; no entanto, tem como
desvantagem a utilização direta do nome interno do objeto (em inglês, inclusive).
Podemos resolver esta situação de outra forma, criando um objeto do tipo Field (F_página) e associando o objeto
interno desejado (Número da Página Física), da mesma forma que fizemos, anteriormente, com a data. Em seguida,
criamos o boilerplate com o texto que desejamos preceder ou adicionar ao valor e fazemos alinhamento como
fizemos com os demais objetos do layout. Esta forma permite que trabalhemos sem ter de saber o nome exato do
objeto interno. Faremos a seleção a partir de uma lista.
Se você abrir a tela de propriedades do objeto F_página, verificará que podemos estabelecer uma máscara de
formato (format mask). Outra propriedade disponibilizada neste caso é a Numeração de Página (Page Numbering),
onde podemos definir quais seções (Cabeçalho, Principal e/ou Trailer) devem ser contabilizadas para este field.
Desta forma podemos criar um contador de página que contabilize somente as páginas do relatório desenvolvido
na seção Principal, um outro que somente contabilize as páginas da seção de cabeçalho e assim por diante. Podemos,
ainda, determinar o valor inicial de contagem e quando essa numeração deverá ser zerada (em um determinado
Repeating Frame, ou seja, em uma determinada quebra ou no final do relatório).
Um arquivo carregado desta forma não precisa estar presente em disco a tempo de execução, pois seu conteúdo é
incorporado ao fonte do relatório.
Observe que no submenu Importar (Import) também podemos importar um arquivo de texto ou um desenho.
Ambas as opções são semelhantes à importação de um arquivo imagem, a diferença está apenas no tipo de arquivo.
EXERCÍCIOS
Neste grupo de relatório estaremos testando a funcionalidade do Editor de Layout. As alterações no layout serão manuais.
8.25) Baseado no relatório REP22, crie um relatório de nome REP25 e acrescente a seguinte funcionalidade:
♦ Campos numéricos formatados e alinhados à direita.
♦ Campos de data formatados e alinhados à esquerda.
♦ Letra arial, tamanho 9 para todos os campos e tamanho 8 e negrito para os cabeçalhos.
♦ Incluir cabeçalho de coluna.
♦ Alinhamento horizontal e vertical de todos os campos e cabeçalhos.
♦ Limitar a apresentação a um departamento por página.
8.26) Baseado no relatório REP25, crie um relatório de nome REP26 e acrescente a seguinte funcionalidade:
♦ Crie uma Capa que apresente o nome do relatório e a lista de departamentos com seus respectivos nomes (use
gabarito NCA Grey para a capa).
♦ Crie uma Contracapa que indique o término do relatório e o usuário solicitante.
♦ Determine cor azul para todos os itens e cor vermelha para os cabeçalhos.
♦ Inclua um título que seja apresentado em todas as páginas.
8.27) Baseado no relatório REP24, crie um relatório de nome REP27 e acrescente a seguinte funcionalidade:
♦ Campos numéricos formatados e alinhados à direita.
♦ Campos de data formatados e alinhados à esquerda.
♦ Letra arial tamanho 9 para todos os campos.
♦ Alinhamento horizontal e vertical de todos os campos e cabeçalhos.
♦ Crie uma marca d’água que seja apresentada como fundo de página (texto inclinado).
♦ Crie uma linha horizontal que separe o Gerente de seu Departamento.
♦ Os campos de nome do gerente e nome do departamento devem ter a possibilidade de crescimento horizontal.
♦ Inclua um número de página que seja reiniciado a cada novo gerente (no rodapé).
♦ Inclua um título que seja apresentado em todas as páginas.
♦ Inclua a data de emissão do relatório em todas as páginas.
8.28) Baseado no relatório REP27, crie um relatório de nome REP28 e acrescente a seguinte funcionalidade:
CONCEITOS INICIAIS
No Report Builder também podemos nos utilizar da PL/SQL a fim de aumentar a flexibilidade de nossos relatórios.
Existem quatro tipos de PL/SQL à nossa disposição:
♦ PL/SQL Intrínseca – São programas de PL/SQL armazenados dentro do nosso relatório e que fazem parte
constitutiva dos objetos; são intrínsecos aos objetos do Modelo de Dados ou do Layout, tais como Format
Triggers, Fórmulas, Filtros, etc.
♦ PL/SQL Interna – São rotinas armazenadas dentro da própria aplicação. São utilizadas para estruturação do código.
♦ Gatilhos de Relatório – São rotinas armazenadas dentro de nosso relatório e que são acionadas de acordo com a
ocorrência de um determinado evento.
♦ PL/SQL Externa – São programas de PL/SQL armazenados em uma biblioteca na rede (Libraries) ou armazenados
no banco de dados (Stored Procedures).
Iniciaremos nosso estudo pela PL/SQL Intrínseca revendo todos os locais onde podemos incluir código de PL/SQL
e analisando a utilização de cada um deles.
PL/SQL INTRÍNSECA
Consistem em funções acionadas pelo Report Builder e associadas a elementos do Modelo de Dados ou do Layout.
Faremos, então, uma revisão de todos estes pontos e objetos em que podemos associar código de PL/SQL.
Para acompanharmos essa revisão, precisamos de um relatório de Teste. Por este motivo, abrimos o relatório
Layout2 e salvamos com o nome de PLSQL1. No Layout retiramos as formatações feitas na seção Cabeçalho (corpo
e margem) e os objetos da margem da seção Principal para que o relatório fique bem simples e nos concentremos
somente na PL/SQL.
Para criá-la, devemos acionar a tela de propriedades do grupo no Modelo de Dados e indicar que o tipo de filtro é PL/SQL.
Na propriedade Filtro PL/SQL (PL/SQL Filter) poderemos, então, definir o texto de uma lógica de PL/SQL.
Para teste, criaremos um filtro no grupo G_CD_DEPTO (de departamento).
No exemplo da Listagem 8.19, fizemos uma lógica bastante simplificada. Sabemos, porém, que em um código de
PL/SQL poderemos nos utilizar de todas as partes da linguagem, inclusive realizando acesso ao banco de dados.
Esta ação, no entanto, não é recomendada, uma vez que tornará a aplicação mais lenta, pois este filtro é executado
uma vez para cada linha lida.
Como regra geral de filtragem, devemos tentar somente trazer as linha úteis à aplicação, isto é, tentar filtrar ao
máximo na própria query que traz as linhas para impressão. Desta forma estaremos diminuindo o fluxo de
informações pela rede. Se isto for totalmente impossível, então, nos utilizamos da filtragem do grupo, procurando
colocar na lógica de PL/SQL apenas restrições que não necessitem de acesso ao banco de dados.
END IF;
end;
No exemplo da Listagem 8.20 criamos uma crítica para o parâmetro P_1 (não esqueça de adicionar o uso do gatilho
na query, isto é, acrescentando a cláusula Where cd_mat >= :p_1).
No texto do gatilho de validação, vemos aparecer pela primeira vez menção ao pacote SRW. Se você expandir o nó
Pacotes Embutidos, verificará que quase todos os pacotes já são de nosso conhecimento, pois são os mesmos utilizados
pelo Form Builder. O pacote SRW, no entanto, ainda não foi apresentado, pois se trata de um conjunto de rotinas
específicas do Report Builder. Dentre elas encontramos aquela que nos permite enviar uma mensagem. Teste esta
crítica e veja os resultados. Existe um tópico específico para que façamos uma revisão das rotinas deste pacote.
Retorne ao Navegador e verifique a existência de dois ícones (P), indicando a presença dos dois códigos de PL/SQL
adicionados até agora. O Report Builder, como já sabemos, faz a indicação visual da presença de PL/SQL nos
objetos (G_CD_DEPTO e P_1).
FÓRMULA (FORMULA)
Uma fórmula nada mais é do que uma coluna adicionada em um dos grupos ou fora da query no Modelo de
Dados. Seu posicionamento define a freqüência com que o código de PL/SQL será executado.
Criaremos, então, uma fórmula que define o valor do INSS dos funcionários. Como se trata de uma ação a ser
calculada para cada funcionário, criaremos esta fórmula no grupo G_CD_MAT.
Na tela de propriedades deste novo objeto encontramos uma propriedade com o nome de Fórmula PL/SQL (PL/SQL
Formula), onde poderemos adicionar um código de PL/SQL que será retornado para a variável associada ao código.
Observe ainda que o tipo da variável definirá o tipo da fórmula, ou seja, nossa variável é numérica, e portanto a
função criada pelo Report Builder será do tipo numérica, retornando um Number.
Como regra geral para as fórmulas, devemos tentar sempre que possível efetuar os cálculos na própria query (no
nosso caso, isto era perfeitamente possível), pois estaremos diminuindo a freqüência com que a PL/SQL Engine é
acionada para a execução de uma ação específica. Se isto for totalmente impossível, então nos utilizamos da fórmula,
procurando colocar na lógica de PL/SQL apenas cálculos que não necessitem de acesso ao banco de dados.
Escolhemos para teste o campo F_vl_sal. Desejamos que, se o valor do salário for maior que 3.000, seja apresentado
em negrito e vermelho.
Utilizaremos a propriedade Gatilho de Formato (Format Trigger) do item de layout F_vl_sal para definirmos o
código de PL/SQL adequado à situação.
Neste exemplo, utilizamos o pacote SRW para estabelecer a formatação desejada para o campo.
Com ele, podemos ter situações em que um objeto seja impresso condicionalmente.
Lembre-se, porém, que este é o último ponto de filtragem. Só devemos utilizá-lo se não houver qualquer outra
alternativa. O melhor lugar para a filtragem é sempre a query, pois os dados não são trazidos pela rede.
PL/SQL INTERNA
A PL/SQL Interna consiste de funções, procedures ou pacotes armazenados dentro da própria aplicação. São utilizados
para estruturação do código e não têm utilização em outros módulos.
Está localizada localmente porque:
♦ Não precisa ser compartilhada por outras aplicações.
♦ Não utiliza estruturas do banco de dados ou utiliza apenas para atualização, não causando impacto no tráfego da rede.
♦ Está associada a ações específicas do ambiente cliente (por exemplo, usa alguma rotina dos Pacotes Embutidos
do Report Builder).
A criação de uma rotina local é feita através do Navegador:
♦ Selecione o nó Unidade de Programa (Program Unit).
♦ Utilize a ferramenta Criar (Create).
O diálogo da Figura 8.62 será apresentado para que possamos determinar o nome e o tipo da unidade de programa.
Neste caso, o tipo de código é Unidade de Programa. Observe que o campo Objeto fica desabilitado.
PL/SQL EXTERNA
ROTINAS ARMAZENADAS NO BANCO DE DADOS
Quando decidimos pelo cadastramento de uma determinada rotina no banco de dados, nossa principal motivação é
compartilhamento. Aquele código pode ser aproveitado (reutilizado) por diversas aplicações, estejam elas no ambiente
cliente (módulos de tela ou relatório) ou no ambiente servidor (outras rotinas armazenadas no banco de dados).
Porém, o compartilhamento também é possível com bibliotecas. Escolheríamos seu uso no banco de dados porque:
♦ A rotina executa ações de leitura e atualização no banco de dados (local ou remoto), de tal forma que sua
performance seja melhorada em função da diminuição do tráfego na rede.
♦ A rotina não está associada a ações específicas do ambiente cliente (tela, navegação, etc.).
♦ A rotina será utilizada por aplicativos em batch (PL/SQL, PRO*C, etc.) apesar de não fazer acesso a estruturas do
banco de dados. Neste caso específico, deve-se analisar o impacto de se duplicar essa rotina: uma para utilização
por aplicativos online (no ambiente de cliente) e outra para os aplicativos em batch (no ambiente servidor).
A criação ou manutenção de uma stored procedure pode ser feita com o próprio Report Builder da seguinte forma:
♦ Expanda o nó Objetos do Banco de Dados (Database Objects). Veremos a lista de usuários criados no banco.
♦ Expanda o nó Desenv (nosso usuário de trabalho). Serão apresentados quatro nós principais: Unidades de Programa
Armazenadas (Stored Program Units), Tabelas (Tables), Bibliotecas de PL/SQL (PL/SQL Libraries) e Views.
♦ Se você expandir o nó Tabelas, verá a lista de tabelas do usuário Desenv.
♦ Escolha uma tabela qualquer e expanda novamente o nó. Encontrará dois nós: Trigger (Database Trigger) e
Colunas (Columns).
Se desejarmos agora dar manutenção em uma rotina gravada no banco de dados ou se quisermos incluir uma nova
rotina, devemos selecionar o nó Unidades de Programa Armazenadas (Stored Program Units) e expandir para encontrar
a rotina desejada, ou pressionar o botão Criar (Create) para que seja apresentado novamente o diálogo da Figura 8.60.
Para efeito de teste, abra uma delas (clique duplo no ícone ou botão direito do mouse com a opção Editor de PL/SQL).
Observe que a janela do editor de PL/SQL é ligeiramente diferente daquelas vistas anteriormente. Ela mostra quem
é o usuário dono da rotina (Owner), o nome e tipo da rotina.
No próximo diálogo devemos indicar os atributos para o tipo Telefone (se um objeto com este nome já existir,
remova-o antes de iniciar os testes). Quando pressionamos o botão Adicionar, o diálogo apresentado pela Figura
8.64 é apresentado, permitindo que indiquemos o nome do atributo, seu tipo escalar e tamanho.
Os botões Editar e Remover, para que possam ser acionados com sucesso, precisam que tenhamos, previamente,
selecionado um dos atributos já criados. Ao preenchermos todos os atributos desejados (numero varchar2(10) e
ddd varchar2(4)), podemos avançar para o diálogo seguinte, o qual nos ajudará na criação dos métodos.
Ao pressionarmos o botão Adicionar, o diálogo da Figura 8.65 será apresentado para que possamos definir os
métodos, seu tipo (procedimento, função, função Map ou função Order) e parâmetros. Adicionalmente poderemos
indicar as restrições de “pureza” para o método (uso da pragma Restrict_References).
Com estas especificações resolvidas podemos passar para o diálogo seguinte, o qual permitirá que verifiquemos o
resultado antes de aplicá-lo ao banco de dados. Observe a Figura 8.66.
Quando pressionamos o botão Encerrar, a especificação do tipo é aplicada ao banco de dados, porém fica faltando
a criação do corpo do tipo, onde desenvolveremos o corpo da função Ver_Tel. O Report Builder, automaticamente,
aciona o editor de PL/SQL com o corpo do tipo já indicado para que façamos, apenas, a inclusão da lógica dos
métodos definidos.
Se não desejarmos realizar esta criação neste momento, poderemos fechar o editor de PL/SQL e, posteriormente,
acioná-lo (clique duplo sobre o ícone do tipo) e selecionar a parte de especificação do tipo ou o corpo do tipo (use
o campo Nome da janela do Editor para navegar de um para o outro).
Se você não desejar usar o Assistente, basta que use a ferramenta de criação sobre o nó Objetos do Banco de Dados.
Uma vez que a opção de Especificação de Tipo e de Corpo do Tipo ficam habilitadas, você poderá fazer a criação
usando diretamente o editor de PL/SQL.
♦ Between Pages – Este gatilho é disparado antes da formatação de uma determinada página e após a formatação da
página anterior. Por exemplo, entre a primeira e a segunda páginas, entre a segunda e a terceira, e assim por diante.
♦ After Report – Este gatilho é disparado após o término da execução do relatório. Pode ser utilizado com o
objetivo de remover uma determinada tabela, reinicializar algum tipo de controle ou mesmo executar outro
relatório seqüencialmente.
Nos exercícios testaremos alguns usos para estes gatilhos.
EMPACOTAMENTO DA LÓGICA
As formas de empacotamento (procedimentos, funções e pacotes) apresentadas acima existem tanto no ambiente
cliente quanto no ambiente servidor.
Com todas estas opções não há justificativa para um código não modular, não estruturado.
♦ Considere quebrar seu código PL/SQL em um pacote (do código X) se a visualização do texto ultrapassar três
páginas (em torno de 80 linhas).
♦ Considere criar rotinas (procedures ou functions) para trechos de programas repetitivos.
♦ Crie uma biblioteca com rotinas que você possa utilizar em diversos sistemas. Podem existir soluções já criadas
em um sistema, que facilitem sua programação em outro.
♦ Documente sempre.
A lista acima é apenas de sugestões. Você encontrará a forma mais adequada para o desenvolvimento das suas aplicações.
DATABASE TRIGGERS
Já vimos que a atualização de objetos do banco de dados é possível com a ferramenta Report Builder. Veremos a
manutenção de um trigger do banco de dados.
Expandiremos o nó Objetos do Banco de Dados (Database Objects), o nó Desenv (usuário em uso), o nó Tabelas
(Tables) e a tabela Func para encontrarmos o nó Trigger.
Acionaremos, então, a ferramenta Criar (Create) para que seja mostrado o diálogo de manutenção de Database
Triggers (o mesmo apresentado pelo Form Builder).
Neste diálogo pressionaremos o botão Novo (New) para que a tela seja habilitada.
O EDITOR DE PL/SQL
O Editor de PL/SQL do Report Builder é exatamente igual ao do Form Builder. Para que não tenhamos de retornar
ao Capítulo 7 para lembrar sua funcionalidade repetiremos sua ações. A janela do editor nos apresenta algumas
informações a respeito do código de PL/SQL em definição.
Na parte superior encontramos um conjunto de botões com as seguintes funcionalidades:
♦ Compilar (Compile) – Aciona a execução do compilador PL/SQL para o código.
♦ Reverter (Revert) – Desfaz todas as modificações realizadas desde a última salva ou compilação bem-sucedida
(que realiza uma salva).
♦ Novo (New) – Cria um novo gatilho (trigger) com o mesmo escopo do atual. Um diálogo contendo a lista de
eventos é apresentado.
♦ Deletar (Delete) – Remove o gatilho atual.
♦ Fechar (Close) – Fecha e salva as modificações efetuadas, sem compilar.
♦ Ajuda (Help) – Aciona o mecanismo de ajuda. Apresenta um diálogo contendo informações sobre o editor PL/SQL.
Imediatamente abaixo dos botões são apresentados o tipo e o escopo do objeto atual:
♦ Tipo – Indica o tipo de código de PL/SQL (Tudo, Nível de Objeto ou Local). O editor de PL/SQL é o mesmo nas
três situações com esta mesma janela de diálogo.
♦ Objeto – Indica a que tipo de objeto (se for o caso) o código está associado. Alguns valores válidos são: Parâmetro,
Coluna, Quadro, Quadro de Repetição, Gráfico, Botão, Relatório, etc.
♦ sem título – Quando o campo Objeto está preenchido com um tipo de objeto do relatório, neste campo
encontramos o nome do objeto.
Finalmente, a última linha de informações apresenta o campo Nome, no qual o Report Builder identifica o tipo
de código de PL/SQL (Gatilho de Formatação, Fórmula, Gatilho de Formato, etc.) associado com o objeto
identificado anteriormente.
Abra a janela de um dos textos de PL/SQL já digitados e verifique os itens comentados a seguir.
INDENTAÇÃO AUTOMÁTICA
Observe que a cada linha digitada o posicionamento do cursor na linha subseqüente acompanha a indentação da
linha que lhe é superior.
INDENTAÇÃO MANUAL
Para indentação manual contamos com as opções Endentar e Endentar Invertido do menu Editar (se usarmos o
mouse) e com as teclas Tab e Shift + Tab, respectivamente, se usarmos o teclado.
CORES
No texto digitado, pudemos observar que houve variação no colorido das informações. As palavras-chaves,
comentários, constantes strings e numéricas, os símbolos de atribuição ( := ) e de concatenação ( || ) são destacados
com cores diferentes que os identificam facilitando a localização das informações.
SELEÇÃO
Podemos selecionar tanto linhas de texto quanto colunas.
Para selecionar uma linha, posicione o mouse no canto esquerdo da linha (sobre a faixa existente na lateral
esquerda) até que o formato do ícone seja a seta e clique no botão esquerdo.
Para selecionar uma coluna pressione a tecla ALT e com o mouse selecione (“pinte”) a(s) coluna(s) desejada(s).
Para realizar estas ações basta que façamos a seleção do trecho de código desejado (linha) e em seguida soltemos o
mouse. Quando aproximarmos o mouse novamente sobre a área selecionada, o desenho do cursor mudará para
seta (em vez do i ).
Neste momento se desejarmos efetuar uma movimentação, simplesmente arrastamos o mouse (sem soltar o botão)
para o ponto desejado e, em seguida, soltamos o botão do mouse. Você notará que o cursor mudará de posição
indicando a localização onde o trecho será incluído. Durante a movimentação o desenho do ícone do mouse
ganhará um retângulo sob a seta.
Se desejarmos copiar o trecho em vez de apenas movimentá-lo, devemos pressionar a tecla Ctrl e efetuar as mesmas
ações descritas anteriormente. Neste caso o desenho do ícone do mouse além do retângulo apresentará, também,
um quadrado preenchido com o sinal +, ambos sob a seta.
Observe na lateral direita, acima da seta da barra de rolagem vertical, a existência de uma pequena barra de split.
Clique sobre ela e arraste o mouse para baixo (sem soltar o botão).
No canto inferior esquerdo, ao lado da seta da barra de rolagem horizontal, a mesma barra de split. Novamente
clique sobre ela e arraste o mouse para a direita (sem soltar o botão). Para desfazer este efeito basta um clique duplo
sobre a linha separadora dos quadros.
OPÇÃO DESFAZER
A opção Desfazer (Undo) pode ser repetida muitas vezes (e não apenas uma). O Report Builder guarda todas as
modificações realizadas no código desde a última operação de Salvar. Esta ação está disponível no menu Editar.
EXERCÍCIOS
8.29) Crie um relatório de nome REP29 que apresente a seguinte funcionalidade:
♦ Selecione as colunas dt_adm, dt_nasc, nm_func, nm_sobrenome e cd_mat da tabela Func.
♦ Defina uma rotina local que receba uma data e retorne-a no formato dd/mm/yyyy hh24:mi:ss.
♦ Defina uma rotina local que receba dois textos, retire os brancos finais e iniciais, concatene os dois textos com
um branco entre eles e retorne a primeira letra de cada palavra em maiúscula.
♦ Utilize essas rotinas dentro do Modelo de Dados para formatar as datas de nascimento e admissão e o nome do
funcionário (nome e sobrenome).
INTRODUÇÃO
Após termos trabalhado bastante no layout conheceremos mais alguns de seus objetos específicos: Quadros (Frames),
Âncoras (Anchors) e Botões (Buttons).
Neste tópico continuaremos desenhado o layout manualmente para que nosso entendimento seja o melhor possível.
Criaremos uma nova aplicação de nome Layout3 contendo duas queries, relacionadas a seguir:
♦ QFunc contém o seguinte comando “Select cd_mat, cd_depto, nm_func, vl_sal from Func”.
♦ QPrjatv contém o seguinte comando “Select cd_proj, cd_ativ, dt_ini, dt_fim from PrjAtv”.
No Layout, inicialmente criaremos apenas a Query QFunc, de acordo com o formato apresentado na Figura 8.67.
Neste Layout desenhamos o Repeating Frame Rfunc contendo as quatro colunas presentes na query. Abaixo deste
Repeating Frame criamos um objeto do tipo imagem.
Sabemos que o Repeating Frame vai se desenvolver verticalmente ao longo da página. O que acontecerá? Os dados
passarão sobre o desenho?
Ao executarmos, observamos que o Report Builder empurrou o objeto até o fim do relatório. O arquivo BMP só foi
impresso na última página do relatório, após a última linha impressa. Por quê?
A Figura 8.68 nos dá uma explicação. Subordinado ao objeto B_1 e ao objeto R_G_CD_MAT, aparece um nó
chamado de Informações sobre Ancoragem. Isto significa que existe uma âncora ligando o objeto B_1 ao objeto
R_G_CD_MAT. Essa âncora vai garantir que somente após a formatação do objeto R_G_CD_MAT, o objeto B_1 será
formatado, impedindo que o Repeating Frame se sobreponha ao objeto.
Neste diálogo existem duas pastas: Geral (General) e Layout. O objetivo deste diálogo é determinar o que deve ser
visualizado no Navegador.
Na pasta Geral (General) temos apenas duas opções que indicam se desejamos visualizar os ícones dos objetos e se
desejamos visualizar o ícone indicador de PL/SQL.
Na pasta Layout indicamos se desejamos visualizar os boilerplates de texto, boilerplates gráficos, boilerplates externos
(Arquivo de Ligação – Link File), boilerplates de imagens, campos, botões, gráficos (do Graphics Builder), objetos
OLE2 e informações sobre ancoragem (que é o nosso objetivo).
ÂNCORAS (ANCHORS)
Âncoras determinam o posicionamento relativo de todos os objetos na impressão do relatório. Elas associam um
objeto de Layout chamado de objeto-filho a um segundo objeto chamado de objeto-pai.
Elas também definem o posicionamento vertical e horizontal do filho em relação ao pai.
Existem dois tipos de âncoras no Report Builder: implícitas e explícitas. No exemplo anterior, tivemos um exemplo
de ancoragem implícita.
O Report Builder cria uma âncora implícita todas as vezes em que há o risco de um objeto se sobrepor a outro. Isto
é muito comum quando definimos um objeto de tamanho variável.
Como teste adicional, vamos diminuir o campo que apresenta o nome do funcionário e vamos transformá-lo em
variável no sentido horizontal.
Retorne ao Navegador e verifique o que o Report Builder criou: ele ancorou o salário do funcionário no nome do
funcionário. Observe que o campo F_nm_func é pai na ancoragem que se relaciona com F_vl_sal.
Portanto, podemos entender os tipos de âncora da seguinte forma:
♦ Âncoras Implícitas – Criadas pelo Report Builder a tempo de execução. Ele as cria objetivando garantir que não ocorrerá
sobreposição de objetos. Somente são geradas âncoras implícitas para objetos que não tenham âncora explícita definida.
♦ Âncoras Explícitas – Criadas pelo desenvolvedor no Report Builder. São criadas com o objetivo de garantir o
posicionamento relativo de objetos. Se sobrepõem a qualquer âncora implícita criada.
Como exemplo, criaremos uma âncora explícita entre F_nm_func e F_vl_sal. A criação da âncora deve seguir os
passos abaixo:
♦ Clicar no objeto âncora (anchor) na paleta de ferramentas (vertical).
♦ Clicar na linha (lateral esquerda) do objeto F_vl_sal. Não adianta clicar no interior do objeto. Tem de ser na
linha. Se necessário, aumente o nível de zoom para melhor visualização. Pode soltar o mouse.
♦ Duplo clique na linha (lateral direita) do objeto F_nm_func.
Observe o resultado na Figura 8.70. Apesar de não identificarmos diferenças no Navegador, as características da
âncora explícita são determinadas por nós. Vejamos suas propriedades. Selecione o objeto âncora e dê um clique
duplo ou use o botão direito do mouse. A tela de propriedades é apresentada.
Neste diálogo observamos logo a indicação de qual objeto é o pai da relação e qual objeto é o filho. As demais
propriedades, porém, requerem um pouco mais de análise.
Começaremos analisando o que significa o tipo de limite para pai e filho (Child Edge Type e Parent Edge Type).
Cada objeto possui quatro lados: Topo, Base, Esquerda e Direita.
No exemplo da Figura 8.71, o objeto-pai (F_nm_func) está com a âncora posicionada no lado direito (À Direita – Right)
e o objeto-filho (F_vl_sal) está com a âncora posicionada no lado esquerdo (À Esquerda – Left). É esta a informação
fornecida pelas propriedades Tipo de Limite-Pai (Parent Edge Type) e Tipo de Limite-filho (Child Edge Type).
Estas propriedades, portanto, determinam as laterais dos dois objetos onde a âncora está pendurada.
Nosso próximo conjunto de propriedades chama-se Percentual de Limite (Edge Percent), tanto para pai (parent)
quanto para filho (child).
No nosso caso, os dois objetos estão posicionados lado a lado. Sendo assim, a distância entre eles é fixa – ou seja,
a tempo de impressão, o posicionamento lateral será sempre distante do tamanho da âncora no desenho. No
entanto, o posicionamento vertical é fornecido como percentual. Isto ocorre porque nosso objeto poderá crescer
também na vertical; sendo assim, a âncora garante que o posicionamento relativo dos dois objetos se manterá
constante a tempo de execução.
Se os objetos estivessem posicionados um sobre o outro, o que se manteria constante seria a distância vertical,
enquanto a distância horizontal se manteria variável.
Na Figura 8.72 verificamos como o Report Builder controla o posicionamento com a âncora. Na parte superior do
desenho apresentamos a definição feita a tempo de Layout: o posicionamento lateral fixo e o posicionamento
vertical 50% para o pai e 50% para o filho em relação à lateral onde está pendurada a âncora.
Na parte inferior, verificamos o que acontece a tempo de execução. Suponhamos que o objeto-pai tenha crescido
tanto verticalmente quanto horizontalmente. Sendo assim, após sua formatação (ele é formatado primeiro que o
objeto-filho), o Report Builder deve manter as mesmas proporções definidas a tempo de Layout; portanto ele determina
o posicionamento vertical de 50% em relação à lateral direita, traça uma distância fixa na horizontal e monta o
objeto-filho com o ponto central (50%) de sua lateral esquerda exatamente na fronteira da distância determinada.
O posicionamento relativo é mantido. Esta é a intenção da ancoragem: garantir que o posicionamento relativo dos
objetos seja mantido.
Ainda temos dois parâmetros para analisar: Fechar Horizontalmente (Collapse Horizontally) e Fechar Verticalmente
(Collapse Vertically).
Estes parâmetros indicam que, se o objeto-pai não for formatado, o objeto-filho deverá ser formatado colado à
posição onde terminaria o objeto-pai, sem a manutenção da distância fixa.
Para entendermos toda esta explicação, retornemos ao nosso exemplo.
A Figura 8.73 nos mostra o layout de teste do nosso exercício. A âncora foi tornada explícita. Para que o nome do
funcionário não fosse formatado em determinada situação, criamos o gatilho de formatação associado a F_nm_func
apresentado na Listagem 8.24.
END IF;
end;
Quando o nome do funcionário não é formatado, a âncora posiciona o objeto-filho exatamente com a distância
definida a tempo de layout. Veja que na Figura 8.74 desenhamos a âncora para mostrar esta distância. O espaço
entre a âncora e o objeto F_cd_depto corresponde à distância que existiria entre F_cd_depto e Fnm_func.
Alteraremos a propriedade desta âncora para definir o colapso horizontal. Observe que na linha de matrícula 10
(nm_func=Cristina), o salário está alinhado com os demais nomes de funcionários, ou seja, a coluna de salário
ocupou, exatamente, a posição do nome. A distância da âncora foi totalmente suprimida.
Observe o resultado na Figura 8.75.
QUADROS (FRAMES)
Um Quadro (Frame) possui um subconjunto das funções de um Repeating Frame. São semelhantes aos Quadros de
Repetição (Repeating Frame) nos seguintes aspectos:
♦ Podem conter qualquer objeto de layout, incluindo outros Quadros (Frames).
♦ Podem se expandir, contrair, ser variáveis ou de tamanho fixo, horizontalmente ou verticalmente.
♦ Podemos definir atributos de apresentação (cor, fontes, etc.) e condições lógicas para o Quadro (Frame) e todos
os objetos pertencentes a ele usando triggers.
Os Quadros (Frames), no entanto, são diferentes dos Quadros de Repetição (Repeating Frames), pois não estão
associados a registros. São impressos tão freqüentemente quanto o objeto no qual eles estão contidos ou aos quais
eles estão associados.
No exemplo da Figura 8.76, a propriedade Impressão de Objeto Ativada (Print Object On) foi preenchida com
Todas as Páginas (All Pages) apenas para o Quadro (Frame). Todos os boilerplates de texto estão com esta propriedade
preenchida com Primeira Página (First Page).
Uma vez que o Quadro (Frame) será formatado em todas as páginas, ou seja, haverá uma nova instância do Frame
em cada página, os objetos pendurados no quadro serão formatados também em todas as páginas do relatório,
porém na primeira página de cada instância do objeto Frame.
Como segundo teste em nossa aplicação, criaremos agora um Layout que apresente não só Funcionário como
também Projeto e Atividade.
No Layout montado, colocamos os dois Repeating Frames (funcionário e projeto-atividade) lado a lado e abaixo de
ambos incluímos uma imagem. Sabemos que o Report Builder, percebendo que existe o risco de sobreposição dos
objetos, criará uma âncora implícita entre o objeto imagem e o objeto que cresce.
Neste caso, porém, existem dois objetos com crescimento vertical. Nesta situação o Report Builder determina onde
será feito o posicionamento da âncora baseado em algoritmos internos, ou seja, a âncora tanto pode ficar pendurada
em R_G_CD_MAT quanto em R_G_CD_PROJ.
O que aconteceria se o Report Builder decidisse pela ancoragem em R_G_CD_MAT? Os objetos do Repeating Frame
R_G_CD_PROJ passariam sobre a imagem.
Este problema ocorre porque um objeto-filho só pode estar ancorado em um objeto-pai.
Como solução de contorno, envolveremos os dois Repeating Frames em um Quadro (Frame), de tal forma que a
ancoragem ocorra em relação ao Frame e não mais em relação aos Repeating Frames.
A Figura 8.78 nos mostra a solução referida acima. Observe que este Quadro (Frame) deve ter a propriedade de
elasticidade vertical ativada, pois os objetos em seu interior gerarão diversas linhas.
BOTÕES (BUTTONS)
Podemos criar botões num relatório a fim de gerar relatórios interativos (online), isto é, um relatório que apresente
o resultado no vídeo.
Esses botões servem para:
♦ Permitir o acesso a arquivos multimídia (Imagens, Vídeo ou Som).
♦ Permitir o acesso a imagens gravadas no banco de dados.
♦ Executar códigos PL/SQL (por exemplo, executar outro relatório).
Criaremos um pequeno exemplo de utilização. Para tal salvaremos nossa aplicação Layout3 com o nome de Lay-
out4 e retiraremos todas as informações referentes a Projeto-Atividade.
Neste exemplo anexaremos um botão ao lado do Repeating Frame de funcionário, como apresentado no layout
da Figura 8.79.
Este botão só será apresentado uma vez no início do relatório, já que não está associado aos objetos do quadro.
Observe, porém, que poderíamos criar um relatório que recebesse como parâmetro um código de matrícula ou
nome e que fosse acionado quando o usuário clicasse no botão.
EXERCÍCIOS
8.33) Crie um relatório contendo duas queries independentes apresentadas lado a lado (uma com dados de
funcionário e outra com dados de projeto X atividade). Apresente duas imagens (uma sob cada querie) somente
quando todo o relatório for concluído.
8.34) Crie um relatório que contenha a lista de departamentos da empresa. Quando o usuário pressionar o botão
adequado, devemos acionar o relatório REP31. Para os departamentos A00, B01 e C01 não apresentar fotos, para os
demais departamentos apresentar.
8.35) Crie um relatório que selecione os seguintes dados da tabela de funcionários: matrícula, nome, salário e
cargo. O relatório deverá ter formato tabular, porém o layout deverá variar de acordo com o parâmetro recebido:
♦ A – Apresentar matrícula, nome e salário.
♦ B – Apresentar matrícula, salário e cargo.
♦ C – Apresentar matrícula, nome e cargo.
Os espaços entre os objetos apresentados na impressão devem ser constantes e semelhantes entre si.
O NÓ PACOTES EMBUTIDOS
Falaremos, agora, nos pacotes que aparecem sob o nó Pacotes Embutidos (Built-in Packages).
Para os testes deste grupo criaremos um relatório de nome Pacote, com as seguintes características:
♦ Colunas cd_depto e nm_depto da tabela Depto.
♦ Botão (pode ser incluído na linha de cada departamento ou ficar isolado).
SRW
Este é o pacote-padrão do Report Builder, ou seja, é aquele pacote que contém as rotinas básicas para utilização
dentro de um relatório. Com ele podemos alterar as propriedades de um objeto (Set_Attr), determinar a quantidade
máxima de linhas de uma query (Set_MaxRow), acionar outro relatório (Run Report) e muitas outras funcionalidades,
algumas delas já utilizadas ao longo dos exemplos e exercícios deste capítulo.
A lista completa das rotinas está presente no Capítulo 21.
OLE2
Conjunto de rotinas PL/SQL APIs para criação, manipulação e acesso a tributos de objetos OLE2 Automation.
Os objetos OLE2 Automation encapsulam um conjunto de atributos e métodos que podem ser manipulados ou
invocados de um OLE2 Automation Client. O pacote OLE2 permite que façamos acesso aos objetos OLE2 Automa-
tion Servers diretamente do PL/SQL.
No Form Builder este pacote, apesar de presente, deixará aos poucos de ser utilizado uma vez que as rotinas
presentes no pacote Standard Extensions realizam as mesmas operações de forma mais simples e eficiente (veja
Exercício 7.57 do capítulo de Form).
No Report Builder, estas rotinas não estão disponibilizadas ainda. Para os mesmos resultados ainda devemos nos
utilizar do pacote OLE2.
DDE
Este pacote permite a utilização do suporte a Dynamic Data Exchange (DDE) dentro dos componentes do Oracle
Developer.
DDE é um mecanismo pelo qual aplicações podem se comunicar e trocar dados em um ambiente Windows.
As funções DDE, habilitadas para as aplicações Oracle (Client) se comunicarem com outras aplicações do ambiente
Windows compatíveis com DDE (Server), compreendem três ações:
♦ Importação de dados.
♦ Exportação de dados.
♦ Execução de comandos para o servidor DDE (a outra aplicação).
Não desenvolveremos exemplos com este pacote. Para maiores informações utilize a ajuda do Report Builder para
exemplos e forma de utilização.
ORA_FFI
Este pacote provê uma interface de uso de funções C (terceira geração) diretamente dentro do PL/SQL.
No ambiente Windows as funções externas devem ser DLLs que, depois de registradas via funções ORA_FFI, podem
ser usadas em uma aplicação Reports.
ORA_DE
Este pacote é para uso interno do Report Builder.
Contém construções usadas pelo Oracle Developer para serviços privativos de PL/SQL.
Não desenvolveremos exemplos com este pacote.
ORA_PROF
Este pacote contém procedimentos, funções e condições de erro que nos permitirão verificar o tempo de execução
de uma determinada unidade de programa.
BEGIN
ORA_PROF.CREATE_TIMER('TEMPO');
ORA_PROF.START_TIMER('TEMPO');
FOR I IN 1..10000 LOOP
CONTA := 0;
END LOOP;
ORA_PROF.STOP_TIMER('TEMPO');
TEMPO := ORA_PROF.ELAPSED_TIME('TEMPO');
ORA_PROF.DESTROY_TIMER('TEMPO');
SRW.MESSAGE(1, 'Tempo transcorrido = '||TEMPO);
END;
Na Listagem 8.25 decidimos determinar o tempo total de somar 1 a uma variável 10.000 vezes. Para isto criamos o
timer, iniciamos a contagem (start), executamos a operação desejada, interrompemos a contagem (stop), destruímos
a área de contagem do tempo e obtivemos o valor do tempo transcorrido (retornado em milissegundos).
Separaremos, agora, este procedimento em duas partes, uma que criará o Timer e outra que verificará o tempo
decorrido. Este dois procedimentos serão acionados por um botão a ser incluído em nossa aplicação. O procedimento
da Listagem 8.26 apenas cria o Timer.
No procedimento da Listagem 8.27 apenas obtemos o resultado do tempo decorrido. Observe que utilizamos a
rotina Message do pacote SRW. Essa rotina mostra a mensagem em uma janela de Alerta. Recebe como parâmetro
um número dado por nós e o texto da mensagem. O número também aparece na mensagem apresentada.
Com a seqüência de testes deste tópico, acionaremos estas rotinas a fim de contabilizar o tempo total de execução
das ações programadas.
Para reinicializar o contador de tempo, devemos usar a rotina Reset_Timer deste pacote.
ORA_NLS
Este pacote permite que obtenhamos informações sobre o ambiente corrente.
Na Listagem 8.28 apresentamos uma procedure, na qual utilizamos duas rotinas do pacote Ora_Nls: a função
Modified_Date_Fmt, que retorna um boleano indicando se o formato de data foi ou não modificado, e a função
Get_Lang_Scalar que pode fornecer diversas características a respeito da linguagem corrente. Podemos obter dados numéricos.
O parâmetro recebido por esta rotina corresponde a uma constante definida no pacote. Os nomes e significados
destas constantes estão na ajuda do Report Builder sob o título Ora_Nls Numeric Constants.
TEXT_IO
Este pacote permitirá que venhamos a ler ou gravar informações para um arquivo do ambiente. É equivalente ao
pacote Text_IO do Form Builder. Trabalharemos com ele apenas nos exercícios.
TOOL_ENV
Permite que obtenhamos informações das variáveis de ambiente do Oracle.
Faremos um teste a título de exemplificação.
Na Listagem 8.29 utilizamos uma rotina do pacote Tool_Env (Getvar) para obter o nome de uma das variáveis do
ambiente. Você pode ver o nome destas variáveis no registrador do Windows com o RegEdit (nó
Hkey_Local_Machine, subnó Software, subnó Oracle, subnó HomeX – de acordo com seu Oracle-Home).
A rotina permite a obtenção destas informações dinamicamente.
Com esta rotina encerramos os testes da aplicação Pacote. Podemos acionar todas as rotinas criadas no botão e
verificar o tempo transcorrido total.
Para acionarmos o botão, devemos escolher a opção Previsualizador de Runtime no menu Exibir (View).
TOOL_RES
Este pacote fornece um mecanismo para extrairmos informações de um arquivo de recursos. Os arquivos de recursos
são providos pelas ferramentas (Form Builder, Report Builder, etc.) e contêm informações diversas utilizadas pelos
software. Podemos gerar nossos próprios arquivos de recursos com o utilitário ResPa21 a partir de um texto com
extensão PRN. Esse utilitário é fornecido juntamente com o Oracle*Terminal.
Não desenvolveremos exemplos com este pacote. Para maiores informações, utilize a ajuda do Report Builder para
exemplos e forma de utilização.
TOOL_ERR
O pacote Debug fornece um conjunto de informações a respeito do erro acontecido em uma área chamada “Error
Stack”. Essa área contém códigos e mensagens de erro organizadas em uma área indexada de 0 a n-1 (onde n é o
número de erros). Esse pacote permitirá a manipulação desta área de stack.
Não desenvolveremos exemplos com esse pacote. Para maiores informações, utilize a ajuda do Report Builder para
exemplos e forma de utilização.
STPROC
Este pacote é para uso interno do Report Builder.
Contém construções usadas pelo Oracle Developer para chamadas a subprogramas armazenados no banco de
dados. A utilização deste pacote nos relatórios é automaticamente montada quando solicitamos o uso de rotinas
presentes no banco de dados.
Não desenvolveremos exemplos com esse pacote diretamente.
LIST
Este pacote contém procedure, funções e condições de erro que podíamos usar para criar e manter listas de textos
(strings). Esta era a forma alternativa de trabalharmos com arrays no Report 2.5, uma vez que a PL/SQL disponível era
versão 1. No Report Builder já não temos mais necessidade desta utilização. Podemos usar o recurso do Type Table.
Não desenvolveremos exemplos com esse pacote diretamente.
DEBUG
O pacote Debug oferece um conjunto de rotinas, funções e condições de erro para realizarmos depuração em
aplicações Reports.
Esse pacote foi bastante utilizado no tópico de Depuração do Form Builder (é o mesmo). O conjunto de rotinas se
acha presente no Capítulo 15 (do Form Builder).
Os exemplos de utilização desse pacote serão vistos no tópico relativo ao Interpreter. Utilize a ajuda do Report
Builder para exemplos e forma de utilização.
STANDARD
Este pacote é utilizado implicitamente por nós todas as vezes que trabalhamos com PL/SQL. Corresponde ao
conjunto de rotinas de PL/SQL válidas no ambiente.
Nesta paleta encontramos a sintaxe completa de cada uma das funções e/ou procedimentos presentes nos pacotes.
Podemos incluir chamadas às rotinas obtendo a sintaxe (com ou sem parâmetros) do diálogo Paleta de Sintaxe. O
botão Incluir transfere para a área de texto PL/SQL onde se encontra o cursor a sintaxe para chamada à rotina
selecionada na Paleta de Sintaxe.
INTRODUÇÃO
Neste tópico, trataremos dos diversos tipos de variáveis de um relatório. Trabalharemos um exemplo que mostrará
a utilidade de cada uma delas.
As variáveis podem ser de diversos tipos, com características e abrangências diferentes:
♦ Variáveis Locais a um PL/SQL.
♦ Variáveis PlaceHolders.
♦ Variáveis de Pacote.
♦ Parâmetros.
VARIÁVEIS LOCAIS
São aquelas declaradas dentro de um gatilho ou rotina. Os valores dessa variável são acessíveis apenas dentro do
trecho de PL/SQL em que é declarada.
Na Listagem 8.31 criamos uma variável de nome Linguagem dentro do trigger Before Report. Essa variável está
obtendo o nome da linguagem, território e charset em uso no banco de dados. Sua vida útil, no entanto, é o
término do trigger onde está inserida.
O tipo destas variáveis é similar aos tipos válidos em PL/SQL (number, char, varchar2, date, <tabela ou
cursor>%rowtype, <coluna>%type, tipos do usuário, etc.).
Uma variável local é, basicamente, uma variável de trabalho. Se desejássemos que o conteúdo da variável local
apresentada na Listagem 8.31 fosse incorporada ao relatório, teríamos necessidade de referenciá-la no Layout.
Sabemos, no entanto, que os objetos do layout têm como origem os objetos do Modelo de Dados. Sendo assim,
precisaremos de um objeto no Modelo de Dados para que nossa informação possa ser apresentada.
Suas características são similares às de uma variável PL/SQL (com restrições). Podemos definir como tipo: caracter,
data ou numérico. Podemos especificar, ainda, tamanho e valor se nulo. Veja suas propriedades.
Continuaremos o exemplo anterior, substituindo a variável local pela variável PlaceHolder (Linguagem) criada no
Modelo de Dados.
Poderíamos criar uma variável de sumário que realizasse esta soma para nós, porém estamos estudando PlaceHolders
e desejamos efetuar a soma a tempo de impressão. Portanto, criaremos uma variável numérica (valor_salario) e a
apresentaremos no layout antes e depois da impressão dos salários. Para acumularmos o valor do salário, criaremos
um trigger de Formatação no campo vl_sal.
Essa mensagem nos avisa que não poderemos atualizar as variáveis Atual e Anterior a tempo de montagem do
layout, o que nos impediria de realizar a operação desejada.
Precisamos acumular o salário a tempo de montagem do layout e precisamos de uma variável no Modelo de Dados que
nos permita a apresentação dos valores. No entanto, não podemos atualizar essa variável durante a montagem do relatório.
VARIÁVEIS DE PACOTE
Quando criamos a parte de especificação de um pacote no Report Builder, todas as variáveis definidas neste local
são chamadas de variáveis de pacote, pois são variáveis de PL/SQL com visibilidade em toda a aplicação.
As variáveis de pacote possuem os mesmos tipos de uma variável local.
Em nossa aplicação substituímos as variáveis PlaceHolders pela variável do pacote no acúmulo de valores. E não
tivemos erro de execução.
Temos, ainda, de apresentar o valor. Sendo assim, criaremos um Field no início da página (porém dentro do corpo)
e um trigger de Formatação para este Field e um outro Field após o Repeating Frame com seu respectivo trigger de
formatação. Ambos os Fields devem fazer referência ao Place Holder valor_salario (mesmo que este não venha a ser
usado). Para garantir que ocorram diversas quebras de página, o Repeating Frame receberá como limitação um
número máximo de 5 registros por página.
A rotina Set_Field_Num permite que alteremos o valor a ser apresentado em um determinado field. Desta forma,
alteramos o valor do field Anterior, posicionado no início da página, acumulamos os valores na variável de pacote
Valor e novamente atribuímos essa variável ao field Atual, posicionado no fim da página.
Numa execução normal, o término da programação seria aqui. No entanto, sabemos que variáveis presentes em
pacotes persistem durante a sessão. Sendo assim, se viermos a executar este programa novamente (sem encerrarmos
a sessão atual), o valor inicial não será zero e sim o valor acumulado na execução anterior. Por este motivo, temos
mais uma tarefa a cumprir, ou seja, zerar essa variável Pacote.valor.
PARÂMETROS
As variáveis do tipo Parâmetro já foram estudadas em tópico específico anteriormente.
EXERCÍCIOS
8.36) Crie um relatório de nome REP36 que receba como parâmetro a página inicial a ser impressa e a quantidade
limite de registros. Devem ser mostrados na capa do relatório os parâmetros recebidos. Utilize a query Q20 para
montagem deste relatório.
CONCEITOS INICIAIS
A tempo de execução é possível modificar a formatação de um determinado objeto de Layout.
Para acompanharmos o exemplo deste tópico, criaremos um relatório de nome Dinamico contendo as colunas
Cd_Mat, Nm_Func, Cd_Depto e Vl_Sal.
Suponhamos que desejássemos destacar todos os valores de salário superiores a R$ 3.000. Poderíamos fazer um
gatilho de formatação com a seguinte lógica, apresentada na Listagem 8.38 e já vista anteriormente.
No entanto o Report Builder nos ajuda na montagem desta formatação uma vez que conta com um método para
formatação condicional bastante amigável. Veja a seguir!
FORMATAÇÃO CONDICIONAL
Retorne ao navegador e abra a tela de propriedades da coluna F_Vl_Sal. No grupo Layout Geral encontramos uma
propriedade chamada Formatação Condicional. Selecione esta propriedade para que seja mostrada a Figura 8.83.
Neste diálogo poderemos definir diversas condições para formatação. Editar uma condição anteriormente definida
(botão Editar), remover uma condição existente (botão Deletar) e mudar a ordem de montagem das condições
(botões Para Cima e Para Baixo).
Pressione o botão Novo para que seja criada uma nova formatação condicional. Teremos a apresentação de um
novo diálogo, mostrado na Figura 8.84.
Preencheremos este diálogo com as condições associadas ao campo que desejarmos. Observe que a formatação será
feita sobre o campo F_Vl_Sal, porém a condição pode ser montada em relação a qualquer dos parâmetros ou
elementos presentes no Modelo de Dados.
O diálogo apresentado é composto de duas partes: na parte superior trataremos de definir as condições e na parte
inferior as formatações.
Na parte superior contamos com um indicador de validade da condição (check box do lado esquerdo), de um
operador para a condição (entre, maior do que, igual a, etc.) e de dois campos para preenchimento de valores (no
caso de a condição necessitar).
Se marcarmos uma nova linha de condição, à direita será habilitado um campo para que informemos o operador
de ligação entre as condições (And ou Or).
Na parte inferior podemos formatar a fonte, cor de preenchimento, cor de linha e a supressão do elemento na
impressão (check box do lado esquerdo – Ocultar o Objeto). O botão Redefinir Formato apaga toda a formatação
que tivermos estabelecido.
Para efeito de teste determinaremos como condição que cd_mat esteja entre 40 e 100 e como formatação escolheremos
como fonte Bookman Old Style (se você não tiver esta fonte no ambiente Windows, escolha uma outra que seja bem
diferente), tamanho 12 e estilo Negrito e Itálico, cor de fundo Cinza e Cor de letra Azul (veja a Figura 8.85).
Quando você retornar ao Navegador, verificará que foi anexado um trigger de formatação ao campo F_vl_sal, cujo
conteúdo é apresentado na Listagem 8.39 a seguir.
return (TRUE);
end;
Este trigger usa um conjunto de rotinas do pacote SRW para a montagem da formatação dos itens.
Execute este relatório e verifique o resultado produzido.
ROTINAS
As rotinas do pacote SRW relativas à formatação de um determinado campo, dinamicamente, estão presentes no
capítulo sobre os pacotes do Report Builder.
VALORES
O Report Builder utiliza uma paleta de cores-padrão cujo arquivo se chama default.pal e que será detalhada a seguir:
♦ A primeira parte da paleta (região superior esquerda) é composta de 16 cores básicas nomeadas como: black,
white, green, darkgreen, gray, darkgray, cyan, darkcyan, red, darkred, blue, darkblue, yellow, darkyellow, ma-
genta, darkmagenta.
♦ A segunda parte da paleta (região inferior esquerda) é composta de oito células vazias em que podemos definir
cores customizadas (não recomendado em função da portabilidade).
♦ As próximas quatro colunas são compostas de variações de cinza. Cada cor tem o formato ‘gray<valor>’, onde o
valor varia de acordo com a percentagem de cinza. Os valores válidos estão no intervalo de 4 a 96, com incre-
mento de 4. Por exemplo: ‘gray4’, ‘gray8’, ‘gray12’, ‘gray16’, ‘gray20’, ‘gray24’, ‘gray28’, ‘gray32’, ...., ‘gray96’.
♦ O restante da paleta de cores contém cores especificadas por variações percentuais das cores vermelha, verde e
azul (RGB). Sendo que:
a) Os valores percentuais para vermelho ou verde são: 0, 25, 50, 75, 88 ou 100.
b) Os valores percentuais para a cor azul são: 0, 50, 75, 88 ou 100.
Cada cor é nomeada de acordo com o formato: ‘r<valor>g<valor>b<valor>’ de acordo com seus valores RGB. Por
exemplo, uma cor composta de 100% de vermelho, 88% de azul e 0% de verde teria o nome: ‘r100g0b88’.
Se desejarmos visualizar a cor em questão e seu nome correspondente, devemos efetuar os seguintes passos:
♦ Na opção Preferências (Preferences) do menu Ferramentas (Tools), preencher a propriedade Modo de Cor (Color
Mode) com o valor Editável (Editable).
♦ No editor do Layout, selecionar o menu Formatar (Format), submenu Opções de Layout (Layout Options),
opção Paleta de Cores (Color Palette).
Será apresentado um diálogo contendo a paleta de cores. Ao selecionarmos uma cor, seu nome é apresentado,
permitindo que o modifiquemos e façamos a customização de novas cores.
A seguir apresentamos alguns valores de Pattern (textura do objeto) na Figura 8.85.
EXERCÍCIOS
8.38) Crie um relatório de nome REP38 baseado na query Q20 e que contenha a seguinte funcionalidade:
♦ Devem ser apresentados em vermelho todos os salários maiores que R$ 4.000,00.
♦ Devem ser apresentados em verde todos os salários menores que R$ 2.000,00.
8.39) Crie um relatório de nome REP39 baseado na query Q20 e que contenha a seguinte funcionalidade:
♦ Às segundas as letras do relatório devem ser azuis.
♦ Às terças as letras do relatório devem ser verdes.
♦ Nos outros dias as letras devem ser pretas.
8.40) Crie um relatório que formate uma borda para os campos numéricos. A espessura da borda e cor serão
recebidas como parâmetro:
♦ Espessura – variando de 0 a 200.
♦ Cor de letra.
♦ Cor de preenchimento.
Baseie o relatório na Q20. Crie um grupo de quebra com desenvolvimento vertical. Teste a propriedade Column Mode.
TÉCNICA
♦ Modificação das características apresentadas e análise dos resultados.
PREFERÊNCIAS
Para obtermos as preferências do Report Builder, devemos escolher o menu Ferramentas e neste a opção Preferências.
Será apresentado um diálogo composto de cinco pastas que estudaremos separadamente.
PASTA GERAL
A pasta Geral contém características que afetam a salva e compilação dos módulos desenvolvidos utilizando este
Report Builder.
No diálogo apresentado, encontramos as seguintes opções:
♦ Suprimir Editor de Relatórios na Abertura (Suppress Report Editor on Open) – Indica se o editor de Relatório
deve ou não ser apresentado a tempo de abertura de um relatório.
♦ Suprimir Paleta de Propriedades na Criação de Objetos (Suppress Property Palette on Object Creation) – Esta
propriedade indica se a paleta de propriedades deve ou não ser apresentada imediatamente após termos criado
um objeto de layout. A marcação desta propriedade agiliza o processo de criação dos objetos do layout; no
entanto, não devemos nos esquecer de que Fields e Repeating Frames necessitam de relacionamento com o
Modelo de Dados antes de o relatório poder ser executado.
♦ Suprimir Recuperação da Lista na Entrada da Caixa de Diálogo (Suppress List Retrieval on Dialog Box Entry) – Indica
que nos diálogos de acesso ao banco de dados não será trazida a lista de objetos do banco de dados por default.
♦ Unidade de Medida (Unit of Measurement) – Especifica a unidade a ser usada na definição de um novo relatório.
As unidades disponíveis são: centímetros, polegadas ou pontos. O default é polegadas.
♦ Modo de Cor (Color Mode) – Esta opção determina como será feita a carga da paleta de cores para a aplicação.
Quando criamos ou abrimos ou carregamos uma aplicação, a paleta de cores associada a ela é carregada na tabela
de cores do sistema. Como esta tabela possui uma quantidade de espaços limitada, o Report Builder pode encontrar
dificuldade em dar manutenção a aplicações utilizando diferentes paletas. Os valores válidos para esta opção são:
a) Editável (Editable) – Indica que desejamos editar, ou seja, criar nossas próprias combinações de cores. Quando
a propriedade Color Mode está preenchida com este valor, a paleta de cores fica vulnerável a modificações da
nossa parte e, involuntariamente, em função da necessidade de carga de uma nova paleta. Somente devemos
utilizá-la quando desejarmos fazer uma modificação na paleta. Ao término, devemos retornar ao estado
normal, que é Read Only – Shared. Para que esta opção tenha efeito, devemos salvar as preferências e fechar
o Report Builder. Ao ativarmos novamente o Report Builder, devemos acionar o Editor de Layout e usar no
menu Formatar (Format), opções de Layout (Layout Options), Paleta de Cores (Color Palette).
O Report Builder utiliza uma paleta de cores-padrão cujo arquivo se chama default.pal, já estudado no tópico anterior.
Para editar uma cor, selecione uma das cores na parte vazia (branca), clique sobre o botão Editar. Será apresentado
um diálogo com cores básicas e matizes. Selecione uma cor básica, varie seu matiz, saturação e luminosidade,
clique sobre o botão Adicionar Cores Personalizadas e dê OK.
A cor definida ocupará a posição selecionada inicialmente na tabela.
Salve esta nova paleta de cores (Menu Arquivo – File, opção Exportar – Export, Paleta de Cores – Color Palette),
volte ao modo Read Only – Shared, preencha o nome do novo arquivo na opção Paleta de Cores, feche o Report
Builder e torne a abri-lo com esta nova paleta.
b) Somente Leitura – Compartilhado (Read Only – Shared) – Nesta opção, ao fazer a carga da paleta de cores
para a tabela de cores do sistema, o Report Builder verifica através do nome se uma determinada cor já existe
na tabela de cores do sistema para fazer o posicionamento similar. Se a cor não existir, será adicionada à
tabela de cores do sistema. Isto diminui a probabilidade de, ao utilizarmos aplicações com paletas de cores
diferentes, termos problemas de falta de espaço na tabela de cores.
c) Somente Leitura – Privado (Read Only – Private) – Esta opção não tem efeito no Report Builder, serve apenas
para compatibilidade com o Graphics Builder.
PASTA ACESSAR
Esta pasta definirá opções para as ações de abertura ou salva de uma aplicação.
O conteúdo da pasta é analisado a seguir:
♦ Acessar – Indica se os módulos serão lidos/gravados em arquivo (file) do sistema operacional, no banco de dados
ou arquivo/banco de dados. Esta última opção indica que a cada abertura ou salva será mostrado um diálogo
que questionará o usuário do local de armazenamento (arquivo ou banco de dados).
♦ Mostrar – Esta opção filtra o que deve ser apresentado no caso de uma leitura: relatórios, gabaritos, consultas,
etc. ou uma combinação daqueles que desejarmos.
PASTA ASSISTENTES
Esta pasta indica se desejamos ou não que o diálogo de abertura dos assistentes seja mostrado como primeiro diálogo.
ESTUDANDO O MÓDULO
As propriedades relativas ao relatório são armazenadas juntamente com o módulo e afetam a todas as execuções deste.
São subdivididas em cinco grandes grupos: Relatório (Report), Janela de Form de Parâmetros (Parameter Form Win-
dow), Escapes de Relatório (Report Escapes), Definições XML (Xml Definitions) e Modo Caractere (Character Mode).
RELATÓRIO (REPORT)
As propriedades deste grupo são:
♦ Unidade de Medida (Unit of Measurement) – Especificação da unidade de medida em que o Report Builder irá
trabalhar. As opções são: Centímetros, Polegadas e Pontos.
♦ Máx. de Páginas de Corpo Horizontais (Maximum Horizontal Body Pages) – Número máximo de páginas físicas
no corpo do relatório (para desenho), no sentido horizontal.
♦ Máx. de Páginas de Corpo Verticais (Maximum Vertical Body Pages) – Número máximo de páginas físicas no
corpo do relatório (para desenho), no sentido vertical.
♦ Ordem de Impressão do Painel (Panel Print Order) – Mostra a ordem de impressão das páginas físicas: para o
lado e para baixo ou para baixo e para o lado.
♦ Direção (Direction) – Associado ao Panel Print Order indica a direção (esquerda para direita ou vice-versa).
♦ Título do Previsualizador (Previewer Title) – Determina o título do Previsualizador (Previewer).
♦ Nome da Função (Role Name) – Indica o nome da role a ser adquirida a tempo de execução. Observe que uma
role só pode ser adquirida se o usuário tiver autorização (Grant) para esta role no banco de dados. Para informarmos
a password da role (se ela tiver) devemos clicar sobre o botão que é apresentado para a propriedade para que seja
apresentado diálogo adequado.
♦ Distribuição (Distribution) – os nomes, formatos, quantidade de cópias, tipos de destino, etc. para os arquivos
gerados pelo Report Builder para distribuição (será estudado em tópico específico).
O número de páginas de corpo não representa o número de páginas necessárias para a impressão de um relatório;
quem determina o número de páginas é a Query.
Desta forma, poderão ser impressas dez mil páginas ou uma e o parâmetro maximum body pages (horizontal e
vertical) continuará sendo 10 x 10. Este número de corpo é definido apenas para que possamos desenhar o relatório
na página de Layout.
♦ Altura (Height) – Altura da tela de parâmetro apresentado a tempo de execução do relatório. É expressa na
unidade de dimensionamento definida.
♦ Número de Páginas (Number of Pages) – Quantidade de páginas desta tela (Form).
válidos para esta propriedade são Texto (Text) e Arquivo (File). Se preenchermos com texto, a propriedade Page
Navigation Control Value deve conter textos de comandos em HTML para controle de navegação entre páginas.
Se preenchermos com arquivo, a propriedade Page Navigation Control Value deve conter referências a arquivos
(em HTML) para controle de navegação entre páginas.
♦ Valor de Controle da Página de Navegação (Page Navigation Control Value) – Nesta propriedade incluímos o
código HTML ou um nome de arquivo contendo código desejado, de acordo com a especificação da propriedade
Page Navigation Control Type.
♦ Desativar Item de Menu do Host (Disable Host Menu Item) – Inibe o item Host no menu File no Runtime
Parameter Form e no Live Previewer. O item Host aparece no menu File do Oracle Reports no modo caracter.
♦ Desativar Tecla de Tela Dividida (Disable Split Screen Key) – Inibe as teclas de função [SPLIT VERTICAL] e [SPLIT
HORIZONTAL].
♦ Desativar Tecla de Zoom (Disable Zoom Key) – Inibe a tecla de função [ZOOM/UNZOOM] no Live Previewer.
♦ Iniciar no Zoom (Start in Zoom) – Executa o Previewer como se tivéssemos pressionado a tecla [ZOOM], isto é,
a borda que normalmente aparece em torno do Previewer não é visível e tudo que pode ser visto é o resultado
do relatório.
♦ Suprimir Título do Previsualizador (Suppress Previewer Title) – Suprime a apresentação do título do Previewer.
EXERCÍCIOS
8.41) Crie um relatório baseado na Q20 que contenha a seguinte funcionalidade:
♦ Gerar estatísticas e verificar o resultado.
♦ Permita que outras aplicações executem enquanto o Report Builder obtém os dados para consulta.
♦ Marcar as seguintes opções para desenvolvimento:
a) A unidade de dimensionamento é pontos.
b) Incluir a máscara DD/MM/RRRR (para datas) e a máscara (9G999G990D00) para numéricos.
c) Módulos armazenados no sistema operacional.
d) Por default, obtenção de módulos do tipo Report.
♦ Modo Caracter.
8.42) Crie um relatório baseado na Q20 que contenha a seguinte funcionalidade:
♦ Criar duas novas cores em sua paleta de cores.
♦ Exporte a paleta de cores com o nome de pteste.pal.
♦ Garanta que sejam lidos aproximadamente 20 registros a cada acesso ao banco de dados.
♦ Quando o relatório concluir com sucesso, deve ser enviado, automaticamente, um commit para o banco de
dados. Caso contrário, deve ser acionado um Rollback.
♦ No layout do relatório devem ser utilizadas as novas cores criadas.
♦ O relatório deve alterar o ramal de todos os funcionários para que sejam formados com quatro números
começando com 9. Se não houver nenhum número a ser alterado, deve ser dado um erro.
CONCEITOS
Uma matriz é um relatório tabular de, pelo menos, quatro conjuntos de dados:
♦ Um conjunto de dados é mostrado ao longo da largura da página.
♦ Um conjunto de dados é mostrado verticalmente na página.
♦ Um conjunto de dados é o produto do cruzamento, que determina todas as possíveis localizações onde os dados
se cruzam.
♦ Um conjunto de dados é mostrado como o recheio das células que se cruzam.
O esquema da Figura 8.86 nos mostra estas características.
Os conjuntos de dados desenvolvidos ao longo da largura da página, tanto horizontalmente quanto verticalmente,
são chamados de grupos de dimensionamento, porque determinam a dimensão da matriz.
Sendo assim, se uma matriz é bidimensional, possui um grupo se desenvolvendo horizontalmente e outro
verticalmente; se uma matriz é tridimensional, possui um grupo se desenvolvendo verticalmente, outro
horizontalmente e um terceiro na horizontal ou vertical.
Existem quatro tipos gerais de relatórios matriciais a serem abordados neste material, porém poderemos criar
outros tipos a nosso critério. São eles:
♦ Simple Matrix.
♦ Nested Matrix.
♦ Cross Product Master/Detail.
♦ Matrix Break.
Para caracterizarmos as diferenças entre cada um destes tipos, criaremos relatórios-exemplo de cada um deles. Nosso
estudo começará pelo modelo Simple, que nos permitirá estudar três aspectos fundamentais de um relatório matricial:
♦ A quantidade de queries.
♦ A quantidade de grupos.
♦ A presença de sumários.
O Assistente de Relatório nos questionará em seguida sobre os dados que se desenvolverão verticalmente na página.
Veja a Figura 8.87.
Como próximo passo devemos especificar o grupo que se desenvolverá horizontalmente na página. Neste caso,
escolheremos nr_cargo.
Em seguida, devemos informar o que será apresentado no interior de cada célula, ou seja, o “recheio”. Escolheremos
o campo QTD.
Criamos este primeiro exemplo sem gabarito para que tivéssemos somente as informações definidas por nós. Para
que o resultado ficasse mais claro, no entanto, as linhas do grupo Recheio foram pintadas de preto para ficar em
destaque. Veja o resultado na Figura 8.88.
Com nossos conhecimentos do Report Builder, já sabemos que a freqüência de impressão está relacionada
diretamente aos grupos; portanto, se desejamos que haja um desenvolvimento horizontal e outro vertical, devemos
ter pelos menos dois grupos. No nosso caso desejamos, ainda, um terceiro grupo que seja o recheio das células.
Veja o resultado na Figura 8.89.
Observe na Figura 8.90 que os grupos foram renomeados para que indicassem exatamente a informação que
contêm. Não deixe de fazer esta ação, pois faremos muitas referências ao nome do grupo.
Outro fato que devemos observar é a ordem em que foi feita a divisão dos grupos. Os grupos de dimensionamento
ficam acima do grupo Recheio, ou seja, os grupos de dimensionamento são “pais” do grupo de recheio. Para cada
célula (chave cargo e departamento) será obtido um recheio.
Neste resultado ainda falta a determinação de um elemento que ligue os dois grupos de dimensionamento, isto é,
um grupo que faça o cruzamento de cada elemento vertical com cada elemento horizontal estabelecendo um
produto. Esse grupo é chamado de Cruzamento.
Podemos defini-lo com a ferramenta Produto Híbrido da paleta de ferramentas (vertical) do Modelo de Dados.
Com esta ferramenta, devemos envolver os dois grupos de dimensionamento. Veja a Figura 8.90.
Com esta especificação definimos o Modelo de Dados de uma Simple Matrix. Antes de passarmos ao Layout,
observemos que possuímos quatro grupos; portanto, precisaremos de quatro objetos no Layout que se relacionem
com estes grupos.
Definiremos, inicialmente, os dois primeiros Repeating Frames relativos ao relatório. O Repeating Frame horizon-
tal se desenvolve no sentido Down e deve ser criado primeiro (ficará atrás), será associado ao grupo Departamento.
O Repeating Frame vertical se desenvolve no sentido Across e será associado ao grupo Cargo.
Para criarmos o grupo de cruzamento, devemos selecionar simultaneamente os dois Repeating Frames e escolher a
opção Matriz de Layout do menu Inserir. O resultado está na Figura 8.91.
O objeto marcado corresponde ao grupo de cruzamento. Podemos, então, dar cor diferenciada a este grupo para
que tenhamos exata visibilidade do resultado gerado.
Como próxima etapa, criaremos o grupo “Recheio”, que será desenhado dentro (e sobre) o grupo de cruzamento.
Passaremos, agora, a definir as colunas do Modelo de Dados nos locais correspondentes no Layout.
Na execução deste relatório verificamos que o grupo Recheio só é montado quando existem dados a serem
apresentados e que a célula da matriz é montada em todas as situações.
Uma vez que não temos uma tabela de cargos, faremos uma simulação partindo da tabela de funcionários. Teríamos,
então, as seguintes queries:
♦ Q1 – Select distinct nr_cargo from func;
Observe na Figura 8.93 que criamos o grupo Matriz (ou de cruzamento) antes de relacionarmos a terceira query.
Esta ordem deve ser respeitada para que o resultado seja satisfatório.
Na Figura 8.94 concluímos o Modelo de Dados deste relatório. A ligação foi feita entre a coluna nr_cargo e a coluna
num_cargo, entre a coluna cd_depto e a coluna cod_depto. Clique no botão Ligação de Dados (Data Link), em
seguida na coluna nr_cargo e, sem soltar o mouse, arraste-o para a coluna num_cargo, soltando-o em seguida.
Repita esta operação para as colunas cd_depto e cod_depto.
A montagem do Layout é semelhante ao anterior, com a diferença de que as colunas cod_depto e num_cargo não
são apresentadas no layout. Foram criadas apenas com a finalidade de relacionar as queries.
CONCLUSÃO
Concluímos destes exemplos que desenvolvemos que o número de queries não importa para o resultado final do
relatório. O que define a quantidade de dimensões e a complexidade da matriz é o número de grupos.
A inclusão de colunas de sumário é feita no grupo matricial quando o sumário estiver relacionado a pelo menos
uma das dimensões da matriz, como é o caso da quantidade de funcionários por cargo (dimensão Cargo) e a
quantidade de funcionários por departamento (dimensão Departamento). Já o total geral de funcionários não está
associado a nenhuma dimensão, e portanto deve ser criado fora dos grupos. Veja a Figura 8.95.
A criação de sumário para uma matriz requer mais informação que a criação de sumário para outros tipos de
relatório. Quando criamos sumários para colunas da sua matriz, necessitamos indicar:
♦ A freqüência do sumário – A freqüência especifica os grupos de dimensionamento para os quais desejamos
calcular o sumário.
♦ A ordem na qual devemos calcular o sumário – A ordem determina o critério de navegação para o cálculo (de
cima para baixo ou da esquerda para a direita). No Report Builder esta especificação é fornecida com a opção
Product Order para o(s) sumário(s).
Obtenha a tela de propriedades da coluna de sumário Sum_Depto. Trata-se de uma soma (propriedade Função),
relativa ao item qtd (propriedade Origem), que deve ser zerada quando houver quebra de departamento (propriedade
Reinicializar em), cujo valor se não existir deve ser mostrado zero (propriedade Valor se Nulo) e que para realizar a
soma precisa que os valores estejam ordenados por departamento (propriedade Ordem do Produto).
A única propriedade ainda não vista é justamente a propriedade Ordem do Produto (Product Order), a qual indica
qual a ordenação a ser aplicada aos valores para que seja gerado o resultado desejado. No exemplo atual, a ordenação
dos dados apenas por departamento ou por departamento e cargo simultaneamente não faz diferença para o
resultado. O que é necessário para a soma correta da quantidade de funcionários por departamento é que os dados
estejam em ordem de departamento.
Baseado nestas explicações, crie o sumário relativo ao cargo.
O sumário geral também não requer nenhuma informação adicional. Passemos, então, ao layout para a criação
desses sumários nos locais adequados. Veja o posicionamento do sumário na Figura 8.96.
NESTED MATRIX
Neste tipo de matriz existem mais de duas dimensões. Trabalharemos com a quantidade de funcionários por cargo,
por departamento e por sexo.
MODELO DE DADOS
Podemos criar o modelo de dados para uma Nested Matrix com uma query ou múltiplas queries.
Devemos ter, pelo menos, três grupos no interior do grupo de cruzamento. A Listagem ilustra a query utilizada
para desenvolvimento deste teste.
Esse modelo matricial é similar ao Simple, com a diferença da quantidade de dimensões. Utilizaremos os grupos na
seguinte ordem: Cargo, Departamento e Sexo. Prepare o Modelo de Dados adequadamente.
LAYOUT
Layout para uma Nested Matrix também é semelhante ao Simple, independente do uso de uma ou múltiplas
queries no seu modelo de dados.
Na Figura 8.97 observamos a presença de mais de um Repeating Frame no sentido vertical (cargo e sexo) cruzado
por um Repeating Frame no sentido horizontal (Departamento).
MODELO DE DADOS
O modelo de dados deve ser criado com mais de uma query para que seja possível estabelecer o relacionamento
Master/Detail.
Novamente, devemos ter pelo menos três grupos pertencentes ao grupo de cruzamento, como vemos na Figura 8.98.
Observe que existe um relacionamento Master/Detail entre duas das dimensões do grupo (G_Depto e G_Cargo).
Uma vez que um dos grupos depende do outro, somente os registros-detalhe relacionados aparecerão para cada
registro-pai.
LAYOUT
O layout para um relatório Cross-Product Master/Detail está apresentado na Figura 8.99.
Execute o relatório e observe que o resultado desse teste apresenta muito menos linhas que o do exemplo anterior
(Nested Matrix).
MATRIX BREAK
Um relatório do tipo Matrix Break possui uma nova matriz para cada registro-pai. No exemplo seguinte, para cada
depto (master) no relatório, existe uma única matriz que contém somente os cargos de cada sexo para aquele
departamento.
MODELO DE DADOS
Quando desejamos uma matriz com quebra, devemos definir, no modelo de dados, um grupo-pai para o grupo
do cruzamento.
LAYOUT
A Figura a seguir ilustra o layout para uma matriz com quebra.
Observe que o Repeating Frame contendo o campo ano (F_cd_depto) envolve os Repeating Frames e o objeto
matricial que representam a matriz.
Este Repeating Frame externo é que faz com que uma matriz separada seja apresentada para cada departamento.
EXERCÍCIOS
Para uma fixação maior do desenvolvimento de uma matriz, criaremos os relatórios deste tópico sem a ajuda do Assistente.
8.43) Crie um relatório de nome REP43 que apresente uma matriz com as seguintes características:
♦ Departamento contra sexo (nome do departamento e sexo por extenso).
♦ Usar uma query.
8.44) Crie um relatório de nome REP44 que apresente uma matriz com as seguintes características:
♦ Departamento contra sexo (nome do departamento e sexo por extenso).
♦ Quantidade de funcionários por sexo e por departamento.
♦ Usar mais de uma query.
♦ Tornar visível a célula da matriz.
8.45) Criar um relatório de nome REP45 baseado no relatório REP44 acrescentando a seguinte funcionalidade:
♦ Sumário com total de funcionários por sexo.
♦ Sumário com total de funcionários por departamento.
♦ Sumário com total geral de funcionários.
♦ Acumulado de funcionários por departamento e por sexo.
8.46) Crie um relatório de nome REP46 que apresente uma matriz com as seguintes características:
♦ Usar uma query.
♦ Sumário de salário por grau de instrução, departamento e sexo.
♦ Sumário de salário por grau de instrução e departamento.
♦ Sumário de salário por grau de instrução e sexo.
♦ Sumário de salário por grau de instrução.
METODOLOGIA
♦ Apresentação conceitual de bibliotecas e métodos para criação e uso.
TÉCNICA
♦ Desenvolvimento de exemplos e exercícios que contemplem o conceito apresentado.
INTRODUÇÃO
Até este ponto trabalhamos exclusivamente com um módulo do tipo RDF, ou seja, um fonte Report criado pelo
Report Builder. Sabemos, no entanto, que esta ferramenta é capaz de criar outros tipos de arquivo, como por
exemplo um módulo Library (extensão PLL).
Uma Biblioteca (Library) é uma coleção de programas PL/SQL incluindo procedimentos, funções e pacotes.
Estas rotinas grupadas em um arquivo podem ser compartilhadas, no ambiente cliente, por diversas outras aplicações,
sejam elas Relatórios, Telas, Menus e outras Bibliotecas (Libraries).
A biblioteca criada deve ser associada a cada módulo no qual desejamos utilizá-la (Attach).
Uma vez anexada, podemos fazer referência às rotinas presentes na biblioteca em qualquer ponto de PL/SQL do
relatório ou em unidades de programa (program unit).
Para acompanharmos sua utilização, criaremos um outro relatório de nome Rep_Lib. Esse relatório está baseado na
tabela Func com as colunas cd_mat, nm_func, cd_depto, nr_cargo, nr_git, in_sexo, dt_nasc e vl_sal. O estilo do
relatório é Tabular.
Após a criação desta aplicação, salve-a e feche-a. Só a utilizaremos após a criação e compilação da biblioteca.
No Modelo de Dados, após a criação da query, colocaremos a coluna cd_depto como grupo de quebra e junto a esta
criaremos a fórmula Nome, conforme apresentada na Listagem 8.38.
♦ A rotina está associada a ações específicas do ambiente cliente (usa rotinas do nó Pacotes Embutidos do Report Builder).
EXERCÍCIOS
8.47) Criar uma biblioteca de PL/SQL de nome BPL47 que contenha as seguintes rotinas:
♦ Rotina (Dv_Matr) para calcular o DV da matrícula do funcionário (noves fora).
♦ Rotina (Intervalo) para determinar o intervalo de anos entre duas datas recebidas como parâmetro.
♦ Rotina (Abono) para calcular o abono salarial (trimestral) de acordo com o número de anos de casa. A rotina
deve receber como parâmetro o tempo de serviço e o salário.
♦ Menos de 1 ano de casa – Não recebe abono.
♦ De 1 a menos de 3 anos de casa – Recebe 3% de abono.
♦ De 3 a menos de 6 anos de casa – Recebe 10% de abono.
♦ Mais de 6 anos de casa – Recebe 15% de abono.
8.48) Crie um relatório de nome REP48 que utilize a biblioteca REP47 para a construção do relatório. Todos os
valores devem ser apresentados na linha-detalhe.
DESCRIÇÃO
Um gabarito é um padrão de layout que estaremos estabelecendo para o desenvolvimento de relatórios de uma instalação.
Esse gabarito pode conter cabeçalhos, rodapés, números de página, capa, contracapa, Figura de marca d’água e
diversas outras características.
Podemos estabelecer padrões gerais ou padrões por estilo de relatório (matricial, tabular, grupado acima, abaixo, etc.).
Para estudarmos criaremos um Gabarito, analisaremos as possibilidades de padrão e faremos a geração de um
relatório com o padrão criado.
A ESTRUTURA DE UM GABARITO
Se você tiver algum módulo aberto (seja biblioteca ou relatório), feche-o para iniciarmos o estudo de gabaritos.
No Navegador de Objetos selecione o nó Gabaritos e, com a ferramenta Create, crie um novo gabarito.
Observamos que contamos com uma área de Modelo de Dados, um Layout, Gatilhos de Relatório, Unidades de
Programa e Bibliotecas Armazenadas.
MODELO DE DADOS
Na área relativa ao Modelo de Dados podemos criar parâmetros de usuário e estabelecer valores-padrão para os
parâmetros de sistema.
Não podemos, no entanto, definir queries ou quaisquer outros objetos relativos ao Modelo de Dados.
Expanda o nó Modelo de Dados e observe o seu conteúdo.
PL/SQL NO GABARITO
Os Gatilhos de Relatório, Bibliotecas Anexadas e Unidades de Programa que viermos a estabelecer em um gabarito
serão copiadas para o relatório-destino a tempo de montagem do relatório, o que nos permitirá definir determinadas
rotinas que sempre venham a ser executadas.
LAYOUT
A área de Layout é onde nos deteremos mais a fim de estudarmos as diversas formas de padronização.
Façamos a expansão do nó Layout para que possamos visualizar o subnó presente. Observe que somente encontramos o
nó Seção, indicando que as especificações que viermos a fazer afetarão às Seções do relatório ao qual fizermos a associação.
Subordinado a este nó encontramos os subnós Margem e Corpo, exatamente como encontramos em um relatório.
O nó margem está vazio e poderá ser preenchido com os mesmos tipos de especificação que costumamos usar em
um relatório; isto quer dizer que poderemos criar boilerplates de texto, gráficos, criar campos (fields) com origem
de data, número de página ou fazer referência a qualquer objeto presente no modelo de dados (observe que no nó
Modelo de Dados somente podemos especificar parâmetros).
Na área do corpo (Body), no entanto, não poderemos criar qualquer objeto, poderemos apenas estabelecer valor
para as propriedades dos objetos que vierem a ser definidos no corpo.
AS SEÇÕES DO CORPO
Se expandirmos o nó Corpo, observaremos que ele está subdividido em duas partes: Default (Default) e
Sobreposição (Override).
SEÇÃO DEFAULT
Todas as propriedades que viermos a estabelecer neste local afetam a todos os estilos de relatório que vierem a ser
desenvolvidos utilizando este Gabarito (Template).
Esta seção está subdividida em cinco partes:
♦ Estruturas (Frames) – Neste local definimos atributos para os frames (Repeating Frames ou Frames) que envolvam
os diversos tipos de elementos: frame-pai que envolve a seção, frame que envolve os cabeçalhos, frames que
envolvam os campos e frames que envolvam os sumários.
♦ Labels / Cabeçalhos de Campos (Field Labels/Headings) – Neste local definimos atributos para os boilerplates
que atuam como Labels ou Cabeçalhos de campos. Encontramos aí nós para especificação de propriedades de
boilerplates, cabeçalhos de campos do tipo alfanumérico, numérico e data.
♦ Campos (Fields) – Neste local definimos atributos para os campos do relatório, com diferenciação para campos
do tipo alfanumérico, numérico e data.
♦ Labels Sumariados (Summary Labels) – Neste local definimos atributos para boilerplates que atuam como labels
(cabeçalhos) de sumários. Encontramos aí nós para especificação de propriedades de boilerplates, cabeçalhos de
sumários do tipo alfanumérico, numérico e data.
♦ Resumos (Summaries) – Neste local definimos atributos para os sumários do relatório, com diferenciação para
sumários do tipo alfanumérico, numérico e data.
GRUPO LAYOUT
Neste grupo encontramos as propriedades:
♦ Alinhamento (Alignment) – Determina como os títulos e campos em uma linha serão posicionados ao longo da
página. Essa propriedade só é valida para o estilo Form. O número de campos por linha é determinado pela
propriedade a seguir. Os valores válidos para esta propriedade são: Esquerda (Left), Direita (Right), Centralizado
(Center), Esvaziar (Flush) e Coluna (Column). No caso de Flush, o campo mais à esquerda será alinhado à
esquerda (junto com seu título), o campo mais à direita será alinhado à direita (junto com seu título) e os
demais serão distribuídos entre os dois primeiros de forma proporcional.
♦ Campos por Linha (Fields Per Line) – Determina o número máximo de campos (fields) por linha de relatório.
Essa propriedade só é valida para o estilo Form. Se atribuirmos o valor zero a essa propriedade, estaremos
indicando que não existe limite e que devem ser configurados quantos campos couberem na linha.
♦ Usar Espaçamento Vertical (Use Vertical Spacing) – Esta propriedade preenche os espaços não usados da linha
anterior (se marcada com Sim – Yes).
♦ Posição (Position) – Define o posicionamento do objeto-pai em relação ao objeto-filho. Por default, o
posicionamento do pai é acima do filho.
♦ Colocar Labels Sobre Campos (Place Labels Above Fields) – Para o estilo de relatório Form, indicamos se devemos
posicionar os Labels acima dos campos (em vez de posicioná-los do lado esquerdo).
♦ Alinhar Sumários com Campos (Align Summaries with Fields) – Determina se os sumários devem ser posicionados
sob seus respectivos campos de origem. Essa propriedade só é aplicável ao estilo de relatório Form.
GRUPO ESPAÇAMENTO
Neste grupo, trataremos do espaço entre os objetos.
♦ Entre Quadros Vertical/Horizontal (Inter Frames) – Indica a quantidade de espaço entre quadros (na vertical e
na horizontal). Se a opção de alinhamento para o Grid for especificada, o alinhamento prevalece sobre a
quantidade de espaço. Esta propriedade é fornecida na unidade de dimensionamento em uso. Se essa unidade
for trocada, essa propriedade deve ser alterada de acordo.
♦ Entre Campos Vertical/Horizontal (Inter Fields) – Indica a quantidade de espaço entre campos (na vertical e na
horizontal). Se a opção de alinhamento para o Grid for especificada, o alinhamento prevalece sobre a quantidade
de espaço. Esta propriedade é fornecida na unidade de dimensionamento em uso. Se essa unidade for trocada,
essa propriedade deve ser alterada de acordo.
♦ Entre Mestre e Detalhado Vertical/Horizontal (Between Master and Detail) – Indica a quantidade de espaço entre o
quadro do grupo Mestre e o quadro do grupo-detalhe (na vertical e na horizontal). Se a opção de alinhamento para
o Grid for especificada, o alinhamento prevalece sobre a quantidade de espaço. Esta propriedade é fornecida na
unidade de dimensionamento em uso. Se esta unidade for trocada, essa propriedade deve ser alterada de acordo.
♦ Entre Quadros Irmãos Vertical/Horizontal (Between Sibiling Frames) – Indica a quantidade de espaço entre
quadros de grupos de mesmo nível (na vertical e na horizontal). Se a opção de alinhamento para o Grid for
especificada, o alinhamento prevalece sobre a quantidade de espaço. Esta propriedade é fornecida na unidade
de dimensionamento em uso. Se essa unidade for trocada, essa propriedade deve ser alterada de acordo.
♦ Entre Quadro e Campos Vertical/Horizontal (Between Frames and Fields) – Indica a quantidade de espaço entre
quadros e campos internos (na vertical e na horizontal). Se a opção de alinhamento para o Grid for especificada,
o alinhamento prevalece sobre a quantidade de espaço. Esta propriedade é fornecida na unidade de
dimensionamento em uso. Se essa unidade for trocada, essa propriedade deve ser alterada de acordo.
♦ Entre Página e Quadros Vertical/Horizontal (Between Page and Frames) – Indica a quantidade de espaço entre a
borda da página e o quadro de maior nível, isto é, mais externo (na vertical e na horizontal). Se a opção de
alinhamento para o Grid for especificada, o alinhamento prevalece sobre a quantidade de espaço. Esta propriedade
é fornecida na unidade de dimensionamento em uso. Se essa unidade for trocada, essa propriedade deve ser
alterada de acordo.
♦ Entre Campo e Labels Horizontal (Between Field and Labels) – Indica a quantidade de espaço entre o label e o
campo na horizontal. Esta opção só é aplicável ao estilo Form quando o título do campo é apresentado à
esquerda do mesmo. Se a opção de alinhamento para o Grid for especificada, o alinhamento prevalece sobre a
quantidade de espaço. Esta propriedade é fornecida na unidade de dimensionamento em uso. Se essa unidade
for trocada, essa propriedade deve ser alterada de acordo.
GRUPO TÍTULO
♦ Fonte (Font) – Esta propriedade determina o nome da fonte a ser usada para textos no Título.
♦ Justificar (Justify) – determina o método a ser usado para alinhamento do texto no Título.
♦ Cor do Texto (Text Color) – determina a cor de texto do objeto.
♦ Cor de Fundo (Foreground Color) / Cor de Fundo (Background Color) – As cores são dadas em duas camadas: a
primeira camada (Foreground Color) e a camada de fundo (Background Color). Aliado a estas duas camadas, existe
o padrão de preenchimento que afeta o resultado apresentado (veja especificação de padrão de preenchimento).
Para os demais padrões, o desenho em preto é apresentado com a cor da primeira camada (Foreground) e o desenho
branco é apresentado com a cor da camada de fundo (Background).
Na paleta de padrões apresentada pelo editor de layout, o padrão sólido é representado pelo quadrado preto
(segundo a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro
a partir do canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando
selecionamos a opção Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
♦ Padrão de Preenchimento (Fill Pattern) – O padrão de preenchimento determina como as duas camadas de
cores serão apresentadas para o usuário. Existem três padrões principais: Solid (o objeto é apresentado com a cor
da primeira camada – Foreground), Transparent (o objeto é apresentado com a cor da camada de fundo –
Background), Clear (None – o objeto é transparente e não é afetado pelas cores das camadas).
♦ Cor de Fundo do Limite (Edge Foreground Color)/Cor de Fundo do Limite (Edge Background Color) – possui o
mesmo significado visto na propriedade Cor de Fundo, porém aplicável a bordas.
♦ Padrão do Limite (Edge Pattern) – possui o mesmo significado da propriedade Padrão de Preenchimento, porém
aplicável a bordas.
♦ Traço (Dash) – esta propriedade determina o estilo de linha (sólido, ponto e traço, ponto, etc.).
♦ Bordas (Borders) – indica em que lados do objeto haverá bordas.
O NÓ ESTRUTURAS (FRAMES)
Neste item estudaremos as propriedades relativas ao nó Estruturas, esteja ele presente em uma seção Default ou de
Sobreposição. Essas propriedades são as mesmas independentemente do tipo de seção.
Encontraremos neste nó quatro subnós: Estrutura da Seção (Section Frame), Estrutura dos Cabeçalhos (Headings
Frame), Estrutura dos Campos (Fields Frame) e Estrutura dos Resumos (Summaries Frame).
Selecione um destes subnós e abra a pasta de propriedades. Você notará que somente um grupo estará presente, o
grupo Estilo (Style). Selecione, alternadamente, cada um dos subnós. Em todos eles as propriedades são as mesmas;
portanto façamos um estudo destas propriedades.
GRUPO ESTILO
Neste grupo encontramos as propriedades:
♦ Cor de Fundo (Foreground Color)/Cor de Fundo (Background Color) – As cores são dadas em duas camadas: a
primeira camada (Foreground Color) e a camada de fundo (Background Color). Aliado a estas duas camadas, existe
o padrão de preenchimento que afeta o resultado apresentado (veja especificação de padrão de preenchimento).
Para os demais padrões, o desenho em preto é apresentado com a cor da primeira camada (Foreground) e o desenho
branco é apresentado com a cor da camada de fundo (Background).
Na paleta de padrões apresentada pelo editor de layout, o padrão sólido é representado pelo quadrado preto
(segundo a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro
a partir do canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando
selecionamos a opção Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
♦ Padrão de Preenchimento (Fill Pattern) – O padrão de preenchimento determina como as duas camadas de
cores serão apresentadas para o usuário. Existem três padrões principais: Solid (o objeto é apresentado com a cor
da primeira camada – Foreground), Transparent (o objeto é apresentado com a cor da camada de fundo –
Background), Clear (None – o objeto é transparente e não é afetado pelas cores das camadas).
♦ Cor de Fundo do Limite (Edge Foreground Color) / Cor de Fundo do Limite (Edge Background Color) – possui
o mesmo significado da propriedade Cor de Fundo, porém aplicável às bordas.
♦ Padrão do Limite (Edge Pattern) – possui o mesmo significado da propriedade Padrão do Limite, porém aplicável
às bordas.
♦ Bordas (Borders) – indica em que lados do objeto haverá bordas.
O NÓ LABELS/CABEÇALHOS DE CAMPO
Neste nó trataremos das características-padrão aplicáveis aos cabeçalhos (ou labels) dos campos. Se subdividem em três
subnós: Caractere, Número e Data. Nos três casos as propriedades são iguais, no entanto, aplicáveis a elementos diversos.
As propriedades estudadas aqui são semelhantes àquelas presentes nos nós: Campos, Labels Sumariados e Resumos.
da primeira camada – Foreground), Transparent (o objeto é apresentado com a cor da camada de fundo –
Background), Clear (None – o objeto é transparente e não é afetado pelas cores das camadas).
♦ Cor de Fundo do Limite (Edge Foreground Color) / Cor de Fundo do Limite (Edge Background Color) – possui
o mesmo significado visto na propriedade Cor de Fundo, porém aplicável a bordas.
♦ Padrão do Limite (Edge Pattern) – possui o mesmo significado da propriedade Padrão de Preenchimento, porém
aplicável a bordas.
♦ Traço (Dash) – esta propriedade determina o estilo de linha (sólido, ponto e traço, ponto, etc.).
♦ Bordas (Borders) – indica em que lados do objeto haverá bordas.
Crie um gabarito com o nome de Gabarito1 (use a ferramenta Criar no nó Gabaritos), com as seguintes características:
SEÇÃO DEFAULT
Expanda o nó Seção, em seguida faça a mesma ação para o subnó Corpo, selecione o nó Default e abra a tela de
propriedades. Preencha as seguintes propriedades:
No grupo Layout:
♦ Alinhamento (Alignment) – Centralizado.
No grupo Título:
♦ Cor de Fundo (Foreground Color) – Yellow (primeira de cima para baixo).
♦ Padrão de Preenchimento (Fill Pattern) – Solid.
ESTRUTURAS (FRAMES)
Para todas as quatro estruturas (da Seção, dos Cabeçalhos, dos Campos e dos Resumos) preencha as seguintes propriedades:
♦ Cor de Fundo do Limite (Edge Foreground Color) – Darkblue.
♦ Padrão de Limite (Edge Pattern) – Solid.
CAMPOS (FIELDS)
Estas propriedades devem ser modificadas para Caractere, Data e Número.
♦ Cor do Texto (Text Color) – black.
♦ Fonte (Font) – Arial – Normal – 9.
RESUMOS (SUMMARIES)
Estas propriedades devem ser modificadas para Caractere, Data e Número.
♦ Cor do Texto (Text Color) – red.
♦ Fonte (Font) – Arial – Negrito – 10.
Após estas especificações, salve o gabarito.
Estabeleça um sumário de contagem para a coluna cd_mat, uma soma e uma média para a coluna vl_sal.
A seguir, indique a utilização do gabarito criado anteriormente. Veja a Figura 8.102.
Observe o resultado do modelo de Layout gerado. Verifique no seu relatório os padrões que estabelecemos em
nível de gabarito. Confira as especificações.
EXERCÍCIOS
8.49) Crie um gabarito de nome GT49 para os relatórios tabulares que determine:
♦ Cor de letra para os cabeçalhos – vermelha (etiqueta).
♦ Tipo de letra para todos os items – Arial.
♦ Tamanho de letra para os cabeçalhos – 9.
♦ Tamanho de letra para os itens – 8.
CAPACIDADE DE DISTRIBUIÇÃO
Podemos efetuar a distribuição do relatório gerado para diversos destinatários.
Esta distribuição pode ser feita em nível de relatório, ou seja, todo o relatório é distribuído para meios de
armazenamento diferentes, quantidade de cópias diferentes, usuários diferentes, etc.
Esta distribuição também pode ser associada às diferentes seções presentes no Layout; desta forma cada seção
produzirá arquivos independentes com características diferenciadas.
Como primeiro passo devemos definir a lista de distribuição. Esta lista poderá ser gerada dentro do Report Builder
ou podemos criar um arquivo com extensão DST. Faremos um primeiro teste utilizando o diálogo fornecido pelo
Report Builder.
Crie um relatório de nome RelDistr a partir da tabela Depto (todas as colunas), formato Tabular e gabarito Cyan
Grid Landscape.
Abra a paleta de propriedades do módulo. Lá você encontrará a propriedade Distribuição, que utilizaremos para
determinar os diversos destinos do relatório como um todo. Se desejarmos, porém, criar saídas específicas por
seção devemos abrir a paleta de propriedades de uma das seções do Layout, por exemplo Seção de Cabeçalho. As
mesmas características que encontramos em nível de módulo encontramos em nível de seção. Estudemos esta
opção com um exemplo.
Suponhamos, então, que desejássemos definir, para todo o relatório, uma lista de distribuição.
A execução deste relatório deve ser feita pela opção Distribuir do menu Arquivo. Uma execução normal (com o
botão Executar não aciona a lista de distribuição). Quando acionamos a distribuição desta forma, o Report Builder
apresenta uma tela de alerta confirmando a distribuição. Execute e verifique os resultados.
Se desejássemos, porém, executar esta mesma ação (gerando o mesmo resultado) para um relatório em produção
utilizaríamos um arquivo de distribuição (extensão .DST) com o layout apresentado pela Listagem 8.46.
deverá ser enviada. Os valores válidos para este parâmetro são: Report (indicando todo o relatório), Header_Section
(indicando apenas a seção Cabeçalho), Main_Section (indicando apenas a seção principal) e Trailer_Section
(indicando apenas a seção Trailer).
Para executarmos este relatório, podemos gerar um ícone no Windows e no campo “Alvo” digitar o texto da
Listagem 8.47.
Não se esqueça que o campo “Iniciar Em” deve estar direcionado para o diretório onde se encontra o módulo.
USO DE DELIMITADORES
Podemos especificar delimitadores no relatório com a finalidade de separação dos diversos dados, facilitando a
importação destes dados em outras ferramentas, tais como Microsoft Excel.
Esta opção permite a definição de quatro informações:
♦ Delimitador
♦ Máscara de formato para números
♦ Máscara de formato para datas
♦ Envoltório de células
Para efetuarmos os testes criaremos um relatório bem simples contendo todas as colunas da tabela Func. Uma vez
que incluiremos no arquivo apenas os dados, usaremos formato Tabular, sem gabarito e sem título para as colunas
(apague todos os labels das colunas e não inclua título no relatório).
A Listagem 8.48 apresenta parte de uma linha exemplo do resultado gerado para o tipo de preenchimento
apresentado na Figura 8.104.
Observe que poderemos escolher um delimitador para separação dos dados e um outro para envoltório destes dados;
isto pode ser útil quando trabalhamos com valores numéricos editados e usamos como separados a vírgula ou o ponto.
Observe que, como escolhemos um formato para números, este formato foi aplicado a todos os números (matrícula,
cargo, grau de instrução, etc.).
Na Listagem 8.49 apresentamos os parâmetros que substituem o diálogo online apresentado anteriormente:
♦ Delimiter – determina o delimitador a ser usado entre os dados, como delimitador.
♦ DateFormatMask – determina a máscara de formatação para os dados do tipo data.
♦ NumberFormatMask – determina a máscara de formatação para os dados numéricos.
♦ CellWrapper – determina um valor a ser incluído antes e depois de cada dado, como um envoltório da célula.
Observe que para o parâmetro CellWrapper utilizamos a palavra reservada Tab no lugar de um caracter. Verifique
na relação de parâmetros do Report Builder os valores válidos para este parâmetro.
Na Listagem 8.50 a seguir apresentamos parte da linha gerada usando os parâmetros apresentados na Listagem 8.49.
Um relatório que gere um documento XML não tem dependência de layout, isto é, o Report Builder (nesta versão)
não faz associação automática entre o layout que tivermos especificado e o resultado do documento. Para tal
devemos determinar nossa própria formatação visual através de especificações no formato XSL, as quais podem ser
especificadas com o uso das propriedades XML Prolog Type e XML Prolog Value.
♦ Tipo de Prólogo XML (XML Prolog Type) – Esta propriedade identifica se usaremos um arquivo de prólogo ou
um texto (que pode ser gerado pelo Report Builder). Este prólogo pode conter declarações XML, instruções e
declarações de tipos de documento (DTD).
♦ Valor de Prólogo XML (XML Prolog Value) – Nesta propriedade incluímos o código XML ou um nome de
arquivo contendo código desejado, de acordo com a especificação da propriedade XML Prolog Type. Um prólogo
XML inclui uma declaração XML mas, também, pode incluir comentários, instruções (tais como stylesheets –
XSL) e uma declaração de tipo de documento.
Estas propriedades se encontram ao nível de módulo, no grupo Escapes de Relatório.
Para visualizarmos o resultado gerado, utilizaremos o relatório RELDISTR montado anteriormente, porém faremos
a geração para arquivo, com extensão XML. Para tal, escolha, no menu arquivo a opção Criar para Arquivo e, como
tipo de arquivo, a opção XML. O arquivo gerado terá o nome RELDISTR.XML.
A Listagem 8.51, a seguir, mostra parte do resultado gerado na execução acima.
Os parâmetros associados aos objetos do Modelo de Dados nos permitem a modificação desta estrutura (XML), se desejarmos.
Da mesma forma que para os demais tipos de saída, podemos usar o parâmetro DESFORMAT com o valor XML,
determinar um nome com o parâmetro DESNAME (por exemplo SAIDA.XML) e indicar a geração para arquivo
com o parâmetro DESTYPE. O resultado produzido é o mesmo visto acima.
EXERCÍCIOS
8.53) Gere um relatório baseado na tabela Func com as seguintes características:
♦ Formato: Agrupar Acima e Agrupar à Esquerda.
♦ Colunas: nome completo do funcionário, matrícula do funcionário, salário do funcionário, código do
departamento, cargo, grau de instrução, data de nascimento. Determine quebra por departamento.
♦ Escolha dois gabaritos diferentes.
♦ O formato Agrupar Acima deve ser gerado em formato HTML.
♦ O formato Agrupar à esquerda deve ser gerado em formato RTF para ser visualizado no Word.
8.54) Crie um relatório que gere arquivos a serem utilizados em aplicações Microsoft Excel com as seguintes características:
♦ Colunas da Tabela Func: matrícula, nome, cargo, salário, data de nascimento, data de admissão.
♦ Colunas da Tabela Depto: cd_depto, nm_depto, total de salário dos funcionários do departamento, nome do gerente.
♦ A formatação de data e número deve ser feita individualmente por coluna.
DESCRIÇÃO
Neste tópico, trataremos da utilização da depuração em relatório. A depuração no Report Builder significa que
acompanharemos a execução dos trechos de PL/SQL definidos no programa passo a passo e, eventualmente,
poderemos intervir no processo.
A forma de depurarmos um relatório é um pouco diferente daquela que experimentamos com uma aplicação Form.
Para exemplificação, abra seu relatório de nome Pacote para que possamos marcar os pontos de interrupção.
No Report Builder, devemos determinar os pontos e tipos de interrupção antes de iniciarmos a execução do relatório,
ou seja, a determinação é estática, mesmo para os BreakPoints.
Para acionarmos o interpretador (depurador), devemos selecionar a opção Interpretador PL/SQL no menu Programa.
Para desenvolvermos os testes deste tópico, usaremos a aplicação Pacote.
A JANELA DE DEPURAÇÃO
Quando acionamos o interpretador, aparece uma janela intitulada Interpretador PL/SQL.
Essa janela está subdividida em dois painéis:
♦ Painel de Fonte – O painel superior nos mostrará trechos dos blocos de PL/SQL presentes na aplicação quando
fizermos a seleção da unidade de programa.
♦ Painel de Comandos – Neste painel, aparece uma linha de comando em que podemos executar comandos
diretamente no ponto de interrupção, alterando o valor de variáveis, executando ações, etc. Corresponde a uma
linha de comando de PL/SQL.
Como ainda estamos na fase de desenvolvimento (não iniciamos a execução), continuamos com acesso a todos os
nós de nossa aplicação. Observe que existe um nó stack vazio no conjunto de nós do relatório. Esse nó será
preenchido à medida que estabelecermos os pontos de interrupção e/ou executarmos a aplicação.
Para que possamos marcar um ponto de interrupção, devemos expandir o nó Unidades de Programa (Program
Units). Encontraremos aí não apenas as unidades de programa criadas explicitamente por nós, como também
todos os triggers que porventura tivermos definido no relatório.
Quando clicamos sobre o nome de uma destas unidades de programa, o texto correspondente é apresentado no
Painel de Fonte do Interpretador. Veja a Figura 8.105.
BREAKPOINT
Para efeito de teste (usaremos a rotina NLS), selecione a primeira linha após o Begin (primeira linha executável) do
trigger. Escolha no menu Depurar (Debug) a opção Interromper (Break) ou efetue um clique duplo no número da
linha que desejamos interromper.
Será mostrado um diálogo para que vejamos ou preenchamos as seguintes informações:
♦ Ponto de Interrupção (Breakpoint) – Indica se este é um ponto de interrupção novo ou já existente. Se for um já
existente, aparecerá um número.
♦ Ativado (Enabled) – Indica se este ponto está habilitado ou não.
♦ Unidade de Programa (Program Unit) – Identifica a unidade de programa. Nome dado pelo Report Builder.
♦ Linha (Line) – Especifica a linha dentro da unidade de programa em que o ponto de interrupção foi marcado.
♦ Gatilho (Trigger) – Define um código de PL/SQL para o ponto de interrupção. Esse código será acionado cada
vez que o ponto de interrupção for atingido.
Listagem 8.52 – Texto incluído no Breakpoint da procedure NLS (quarta linha – IF)
DEBUG.SETN ('DIA_SEMANA', 5);
O pacote Debug contém rotinas que nos permitirão alterar o valor das variáveis locais do trecho de código que
estamos analisando. No caso do exemplo, quando o ponto de interrupção for atingido, a variável local dia_semana
receberá o valor 5. Verifique que seu valor inicial é 0.
Quando pressionarmos a tecla OK, o ponto de interrupção é criado. Observe que no Painel de Fonte aparecerá o
texto B(01) em vez do número da linha (4). Verifique também o nó Ações de Depuração no Navegador, você
encontrará a criação do ponto de interrupção. No nó Unidades de Programa do Navegador, também visualizamos
uma nova rotina chamada BreakTrig_1.
Se não desejarmos preencher nenhum texto a ser executado juntamente com o ponto de interrupção, podemos selecionar
a linha que desejamos interromper e efetuar um clique duplo. O ponto de interrupção será marcado da mesma forma.
Para desmarcar o ponto de interrupção, selecione a linha em que o ponto está marcado e efetue um clique duplo.
Verifique o nó Ações de Depuração e observe que o ponto de interrupção foi removido.
TRIGGER
Um gatilho funciona ligeiramente diferente de um ponto de interrupção. No gatilho, escreveremos uma lógica
que determinará se a interrupção ocorrerá ou não.
A criação do gatilho é similar à criação do ponto de interrupção. Selecionamos a linha desejada (mesma anterior),
escolhemos no menu Depurar (Debug) a opção Gatilho (Trigger).
O texto informado está descrito na Listagem 8.53. As informações relativas ao diálogo são definidas a seguir:
♦ Gatilho (Trigger) – Indica se esse é um gatilho novo ou já existente. Se for um já existente, aparecerá um número.
♦ Ativado (Enabled) – Indica se esse gatilho está habilitado ou não.
♦ Local (Location) – Especifica a localização do gatilho de depuração:
a) Unidade de Programa (Program Unit) – Indica que o gatilho de depuração estará localizado exatamente na unidade
de programa especificada e na linha especificada. Somente nesta opção estes dois campos estarão preenchidos.
b) Depurar Entrada (Debug Entry) – Nesta situação o depurador é acionado quando a execução do programa for
interrompida por um ponto de interrupção, gatilho de unidade de programa, etc.
c) Toda Instrução (Every Statement) – Faz com que o trecho de PL/SQL seja avaliado antes de cada linha de PL/
SQL da aplicação.
♦ Unidade de Programa (Program Unit) – Identifica a unidade de programa. Nome dado pelo Report Builder.
♦ Linha (Line) – Especifica a linha dentro da unidade de programa em que o gatilho foi marcado.
♦ Corpo do Gatilho (Trigger Body) – Especifica o código de PL/SQL para o gatilho.
Quando aceitarmos este diálogo (OK), retornaremos à janela de depuração com a linha 4 preenchida com T(01) no
lugar do número da linha.
Observe a Figura 8.106. O ponto em que o programa está parado é marcado no Painel de Fonte com o sinal -> (em
amarelo). Verifique o nó Stack, ele contém o valor das variáveis locais deste trecho de código.
Na parte superior da janela encontramos diversos botões, agora habilitados, que nos permitirão executar uma
linha de cada vez. São eles:
♦ Entrar (Step Into) – Esta opção executa cada linha do programa passo a passo. Ocorre a interrupção a cada
comando. Se o código acionar uma unidade de programa, esta também é acompanhada passo a passo.
♦ Transpor (Step Over) – Esta opção também executa cada linha do programa passo a passo, porém se houver chamada
a uma unidade de programa, esta não é detalhada. A sub-rotina é executada como se fosse uma linha simples.
♦ Sair (Step Out) – Esta opção é para ser usada dentro de uma unidade de programa chamada, pois ela termina a
unidade de programa atual e retorna a quem a chamou. Se estivermos no código principal, esta opção encerrará
a depuração. O trecho de código final é executado.
♦ Ir (Go) – Esta opção encerra a execução passo a passo voltando para a forma normal do programa. O restante do
código é executado.
♦ Reinicializar (Reset) – Esta opção desiste da execução passo a passo. O restante do código não é executado.
Faça outros testes com estas opções. Você verificará que a depuração é bastante similar ao processo já visto com o
Form Builder. A diferença está exatamente no momento em que marcamos o ponto de interrupção.
Observe que, ao encerrarmos a execução, os pontos de interrupção ainda estão marcados. Podemos voltar a executar
o relatório e interromper a ação novamente.
EXERCÍCIOS
8.55) Construa uma aplicação de nome REP55 baseada na aplicação REP48. Acrescente a seguinte funcionalidade:
♦ Marque um Breakpoint no PL/SQL que aciona a rotina para cálculo do intervalo de datas.
O PREVISUALIZADOR DA WEB
Se desejarmos verificar o resultado da execução que um determinado relatório terá quando for visualizado por um browser
(ou seja, na Web), podemos direcionar a execução do relatório para a Web diretamente de dentro do Report Builder.
Abra um relatório qualquer (que possua o parâmetro DesType como Screen). Execute este relatório. Quando o
Previsualizador Ativo for acionado, selecione a opção Previsualizador de Web (Web Preview) presente no menu
Visualizar (View). As seguintes opções serão apresentadas:
♦ Usar HTML (Use HTML) – indica que o formato de saída deve ser HTML (default).
♦ Usar Folhas de Estilos HTML (Use HTML Style Sheets) – indica que o formato de saída deve ser HTMLCSS
(somente para browsers capazes de ler este formato).
♦ Usar PDF (Use PDF) – indica que o formato de saída deve ser PDF.
♦ Mostrar Página Atual (Show Current Page) – gera apenas a página atual do relatório.
♦ Mostrar Todas as Páginas (Show All Pages) – gera todas as páginas do relatório.
As especificações acima funcionam como preferências para a futura execução na Web. Para que o relatório seja
executado gerando a saída definida, devemos escolher a opção a seguir:
♦ Criar para Navegador da Web (Generate to Web Browser) – executa o relatório e aciona o browser default da sua
estação (se você tiver mais de um browser instalado, o Report Builder poderá questioná-lo sobre qual browser usar).
Outra forma de executarmos para a Web é a utilização do botão Previsualizador da Web (Web Preview) presente na
tela do Previsualizador Ativo (Live Preview).
Utilize esta característica para testar os relatórios a serem desenvolvidos nos próximos tópicos.
Os arquivos gerados para estes produtos podem ter características especiais, tais como hyperlinks, tags, etc. Para
efeito de teste, criaremos dois arquivos HTML a serem usados no início e no fim do relatório. Construa o HTML de
início de acordo com as informações apresentadas na Listagem 8.54.
O arquivo de fechamento do relatório será igual ao texto apresentado na Listagem 8.55. Reproduza-a e crie o
arquivo Fechamento.htm.
Para analisarmos o resultado de uma geração deste tipo usaremos o Assistente de Web. Posteriormente, modificaremos
nosso relatório manualmente para conhecermos as propriedades associadas a estes tipos de arquivos.
Criemos, então, um relatório de nome Web, contendo as colunas cd_mat, nm_func, vl_sal e dt_nasc da tabela Func.
Após a montagem da query, acione o Assistente de Web. No diálogo apresentado poderemos informar o nome de
um arquivo HTML que seja apresentado antes do relatório (no nosso caso Abertura.htm) e outro arquivo HTML
que seja apresentado depois do relatório (no nosso caso Fechamento.htm).
Prosseguiremos com o Assistente e outro diálogo nos será apresentado.
Nesse diálogo, devemos marcar uma das seguintes opções:
♦ Gerar saída HTML agora – Indica que um arquivo com extensão HTM deve ser gerado imediatamente para que
possamos verificar o resultado em um Browser.
♦ Gerar a saída da folha de estilo HTML agora – Style Sheets são extensões para o HTML que fornecem maior
flexibilidade, como por exemplo qualquer tamanho ou estilo de fonte, objetos sobrepostos, paginação e outras
características. Para a visualização de um documento HTML com as vantagens do Style Sheets, devemos usar
um Browser que suporte este tipo de extensão (por exemplo, Microsoft Internet Explorer 3.01 ou superior).
♦ Gerar saída PDF agora – Neste caso o arquivo gerado não é HTML e sim PDF.
♦ Retornar ao Designer – Se escolhermos esta opção, as informações relativas aos arquivos HTML a serem mostradas
antes e depois do documento são armazenadas em nosso fonte, mas o documento HTML não é gerado.
Se marcarmos a opção Saída para o browser Web, além de gerar o arquivo HTM, o Report Builder também aciona
o browser default instalado em seu ambiente.
Um trecho do resultado desta geração está apresentado na Figura 8.107, na qual visualizamos o início do relatório
e o aparecimento do arquivo HTM mostrado no início do relatório.
Suponhamos, agora, que desejássemos regerar este relatório para adicionar, por exemplo, uma restrição às linhas
lidas. Para indicarmos ao Report Builder que desejamos criar um arquivo HTM utilizaremos os parâmetros de sistema:
♦ DesFormat – Este parâmetro determina o formato da saída. Poderemos optar entre HTML, HTMLCSS (para a
utilização de Style Sheets) ou PDF.
♦ Destype – Este parâmetro indica o tipo de destino. Indicaremos File (pois desejamos gerar um arquivo em disco).
♦ Desname – Neste parâmetro, forneceremos o nome do arquivo de saída a ser gerado. O nome pode ser diferente
do nome do relatório, mas deve ter a extensão HTM.
♦ PrintJob – Neste parâmetro indicamos se desejamos ou não que seja apresentado o diálogo relativo à impressão.
Preencheremos com NO (faça um teste com Yes para verificar o resultado).
♦ Mode – Indicaremos que o resultado deste relatório é gráfico, e portanto o Mode é BITMAP.
Para que estes parâmetros fiquem fixos, devemos alterar a propriedade Valor Inicial de cada um deles.
Após o cumprimento desta etapa, podemos executar o relatório quantas vezes quisermos, pois a cada execução um
novo arquivo extensão HTM será gerado.
Verificaremos, agora, onde o Assistente armazenou a informação sobre o nome do arquivo a ser apresentado antes
e depois do relatório.
Trata-se da paleta de propriedades do módulo. Retorne, pois, ao tópico Características Gerais e verifique que outras
informações podem ser preenchidas nestas propriedades para incrementar a apresentação do relatório na Web.
Observe a paleta de propriedades de um objeto de layout. Todos os objetos de layout possuem estas propriedades.
♦ Destino de Hiperligação (Hyperlink Destination) – Corresponde a um identificador único para um objeto e que
será utilizado como destino do Hypertext Link.
♦ Marcador de Livros (BookMark) – É um Hypertext Link que aparecerá em um BookMark Frame do documento
HTML principal ou na área de BookMark do PDF Viewer. Clicando-se no BookMark será mostrado o objeto
associado no topo da janela.
♦ Ação PDF (PDF Action) – Esta propriedade especifica um tipo de ação a ser associada com o objeto quando este é clicado
no PDF Viewer. Os valores válidos são Usar Hiperligação (Use Hyperlink) ou Inicializar Aplicativo (Launch Application).
♦ Linha de Comandos do Aplicativo PDF (Application Command Line – PDF) – Corresponde à linha de comandos
que será executada na máquina local quando o objeto (presente no documento PDF) for clicado no PDF Viewer.
Por exemplo, a execução de um programa que exista na máquina local.
Para efetuarmos um teste simples (não entraremos em detalhes sobre o Oracle Graphics), criaremos um relatório
baseado no comando Select da Listagem 8.56 a seguir.
No Modelo de Dados estabeleceremos a coluna cd_depto como coluna de quebra e incluiremos uma variável de
resumo que calcula a soma dos salários por departamento (sum_sal).
Em seguida, com a ajuda do Assistente de Relatórios definiremos o layout como Agrupar Acima e o gabarito
como Corporate1.
Nosso próximo passo é a criação do gráfico. Desta forma acionaremos o Assistente de Gráfico e preencheremos os
diálogos como descrito a seguir:
♦ No primeiro diálogo definiremos o título do gráfico como “Salários por Depto”. O Tipo de gráfico como Pie e o
Subtipo de Gráfico como Plain.
♦ No segundo diálogo informaremos como eixo X a coluna cd_depto.
♦ No diálogo seguinte informaremos como eixo Y, ou seja, o valor, a coluna sum_sal (resumo).
♦ No próximo diálogo devemos indicar a freqüência de impressão do gráfico. Escolheremos “uma vez por
Cd_depto(R_G_cd_depto)”.
♦ Finalmente será solicitado o nome de um arquivo para a gravação do gráfico. Definimos Hyper.ogd.
Cumprida esta etapa o gráfico é criado e incluído no layout, dentro do grupo de departamento.
Nossa próxima etapa será a definição do resultado na Web. Acionaremos, portanto, o Assistente de Web e
preencheremos os diálogos como se seguem:
♦ No primeiro diálogo, será possível a escolha de uma coluna como BookMark. A única coluna disponibilizada é
cd_depto, e, portanto, a selecionaremos.
♦ No segundo diálogo será possível escolhermos um gráfico para gerar links entre este gráfico e o restante do relatório.
Como este é exatamente o nosso objetivo, selecionaremos o único nome de gráfico presente: CT_1 (no meu caso).
♦ No próximo diálogo poderemos escolher um arquivo HTML a ser incluído apenas no início do relatório e outro
para ser incluído apenas no fim do relatório. Neste caso não fizemos qualquer preenchimento.
Para visualizarmos o resultado gerado, no último diálogo escolhemos as opções: Criar Saída HTML agora e Gerar
Saída para um Browser da Web. O resultado gráfico é visto na Figura 8.108.
Do lado esquerdo visualizamos o marcador de livro gerado a partir da coluna cd_depto. Se você clicar sobre um dos
códigos de departamento apresentados será feita a navegação para esta área do relatório.
Observe, porém, o gráfico. Passe o mouse vagarosamente sobre cada um dos pedaços da Pizza. No rodapé do
browser, nos é apresentado o conteúdo deste campo, ou seja, cada cor aponta para uma parte do relatório. Poderemos
navegar também desta forma.
Por exemplo, se desejarmos ver os detalhes dos salários que fizeram a composição para o departamento D11, basta
que pressionemos o mouse sobre o desenho correspondente na Pizza.
Ao retornarmos ao Data Model perceberemos a inclusão de um novo sumário do tipo contagem sobre a coluna
cd_depto. Consideraremos o nome desta coluna cs_cd_depto (no menu caso). Esta coluna foi criada com o objetivo
de auxiliar a montagem e derivação do gráfico.
A indicação de marcador de livro está presente na propriedade Marcador de Livro (Bookmark) do grupo Configurações
da Web para o item F_Cd_Depto. Esta coluna recebeu dois apelidos, como mostrado na Listagem 8.57 a seguir:
NAVEGAÇÃO
Para que isto fique viável devemos estabelecer uma forma de navegação entre as páginas, uma vez que serão
arquivos diferentes. Isto pode ser feito de duas formas:
♦ usando a rotina predefinida fornecida pelo Report Builder (em JavaScript).
♦ desenvolvendo nossa própria rotina.
Se decidirmos pela construção de nossa própria rotina de paginação, podemos usar duas variáveis de sistema no
script: &TotalPages(número total de paginas) e &file_name(nome do arquivo destino). O Report Builder associa
valores a estas variáveis durante a formatação, fazendo a substituição do parâmetro por seu valor.
A definição da navegação, manual, ou seja, definida por nós, pode ser feita de duas formas:
♦ através do PL/SQL no trigger Before Report com a ajuda da rotina SRW.Set_Page_Navigation_Html.
♦ na paleta de propriedades do relatório (módulo), com o preenchimento das propriedades Tipo de Controle da
Página de Navegação (que pode ser preenchido com File ou Texto) e Valor de Controle da Página de Navegação
(que pode ser preenchido com o nome do arquivo que contém o script ou com o texto do script, de acordo com
o que tiver sido definido na propriedade anterior).
PARÂMETRO
O parâmetro PageStream deve ser informado na linha de comando (esta opção não pode ser habilitada através do
Report Builder).
Iniciemos, então, criando um relatório para as colunas cd_mat, cd_depto e vl_sal, usando o formato Form com um
gabarito à sua escolha.
Compile este relatório (gerando um .REP) e crie um ícone no Windows com o texto da Listagem 8.58 (como já
fizemos anteriormente).
Ele vai criar um frame, sendo que a parte superior corresponde à página do relatório e a parte inferior, à rotina de navegação.
Se você preencher o parâmetro Desname, não esqueça de preencher a extensão HTM. Caso contrário, o arquivo-base (o que deve ser executado
inicialmente) fica sem extensão, impossibilitando sua identificação pelo browser.
O texto acima corresponde ao script padrão gerado pelo Report Builder com algumas simplificações. Crie um
arquivo com este texto.
Na propriedade do módulo Tipo de Controle da Página de Navegação preencha com File e na propriedade Valor
de Controle da Página de Navegação preencha com o nome do arquivo. Em seguida, compile o relatório novamente
e o execute.
Quando ativar o browser, para o arquivo <nome>.htm, não se esqueça de fazer um Reload para que ele não
apresente o arquivo anterior. Utilize a opção de visualização do código HTML para conferir o resultado.
As particularidades relativas à geração de um relatório a ser visualizado na Internet não param aí. Trabalharemos
com outros exemplos nos exercícios.
EXERCÍCIOS
8.56) Crie um relatório baseado na Q20 que inclua as seguintes características:
♦ Um boilerplate de Texto contendo uma Tag de HTML.
♦ Uma imagem como URL, referenciada através de um Link File.
Com este objeto, poderemos acionar diretamente o Report Builder para a construção do relatório que viermos a
usar dentro da aplicação, deixando, inclusive, documentada sua utilização.
Observe que a utilização do botão direito do mouse permite que acionemos o Report Builder a qualquer momento.
A Figura 8.109 nos mostra o diálogo apresentado quando criamos um objeto neste nó. Nele podemos criar um
novo relatório ou associar um relatório já existente. Se viermos a criar um novo relatório podemos escolher um dos
blocos da aplicação para que o relatório se baseie. O assistente de relatório é acionado automaticamente usando
este bloco. Experimente!
Ao concluir a construção, retorne ao Forms e abra a paleta de propriedades deste objeto. Nesta paleta encontramos três
grupos: Geral, Integração do Oracle Developer e Relatórios. As informações apresentadas no grupo Relatórios
correspondem a parâmetros do próprio Report (já nossos conhecidos) e as informações do grupo Integração do Oracle
Developer dizem respeito à forma como o Oracle Forms acionará o Report Builder para a construção do relatório.
EXERCÍCIOS
8.57) Retorne aos exercícios de Forms (7.40) e teste a execução de um dos relatórios (REP17) que recebem parâmetro
a partir do Forms.
METODOLOGIA
♦ Apresentação das características de integração entre o banco de dados e o relatório.
TÉCNICA
♦ Utilização destes elementos em exemplos e exercícios.
Antes de passar para o layout, abra a tela de propriedades para a coluna Blob e altere o valor da propriedade
Formato de Arquivo para Imagem para que seja trazida a imagem armazenada no banco e não seu texto.
Acione, agora, o Assistente de Relatório para a montagem do layout.
Na pasta Labels, altere o tamanho dos campos C_Clob1 para 50 (o default é 4) e C_Blob1 para 100 (o default
também é 4) a fim de que o layout gerado seja compatível com as informações armazenadas. Inicialmente gere o
relatório sem modelo para que o resultado fique mais claro.
Para que a imagem seja apresentada com um tamanho maior podemos indicar elasticidade na vertical tanto para
o C_Blob1 quanto para o C_Clob1. Se você escolher esta ação não esqueça de expandir na vertical o Repeating
Frame que envolve os objetos.
No diálogo que apresenta os Campos Disponíveis para que venhamos a escolher aqueles que serão apresentados no
relatório, nos deparamos novamente com as mesmas características apresentadas pelo Form Builder, ou seja, as colunas do
tipo Ref podem ser expandidas para que venhamos a selecionar os atributos presentes no objeto apontado pela referência.
Observe na Figura 8.111 que selecionamos as colunas cd_depto, nm_depto, cd_mat (gerente) e nm_sobrenome
(gerente). Conclua o desenvolvimento deste relatório. Na pasta de layout aumente o tamanho da coluna nm_depto
para 40 posições e nm_sobrenome para 15.
A execução deste relatório se processa normalmente.
Ele apresenta todas as colunas da tabela Tb_Depto (cd_depto, nm_depto, cd_depto_ctb e cd_gerente). Como não
utilizamos nenhum atributo do objeto apontado pela referência cd_depto_ctb, esta aparece contraída.
Para a coluna cd_gerente já escolhemos os atributos cd_mat e nm_sobrenome; desta forma não só esta coluna aparece
expandida como também os atributos escolhidos estão localizados próximos às colunas cd_depto e nm_depto.
Retornemos ao Assistente de Relatório e no diálogo para seleção das colunas expanda a coluna cd_depto_ctb,
conclua a montagem do relatório e retorne ao Data Model (não precisa selecionar nada). Você observará que no
Data Model os atributos apontados por cd_depto_ctb também aparecem expandidos. Esta ação tem a finalidade de
tornar visível em nível de Data Model os atributos derivados para que possamos utilizar (talvez) funções sobre eles.
Mais um detalhe: o atributo Nr_Tel (cd_gerente) aparece com um sinal de interrogação uma vez que se trata de uma
coleção. As coleções (Varrays e Nested Tables) não são suportadas nesta versão. Abra a tela de propriedades para este
elemento e comprove que a propriedade Tipo da Coluna está preenchida com Banco de Dados – Desconhecido.
EXERCÍCIOS
8.58) Gere um relatório baseado na tabela TB_Func com as seguintes características:
♦ Formato carta
♦ Colunas: nome completo do funcionário, nome do gerente, nome do departamento, matrícula do funcionário,
salário do funcionário.
♦ Gabarito Corporate 1.
♦ Cada carta deve ser gerada em um arquivo HTML em separado.
♦ Deve ser possível a navegação seqüencial entre páginas (use um ícone de navegação).
♦ Garanta que para os funcionários gerentes o salário não seja mostrado.
Como segunda etapa, trataremos de acionar o Query Builder para a construção da query desejada. Imediatamente
será mostrado um diálogo contendo a lista de tabelas (e/ou sinônimos e/ou views e/ou snapshots) para que
informemos o nome das tabelas onde se encontram os dados que desejamos apresentar. Neste primeiro exercício,
todos os dados se acham presentes na tabela Func.
No Query Builder faremos um clique duplo no nome da tabela Func para que todas as colunas sejam selecionadas.
Em seguida, pressionaremos o botão Show SQL para que o comando SQL a ser mostrado pelo Query Builder possa
ser visualizado e conferido. Veja a Listagem-resposta 8.01A. Estando tudo certo, pressionaremos o botão OK.
Listagem-resposta 8.01A
SELECT ALL FUNC.CD_MAT, FUNC.NM_FUNC,
FUNC.NM_SOBRENOME, FUNC.CD_DEPTO, FUNC.NR_RAMAL, FUNC.DT_ADM,
FUNC.NR_CARGO, FUNC.NR_GIT, FUNC.IN_SEXO, FUNC.DT_NASC,
FUNC.VL_SAL, FUNC.NM_FOTO
FROM DESENV.FUNC
Retornamos ao Assistente de Relatórios e navegamos para o próximo diálogo. Neste, informaremos quais colunas
devem ser mostradas no resultado. No nosso caso, todas.
Seguiremos para o próximo diálogo onde definiremos os dados de cálculo.
Neste diálogo selecionaremos a coluna vl_sal e pressionaremos os botões Soma, Mínimo e Máximo, indicando que
desejamos que estes três cálculos sejam efetuados.
No próximo diálogo escolheremos os nomes dos cabeçalhos de coluna. Veja a Figura-resposta 8.01A.
A última etapa na montagem do relatório é a definição do gabarito a ser usado. Neste primeiro caso, escolhemos Corporate1.
Quando encerrarmos as etapas do Assistente, nosso relatório será executado. Que tal o resultado?
8.02) Criar um relatório de nome REP02 com as seguintes características:
♦ Formato Form.
♦ Todas as colunas da tabela Depto.
♦ Incluir a quantidade de departamentos apresentados.
♦ Fornecer nomes adequados para os títulos de coluna.
♦ Utilizar o gabarito Confidential Heading.
A construção deste relatório é similar à construção do relatório anterior. Iniciaremos criando um novo módulo e
aceitando a utilização do Assistente.
No primeiro diálogo apresentado, escolheremos o formato “Formato de Form”. O segundo diálogo é aquele no
qual definimos a query. Mais uma vez utilizaremos o Query Builder para a construção do comando Select.
Escolheremos a tabela Depto e, quando o quadro contendo as colunas desta tabela for apresentado, executaremos
um clique duplo sobre o nome da tabela para que todas as colunas sejam selecionadas.
Quando aceitarmos esta construção, a query é transferida para o Assistente de Relatório. O comando Select Resultante
é apresentado na Listagem-resposta 8.02A.
Listagem-resposta 8.02A
SELECT ALL DEPTO.CD_DEPTO, DEPTO.NM_DEPTO,
DEPTO.CD_GERENTE, DEPTO.CD_DEPTO_CTB
FROM DESENV.DEPTO
No próximo diálogo indicaremos que todas as colunas devem ser apresentadas no relatório. Nosso próximo passo
é contabilizar a quantidade total de departamentos: o que é resolvido com a função Count sobre a coluna cd_depto.
Nos diálogos seguintes escolhemos os cabeçalhos dos campos e o gabarito em relação ao qual o relatório se baseará.
Execute a aplicação montada.
Observe que cada linha de departamento é apresentada em uma página. Esta é a regra do formato Form, ou seja,
formulário. Cada informação é apresentada em página em separado. Navegue até a última página para encontrar
o total solicitado.
Você observou também que os cabeçalhos das colunas aparecem em vermelho e que o total aparece em letras
amarelas sobre fundo cinza? Isto ocorre por causa do gabarito (Template). Num template poderemos determinar
fonte, cor, alinhamento, enfim, características para cada uma das seções de nosso relatório, afetando inclusive os
dados a serem impressos.
O Query Builder apresenta os dois relacionamentos existentes entre as duas tabelas. Quando o comando Select for
gerado para o Assistente, devemos retirar o relacionamento de Gerente-Matrícula pois desejamos obter todos os
funcionários com seus respectivos departamentos (independente de serem ou não gerentes).
Listagem-resposta 8.03A
SELECT ALL DEPTO.CD_DEPTO, DEPTO.NM_DEPTO,
DEPTO.CD_DEPTO_CTB, FUNC.CD_MAT, FUNC.NM_FUNC,
FUNC.NM_SOBRENOME, FUNC.CD_DEPTO, FUNC.NR_RAMAL, FUNC.DT_ADM,
FUNC.NR_CARGO, FUNC.NR_GIT, FUNC.IN_SEXO, FUNC.DT_NASC,
FUNC.VL_SAL, FUNC.NM_FOTO, DEPTO.CD_GERENTE
FROM DEPTO, FUNC
WHERE FUNC.CD_DEPTO=DEPTO.CD_DEPTO
Na Listagem-resposta 8.03A a cláusula Where apresentada somente estabelece a relação através da coluna cd_depto.
Em seguida, definimos quais as colunas pertencentes ao grupamento.
Para que mais de uma coluna seja incluída no mesmo grupamento, antes de transferir a coluna clique sobre o
título Nível 1, indicando que a coluna a ser transferida o será para este mesmo nível. A ordem também pode ser
alterada, bastando que arrastemos a coluna selecionada para cima ou para baixo.
Não temos necessidade de apresentar a coluna cd_depto duas vezes (cd_depto de Func e cd_depto de Depto). Por
este motivo, não exibiremos uma destas colunas.
No Query Builder, poderíamos ter restringido a leitura de uma das colunas. Sempre que possível, opte por esta
solução, uma vez que a informação desnecessária não precisa ser transferida do ambiente servidor para o cliente,
diminuindo o tráfego na rede.
Na etapa seguinte, indicamos os cálculos a serem efetuados (média e percentual). Agora execute a aplicação.
Observe que o resultado gerado calcula a média do departamento e da empresa, o percentual do salário do funcionário
em relação ao departamento e do departamento em relação à empresa.
O gabarito escolhido afetou a cor da letra, o preenchimento do campo, etc.
8.04) Criar um relatório de nome REP04 com as seguintes características:
♦ Formato grupado acima.
♦ Todas as colunas da tabela Func, a coluna nm_depto da tabela Depto e todas as colunas da tabela Proj. O
relacionamento entre essas tabelas deve ser feito pelo código do departamento.
♦ Criar um grupo de quebra principal contendo o nome do departamento e seu código.
♦ Criar um grupo de quebra secundário contendo o código do projeto, seu nome, o código do responsável, data
de início e fim.
A próxima etapa é a indicação do total salarial. Informamos apenas que desejamos que seja feito o cálculo do total
em relação à coluna vl_sal. Não há necessidade de informarmos em que nível deve ser realizado este cálculo.
Quando vamos informar os cabeçalhos das colunas, já encontramos os três campos incluídos justamente para
cálculo da soma por projeto, departamento e geral.
Neste exercício escolhemos o gabarito Confidential Heading Landscape. Observe que o uso de gabarito permite a
colocação de títulos, número de página, letra diferenciada para quebra e detalhe, etc.
Repetimos este procedimento para criar uma nova expressão que obtenha apenas o dia e mês de nascimento, ou
seja, to_char(dt_nasc, ‘dd/mm’).
Após a criação destas novas colunas, devemos marcá-las e também às colunas nr_ramal e vl_sal.
Resta ainda a indicação de ordenação. Para tal, devemos pressionar o botão relativo à Sort na barra de ferramentas.
Indicaremos que a ordenação será ascendente pela coluna Nome (criada anteriormente).
Antes de aceitarmos este diálogo, podemos visualizar o SQL a ser gerado para verificarmos se está compatível com
o que desejamos.
Listagem-resposta 8.05A
SELECT ALL FUNC.NM_FUNC||FUNC.NM_SOBRENOME nome,
TO_CHAR(FUNC.DT_NASC, 'dd/mm') nasc, FUNC.NR_RAMAL, FUNC.VL_SAL
FROM DESENV.FUNC
ORDER BY FUNC.NM_FUNC||FUNC.NM_SOBRENOME ASC
No Query Builder, nosso primeiro passo será calcular o abono. Definimos, portanto, uma nova coluna que efetue
o cálculo desejado, ou seja, vl_sal * 0.15.
Precisamos, agora, formatar este abono. Definimos, então, uma nova coluna chamada Abono_Formatado que
formata o abono calculado anteriormente, como nos mostra a Listagem-resposta 8.06A.
Listagem-resposta 8.06A
TO_CHAR(ABONO, 'L999G990D00', 'NLS_CURRENCY=R$')
Selecionamos também o dia e mês do nascimento do funcionário. Para tal, definimos uma coluna Aniv para
montagem desta formatação. Como etapa seguinte, marcamos todas as colunas que desejamos sejam obtidas do
banco de dados: Abono_Formatado, Aniv, nm_func e nr_cargo.
Estabelecemos a restrição das linhas a serem trazidas na área própria (no quadro à esquerda). Para verificarmos se
o comando Select ficou adequado, clicamos no botão Show SQL e conferimos o resultado.
Listagem-resposta 8.06B
SELECT ALL FUNC.NM_FUNC,
TO_CHAR(FUNC.VL_SAL*0.15, 'L999G990D00', 'NLS_CURRENCY=R$') ABONO_FORMATADO,
TO_CHAR(FUNC.DT_NASC, 'DD/MM') ANIV, FUNC.NR_CARGO
FROM DESENV.FUNC
WHERE TO_NUMBER(TO_CHAR(FUNC.DT_NASC, 'MM'))=TO_NUMBER(TO_CHAR(SYSDATE, 'MM'))
Em seguida, montamos a carta no espaço adequado. Quando desejarmos que um valor seja incluído no resultado,
basta que façamos a seleção da coluna para dentro do texto da carta.
Neste tópico estaremos focando o Editor do Modelo de Dados portanto criaremos os grupos, os relacionamentos
entre queries manualmente. Só o layout deve ser criado com o uso do Assistente.
Listagem-resposta 8.07A
SELECT ALL FUNC.CD_MAT, FUNC.NM_FUNC, FUNC.NM_SOBRENOME, FUNC.CD_DEPTO,
FUNC.NR_RAMAL, FUNC.DT_ADM, FUNC.NR_CARGO, FUNC.NR_GIT,
FUNC.IN_SEXO, FUNC.DT_NASC, FUNC.VL_SAL, FUNC.NM_FOTO
FROM DESENV.FUNC
Como a restrição deve ser feita em nível de grupo, devemos abrir a tela de propriedades do grupo e determinar que
apenas as 25 primeiras linhas devem ser selecionadas.
Com esta especificação, encerramos a parte relativa a dados. Para a construção do layout, acionamos o Assistente. Nesta
situação, o Assistente nos mostra as diversas pastas referentes às etapas da construção do relatório. Podemos navegar por
cada uma delas. Nos interessa determinar quais as colunas a serem impressas e qual o gabarito do resultado.
Na definição das colunas a serem formatadas, escolheremos todas. Para gabarito, NCA Yellow.
Listagem-resposta 8.08A
SELECT ALL DESENV.DEPTO.CD_DEPTO, DEPTO.NM_DEPTO, DEPTO.CD_GERENTE,
DEPTO.CD_DEPTO_CTB, FUNC.CD_MAT, FUNC.NM_FUNC,
FUNC.NM_SOBRENOME, DESENV.FUNC.CD_DEPTO, FUNC.NR_RAMAL,
FUNC.DT_ADM, FUNC.NR_CARGO, FUNC.NR_GIT, FUNC.IN_SEXO,
FUNC.DT_NASC, FUNC.VL_SAL, FUNC.NM_FOTO
FROM DESENV.DEPTO, DESENV.FUNC
WHERE DEPTO.CD_DEPTO=FUNC.CD_DEPTO
Devemos, agora, criar o grupo de quebra. Arraste, portanto, o código do departamento para cima e para fora do
grupo de funcionário. Desta forma, será criado um grupo acima do grupo atual. Arraste para esse mesmo grupo as
demais colunas da tabela Depto.
A fim de estabelecermos a restrição, devemos abrir a paleta de propriedades do grupo Func e definir que haverá um
filtro do tipo PL/SQL.
Em seguida, abrimos a função associada Filtro e definimos o código de PL/SQL compatível. Quando o retorno
desta função é True, a linha é aceita e apresentada no relatório. Quando é False, a linha é omitida.
Listagem-resposta 8.08B
function G_funcGroupFilter return boolean is
begin
IF :VL_SAL > 3000 THEN
return (TRUE);
ELSE
RETURN FALSE;
END IF;
end;
Podemos, agora, acionar o Assistente de Relatório (presente na barra de ferramentas do Modelo de Dados) a fim de
definirmos: o formato do relatório, os campos a serem apresentados e os títulos de cada campo, além dos tamanhos.
No diálogo em que determinamos quais as colunas a serem impressas, devemos retirar uma das colunas cd_depto
para que não haja repetição (esta ação poderia ser feita diretamente no Query Builder).
O resultado final da execução utiliza o gabarito NCA Yellow novamente.
Neste relatório, nosso primeiro passo após abrir o Query Builder é criar as três especificações de coluna solicitadas
usando o botão Define Column.
Listagem-resposta 8.09A
Nome - FUNC.NM_FUNC||' '||FUNC.NM_SOBRENOME
Salario - TO_CHAR(FUNC.VL_SAL, 'C999G990D00')
Admissao - TO_CHAR(FUNC.DT_ADM, 'dd/mm/yyyy')
Após estas definições, devemos selecionar essas colunas criadas e as colunas cd_mat e NM_FOTO. As colunas
dt_adm, nm_func, nm_sobrenome e vl_sal são selecionadas indiretamente pelo Query Builder em virtude da
seleção das colunas definidas.
A Listagem-resposta 8.09B apresenta a query resultante contendo as colunas originais mascaradas de acordo com
as solicitações.
Listagem-resposta 8.09B
SELECT ALL FUNC.NM_FUNC||' '||FUNC.NM_SOBRENOME Nome,
FUNC.CD_MAT, TO_CHAR(FUNC.VL_SAL, 'C999G990D00') Salario, DEPTO.NM_DEPTO,
TO_CHAR(FUNC.DT_ADM, 'dd/mm/yyyy') Admissao, FUNC.NM_FOTO
FROM DESENV.DEPTO, DESENV.FUNC
WHERE ((DEPTO.CD_GERENTE=FUNC.CD_MAT)
AND (DESENV.FUNC.CD_DEPTO=DESENV.DEPTO.CD_DEPTO))
Para que seja apresentada a foto no lugar do seu texto, devemos abrir a tela de propriedades referente à coluna
nm_foto e modificar as propriedades:
♦ Ler a partir do Arquivo (Read from File) – Indicando que o conteúdo deste campo, na verdade, é o endereço de
um arquivo em disco, do qual desejamos apresentar o conteúdo.
♦ Formato do Arquivo (File Format) – Indicando que o arquivo a ser lido do disco é uma imagem.
A ação resultante é a apresentação da imagem correspondente ao caminho determinado na coluna nm_foto.
8.10) Criar um relatório de nome REP10 com as seguintes características:
♦ Todas as colunas da tabela Func e da tabela Depto.
♦ O relacionamento entre as tabelas deve ser feito com o uso de um link pela coluna cd_depto.
♦ Estabeleça uma restrição para que sejam fornecidos apenas os funcionários com salário maior que R$ 2.000,00.
♦ Formato Agrupar Acima.
♦ Fornecer nomes adequados para os títulos de coluna.
♦ Utilizar o gabarito Confidential Background Landscape.
Neste relatório, acionaremos o Query Builder duas vezes separadamente. Na primeira, obtemos as colunas da
tabela Func e na segunda, as colunas da tabela Depto, de tal forma que produzimos como resultado duas queries.
Estas duas queries são ligadas dentro do Modelo de Dados (e não por Join), como nos mostra a Figura-resposta 8.10A.
Uma vez que não foi solicitado local para estabelecermos a restrição de salário, escolhemos fazê-lo diretamente na query.
Listagem-resposta 8.10B
SELECT ALL FUNC.CD_MAT, FUNC.NM_FUNC, FUNC.NM_SOBRENOME, FUNC.CD_DEPTO,
FUNC.NR_RAMAL, FUNC.DT_ADM, FUNC.NR_CARGO, FUNC.NR_GIT,
FUNC.IN_SEXO, FUNC.DT_NASC, FUNC.VL_SAL, FUNC.NM_FOTO
FROM DESENV.FUNC
WHERE VL_SAL > 2000
Quando acionamos o Assistente para a montagem do layout, devemos indicar como os dados grupos devem ser
apresentados (verticalmente ou horizontalmente).
Escolhemos o formato vertical (down) para ambos os grupos. Repita este exercício em seguida e verifique a diferença
para o formato horizontal.
No grupo de exercícios a seguir, trabalharemos com os sumários e fórmulas, e portanto, não devemos utilizar o
Assistente para a montagem do Modelo de Dados.
8.11) Criar um relatório de nome REP11 com as seguintes características (utilize o Assistente para a montagem dos totais):
♦ Todas as colunas da tabela Func.
♦ Crie os seguintes sumários:
a) Total de funcionários.
b) Total de salários.
c) Média salarial.
d) Maior cargo.
e) Menor grau de instrução.
♦ Formato Tabular.
♦ Gabarito Confidential Background.
Iniciamos a resolução acionando o Modelo de Dados e criando uma query (com a ajuda do Query Builder) que
obtenha todas as colunas de Func.
8.13) Criar um relatório de nome REP13 com as seguintes características (não utilize o Assistente):
♦ Todas as colunas da tabela Func e da tabela Depto.
♦ O relacionamento entre as tabelas deve ser feito com o uso de um join pela coluna cd_depto.
♦ Crie os seguintes sumários:
a) Total de funcionários por departamento.
b) Total de funcionários geral.
c) Total de salários por departamento.
d) Total de salários geral.
e) Média salarial por departamento.
f) Percentual do salário do funcionário em relação ao departamento.
g) Percentual do salário do funcionário em relação à empresa.
h) Percentual do total salarial do departamento em relação à empresa.
i) Maior cargo por departamento.
j) Maior cargo da empresa.
k) Menor grau de instrução por departamento.
l) Menor grau de instrução da empresa.
♦ Formato Agrupar Acima.
♦ Gabarito Corporate 2.
Nesta resolução, a utilização do Query Builder não precisa mais ser apresentada, pois já efetuamos diversos testes.
Iniciamos, então, a resolução incluindo os seguintes sumários (manualmente) no Modelo de Dados:
♦ qtd_func_depto (grupo G_depto)
a) Função (function) – contagem (count)
b) Origem (source) – cd_mat
c) Reinicializar em (reset at) – g_depto
♦ qtd_func_geral
a) Função (function) – contagem (count)
b) Origem (source) – cd_mat
c) Reinicializar em (reset at) – report
♦ tot_sal_depto(grupo G_depto)
a) Função (function) – soma(sum)
b) Origem (source) – vl_sal
c) Reinicializar em (reset at) – g_depto
♦ tot_sal_geral
a) Função (function) – soma(sum)
b) Origem (source) – vl_sal
c) Reinicializar em (reset at) – report
♦ med_sal_depto (grupo G_depto)
a) Função (function) – media(avg)
b) Origem (source) – vl_sal
c) Reinicializar em (reset at) – g_depto
♦ perc_sal_depto (grupo G_func)
a) Função (function) – % do total(% of total)
b) Origem (source) – vl_sal
c) Reinicializar em (reset at) – g_func
d) Calcular em (compute at) – g_depto
♦ perc_sal_geral(grupo G_func)
a) Função (function) – % do total(% of total)
b) Origem (source) – vl_sal
c) Reinicializar em (reset at) – g_func
d) Calcular em (compute at) – report
♦ perc_saldep_geral(grupo G_depto)
a) Função (function) – % do total(% of total)
b) Origem (source) – tot_sal_depto
c) Reinicializar em (reset at) – g_depto
d) Calcular em (compute at) – report
♦ max_cargo_depto(grupo G_depto)
a) Função (function) – máximo(max)
b) Origem (source) – nr_cargo
c) Reinicializar em (reset at) – g_depto
♦ max_cargo_geral
a) Função (function) – máximo(max)
b) Origem (source) – nr_cargo
8.14) Criar um relatório de nome REP14 com as seguintes características (não utilize o Assistente):
♦ Selecione as colunas cd_mat, nm_func, vl_sal e cd_depto da tabela Func e as colunas cd_depto e nm_depto da
tabela Depto.
♦ O relacionamento entre as tabelas deve ser feito com o uso de um link pela coluna cd_depto.
♦ Crie as seguintes fórmulas:
a) FGTS (8% do salário bruto).
b) INSS (10% do salário bruto limitado a R$ 300,00).
c) TICKET (R$ 5,00 por dia útil, de acordo com o mês atual).
d) Total de Gastos por Funcionário (Salário + INSS + TICKET + FGTS).
e) Previsão de aumento salarial de 15% por funcionário.
f) Total de Gastos Previstos por funcionário.
♦ Calcule os seguintes sumários:
a) Total de Gastos da empresa.
b) Total salarial previsto.
c) Total salarial real.
♦ Formato Agrupar à Esquerda.
♦ Gabarito Bright 1.
Neste relatório, após a criação adequadas das queries, devemos calcular as fórmulas solicitadas.
Listagem-resposta 8.14A
function FGTSFormula return Number is
begin
RETURN :VL_SAL * 0.08;
end;
Listagem-resposta 8.14B
function INSSFormula return Number is
VALOR NUMBER;
begin
A terceira corresponde ao cálculo dos dias úteis (Segunda a Sexta) para determinação do valor do Ticket do mês vigente.
Listagem-resposta 8.14C
function TICKETFormula return Number is
DIAS NUMBER := 0;
INICIO DATE := TRUNC(SYSDATE, 'MM');
FIM DATE := LAST_DAY(SYSDATE);
begin
WHILE INICIO <= FIM LOOP
IF TO_CHAR(INICIO, 'D') BETWEEN 2 AND 6 THEN
DIAS := DIAS + 1;
END IF;
INICIO := INICIO + 1;
END LOOP;
RETURN DIAS * 5;
end;
A próxima fórmula depende das anteriores e corresponde à soma das mesmas. A última acrescenta 15% ao valor do
salário a título de previsão de aumento.
As colunas de sumário farão referência (origem) às colunas Gastos, Previsão e vl_sal, respectivamente, e somente
serão zeradas no fim do relatório.
O resultado deve ser gerado para o gabarito Bright1. Verifique se o resultado ficou coerente com os cálculos.
8.15) Criar um relatório de nome REP15 baseado no REP14 com as seguintes características adicionais (não utilize
o Assistente):
♦ Total de gastos previstos por funcionário.
♦ Total de gastos por departamento previsto e atual.
♦ Total de gastos da empresa previsto e atual.
♦ Total de INSS por departamento e da empresa.
♦ Total de TICKET por departamento e da empresa.
♦ Total de FGTS por departamento e da empresa.
♦ Percentual dos gastos do funcionário em relação ao departamento.
♦ Percentual dos gastos do funcionário em relação à empresa.
♦ Percentual dos gastos do departamento em relação à empresa.
♦ Formato Agrupar acima.
♦ Gabarito Cyan Grid Landscape.
Para diminuir um pouco a quantidade de informações apresentadas, retiramos os três sumários criados no relatório 14.
Neste relatório, devemos acrescentar mais uma fórmula em nível de funcionário para cálculo da previsão de gastos
acontecida com o aumento salarial previsto.
Listagem-resposta 8.15A
function GASTOS_PREVISTOSFormula return Number is
VALOR NUMBER;
begin
VALOR := :PREVISAO * 0.1;
IF VALOR > 300 THEN
VALOR := 300;
END IF;
RETURN (:PREVISAO*0.08)+VALOR+:TICKET+:PREVISAO;
end;
No grupo de exercícios a seguir, estaremos focando os parâmetros; portanto, se você desejar, pode se utilizar do Assistente.
8.16) Criar um relatório de nome REP16 com as seguintes características:
♦ Todas as colunas da tabela Func.
♦ Formato tabular.
♦ Receber como parâmetro um valor de salário.
♦ Somente selecionar os funcionários que recebam mais do que o salário informado.
♦ Use o editor do Form de Parâmetro para modificar a tela de parâmetros.
Nos exercícios, poderemos nos utilizar do gabarito desejado ou até mesmo não usar gabarito.
Logo na criação da query, já definimos que haverá um parâmetro (ainda não criado) de nome P_sal.
Quando aceitamos o diálogo no Query Builder com o texto informado, retornamos para o Assistente. Quando, novamente,
aceitamos o diálogo, o Report Builder nos informa que criará o parâmetro automaticamente.
Listagem-resposta 8.16A
SELECT ALL FUNC.CD_MAT, FUNC.NM_FUNC, FUNC.NM_SOBRENOME, FUNC.CD_DEPTO,
FUNC.NR_RAMAL, FUNC.DT_ADM, FUNC.NR_CARGO, FUNC.NR_GIT,
FUNC.IN_SEXO, FUNC.DT_NASC, FUNC.VL_SAL, FUNC.NM_FOTO
FROM DESENV.FUNC
WHERE FUNC.VL_SAL>:P_SAL
A seguir, escolheremos a opção Criador de Form de Parâmetros (Parameter Form Builder) a fim de criarmos a tela
de parâmetros da forma mais adequada à nossa aplicação.
O Report Builder, então, apresentará um diálogo para que possamos selecionar, dentre os parâmetros existentes nesta
aplicação, aqueles que devem ser apresentados na tela de parâmetros. No nosso caso, escolhemos apenas P_sal.
Será, então, apresentada uma tela com os parâmetros escolhidos, incluindo um ou mais títulos, de acordo com o
preenchimento que tivermos efetuado no diálogo anterior.
Na tela de propriedades do parâmetro P_sal, devemos verificar seu tipo e tamanho.
Definimos uma máscara para digitação do valor (LNNNGNNNGNN0D00). Isto significa que o usuário deverá
digitar o valor do salário respeitando a máscara definida. Neste caso, o valor inicial também deve respeitar esta
sintaxe (Cr$0,00).
A tempo de execução, a tela de parâmetros será apresentada para que o usuário informe o valor do salário. Como
teste, tente informar um valor que fira a sintaxe da máscara. O que acontece?
8.17) Criar um relatório de nome REP17 com as seguintes características:
♦ Todas as colunas da tabela Func.
♦ Formato tabular.
♦ Receber como parâmetro o código do departamento. Deve-se apresentar o nome do departamento para o usuário,
que poderá escolher apenas dentre os valores da lista.
♦ Somente selecionar os funcionários que pertençam ao departamento informado.
♦ Use o editor do Form de Parâmetro para modificar a tela de parâmetros.
Iniciamos da mesma forma que o anterior, definindo no Query Builder a restrição a ser aplicada à query de tal
forma que o resultado seja o apresentado na Listagem-resposta 8.17A.
Listagem-resposta 8.17A
SELECT ALL FUNC.CD_MAT, FUNC.NM_FUNC, FUNC.NM_SOBRENOME, FUNC.CD_DEPTO,
FUNC.NR_RAMAL, FUNC.DT_ADM, FUNC.NR_CARGO, FUNC.NR_GIT,
FUNC.IN_SEXO, FUNC.DT_NASC, FUNC.VL_SAL, FUNC.NM_FOTO
FROM DESENV.FUNC
WHERE FUNC.CD_DEPTO=:p_depto
Nosso próximo passo é configurar o que deve ser apresentado ao usuário nesta tela de parâmetro. Devemos, então,
fazer acesso à tela de propriedades do parâmetro, determinar seu tipo e tamanho e determinar a lista de valores.
Como foi solicitada a apresentação do nome do departamento, devemos escolher a criação de um comando Select
para o preenchimento das opções de valores do parâmetro. Selecione a propriedade Lista de Valores e preencha
como na Listagem-resposta 8.17B.
Listagem-resposta 8.17B
SELECT CD_DEPTO, NM_DEPTO FROM DEPTO
Para que seja apresentado o nome do departamento e recebido o código no parâmetro, devemos colocar o código
como primeira coluna do Select e definir que essa coluna seja oculta. Para obrigar o usuário a escolher dentre um dos
valores da lista, devemos marcar a opção Restringir Lista a Valores Predeterminados.
Para teste de posicionamento, preenchemos todas as opções de título presentes no diálogo de construção da tela
de parâmetro. Veja o resultado na Figura-resposta 8.17A.
8.18) Criar um relatório de nome REP18 com as seguintes características:
♦ Todas as colunas da tabela Func.
♦ Formato tabular.
♦ Este relatório deve receber como parâmetro uma das seguintes informações:
a) Ordenar por departamento – Se este parâmetro for informado, os dados devem ser ordenados por código de
departamento.
b) Ordenar por nome – Se este parâmetro for informado, os dados devem ser ordenados por nome do funcionário.
c) Ordenar por matrícula – Se este parâmetro for informado, os dados devem ser ordenados por matrícula do funcionário.
♦ Apresente os textos para que o usuário escolha dentre uma das formas de ordenação ou nenhuma.
♦ Use o editor do Form de Parâmetro para modificar a tela de parâmetros.
♦ Utilize sintaxe léxica na query.
Neste exercício, utilizaremos a sintaxe léxica do parâmetro; isto significa que modificaremos um trecho da sintaxe
da query a tempo de execução.
Listagem-resposta 8.18A
SELECT ALL FUNC.CD_MAT, FUNC.NM_FUNC, FUNC.NM_SOBRENOME, FUNC.CD_DEPTO,
FUNC.NR_RAMAL, FUNC.DT_ADM, FUNC.NR_CARGO, FUNC.NR_GIT,
FUNC.IN_SEXO, FUNC.DT_NASC, FUNC.VL_SAL, FUNC.NM_FOTO
FROM DESENV.FUNC
&p_ordem
Na Listagem-resposta apresentada, o parâmetro P_ordem será substituído por um comando Order By ou Null (caso
não haja ordenação).
Para a montagem deste parâmetro, utilizaremos a sintaxe da Lista de Valores com Select. A primeira coluna contém
o comando Order By a ser recebido pelo parâmetro, e a segunda coluna o texto a ser apresentado na tela, bastando
que ocultemos a primeira coluna. Observe que na quarta linha o parâmetro recebido será Null, indicando que não
haverá ordenação específica.
Listagem-resposta 8.18B
SELECT 'order by cd_depto', 'Ordenar por Departamento' FROM DUAL
UNION ALL
SELECT 'order by nm_func', 'Ordenar por Nome' FROM DUAL
UNION ALL
SELECT 'order by cd_mat', 'Ordenar por Matrícula' FROM DUAL
UNION ALL
SELECT NULL, 'Sem ordenação' FROM DUAL
Listagem-resposta 8.19A
SELECT ALL FUNC.CD_MAT, FUNC.NM_FUNC, FUNC.NM_SOBRENOME, FUNC.CD_DEPTO,
FUNC.NR_RAMAL, FUNC.DT_ADM, FUNC.NR_CARGO, FUNC.NR_GIT,
FUNC.IN_SEXO, FUNC.DT_NASC, FUNC.VL_SAL, FUNC.NM_FOTO
FROM DESENV.FUNC
&p_where
Uma vez que o usuário fornecerá uma matrícula e/ou um código de departamento e/ou uma data de nascimento,
criamos três outros parâmetros (dep, mat e nasc). Estes serão visíveis e utilizados pelo usuário. Já o parâmetro P_Where
não será mostrado na tela de parâmetros, pois sua montagem será interna.
Os três parâmetros (dep, mat e nasc) são solicitados ao usuário, que poderá ou não informá-los. De acordo com a
opção fornecida, a cláusula Where será montada adequadamente.
Listagem-resposta 8.19B
function MATValidTrigger return boolean is
begin
if :p_where is null then
if :mat is not null then
:p_where := 'WHERE CD_MAT = '||:MAT;
end if;
elsif :mat is not null then
:p_where := :P_WHERE||' AND CD_MAT = '||:MAT;
end if;
return (TRUE);
end;
Na Listagem-resposta 8.19B encontramos o trigger de validação associada ao parâmetro MAT. Se o parâmetro p_where não
estiver preenchido, incluímos a cláusula Where. Caso tenha sido preenchido anteriormente, anexamos uma nova restrição
(And) a uma cláusula Where já existente. É desta forma que definimos a lógica dos dois outros parâmetros (Nasc e Dep).
Veja a Listagem-resposta 8.19C com o trigger de validação para Dep.
Listagem-resposta 8.19C
function DEPValidTrigger return boolean is
begin
if :p_where is null then
if :dep is not null then
:p_where := 'WHERE CD_DEPTO = '''||:DEP||'''';
end if;
elsif :dep is not null then
:p_where := :P_WHERE||' AND CD_DEPTO = '''||:DEP||'''';
end if;
return (TRUE);
end;
Nos exercícios a seguir, estaremos estudando os objetos de Layout. Criaremos, também, uma query que possa ser
utilizada nos exemplos. A utilização do Assistente para a geração do Layout será minimizada.
8.20) Crie uma query externa que apresente numa mesma linha o nome, sobrenome (concatenados), o cargo, o
salário, matrícula e data de admissão do funcionário; o código e nome do departamento; o nome e sobrenome
(concatenados) e ramal do gerente. Salve essa query com o nome Q20.
Neste exercício, criaremos um arquivo em disco contendo uma query que será utilizada em diversas montagens de
relatório. Utilizaremos o nó Consultas SQL Externas (External SQL Queries).
Quando efetuamos um clique duplo sobre a query criada, é acionado o editor de query externa para que possamos
definir o comando SQL. Veja a Listagem-resposta 8.20A.
Listagem-resposta 8.20A
SELECT F.NM_FUNC||' '||F.NM_SOBRENOME NOME, F.NR_CARGO, F.VL_SAL,
F.CD_MAT, F.DT_ADM, D.CD_DEPTO, D.NM_DEPTO,
G.NM_FUNC||' '||G.NM_SOBRENOME GERENTE, G.NR_RAMAL
FROM FUNC F, DEPTO D, FUNC G
WHERE F.CD_DEPTO = D.CD_DEPTO
AND D.CD_GERENTE = G.CD_MAT
AND F.CD_MAT <> G.CD_MAT
Este editor não aciona o Query Builder como auxiliar na montagem do relatório. Se desejarmos utilizar este recurso,
devemos criar um relatório, acionar o Query Builder e salvar a query em disco com a extensão SQL.
8.21) Crie um relatório com o nome de REP21 baseado na query externa Q20. O relatório deve ter formato tabular.
Neste exercício, utilizaremos o Assistente para a montagem do relatório. Quando for solicitada a query, em vez de digitarmos
um novo texto, importaremos o arquivo Q20.SQL do disco pressionando o botão Importar Consulta de SQL.
O resultado da montagem deste relatório será feito com o gabarito Bright1.
A partir deste ponto, a montagem dos relatórios subseqüentes deverá ser feita sem a ajuda do Assistente para que
possamos estudar os objetos do Layout.
8.22) Crie um relatório com o nome de REP22 baseado na query externa Q20. O relatório deve ter uma quebra
contendo os dados do gerente e do departamento.
Neste exercício, toda a construção será manual; portanto, criamos uma query no Modelo de Dados e importamos
o texto da Q20. Observe que a importação não impede que façamos alguma alteração no texto resultante. Neste
caso incluímos uma ordenação por código de matrícula.
Em seguida, estabelecemos o grupo de quebra com as colunas gerente, código do departamento e nome do
departamento. Para identificarmos mais facilmente os grupos, estabelecemos nomes indicativos G_Func e G_Depto.
Para definição da quebra e conseqüente ordenação, consideramos como quebra apenas o código do departamento.
Essa característica corresponde à propriedade Definir Ordem de Interrupção.
Nosso próximo passo é definir o layout deste relatório. Uma vez que existem dois grupos no Modelo de Dados, devem
existir também dois Repeating Frames no Layout, cada um contendo os campos correspondentes.
Observe na Figura-resposta 8.22C que no Repeating Frame de fora (R_Depto) definimos que a elasticidade vertical
seria Expandir (Expand), pois o elemento interno (R_Func) precisa de espaço para se desenvolver. Adicionalmente,
definimos elasticidade vertical também para os dois campos de nome (gerente e funcionário) caso houvesse
necessidade de expansão. No caso de nome do funcionário, tivemos de definir elasticidade vertical também para o
Repeating Frame que o contém (R_Func), pois, se houvesse expansão do nome, o Repeating Frame cederia espaço
para uma segunda linha.
Antes de passar para o próximo exercício, faça o seguinte teste: diminua o tamanho do campo de nome do funcionário
e retire a elasticidade vertical do Repeating Frame R_Func. Observe que, quando ocorre a quebra de linha, o relatório
ganha uma nova página. Isto ocorre porque quando o Report Builder não consegue formatar o campo por falta de
espaço ele quebra de página e continua o campo na próxima.
8.23) Crie um relatório com o nome de REP23 baseado na query externa Q20. O relatório deve conter a seguinte carta:
Figura-resposta 8.23A
Iniciamos o desenvolvimento deste relatório criando uma query no Modelo de Dados e importando o texto do
arquivo Q20.
Uma vez que necessitamos da data de nascimento e de um valor de abono, fizemos algumas alterações em seu conteúdo.
Listagem-resposta 8.23A
SELECT F.NM_FUNC||' '||F.NM_SOBRENOME NOME, F.NR_CARGO, TRUNC(F.VL_SAL /5) ABONO,
F.CD_MAT, F.DT_ADM, TO_CHAR(F.DT_NASC, 'DD/MM') ANIV,
D.CD_DEPTO, D.NM_DEPTO,
G.NM_FUNC||' '||G.NM_SOBRENOME GERENTE, G.NR_RAMAL
FROM FUNC F, DEPTO D, FUNC G
WHERE F.CD_DEPTO = D.CD_DEPTO
AND D.CD_GERENTE = G.CD_MAT
AND F.CD_MAT <> G.CD_MAT
AND TO_CHAR(F.DT_NASC, 'MM') = TO_CHAR(SYSDATE, 'MM')
A seguir, passamos ao layout. Como primeiro passo devemos criar o Repeating Frame e associá-lo ao grupo G_1
(único grupo).
Em seguida, criaremos os cinco campos necessários à carta, porém fora do Repeating Frame. Esses campos devem
ter a propriedade Visível marcada com Não.
Dentro do Repeating Frame, criaremos um Boilerplate de Texto com o texto da carta. Na posição correspondente
aos campos, indicaremos com &<nome do campo> para que esse texto seja substituído pelo conteúdo do campo
correspondente. Veja a Figura-resposta 8.23B.
No texto incluímos também a data do dia da execução. Essa inclusão pode ser feita de duas formas: como referência direta,
como adotamos no exemplo, ou seja, colocamos o símbolo & na frente do nome da coluna <current_date> (estas colunas
aparecem na lista de colunas possíveis de serem associadas a um determinado Field). Outra forma de inclusão é a criação
de um Field e a associação com esta mesma coluna (esta forma tem como vantagem sobre a anterior a possibilidade de
formatarmos o texto da forma mais conveniente). O formato default adotado é o da linguagem (NLS_Territory) em uso.
Atribuímos elasticidade horizontal para todos os campos definidos neste layout, além de termos estabelecido
formatação para o salário do funcionário. Qualquer característica que especificarmos para o campo (Field) é utilizada
pelo Report Builder a tempo de montagem da carta. Teste este exercício com diferentes formatos para os campos
que compõem a carta e observe a diferença no resultado.
8.24) Crie um relatório com o nome de REP24 baseado na query externa Q20. O relatório deve ter quebra por
gerente (primeiro nível) e por departamento (segundo nível). Devem ser apresentados os seguintes sumários:
♦ Soma salarial por departamento.
♦ Soma salarial por gerente.
♦ Soma salarial geral.
♦ Total de funcionários por departamento.
♦ Total de funcionários por gerente.
♦ Total de funcionários geral.
Iniciamos a construção pelo Modelo de Dados importando a query Q20. Em seguida, estabelecemos os grupos de quebra
solicitados. Como último passo, criamos os sumários em cada nível. Observe o resultado na Figura-resposta 8.24A.
Os campos de soma têm como função Soma (Sum). A definição de reinício (Reset At) depende dos níveis Report
para geral, G_gerente para gerente e G_depto para depto. Os campos de total têm como função Contagem (Count).
A definição de reinício (Reset At) é similar ao anterior.
Nossa próxima etapa é a construção do layout.
Uma vez que definimos três grupos no Modelo de Dados, desenvolveremos três Repeating Frames no Layout, um
associado a cada grupo. A seguir, incluiremos os campos correspondentes a cada uma das colunas definidas no
Modelo de Dados. Os campos devem ser criados subordinados ao Repeating Frame que corresponda ao grupo no
qual a coluna que ele faz referência esteja incluída.
Não se esqueça de estabelecer elasticidade vertical para os quadros de repetição que contenham outros quadros de repetição.
Para que o resultado visual ficasse mais claro, definimos linhas para cada um dos quadros e definimos como limite
uma página por gerente (no Repeating Frame de Gerente, limitamos a um registro por página). Estabelecemos,
ainda, a distância vertical de 0.1 entre duas impressões dos Repeating Frames do grupo de funcionário.
No próximo grupo de relatórios estaremos testando a funcionalidade do editor de Layout. As alterações no layout
serão manuais.
8.25) Baseado no relatório REP22, crie um relatório de nome REP25 e acrescente a seguinte funcionalidade:
♦ Campos numéricos formatados e alinhados à direita.
♦ Campos de data formatados e alinhados à esquerda.
♦ Letra arial, tamanho 9 para todos os campos e tamanho 8 e negrito para os cabeçalhos.
♦ Incluir cabeçalho de coluna.
♦ Alinhamento horizontal e vertical de todos os campos e cabeçalhos.
♦ Limitar a apresentação a um departamento por página.
Neste relatório trabalharemos apenas no layout para estabelecer as formatações solicitadas.
O alinhamento dos campos é realizado através do menu Formatar (Format), submenu Justificar (Justify). As máscaras
são estabelecidas dentro das propriedades de cada campo.
Finalmente, para limitarmos a quantidade de registros de departamento a um por página, devemos alterar a
propriedade correspondente do Repeating Frame.
Para que o alinhamento e ajuste dos campos seja mais perfeito, desmarque a opção de alinhamento pela grade
presente no menu Exibir.
8.26) Baseado no relatório REP25, crie um relatório de nome REP26 e acrescente a seguinte funcionalidade:
♦ Crie uma Capa que apresente o nome do relatório e a lista de departamentos com seus respectivos nomes (use
gabarito NCA Grey para a capa).
♦ Crie uma Contracapa que indique o término do relatório e o usuário solicitante.
♦ Determine cor azul para todos os itens e cor vermelha para os cabeçalhos.
♦ Inclua um título que seja apresentado em todas as páginas.
Neste exercício estaremos focando o editor de Layout.
Como primeiro passo, visando à criação da Capa do relatório, devemos incluir uma nova query no Modelo de
Dados que selecione o código e nome do departamento. Esta query não deve ter nenhum vínculo com a query
principal. Observe a Figura-resposta 8.26A.
A fim de criarmos a capa do relatório, automaticamente, devemos navegar para a área do layout chamada Cabeçalho
(Header). Com esta área selecionada devemos acionar o Assistente de Relatório e selecionar apenas os campos e
grupos pertencentes à segunda query. Observe a Figura-resposta 8.26B.
Em seguida escolha o gabarito adequado e encerre o Assistente. Navegue para o Editor de Layout (Layout Model)
e verifique que na área de Cabeçalho existe um layout (corpo e margem) totalmente diferente daquele presente na
seção Principal.
à coluna Usuário incluída no Modelo de Dados e que corresponde a uma fórmula que retorna a função User (ou
seja, o nome do usuário conectado com o banco de dados). A navegação para esta parte do layout é similar à
anterior. Desta vez devemos pressionar o botão Trailer.
Observe que neste caso utilizamos o mesmo campo F_usuário, uma vez que os campos definidos em uma área do
layout são acessíveis em qualquer uma das partes do layout.
A inclusão do título de página é feita na margem do relatório. Observe, porém, que existe margem para cada uma das
seções do relatório (Cabeçalho, Principal e Trailer). Na seção de Cabeçalho, a margem (com seu respectivo título) foi
construída automaticamente pelo Assistente e não incluiremos título na seção de Trailer. Navegaremos então para a
seção do layout de nome Principal e, em seguida, para a Margem desta área e desenvolveremos o título.
Observe que quando navegamos para a margem temos visibilidade da parte de corpo do relatório. A linha preta
que aparece delimita o corpo do relatório, isto é, o corpo não pode se expandir para fora dos limites dessa área.
No nosso exercício, empurramos a área de limite do corpo para baixo cerca de 0.5 polegadas para garantirmos que
o desenvolvimento do corpo não recobrirá o título.
O próximo passo é definir a cor de letra dos campos e boilerplates. Esta ação é feita com a ajuda da barra de ferramentas
vertical (botão Cor de Texto). Selecione o campo e escolha na paleta de cores apresentada a cor desejada.
8.27) Baseado no relatório REP24, crie um relatório de nome REP27 e acrescente a seguinte funcionalidade:
♦ Campos numéricos formatados e alinhados à direita.
♦ Campos de data formatados e alinhados à esquerda.
♦ Letra arial tamanho 9 para todos os campos.
♦ Alinhamento horizontal e vertical de todos os campos e cabeçalhos.
♦ Crie uma marca d’água que seja apresentada como fundo de página (texto inclinado).
♦ Crie uma linha horizontal que separe o Gerente de seu Departamento.
♦ Os campos de nome do gerente e nome do departamento devem ter a possibilidade de crescimento horizontal.
♦ Inclua um número de página que seja reiniciado a cada novo gerente (no rodapé).
♦ Inclua um título que seja apresentado em todas as páginas.
♦ Inclua a data de emissão do relatório em todas as páginas.
Neste relatório desenvolveremos o layout apenas na Seção Principal.
Para a organização deste relatório, a primeira etapa a ser cumprida é a colocação de cabeçalho para todos os
campos. Inclua-os sem se preocupar com posicionamento.
Nossa segunda etapa é a definição do tamanho das letras dos campos e textos. Você pode optar por usar a barra de
ferramentas horizontal presente na tela (em que temos campos de tipo da letra e tamanho) ou a opção Fonte do
menu Formatar. Em seguida, trataremos do alinhamento interno dos campos numéricos e alfanuméricos. Esta ação
também pode ser feita com o uso dos botões presentes na barra de ferramentas horizontal (acima da área de desenho).
A especificação de máscara de edição é preenchida para cada campo. Selecione simultaneamente todos os campos de
soma salarial e o próprio campo Salário. Abra a tela de propriedades e informe uma máscara (FM999G999G990D00)
compatível. Em seguida, selecione os demais campos numéricos e estabeleça outra máscara (FM9G999G900).
Como próxima etapa, alinhe os títulos e campos para que fiquem com um aspecto agradável. Como sugestão, veja
o alinhamento definido na Figura-resposta 8.27A.
A marca d’água deve ser definida na Margem para que o desenvolvimento do corpo seja feito sobre o desenho que
viermos a criar.
Para teste, crie o texto Confidencial (boilerplate de texto) com letra Arial e tamanho 48. Em seguida, utilizando a
ferramenta de rotação, incline o texto conforme apresentado na Figura-resposta 8.27A. Dê cor de letra cinza-claro.
Observe ainda nesta mesma figura-resposta que o nome do gerente foi diminuído de tamanho, tornado expansível
na horizontal e colocado dentro de um frame expansível na horizontal. Realize também estas operações (não esqueça
de colocar o frame atrás destes campos e na frente do Repeating Frame de gerente).
Abaixo do nome do gerente, inclua uma linha que se estenda até o frame. Essa linha deve ter a propriedade
Extensão da Linha com Quadro (Line Stretch With Frame) preenchida com o nome do frame recém-criado. Isto
fará com que a linha aumente ou diminua quando o Frame aumentar ou diminuir horizontalmente.
As próximas solicitações devem ser construídas na Margem. Neste exemplo, preferimos criar um campo para
página (que faz referência à quantidade de páginas físicas) e um campo para data de emissão (que faz referência à
data atual) e determinar que a propriedade visível de ambos os campos fosse preenchida com Não. Desta forma,
pudemos utilizá-los dentro dos boilerplates de texto e estabelecer máscaras de formatação simultaneamente.
8.28) Baseado no relatório REP27, crie um relatório de nome REP28 e acrescente a seguinte funcionalidade:
♦ Apresente a foto do funcionário.
♦ Inclua no cabeçalho o símbolo da empresa (utilize Link File).
♦ Limite a quantidade de funcionários a três por página.
Na margem do relatório devemos criar um elemento Link File e escolher uma imagem qualquer do disco.
Para limitarmos a quantidade de funcionários a três por página, devemos preencher a propriedade Máximo de
Registros por Página do Repeating Frame de funcionário com 3.
Listagem-resposta 8.29A
FUNCTION FDATA(DATA IN DATE) RETURN VARCHAR2 IS
BEGIN
RETURN TO_CHAR(DATA, 'DD/MM/YYYY HH24:MI:SS');
END;
Listagem-resposta 8.29B
FUNCTION FTEXTO(TXT1 IN VARCHAR2, TXT2 IN VARCHAR2)
RETURN VARCHAR2 IS
BEGIN
RETURN INITCAP(LTRIM(RTRIM(TXT1))||' '||LTRIM(RTRIM(TXT2)));
END;
Listagem-resposta 8.29C
function Fdt_admFormula return Char is
begin
:FDT_NASC := FDATA(:DT_NASC);
:NOME := FTEXTO(:NM_FUNC, :NM_SOBRENOME);
RETURN FDATA(:DT_ADM);
end;
Na Listagem-resposta 8.29C, observamos que a coluna Fdt_adm recebe o resultado da função (Return) pois se trata
da coluna de fórmula. As demais colunas (PlaceHolders) recebem a atribuição diretamente da coluna de fórmula.
No layout definido, o Repeating Frame recebeu direção de impressão horizontal; observe a direção da seta na linha
do Repeating Frame quando essa opção for marcada.
Como resultado temos duas impressões por página. Não use gabarito para melhor visualização do resultado.
8.30) Crie um relatório de nome REP30 baseado no relatório REP29 e acrescente a seguinte funcionalidade:
♦ Retire a utilização das rotinas do Modelo de Dados.
♦ A modificação dos valores deve ser feita dinamicamente, no momento da montagem da linha.
♦ O desenvolvimento do relatório deve ser horizontal/vertical.
Como primeiro passo deste exercício, devemos retirar a fórmula associada à coluna Fdt_adm. Recriamos esta
coluna como um PlaceHolder (sem fórmula).
No layout, para cada um dos três campos associados às colunas de espaço reservado (PlaceHolders), criamos um gatilho
de formato (Format Trigger) que atribua ao campo o valor desejado a tempo de formatação.
Listagem-resposta 8.30A
function F_Fdt_admFormatTrigger return boolean is
begin
srw.set_field_char(0, fdata(:dt_adm));
return (TRUE);
end;
A Listagem-resposta 8.30A mostra este gatilho para a coluna F_dt_adm. A rotina Set_Field_Char substitui o valor do
campo na hora da impressão. A seguir, a Listagem-resposta 8.30B com o trigger de formatação para o campo F_Nome.
Listagem-resposta 8.30B
function F_NomeFormatTrigger return boolean is
begin
srw.set_field_char(0, ftexto(:nm_func, :nm_sobrenome));
return (TRUE);
end;
Como passo seguinte, alteramos a direção de impressão para Horizontal/Vertical, aumentamos verticalmente o tamanho
do Repeating Frame e colocamos sua cor de linha vermelha para que possamos mais facilmente entender o resultado.
Observe que os valores apresentados em cada campo são similares ao resultado do exercício anterior. O que mudou
foi o momento da formatação do dado.
8.31) Crie um relatório de nome REP31 baseado no relatório REP30, e acrescente a seguinte funcionalidade:
♦ Obtenha a quantidade de registros da tabela Func a ser apresentada na capa do relatório.
♦ Que receba como parâmetro uma indicação da formatação ou não das fotos do funcionário. Caso a foto não seja
formatada, apresente um boilerplate retangular na posição correspondente.
Utilizando o Report Builder, crie um trigger (de banco de dados) que impeça que o cargo seja aumentado sem
aumento de salário e que impeça que o cargo e o salário sejam diminuídos.
Neste relatório, nosso primeiro passo é criar uma coluna do tipo espaço reservado (PlaceHolder) para receber a
quantidade de registros da tabela Func. Poderíamos ter criado uma fórmula fora da Query para atender a esta
solicitação. Optamos por criar um PlaceHolder e colocar o comando Select no trigger Before Report, como mostrado
na Listagem-resposta 8.31A.
Listagem-resposta 8.31A
function BeforeReport return boolean is
begin
SELECT COUNT(*) INTO :QTD_REGS
FROM FUNC;
return (TRUE);
end;
Em seguida, criamos uma capa para o relatório para apresentação deste valor, incluindo um campo Fqtd_regs e um
texto (boilerplate de texto) com “Quantidade de Registros em Funcionário &Fqtd_regs”.
Para a apresentação da foto do funcionário, alteramos a Query (no Modelo de Dados) para que selecionasse também
esta coluna.
Listagem-resposta 8.31B
SELECT CD_MAT, DT_NASC, DT_ADM, NM_FUNC, NM_SOBRENOME, NM_FOTO
FROM FUNC
O layout foi alterado também para a inclusão da coluna de foto. Para que fosse apresentado alternativamente a
foto ou um boilerplate retangular, desenhamos um sobre o outro e incluímos um trigger de formatação para cada
um. Quando o parâmetro for S, será formatada a foto, e quando for N, será formatado o retângulo.
Listagem-resposta 8.31C
function B_2FormatTrigger return boolean is
begin
IF :P_FOTO = 'N' THEN
return (TRUE);
ELSE
RETURN FALSE;
END IF;
end;
Listagem-resposta 8.31D
function F_NM_FOTOFormatTrigger return boolean is
begin
IF :P_FOTO = 'S' THEN
return (TRUE);
ELSE
RETURN FALSE;
END IF;
end;
Execute a aplicação e passe como parâmetro S. Observe que o retângulo não é formatado.
Listagem-resposta 8.32A
function AfterPForm return boolean is
begin
:TABELA := :pdep||user;
:col5 := 'nm_gerente';
:col6 := 'nm_depto';
srw.do_sql ('create table '||:pdep||user||
'(cd_mat number(5), nm_func varchar2(12), vl_sal number(9,2), '||
'dt_nasc date, nm_gerente varchar2(12), nm_depto varchar2(40))');
srw.do_sql ('insert into '||:pdep||user||
' select f.cd_mat, f.nm_func, f.vl_sal, f.dt_nasc, '||
' g.nm_func, d.nm_depto from func f, func g, depto d'||
' where f.cd_depto = d.cd_depto and'||
' g.cd_mat = d.cd_gerente and' ||
' d.cd_depto = '''||:pdep||'''');
— srw.do_sql('commit');
COMMIT;
return (TRUE);
end;
Verifique o código da Listagem-resposta 8.32A. Como primeiro passo, executamos a rotina Do_Sql para criar a
tabela cujo nome é uma combinação do parâmetro Pdep com a função User (de PL/SQL). A seguir incluímos nessa
tabela as linhas da tabela Func que pertencem ao departamento informado como parâmetro. Utilizamos, neste
caso, também a rotina Do_Sql, porque o nome da tabela é variável e não existe a tempo de compilação (só execução).
Como última etapa fizemos um Commit (não precisava ser com a Do_Sql) para garantir que o comando Insert seja
gerado no banco de dados.
A seguir, precisamos direcionar a query para a leitura desta tabela. Temos um problema, porém: a query tem de ser
compilada no momento do desenvolvimento. Como a tabela não existe, teremos de direcionar a compilação para
uma tabela que exista e trocar seu nome a tempo de execução.
Listagem-resposta 8.32B
SELECT &COL1, &COL2, &COL3, &COL4, &COL5 NM_GERENTE,
&COL6 NM_DEPARTAMENTO FROM &TABELA
Na Listagem-resposta 8.32B criamos uma query indicando que as colunas e a tabela seriam fornecidas por parâmetros
(substituição léxica). Para efeito de compilação, porém, a sintaxe da query deve estar correta. Para que isto ocorra,
cada um dos parâmetros ganhou um valor inicial.
Este valor inicial não pode ser qualquer, ou seja, se a coluna da tabela se chama cd_mat e é do tipo number(5),
então o valor inicial deve fazer referência a uma coluna de nome cd_mat e tipo number(5). Esta foi a nossa
alternativa para o parâmetro col1. Isto foi possível porque o parâmetro Tabela recebeu como valor inicial Func.
Deste modo, pudemos considerar a tabela Func como base para compilação. Utilizamos esta mesma estratégia para
as colunas nm_func, vl_sal e dt_nasc.
Quando chegou a vez do nome do gerente e do nome do departamento, tivemos um problema, pois não temos uma
coluna na tabela Func com estes nomes e nem com os tipos que desejávamos. Utilizamos, então, outra estratégia.
Listagem-resposta 8.32C
LPAD(' ', 40)
Na Listagem-resposta 8.32C observamos que o valor inicial do parâmetro Col6 é uma expressão cujo resultado é um
varchar2(40), que era o nosso objetivo. Se você retornar à query apresentada na Listagem-resposta 8.32B, observará
que esta coluna foi apelidada de nm_departamento. Para o parâmetro Col5 utilizamos esta mesma estratégia.
Quando concluirmos estas definições, podemos aceitar o diálogo da query para que o Report Builder efetue a compilação.
Na Figura-resposta 8.32A observamos o resultado no Modelo de Dados. Para verificação do resultado gerado pelo
Report Builder, obtenha as propriedades da coluna Nm_Departamento que ele criou. Veja que prevaleceram os 40
bytes que desejávamos.
Verifique, você mesmo, o que aconteceu com as propriedades das demais colunas.
Com esta etapa vencida, podemos gerar o layout com o auxílio do Assistente usando até mesmo um gabarito.
Retorne agora à Listagem-resposta 8.32A e verifique que no momento de execução do trigger After Parameter Form
trocamos o nome dos parâmetros Tabela, Col5 e Col6 para os nomes correspondentes na tabela temporária. Isto é
necessário pois desejamos que a leitura seja feita para a tabela temporária.
A última etapa deste relatório é a remoção da tabela ao término da execução. Escolhemos realizar esta tarefa no
trigger After Report.
Listagem-resposta 8.32D
function AfterReport return boolean is
begin
SRW.DO_SQL('DROP TABLE '||:PDEP||USER);
return (TRUE);
end;
Para executarmos este relatório com sucesso, devemos usar a opção Previsualizador de Runtime do menu Exibir. O
Previsualizador Ativo (Live Previewer) executa o relatório criando a tabela e preenchendo os dados, porém não
executa o trigger para remover a tabela, pois o relatório não é encerrado. Com o Previsualizador de Runtime isto
ocorre normalmente.
8.33) Crie um relatório contendo duas queries independentes apresentadas lado a lado (uma com dados de
funcionário e outra com dados de projeto X atividade). Apresente duas imagens (uma sob cada query) somente
quando todo o relatório for concluído.
Neste exercício, nossa primeira tarefa é a criação do Modelo de Dados com as duas queries independentes.
Em seguida, os objetos correspondentes às duas queries foram criados no layout, uma ao lado da outra. Abaixo de
cada uma delas foi incluída uma imagem qualquer.
Quando executamos o relatório desta forma, observamos que cada figura-resposta é apresentada quando é encerrado
o Repeating Frame imediatamente superior. Isto ocorre porque o Report Builder cria uma âncora implícita para
cada uma das figuras a fim de garantir que o Repeating Frame que lhe é superior não passe por cima da figura.
Como nosso desejo é que as duas figuras sejam impressas apenas no fim de todo o relatório, incluímos um frame
ao redor dos dois Repeating Frames.
Neste caso, a ancoragem ainda ocorrerá, porém as duas figuras serão ancoradas no frame, fazendo com que ambas
sejam apresentadas juntas somente no fim da impressão do frame, o que acontecerá apenas quando ambos os
Repeating Frame acabarem.
Para que o resultado seja satisfatório, não esqueça de estabelecer elasticidade vertical para o frame.
8.34) Crie um relatório que contenha a lista de departamentos da empresa. Quando o usuário pressionar o botão
adequado, devemos acionar o relatório REP31. Para os departamentos A00, B01 e C01 não apresentar fotos, para os
demais departamentos, apresentar.
Neste relatório, incluímos no Layout um botão de repeating frame, causando o aparecimento do botão a cada
linha impressa no relatório.
Listagem-resposta 8.34A
procedure rep31ButtonAction is
begin
Na lógica associada à ação do botão, acionamos a rotina SRW.Run_Report para executar o relatório desejado. Quando
não especificamos a extensão (RDF) para o parâmetro Module, será assumido REP. Essa extensão corresponde ao módulo
gerado por um processo de compilação. Se você desejar testar, selecione no menu Arquivo (File) o submenu Administração
(Administration) e a opção Compilar Relatório (Ctrl+T).
8.35) Crie um relatório que selecione os seguintes dados da tabela de funcionários: matrícula, nome, salário e
cargo. O relatório deverá ter formato tabular, porém o layout deverá variar de acordo com o parâmetro recebido:
♦ A – Apresentar matrícula, nome e salário.
♦ B – Apresentar matrícula, salário e cargo.
♦ C – Apresentar matrícula, nome e cargo.
O espaço entre os objetos apresentados na impressão deve ser constante e semelhante entre si.
O objetivo deste relatório é fazermos uma experiência usando âncoras. Para tal, selecionamos apenas as colunas
Matrícula, Nome, Salário e Cargo da tabela Func.
No Layout, posicionamos estes quatro campos lado a lado.
Observe na Figura-resposta 8.35A que ancoramos um objeto no seu “pai” imediatamente à esquerda, ou seja, a
coluna nm_func (filha) está ancorada na coluna cd_mat (pai), a coluna vl_sal (filha) está ancorada na coluna
nm_func (pai) e assim por diante. Com os cabeçalhos acontece o mesmo.
Em seguida, preenchemos a propriedade Fechar Horizontalmente (Collapse Horizontally) de todas as âncoras
indicando que, se o objeto-pai não for formatado, a distância especificada deverá ser removida.
Listagem-resposta 8.35A
function F_nm_funcFormatTrigger return boolean is
begin
IF :PLAYOUT IN ('A','C') THEN
return (TRUE);
ELSE
RETURN FALSE;
END IF;
end;
Para que o objeto fosse formatado somente quando desejássemos, criamos um gatilho de formatação para cada um
destes elementos, indicando quando a formatação deveria ou não ocorrer.
Listagem-resposta 8.35B
function F_nr_cargoFormatTrigger return boolean is
begin
IF :PLAYOUT IN ('B','C') THEN
return (TRUE);
ELSE
RETURN FALSE;
END IF;
end;
Nas Listagens-resposta 8.35A e 8.35B encontramos dois destes triggers de formatação. Eles foram associados a um
parâmetro (Playout) do tipo Char com tamanho 1 e valor inicial A. A formatação ocorrerá de acordo com a
solicitação do relatório.
Execute, agora, o relatório e verifique a diferença de resultados.
8.36) Crie um relatório de nome REP36 que receba como parâmetro a página inicial a ser impressa e a quantidade
limite de registros. Devem ser mostrados na capa do relatório os parâmetros recebidos. Utilize a query Q20 para
montagem deste relatório.
Uma vez que a query Q20.sql já existe em disco, não precisaremos defini-la novamente. Em vez de importarmos a
query, preencheremos seu nome na propriedade Arquivo de Origem de Consulta Externa (External Query Source
File). Desta forma, o arquivo será importado, porém ficaremos sem acesso ao texto da query para efetuar modificações.
Veja a Figura-resposta 8.36A.
Este programa recebe dois parâmetros: Pmax, que determina o número máximo de linhas a serem lidas na query;
e o parâmetro Ppag, que determina a página inicial do relatório.
Listagem-resposta 8.36A
function BeforeReport return boolean is
begin
SRW.SET_MAXROW('Q_1', :PMAX);
PGLOBAL.PAG := :PPAG;
return (TRUE);
end;
Na Listagem-resposta 8.36A, encontramos o trigger de Before Report que limitará a quantidade de linhas lidas pela
query. A rotina Set_Maxrow deve ser utilizada neste trigger (antes do início da leitura).
Simultaneamente, estamos atribuindo a uma variável de pacote (Pglobal.Pag), criada no relatório, o valor recebido
no parâmetro Ppag.
Para que o número da página possa ser apresentado, devemos criar uma variável de trabalho (Variável de Espaço
Reservado – PlaceHolder) que possa ser mencionada por um objeto de layout.
Na área reservada para rodapé (na margem), incluímos um campo F_Pag e um texto (boilerplate de texto) com
“Page &F_Pag”.
O campo F_Pag tem como origem a variável do tipo PlaceHolder declarada no Modelo de Dados. Esse campo foi
definido com a propriedade Visível recebendo o valor Não. Desta forma, pode ser adicionado ao boilerplate de
texto definido no rodapé da página.
Listagem-resposta 8.36B
function BetweenPage return boolean is
begin
PGLOBAL.PAG := PGLOBAL.PAG + 1;
return (TRUE);
end;
Como última etapa, criamos um trigger de formatação que preencha o valor do campo F_Pag com o número da
página atual.
Listagem-resposta 8.36C
function F_PAGFormatTrigger return boolean is
begin
SRW.SET_FIELD_NUM(0, PGLOBAL.PAG);
return (TRUE);
end;
Listagem-resposta 8.37A
SELECT NM_FUNC, NR_CARGO, VL_SAL, NM_DEPTO, D.CD_DEPTO
FROM FUNC F, DEPTO D
WHERE F.CD_DEPTO = D.CD_DEPTO
Após sua especificação, foi a vez da criação das variáveis de sumário para montagem das solicitações de totais.
As variáveis criadas em nível de Grupo de Quebra correspondem a sumários baseados na soma da coluna Vl_Sal, sendo
que Tot_Depto é reinicializado a cada troca de departamento e Acum_Depto é reinicializado somente no fim do relatório.
Para totais relativos à página, temos o sumário Tot_Página, que é baseado na soma da coluna Vl_Sal, porém com
reinicialização a cada página. Além destes, criamos uma variável de trabalho (PlaceHolder) para nos auxiliar a
calcular o acumulado por página e o total da página anterior.
No layout criamos, na parte superior, um campo baseado na variável Tot_Atual que apresentará o valor acumulado
na página anterior. Dentro dos Repeating Frames, criamos as variáveis de sumário relativas ao grupo de Quebra.
Após o desenvolvimento do Repeating Frame do grupo de quebra (no fim da página), criamos os dois campos que
apresentarão os totais por página. Do lado direito criamos o campo F_Tot_Pag, baseado na coluna Tot_Página, que
apresentará o total de salários da página. Do lado esquerdo, criamos o campo F_Acum_Pag, baseado na coluna
Tot_Página que apresentará o valor acumulado dos salários (portanto, será substituído a tempo de execução).
Além destes campos, criamos um pacote de nome Pglobal que contém duas variáveis que serão as responsáveis por
acumular os salários de cada funcionário (TOT_ANT e TOT_ATU). Essas variáveis devem ser inicializadas no trigger
de Before Report uma vez que uma variável de pacote fica ativa enquanto a sessão não for fechada (em uma segunda
execução, o valor inicial seria o valor acumulado na sessão anterior).
Nosso próximo passo é acumular os valores de salário e atribuir esses valores acumulados aos campos correspondentes.
Listagem-resposta 8.37B
function F_VL_SALFormatTrigger return boolean is
begin
PGLOBAL.TOT_ATU := PGLOBAL.TOT_ATU + NVL(:VL_SAL, 0);
return (TRUE);
end;
Na Listagem-resposta 8.37B mostramos o trigger de formatação associado ao campo F_vl_sal. Desta forma, a cada
salário formatado para impressão, acumulamos seu valor na variável Tot_Atu do pacote Pglobal. Quando ocorre a
mudança de página, atribuímos o valor desta variável à variável Tot_Ant do pacote Pglobal.
Com estas duas rotinas fechamos a parte de cálculo. Resta a parte de atribuição.
Listagem-resposta 8.37C
function F_acum_pagFormatTrigger return boolean is
begin
SRW.SET_FIELD_NUM(0, PGLOBAL.TOT_ATU);
return (TRUE);
end;
No trigger de formatação do campo F_acum_Pag (definido após o Repeating Frame do grupo de quebra) alteramos o
valor do campo para o valor da variável de pacote Tot_Atu. Veja a Listagem-resposta 8.37C.
Listagem-resposta 8.37D
function F_TOT_ANTFormatTrigger return boolean is
begin
SRW.SET_FIELD_NUM(0, PGLOBAL.TOT_ANT);
return (TRUE);
end;
No trigger de formatação do campo F_tot_Ant (definido na parte superior da página) alteramos o valor do campo
para o valor da variável de pacote Tot_Ant. Veja a Listagem-resposta 8.37D.
Com esta montagem, no início da página temos o total da página anterior, e no fim desta o total acumulado e o
valor apenas somado na página (através de sumário).
Teste este exercício você mesmo. Como teste adicional, mude a referência do campo F_Acum_Pag de Tot_Pagina
para Tot_Atual. Verifique o que acontece e analise por quê.
8.38) Crie um relatório de nome REP38 baseado na query Q20 e que contenha a seguinte funcionalidade:
♦ Devem ser apresentados em vermelho todos os salários maiores que R$ 4.000,00.
♦ Devem ser apresentados em verde todos os salários menores que R$ 2.000,00.
Este relatório só tem como particularidade a troca de cores a tempo de impressão. Passaremos direto, portanto,
para esta fase.
A modificação das cores deve ser feita no trigger de formatação do objeto que desejamos alterar.
Listagem-resposta 8.38A
function F_vl_salFormatTrigger return boolean is
begin
— Criado Automaticamente a partir do Report Builder.
if (:vl_sal > '4000')
then
srw.set_text_color('red');
end if;
Para realizarmos esta modificação sem esforço utilizaremos a propriedade Formatação Condicional presente no
grupo Layout Geral do campo F_vl_sal (no layout). Criaremos duas condições (uma vez que desejamos atribuir
valores diferentes a cada situação). A terceira condição, isto é, para salário entre 2000 e 4000 não precisou ser
incluída uma vez que a cor default é ‘Black’. O gatilho de formatação criado, automaticamente, pelo Report Builder
é mostrado na Listagem-resposta 8.38A.
8.39) Crie um relatório de nome REP39 baseado na query Q20 e que contenha a seguinte funcionalidade:
♦ Às segundas, as letras do relatório devem ser azuis.
♦ Às terças, as letras do relatório devem ser verdes.
♦ Nos outros dias as letras devem ser pretas.
Crie um grupo de quebra e garanta que todos os elementos sejam impressos na mesma página.
Para a confecção deste relatório, adicionamos o nome do arquivo que contém a query na propriedade Arquivo de
Origem de Consulta Externa (External Query Source File).
A montagem deste relatório pode ser feita com o Assistente de Relatórios. Com o relatório pronto, criamos as
rotinas para controle das cores.
Inicialmente criaremos um pacote de nome Pacote contendo uma variável Cor de tamanho varchar2(10).
Listagem-resposta 8.39A
function BeforeReport return boolean is
DIA NUMBER := TO_CHAR(SYSDATE, 'D');
begin
IF DIA = 4 THEN
PACOTE.COR := 'BLUE';
ELSIF DIA = 5 THEN
PACOTE.COR := 'GREEN';
ELSE
PACOTE.COR := 'BLACK';
END IF;
return (TRUE);
end;
Desta vez não usaremos o auxílio do Report Builder, criaremos, manualmente, os triggers para formatação de cor.
Para diminuirmos a quantidade de código repetitivo, usamos o trigger Before Report para a preparação da variável
com a cor correspondente ao dia da semana escolhido.
Listagem-resposta 8.39B
function F_cd_deptoFormatTrigger return boolean is
begin
SRW.SET_TEXT_COLOR(PACOTE.COR);
return (TRUE);
end;
Para cada objeto de layout que for mudar de cor, devemos atribuir a variável criada da mesma forma que fizemos
na Listagem-resposta 8.39B.
8.40) Crie um relatório que formate uma borda para os campos numéricos. A espessura da borda e cor serão
recebidas como parâmetro:
♦ Espessura – variando de 0 a 200.
♦ Cor de letra.
♦ Cor de preenchimento.
Baseie o relatório na Q20. Crie um grupo de quebra com desenvolvimento horizontal e um grupo detalhe com
desenvolvimento vertical. Teste a propriedade Column Mode.
Iniciamos o relatório montando uma query baseada no texto do arquivo Q20.sql. Em seguida, dividimos as colunas
em dois grupos (quebra e detalhe).Veja a Figura-resposta 8.40A.
Nosso próximo passo é determinar o layout. Desta vez, faremos a alteração de mais de uma informação. Como não
precisaremos de lógica específica, podemos utilizar os parâmetros diretamente no gatilho de formatação de cada coluna.
Listagem-resposta 8.40A
function Fcd_matFormatTrigger return boolean is
begin
srw.set_text_color (:p_letra);
srw.set_foreground_border_color(:p_borda);
srw.set_border_pattern('solid');
srw.set_border_width(:p_espessura);
srw.set_foreground_fill_color(:p_preenchimento);
srw.set_fill_pattern('solid');
return (TRUE);
end;
O layout deste relatório foi construído especialmente para testarmos o resultado de uma execução com a propriedade
Column Mode ativada e desativada.
O grupo externo deve ter direção de impressão horizontal; o interno, vertical. Veja a Figura-resposta 8.40B.
Para causarmos a situação de uso do modo de coluna devemos fazer com que um determinado departamento
comece a imprimir os detalhes em uma página e conclua em outra, ou seja, devemos forçar uma quebra no meio
do desenvolvimento do grupo de quebra.
Execute o relatório e observe a página do departamento D11. Iniciamos a impressão na coluna da direita do
departamento D11, que possui mais registros do que os apresentados.
Observe que, na página de continuação, o restante das linhas do departamento D11 foi formatada na coluna da
esquerda. Isto ocorre porque não estamos trabalhando com o modo de coluna.
Se você não conseguiu reproduzir esta situação, diminua o tamanho da página da seguinte forma: navegue para a
margem e diminua verticalmente o tamanho da área de desenvolvimento do corpo. Teste novamente o relatório
até que ocorra uma mudança de página no meio da impressão de um determinado departamento.
Após entendermos este resultado, devemos estabelecer o modo de coluna para o Repeating Frame do grupo de
quebra e executar o relatório novamente. Observe agora que o grupo D11 continua sendo impresso na coluna da
direita, isto é, a coluna é preservada.
Observe, porém, que as preferências não são salvas juntamente com o relatório. Se aplicam à estação do usuário
(existe em disco, no diretório <oracle-home>, um arquivo de nome Cauprefs.ora, com as preferência em uso
atualmente). Quando efetuamos uma alteração nas preferências, o arquivo Cauprefs.ora é alterado e esta modificação
passa a valer a partir deste momento.
Na pasta Definições de Runtime alteramos a permissão para outras aplicações executarem (SQL de Não Bloqueio)
e acionamos o botão para formatação das máscaras solicitadas (Editar Máscaras).
A unidade de dimensionamento do relatório pode ser feita no grupo de propriedades do módulo Rep41. Desta
forma, ocorrerá seu armazenamento para disco.
Listagem-resposta 8.41A
function CF_1Formula return Number is
begin
srw.do_sql('alter session set sql_trace = true');
return 0;
end;
A definição de estatísticas pode ser feita de duas formas: ou criamos uma fórmula fora dos grupos existentes ou
usamos um trigger de relatório (Before Parameter Form ou After Parameter Form) para incluir o comando apresentado
na Listagem-resposta 8.41A. A partir do ponto em que executamos esta ação, nossa sessão passa a ser monitorada.
A referência à leitura de arquivos do sistema operacional e obtenção de módulos do tipo relatório (extensão RDF)
também é indicada nas preferências, na pasta Acessar.
Para que o relatório seja impresso em modo caracter, devemos colocar como valor inicial para o parâmetro de
sistema Mode o valor Character.
Os parâmetros relativos ao modo caracter são especificados em nível de módulo; portanto abra a tela de propriedades
do módulo Rep41 que você está desenvolvendo agora.
Neste grupo de propriedades devemos determinar a largura e altura da página. Estas informações são utilizadas
pelo Report Builder para estimar o tamanho do caracter a ser usado na impressão, isto é, o tamanho da página
física (largura, por exemplo) dividido pelo número de caracteres que cabem na página (informado na propriedade
Largura do Relatório do grupo Caractere das propriedades do módulo). Veja a formatação de grade feita no layout
(Figura-resposta 8.41A).
Se desejarmos que os objetos do tipo BitMap tenham sua posição marcada a tempo de execução, devemos marcar
a opção Incluir Objetos de BitMap.
Execute este relatório usando o Previsualizador de Runtime. O Previsualizador de Runtime apresenta a imagem que
será gerada para a impressão final, levando em consideração a característica de modo caracter.
Você encontrará o arquivo de trace no diretório definido pela variável de ambiente user_dump_dest no arquivo
init.ora. O arquivo tem a forma ORA<número>.TRC. Se o seu banco de dados é Personal e você manteve a instalação
padrão, o arquivo deve estar no diretório c:\oracle\admin\<nome do banco de dados>\udump. O <nome do
banco de dados> você forneceu durante o processo de instalação.
8.42) Crie um relatório baseado na Q20 que contenha a seguinte funcionalidade:
♦ Criar duas novas cores em sua paleta de cores.
♦ Exporte a paleta de cores com o nome de pteste.pal.
♦ Garanta que sejam lidos aproximadamente 20 registros a cada acesso ao banco de dados.
♦ Quando o relatório concluir com sucesso, deve ser enviado, automaticamente, um commit para o banco de
dados. Caso contrário, deve ser acionado um Rollback.
♦ No layout do relatório devem ser utilizadas as novas cores criadas.
♦ O relatório deve alterar o ramal de todos os funcionários para que sejam formados com quatro números começando
com 9. Se não houver nenhum número a ser alterado, deve ser dado um erro.
Como primeira tarefa para montagem do relatório, criamos duas novas cores na paleta de cores. Devemos incluí-
las no canto inferior esquerdo onde existem oito células em branco.
Em seguida, exportamos esta paleta usando a opção Exportar do menu Arquivo.
As opções de Commit/Rollback e leitura de 20 KB a cada acesso ao banco de dados (tamanho do array) é uma
característica do usuário estabelecido em nível de preferência, pasta Definições de Runtime.
Utilizamos as novas cores no layout para os campos F_nome, F_nr_cargo, Fcd_mat e F_vl_sal.
Criamos, também, um botão que realizasse o cálculo quando o usuário desejasse.
Listagem-resposta 8.42A
procedure U_1ButtonAction is
erro exception;
begin
update func
set nr_ramal = to_number(lpad(nr_ramal,4,'9'))
where length(nr_ramal) < 4;
srw.message (1, sql%rowcount);
if sql%rowcount = 0 then
srw.message(1, 'ramais inexistentes');
raise erro;
end if;
end;
Listagem-resposta 8.43A
SELECT NM_DEPTO, DECODE(IN_SEXO, 'F', 'FEMININO', 'MASCULINO') SEXO, SUM(VL_SAL) SAL
FROM FUNC F, DEPTO D
WHERE F.CD_DEPTO = D.CD_DEPTO
GROUP BY NM_DEPTO, DECODE(IN_SEXO, 'F', 'FEMININO', 'MASCULINO')
O Modelo de Dados é simples, uma vez que ainda não incluímos os sumários.
O layout também não é complexo. Para a criação do grupo matricial no layout, selecione simultaneamente os dois
quadros de repetição e utilize, no menu Inserir, a opção Matriz de Layout. O quadro com desenvolvimento vertical
deve ser o quadro de fundo (mais atrás).
8.44) Crie um relatório de nome REP44 que apresente uma matriz com as seguintes características:
♦ Departamento contra sexo (nome do departamento e sexo por extenso).
♦ Quantidade de funcionários por sexo e por departamento.
♦ Usar mais de uma query.
♦ Tornar visível a célula da matriz.
Este relatório é similar ao anterior em relação ao layout, porém para a construção do Modelo de Dados utilizamos
mais de uma query.
Listagem-resposta 8.44A
SELECT 'FEMININO' SEXO FROM DUAL
UNION
SELECT 'MASCULINO' FROM DUAL
Simulamos a query de sexo com um Union da tabela Dual (veja a Listagem-resposta 8.44A). A query de departamento
obtém as informações da tabela Depto e a query de recheio é similar ao exercício anterior.
Observe a montagem do Modelo de Dados na Figura-resposta 8.44A.
Desta vez, porém, queremos destacar a célula da matriz e não o recheio; portanto, selecione a célula matricial e
determine uma cor para ela. Em seguida, execute o relatório.
8.45) Criar um relatório de nome REP45 baseado no relatório REP44 acrescentando a seguinte funcionalidade:
♦ Sumário com total de funcionários por sexo.
♦ Sumário com total de funcionários por departamento.
♦ Sumário com total geral de funcionários.
♦ Acumulado de funcionários por departamento e por sexo.
Para a confecção deste relatório, devemos salvar o anterior com o nome de Rep45 e acrescentar no modelo de
dados os sumários capazes de criar as totalizações desejadas.
Todos os sumários associados à matriz são criados dentro do grupo de matricial. Fora dos grupos utilizados no
relatório, só criamos o sumário relativo ao total geral de funcionários.
O sumário que contabiliza a quantidade de funcionários por sexo deve ser zerado toda vez que a indicação de sexo
for alterada. A ordem do produto, ou seja, a ordem em que os dados devem ser ordenados para a produção do
sumário deve ser de sexo. O sumário que contabiliza a quantidade de funcionários por departamento é similar a
este, porém relativamente a departamento.
O sumário que acumula a quantidade de funcionários por departamento e sexo possui como diferença básica que, para a
sua geração, precisamos que os dados estejam em ordem de departamento e sexo. Somente quando ocorrer a troca de
departamento, zeraremos este sumário, criando um acumulado em relação a sexo.
O layout definido foi alterado para acomodar os sumários. Os campos associados aos sumários são incluídos em
relação à ordem do produto, ou seja, se um sumário só é influenciado pelo grupo Sexo, deve ser incluído apenas no
Repeating Frame desse grupo. O mesmo ocorre com o sumário associado ao grupo Depto. O sumário geral fica fora
da matriz, pois não é influenciado por nenhum dos grupos.
O acumulado é influenciado pelos dois grupos (Ordem do Produto), e portanto, deve ser incluído no grupo da matriz.
Para que pudéssemos verificar com mais clareza o resultado, colocamos a célula do sumário acumulado destacada
em verde. Do lado direito da matriz aparece o total da linha (ou seja, do grupo Departamento). Na parte inferior da
matriz está contabilizado o total por coluna (ou seja, do grupo Sexo) e no canto direito inferior está contabilizado
o total geral (confira no Layout 8.45A).
8.46) Crie um relatório de nome REP46 que apresente uma matriz com as seguintes características:
♦ Usar uma query.
♦ Sumário de salário por grau de instrução, departamento e sexo.
♦ Sumário de salário por grau de instrução e departamento.
♦ Sumário de salário por grau de instrução e sexo.
♦ Sumário de salário por grau de instrução.
Neste exercício foi solicitada a utilização de uma única query. Desta forma, a Listagem-resposta 8.46A apresenta o
comando Select necessário à montagem da matriz.
Listagem-resposta 8.46A
SELECT ROUND(SUM(VL_SAL)) SAL, NR_GIT, CD_DEPTO,
DECODE(IN_SEXO, 'F', 'FEMININO', 'MASCULINO') IN_SEXO
FROM FUNC
GROUP BY NR_GIT, CD_DEPTO, DECODE(IN_SEXO, 'F', 'FEMININO', 'MASCULINO')
Em seguida, separamos os três grupos de quebra: um para departamento, outro para grau de instrução e outro para sexo.
Nossa última tarefa no Modelo de Dados é definir os sumários de acordo com a solicitação. A Figura-resposta 8.46A
indica que o posicionamento de todos eles está subordinado ao grupo Matriz uma vez que cada um deles está
associado a pelo menos uma das colunas de dimensionamento da matriz.
Todos os sumários usam a função Soma relativamente à coluna Sal (que na verdade é sum(vl_sal)). A diferença entre eles
ocorre em nível de Ordem do Produto e momento de zerar. Estabelecemos a seguinte lista:
♦ Sumário de salário por grau de instrução, departamento e sexo – O produto segue a ordem Git-Depto-Sexo. O
valor será zerado quando houver mudança de Git.
♦ Sumário de salário por grau de instrução e departamento – O produto segue a ordem Git-Depto. O valor será
zerado quando houver mudança de Depto.
♦ Sumário de salário por grau de instrução e sexo – O produto segue a ordem Git-Sexo. O valor será zerado quando
houver mudança de Sexo.
♦ Sumário de salário por grau de instrução – O produto segue a ordem Git. O valor será zerado quando houver
mudança de Git.
Nosso objetivo, neste momento, é testar o resultado da propriedade Ordem do Produto.
Observe na Figura-resposta 8.46B que o sumário Sum_Git_Dep_Sexo foi incluído dentro do Repeating Frame relativo ao
grupo Recheio. Isto não é obrigatório. Ele pode ser incluído no grupo matricial (que corresponde ao cruzamento dos
três quadros) mas ficar fora do Repeating Frame Recheio. A diferença é a quantidade de vezes que ele será formatado. Se
ficar no grupo matricial, ele será formatado tantas vezes quantas o grupo matricial o for. Se ficar no grupo Recheio, ele
será formatado somente quando houver valor a ser mostrado. Após a execução deste relatório, altere o posicionamento
desse grupo e faça um teste.
Para facilitar o entendimento e o cálculo do resultado esperado altere as cores de cada um dos sumários e verifique
o resultado.
Antes de dar como encerrado este exercício, retorne ao Modelo de Dados e mude a freqüência com que este último
sumário é reinicializado e verifique os resultados.
8.47) Criar uma biblioteca de PL/SQL de nome BPL47 que contenha as seguintes rotinas:
♦ Rotina (Dv_Matr) para calcular o DV da matrícula do funcionário (noves fora).
♦ Rotina (Intervalo) para determinar o intervalo de anos entre duas datas recebidas como parâmetro.
♦ Rotina (Abono) para calcular o abono salarial (trimestral) de acordo com o número de anos de casa. A rotina
deve receber como parâmetro o tempo de serviço e o salário.
♦ Menos de 1 ano de casa – Não recebe abono.
♦ De 1 a menos de 3 anos de casa – Recebe 3% de abono.
♦ De 3 a menos de 6 anos de casa – Recebe 10% de abono.
♦ Mais de 6 anos de casa – Recebe 15% de abono.
Neste exercício, nosso primeiro passo é a criação de um objeto no nó Bibliotecas de PL/SQL (PL/SQL Libraries) com
o nome de BPL47.
Listagem-resposta 8.47A
FUNCTION DV(MAT IN NUMBER) RETURN NUMBER IS
BEGIN
RETURN MOD(MAT,9);
END;
Listagem-resposta 8.47B
FUNCTION INTERVALO(DINI IN DATE, DFIM IN DATE) RETURN NUMBER IS
BEGIN
RETURN TRUNC(ABS((DFIM - DINI))/365.25);
END;
Na Listagem-resposta 8.47B encontramos a rotina que calcula o intervalo entre duas datas retornando o número de anos.
Observe que as datas podem ser fornecidas em qualquer ordem, pois usamos a função Abs para obter o valor absoluto.
Listagem-resposta 8.47C
FUNCTION ABONO(TEMPO IN NUMBER, SAL IN NUMBER) RETURN NUMBER IS
BEGIN
IF TEMPO < 1 THEN
RETURN 0;
ELSIF TEMPO BETWEEN 1 AND 2.99 THEN
RETURN ROUND((SAL*3)/100);
ELSIF TEMPO BETWEEN 3 AND 5.99 THEN
RETURN ROUND((SAL*10)/100);
ELSE
RETURN ROUND((SAL*15)/100);
END IF;
END;
Listagem-resposta 8.48A
function ABONO_FUNCFormula return Number is
TEMPO NUMBER;
begin
:DV_MAT := DV(:CD_MAT);
TEMPO := INTERVALO(SYSDATE, :DT_ADM);
RETURN ABONO(TEMPO, :VL_SAL);
end;
Como desejamos criar uma formatação para relatórios tabulares, já podemos usar a seção subordinada ao nó
Tabular. Veja a Figura-resposta 8.49A.
Para os cabeçalhos, alteramos o tipo de letra para Arial e tamanho 9 e a cor de letra para vermelho. Observe que, quando
alteramos alguma propriedade, ela perde o símbolo indicativo de herança. Os valores-padrão foram herdados da Seção
Default. Poderíamos supor que este gabarito viesse a ser utilizado por todos os tipos de relatório e que somente no caso
de Tabular estaríamos criando características específicas.
Para os itens, isto é, Campos, devemos alterar a cor de letra para verde e a letra para Arial com tamanho 8.
Finalmente, os sumários serão pintados de azul (mantivemos a letra Arial com tamanho 8).
8.50) Crie um relatório de nome REP50 que seja baseado na query Q20. Não crie grupos de quebra e utilize o gabarito
especificado no Exercício 8.49. Crie Totais para salário (soma e % do total) e matrícula (count).
A criação de um gabarito qualquer será sempre realizada em conjunto com a criação de um relatório-exemplo para
que possamos verificar o resultado das especificações.
Vejamos, agora, o que resultará do Exercício 8.49.
Utilizaremos o Assistente para a criação deste relatório Tabular. Quando você chegar no diálogo que solicita o
gabarito, selecione do disco o arquivo GT49.TDF.
Observe que o resultado (apesar de colorido demais) indica que podemos estabelecer padrões que diminuam o
esforço de programação de um relatório. Façamos o próximo exemplo.
8.51) Crie um gabarito de nome CQ51 para os relatórios que contenham pelo menos um grupo de quebra.
♦ Características para o grupo de quebra 1:
a) Cabeçalho: cor de fundo darkblue, letra Arial, tamanho 10, cor de letra branca.
b) Corpo: cor de fundo branca, letra Arial, tamanho 9, cor de letra darkblue.
♦ Características para o grupo de quebra 2:
a) Cabeçalho: cor de fundo darkgreen, letra Comic Sans Ms, tamanho 9, itálico, cor de letra cinza.
b) Corpo: cor de fundo branca, letra Comic Sans Ms, Bold, tamanho 9, cor de letra darkgreen.
Poderíamos especificar estas características dentro do arquivo GT49 uma vez que se tratam de especificações para
relatórios diferentes.
Na Figura-resposta 8.51A verificamos as duas seções subordinadas ao nó Agrupar Acima. Na primeira seção, estabeleceremos
as características relativas ao grupo de quebra1 e na segunda as características relativas ao grupo de quebra2.
Nas propriedades relativas a corpo devemos alterar a fonte e cor de texto para as etiquetas e as colunas.
Você verá o resultado no próximo exercício.
8.52) Crie um relatório de nome REP52 que seja baseado na query Q20. Crie 2 grupos de quebra e utilize o gabarito
especificado no Exercício 8.51.
A criação deste relatório será efetuada totalmente com a ajuda do Assistente. Quando você atingir o diálogo relativo
ao gabarito, selecione o arquivo GQ51.TDF.
Para observar melhor os detalhes, crie um sumário para que este herde as características da seção default.
Listagem-resposta 8.53A
SELECT NM_FUNC||' '||NM_SOBRENOME NOME, CD_MAT, VL_SAL,
CD_DEPTO, NR_GIT, DT_NASC
FROM FUNC
Estabelecemos a coluna cd_depto como quebra (ficou isolada no grupo de quebra no Data Model).
Em seguida, com o auxílio do Assistente de Relatórios criamos na Seção Principal o layout Agrupar à Esquerda
(escolhemos o gabarito Confidential Heading). Após a criação, navegamos para o Editor de Layout (Layout Model)
e navegamos para a Seção Cabeçalho, acionamos o Assistente novamente e geramos o layout Agrupar Acima
(escolhemos o gabarito Corporate1).
Nossa próxima etapa é definir a lista de distribuição. Como desejamos separar os dois resultados, definiremos esta
característica como propriedade de cada uma das seções envolvidas.
Para a Seção Cabeçalho, incluiremos um registro na lista de distribuição (propriedade Distribuição da Seção) indicando
que o resultado será gerado em arquivo do tipo HTMLCSS, com uma cópia e nome Rel53_A.Htm.
Para a Seção Principal, incluiremos um registro na lista de distribuição (propriedade Distribuição desta Seção)
indicando que o resultado será gerado em arquivo do tipo RTF, com uma cópia e nome Rel53_E.Rtf.
Para executar acione a opção Distribuir do menu Arquivo.
Se o seu arquivo RTF não apresentou a página inteira do resultado, retorne ao Report Builder, abra a tela de propriedades
da Seção Principal e preencha a propriedade Largura com 4.5 e a propriedade Painéis Horizontais por Página com 2.
Realize a distribuição novamente e verifique a página de continuação gerada.
Os arquivos são gerados por default no diretório <oracle-home>\BIN, a não ser que você tenha alterado as
propriedades das variáveis de ambiente correspondentes.
8.54) Crie um relatório que gere arquivos a serem utilizados em aplicações Microsoft Excel com as seguintes características:
♦ Colunas da Tabela Func: matrícula, nome, cargo, salário, data de nascimento, data de admissão.
♦ Colunas da Tabela Depto: cd_depto, nm_depto, total de salário dos funcionários do departamento, nome do gerente.
♦ A formatação de data e número deve ser feita individualmente por coluna.
Para gerarmos o resultado desejado, definiremos duas queries separadas, uma obtendo os dados de funcionário, apresentada
na Listagem-resposta 8.54A e outra obtendo os dados de departamento, apresentada na Listagem-resposta 8.54B.
Listagem-resposta 8.54A
SELECT CD_MAT, NM_FUNC, NR_CARGO, VL_SAL, DT_NASC, DT_ADM
FROM FUNC
Para que todas as informações solicitadas sejam apresentadas, há necessidade de se estabelecer um Join na query
de departamento, como veremos a seguir.
Listagem-resposta 8.54B
SELECT D.CD_DEPTO, D.NM_DEPTO, SUM(F.VL_SAL) TOTSAL, G.NM_FUNC NM_GER
FROM FUNC F, DEPTO D, FUNC G
WHERE F.CD_DEPTO = D.CD_DEPTO
AND D.CD_GERENTE = G.CD_MAT
AND G.CD_MAT <> F.CD_MAT
GROUP BY D.CD_DEPTO, D.NM_DEPTO, G.NM_FUNC
A montagem do layout pode ser feita com a ajuda do Assistente. Não devemos colocar label para os campos. Definir
os tamanhos adequados para nome do departamento, datas, nome do funcionário, etc.
Com o layout gerado, devemos estabelecer as máscaras de formato para vl_sal(LNNGNN0D00), dt_nasc (DD/MM/
YYYY), dt_adm(DD/MM/YYYY) e total de salários(LNNNGNN0D00).
Execute este relatório para teste e verifique se os valores ficaram corretos.
A próxima etapa é estabelecer valores iniciais para os parâmetros de sistema, da seguinte forma: Desname=Rel54.txt,
Desformat=Delimited, Destype=File, Mode=Character, Printjob=No.
Quando executarmos o relatório, agora, será gerado o arquivo em disco, sendo que os valores de separação dos campos
obedecerão ao default. Para estabelecermos os separadores desejados podemos usar a opção Criar Para Arquivo (Texto) do
menu Arquivo, para que seja apresentado o diálogo adequado ou podemos criar um executável e na linha de comandos
do Windows, definir o texto apresentado na Listagem-resposta 8.54C.
Listagem-resposta 8.54C
C:\ORAWIN95\BIN\RWRUN60.EXE MODULE=REL54.REP USERID=DESENV/DESENV@DESENV
DELIMITER=: CELLWRAPPER=|
Observe que, imediatamente após a marcação do ponto de interrupção, o nó Ações de Depuração fica preenchido
indicando este ponto. Observe que este nó é externo ao relatório, e portanto, quando o abrirmos de novo não mais
estará presente (não é armazenado com o fonte do relatório).
A execução destas rotinas ocorrerá tantas vezes quantas forem as linhas lidas do banco de dados, uma vez que
estão contidas na formatação da linha-detalhe.
A utilização do Interpretador é similar à utilização do Depurador do Forms, e, portanto, não faremos mais testes com ele.
Para que o resultado deste texto seja gerado como uma Tag de HTML, devemos marcar a propriedade Contém Tags
HTML do grupo Layout Geral do boilerplate de texto.
Ainda na margem do relatório, criamos um objeto Link File. Quando indicamos que o tipo do arquivo é uma Imagem
URL, automaticamente o formato do texto correspondente ao nome do arquivo adquire a sintaxe de uma URL.
Listagem-resposta 8.56A
FILE://C:/Teste\Begin.gif
Observe no resultado que o tamanho do objeto definido no Layout (relativo à imagem URL) determina o tamanho
da imagem HTML. As propriedades de elasticidade que associarmos ao objeto serão ignoradas.
As possíveis sintaxes de imagens URL (Uniform Resource Locator) são as seguintes:
♦ HTTP://www.reportbuilder.com.br/logo1.gif – Nesta sintaxe, o browser pesquisará o site da empresa ReportBuilder
a fim de obter a imagem logo1.git para incorporá-la à página do relatório gerado.
♦ HTTP://&<servidor>/&<arq> – Nesta sintaxe, servidor e arq são parâmetros do relatório (tipo texto). A tempo de
execução do Report Builder faz a modificação pelo valor do parâmetro.
♦ FILE://c:/teste\begin.gif – Nesta sintaxe indicamos a localização do arquivo em algum ponto da rede local do usuário.
Em nosso exemplo, utilizamos esta última sintaxe. Resta-nos, agora, verificar o resultado gerado.
Este resultado pode ser visto através do botão Previsualizador de Web, quando usamos o Previsualizador Ativo. Este
botão, enquanto estiver pressionado, acionará o browser default do usuário cada vez que modificarmos alguma
característica do relatório. Quando tivermos concluído a geração podemos desabilitá-lo.
O Report Builder também conta com a possibilidade de incorporarmos trechos de HTML antes e depois do relatório,
página ou form (parâmetro). Isto pode ser especialmente útil se desejarmos incorporar nosso relatório a um padrão
de página da empresa.
Incluiremos um texto simples apenas para avaliação de resultado.
Ao retornarmos à aplicação 7.40, observamos que o relatório a ser acionado é o REP17. Como primeiro passo,
devemos verificar se o texto do trigger When-Button-Pressed do botão REP17 está de acordo com o apresentado na
Listagem-resposta 8.57A.
Listagem-resposta 8.57A
DECLARE
PLIST PARAMLIST;
BEGIN
PLIST := CREATE_PARAMETER_LIST('REP17');
ADD_PARAMETER (PLIST, 'PDEPTO', TEXT_PARAMETER, :FUNC.CD_DEPTO);
RUN_PRODUCT(REPORTS, 'REP17.RDF', SYNCHRONOUS,
RUNTIME, FILESYSTEM, PLIST, NULL);
DESTROY_PARAMETER_LIST (PLIST);
END;
Execute a aplicação e observe que a tela de parâmetros do relatório foi apresentada, uma vez que não solicitamos
sua omissão.
Todos os parâmetros de sistema ou do usuário que desejarmos modificar a tempo de execução devem ser passados
pela aplicação de tela (Form). Sendo assim, modificamos novamente o texto do trigger do botão para que a tela de
parâmetros não seja exibida.
Listagem-resposta 8.57B
DECLARE
PLIST PARAMLIST;
BEGIN
PLIST := CREATE_PARAMETER_LIST('REP17');
ADD_PARAMETER (PLIST, 'PARAMFORM', TEXT_PARAMETER, 'NO');
ADD_PARAMETER (PLIST, 'PDEPTO', TEXT_PARAMETER, :FUNC.CD_DEPTO);
RUN_PRODUCT(REPORTS, 'REP17.RDF', SYNCHRONOUS,
RUNTIME, FILESYSTEM, PLIST, NULL);
DESTROY_PARAMETER_LIST (PLIST);
END;
Desta vez, a execução do relatório é iniciada imediatamente sem a presença da tela de parâmetros.
8.58) Gere um relatório baseado na tabela TB_Func com as seguintes características:
♦ Formato carta.
♦ Colunas: nome completo do funcionário, nome do gerente, nome do departamento, matrícula do funcionário,
salário do funcionário.
♦ Gabarito Corporate 1.
♦ Cada carta deve ser gerada em um arquivo HTML em separado.
♦ Deve ser possível a navegação seqüencial entre páginas (use um ícone de navegação).
♦ Garanta que para os funcionários gerentes o salário não seja mostrado.
Iniciaremos definindo uma query com o texto apresentado na Listagem-resposta 8.58A a seguir.
Listagem-resposta 8.58A
SELECT NM_FUNC||' '||NM_SOBRENOME NOME_FUNC, F.CD_DEPTO.CD_GERENTE.NM_FUNC
NOME_GERENTE, F.CD_DEPTO.NM_DEPTO NM_DEPTO, CD_MAT, VL_SAL,
DECODE (CD_MAT, F.CD_DEPTO.CD_GERENTE.CD_MAT, 1, 0) IND_GERENTE
FROM TB_FUNC F
Nesta query, além de obtermos os dados requisitados pelo exercício, incluímos mais uma coluna que identificasse
se o funcionário lido é ou não gerente de departamento (Ind-Gerente).
Após a definição da query estabelecemos o layout da carta (bem simples), conforme apresentado pela Figura 8.58A.
Quando o Assistente concluir a definição do layout e navegar para sua visualização, observará que seu layout é
diferente deste apresentado na Figura-resposta 8.58A. Algumas mudanças foram implementadas manualmente
para atender ao exercício.
Como primeira diferença observe que criamos um item F_vl_sal baseado na coluna Vl_Sal (do Data Model). O
objetivo da criação desta coluna é a possibilidade de estabelecermos uma formatação condicional para o salário
(pode ou não ser impresso). Este campo possui a propriedade Visível(Visible) marcado com Não, de tal forma que
sua referência (feita dentro do boilerplate de texto: &F_Vl_Sal) seja impressa dentro das regras estabelecidas.
Com este campo criado podemos preencher a propriedade Formatação Condicional (do grupo Layout Geral),
indicando que quando o funcionário for gerente este campo não deve ser formatado (ou seja, omitido). Se abrirmos
a propriedade Gatilho de Formato, devemos obter o resultado apresentado na Listagem-resposta 8.58B.
Listagem-resposta 8.58B
FUNCTION F_VL_SALFORMATTRIGGER RETURN BOOLEAN IS
BEGIN
— CRIADO AUTOMATICAMENTE A PARTIR DO REPORT BUILDER.
IF (:IND_GERENTE = '1')
THEN
RETURN (FALSE);
END IF;
RETURN (TRUE);
END;
Nosso próximo passo é estabelecer navegação entre as páginas geradas pelo relatório. Como definimos que cada carta deve
ser apresentada em páginas diferentes, escolhemos paginar usando dois arquivos Bmps contendo uma seta para cima e
outra para baixo (a referência aos arquivos aparece na Figura-resposta 8.58A).
Para que cada carta tivesse um nome diferente (e seqüencial), de tal forma que pudéssemos navegar para a frente
e para trás, criamos, no Data Model, duas variáveis de sumário (uma dentro do grupo, pois só é incrementada
quando ocorre a montagem do grupo) e outra fora do grupo. Ambas as variáveis contam(Count) matrículas, sendo
zeradas apenas no fim do relatório.
Preenchemos, então, a propriedade Destino de Hiperligação do boilerplate de texto (a própria carta) com o valor
apresentado na Listagem-resposta 8.58C, onde cs_cd_mat corresponde ao nome do sumário que ficou dentro do grupo.
Listagem-resposta 8.58C
DESTINO&<CS_CD_MAT>
Desta forma cada boilerplate que for montado terá nomes seqüenciais: Destino1, Destino2, etc.
Na propriedade Gatilho de Formato do Boilerplate com Seta para Cima, preenchemos o texto apresentado pela
Listagem-resposta 8.58D.
Listagem-resposta 8.58D
FUNCTION ANTFORMATTRIGGER RETURN BOOLEAN IS
BEGIN
IF :CS_CD_MAT > 1 THEN
SRW.SET_HYPERLINK('#'||'DESTINO'||TO_CHAR((:CS_CD_MAT - 1), 'FM999'));
ELSE
SRW.SET_HYPERLINK('#'||'DESTINO'||TO_CHAR(:CS_CD_MAT, 'FM999'));
END IF;
RETURN (TRUE);
END;
Desta forma, a propriedade Hiperligação (HyperLink) deste objeto apontará para endereços dentro do próprio
resultado. Como controle adicional, impedimos que a primeira instância deste objeto apontasse para um objeto
endereço inexistente.
Agimos da mesma forma na propriedade Gatilho de Formato do boilerplate com desenho Seta para Baixo, incluindo
o texto apresentado pela Listagem-resposta 8.58E.
Listagem-resposta 8.58E
FUNCTION PROXFORMATTRIGGER RETURN BOOLEAN IS
BEGIN
IF :CS_CD_MAT < :TOTAL_PAG THEN
SRW.SET_HYPERLINK('#'||'DESTINO'||TO_CHAR((:CS_CD_MAT + 1), 'FM999'));
ELSE
SRW.SET_HYPERLINK('#'||'DESTINO'||TO_CHAR(:CS_CD_MAT, 'FM999'));
END IF;
RETURN (TRUE);
END;
A variável Total_Pag corresponde ao sumário criado no Data Model (fora do grupo), que indicará a última carta (ou
total de cartas).
Estabelecemos a mesma crítica do exemplo anterior para que na última instância do objeto não houvesse
endereçamento inválido.
Com estas informações montadas já podemos testar a execução deste relatório (para um único HTML).
Para tal devemos preencher o valor inicial dos parâmetros de sistema da seguinte forma: Desname=rel58.htm,
Destype=File, Desformat=Html, Printjob=No.
Como passo final, acionar o relatório na linha de comando do Windows com o texto criado na Listagem-resposta
8.58F. Isto é necessário pois o parâmetro PageStream somente pode ser usado na linha de comando.
Listagem-resposta 8.58F
C:\ORAWIN95\BIN\RWRUN60.EXE USERID=DESENV/DESENV@DESENV MODULE=REL58.REP PAGESTREAM=YES
Quando você executar o relatório observará que a navegação continua funcionando, mesmo sendo em arquivos
diferentes, pois o Report completa o endereço do destino com o nome do arquivo correspondente.
Capítulo 9
O FORMS NA WEB
Neste capítulo, estudaremos como implementar uma aplicação Forms ou Reports em um ambiente Intranet ou Internet.
Neste estudo verificaremos as mudanças a serem feitas no Forms e no Reports para obtenção de uma boa performance.
Apesar de estudarmos, para efeito de teste, os parâmetros de configuração do Forms Server e do Reports Server, o
ambiente de produção incluindo o Oracle9i não será abordado. Desta forma, uma análise da documentação da
Oracle (fornecida juntamente com a ferramenta) é indispensável para uma configuração adequada.
Cliente
Neste esquema os equipamentos dos clientes devem ter capacidade de processamento e memória compatíveis com
a tarefa de execução das aplicações localmente. O único servidor com capacidade de processamento significativa é
o servidor de banco de dados.
Cliente
Em um ambiente Web, os serviços de Runtime do Forms e toda a lógica das aplicações são instalados no servidor
de aplicação e não mais nas máquinas-cliente. Os triggers (do Forms) são processados no servidor de aplicação,
enquanto que o processamento da interface com o cliente ocorre no ambiente cliente.
Neste esquema os equipamentos dos clientes não necessitam de uma grande capacidade de processamento. Esta
necessidade será transferida para o servidor de aplicação (que não precisa ser constituído de uma única máquina,
pode ser um pool), que deverá ser capaz de atender aos requisitos dos clientes.
OS COMPONENTES
Para atender a esta arquitetura de três camadas, a Oracle disponibilizou um conjunto de programas ou serviços
chamados conjuntamente de Forms Services. Com estes produtos poderemos utilizar nossa aplicação desenvolvida
para ambiente de duas camadas em ambiente de três camadas (inclusive na Internet).
requisições do cliente, e quando está em comunicação com o servidor de banco de dados ele age como um
cliente solicitando informações.
Em resposta a esta solicitação uma página de HTML (a página inicial) é enviada ao browser. Nesta primeira solicitação
também pode ser enviado para o cliente o arquivo Java que contém a Forms applet.
Em seguida a Forms applet é iniciada (instantiated) e captura os parâmetros informados (login, por exemplo) na
primeira tela para enviar ao servidor, indicando que aplicação Forms deve ser iniciada.
A Forms applet envia uma requisição ao Listener (corresponde a uma porta específica na máquina servidora de
aplicação) juntamente com os parâmetros capturados da tela.
O Listener estabelece a conexão entre o cliente e o Forms Server.
A partir desta conexão, a comunicação passa a ser feita, diretamente, entre a Forms applet e o Forms Runtime e
entre o Forms Runtime e o banco de dados. O Listener fica, então, disponível para receber novas requisições de
conexão de outros usuários.
CONSIDERAÇÕES INICIAIS
Antes de analisarmos os parâmetros específicos relativos aos Form Services, comentaremos, superficialmente, as
opções de configuração e seus significados.
QUANTO À CONEXÃO
O Form Services pode usar três métodos de conexão:
♦ Sockets – Uma conexão Sockets utiliza uma interface padrão TCP/IP. Nesta forma de comunicação um cliente
envia uma requisição a uma URL que possua um número de porta específico, por exemplo, http://
www.xxx.com.br:90. Isto significa que o browser do cliente tentará estabelecer conexão ao socket número 90 e
que existirá no servidor um “ouvidor” (listener) associado a esta porta (90).
Este método é simples, porém as máquinas cliente e servidora devem estar aptas a se comunicarem uma com a
outra diretamente na rede. Não é possível o uso de um proxy no servidor neste modo.
O proxy é uma característica de segurança (invisível para o cliente), que tem a finalidade de impedir acessos não
autorizados ao servidor. Se o servidor e o cliente estiverem separados por uma rede não segura, como é o caso da
Internet, o uso deste método pode acarretar riscos no que se refere à segurança.
♦ HTTP – esta forma de comunicação utiliza HTTP socket para conexão. O “ouvidor” do Form (Listener) espera
por uma conexão HTTP em vez de uma conexão proprietária. Toda a comunicação entre o Form Services e o
cliente é encapsulada em pacotes HTTP. Este tipo de comunicação pode ser utilizado em sites que usam Firewall
(proteção utilizada na Internet). A utilização de proxy é completamente transparente para o cliente.
♦ HTTPS – esta forma de comunicação utiliza o mesmo mecanismo visto acima (HTTP), com a adição de regras de
segurança SSL (secure sockets layer). O Form Services pode utilizar SSL como um protocolo transparente com o
objetivo de fornecer privacidade (com criptografia das mensagens), integridade (impede que as mensagens
sejam modificadas) e autenticação (a máquina-cliente tem condições de verificar se o servidor é quem diz ser).
♦ A variável de ambiente FORMS60_HTTP_NEGOTIATE_DOWN vai determinar a possibilidade de comunicação
entre ambientes cliente e servidor com diferentes níveis de criptografia.
Diversos certificados gerados por companhias externas à Oracle estão homologados para uso com o Form Services.
Em virtude do ambiente Internet/Intranet e Servlets corresponder a uma tecnologia mais atual, é provável que as
implementações futuras da Oracle sejam desenvolvidas nesta tecnologia. Fique atento!
CUSTOMIZANDO O PRODUTO
CONFIGURANDO O SERVIDOR WEB
Para que possamos executar nosso aplicativo desenvolvido em Forms, precisaremos de um servidor Web. Você
poderá usar o servidor pessoal que quiser. Para efeito de teste, utilizaremos o IIS da Microsoft.
A tempo de instalação do servidor Web (Oracle9i IAS) são criados alguns caminhos virtuais para a instalação dos
arquivos de software do Forms.
No nosso caso instalamos apenas o Forms Server (e não o IAS), de forma que os diretórios relativos aos softwares
estão subordinados ao <Oracle_Home> que escolhemos durante a etapa de instalação (C:\ORAFORMS). Os diretórios
físicos apresentados, portanto, se referem a esta escolha. Posteriormente faremos a configuração do servidor Web
(no exemplo deste tópico) e precisaremos do quadro abaixo.
O quadro abaixo apresenta estes caminhos virtuais com seus caminhos físicos correspondentes (default).
No caso do Oracle9i IAS os diretórios virtuais são especificados em um arquivo chamado 6iserver.conf localizado
no diretório <oracle_home>/6iserver.
♦ Forms60_Timeout – Este parâmetro especifica a quantidade de tempo (em minutos) em que o processo Forms
Services é terminado quando não ocorrerem solicitações dos clientes. Esta variável não está criada. Se desejarmos
modificar seu valor default, que é 15, devemos incluí-la. O intervalo de valores válidos é de 1 a 1440 (1 dia).
♦ Forms60_Mapping – Nesta variável indicamos o diretório virtual relativo ao diretório físico especificado na
variável Forms60_Output. O valor preenchido na nossa instalação foi: /dev60temp.
♦ Forms60_Repformat – Nesta variável especificamos o formato que o relatório gerado através de uma chamada à
rotina RUN_PRODUCT (no Forms) terá. Os valores válidos são HTML e PDF. O valor preenchido na nossa
instalação foi: HTML.
♦ Forms60_Message_Encryption – Esta variável não está criada. Por default as mensagens são criptografadas (usando
criptografia de 40 bits – RC4 40-bit). Não temos necessidade de incluir esta variável.
♦ Forms60_Wallet – Esta variável é utilizada para implementação do modo de comunicação HTTPS. Nesta variável
indicaremos o diretório físico contendo o “wallet” que suporta o certificado usado para a comunicação segura
com o servidor. Ao tempo de instalação a variável já foi preenchida com o valor C:\ORAFORMS\FORMS60\
WALLET. Uma vez que não faremos a configuração de um ambiente servidor, inclusive nossa comunicação é via
Socket, não usaremos esta variável.
♦ Forms60_Https_Negotiate_Down – Esta variável não é criada, por default, ao tempo de instalação e não teremos
necessidade de criá-la. Esta somente será usada em comunicações seguras (HTTPS) para indicar ao servidor se
deve ou não aceitar chaves de criptografia oriundas do ambiente cliente com chave de criptografia inferior a
128-bits. Esta variável somente precisa ser preenchida se no ambiente servidor estivermos usando chave de
criptografia de 128-bits e pretendermos estabelecer comunicação com clientes que usem criptografia de 40-bits.
Na Figura 9.03 observamos que na parte inferior da tela encontramos um campo no qual podemos preencher
modificações para os parâmetros do serviço, como por exemplo port=9002 mode=http pool=5 log=c:\logs\fserv.log.
No nosso caso, podemos preencher apenas o nome do arquivo de log e deixar os demais parâmetros como default.
Quando um usuário (cliente) vier a acionar a aplicação Web, deverá fornecer a configuração adequada. Por exemplo:
http://www.xxx.com.br/dev60cgi/ifcgi60.exe?config=<nome da seção>.
Os parâmetros aplicáveis ao formsweb.cfg são apresentados a seguir. Para que você possa acompanhar esta
configuração, abra o arquivo c:\oraforms\forms60\server\formsweb.cfg. Os parâmetros estão subdivididos de
acordo com seu uso.
Parâmetros de Sistema:
♦ baseHTML, baseHTMLJInitiator, baseHTMLIE (*) – em nosso arquivo de configuração podemos estabelecer todos
os três parâmetros, de acordo com o tipo de usuários (cliente) com os quais viremos a estabelecer comunicação.
Todos os três determinam o caminho físico do arquivo HTML básico a ser usado quando o usuário (cliente), pela
primeira vez, acionar a aplicação inicial do nosso sistema. Cada um deles é utilizado em uma situação específica.
O arquivo baseHTML é utilizado quando, no ambiente cliente, usamos Appletviewer. O arquivo
baseHTMLJInitiator é utilizado quando, no ambiente cliente, usamos o Oracle Jinitiator e, finalmente, o
baseHTMLIE é utilizado quando, no ambiente cliente, usamos a JVM nativa do Internet Explorer 5.
♦ ie50 – este parâmetro deve ser usado se houver clientes utilizando Internet Explorer 5. Se o preenchermos com
“Jinitiator”, estamos indicando que o cliente usará Jinitiator e se o preenchermos com “native”, indicamos que
o cliente usará a JVM nativa do browser. Se o cliente estiver utilizando AppletViewer, este parâmetro será ignorado.
♦ HTM delimiter (*) – determina o delimitador para os nomes das variáveis presentes no arquivo HTM, as quais
serão substituídas pelos valores das variáveis correspondentes presentes neste arquivo de configuração.
♦ MetricsServerHost, MetricsServerPort, MetricsServerErrorURL, MetricsTimeout, leastloadedhost – estes parâmetros
se referem a “Load Balancing” que é a capacidade de se distribuir a execução das aplicações Forms por diversos
servidores de aplicação (um “pool” de servidores). Isto é conseguido pela implementação de uma servlet, a qual pode
ser executada em qualquer servidor Web. Uma vez que estaremos trabalhando localmente para analisar o ambiente
e não em produção, não teremos necessidade de preencher estes parâmetros. Não faremos modificações para ele.
A Listagem 9.01 a seguir apresenta este trecho do arquivo default de configuração criado ao tempo de instalação do
produto Forms Server. Observe que o valor %FORMS60% será substituído pelo conteúdo da variável de ambiente
FORMS60, que no nosso caso contém C:\ORAFORMS\FORMS60.
♦ type (*) – para esta variável existe uma diferença de nome entre o parâmetro presente no HTM (que é TYPE,
observe a tag PARAM) e o parâmetro presente no arquivo formsweb.cfg, cujo nome é jinit_mimetype. A variável
jinit_mimetype será vista no grupo de variáveis específicas do Jinitiator.
♦ serverHost – Host no qual o Form Services executa.
♦ ServerPort (*) – indica a porta na qual o serviço Forms Server (para o NT) aguarda solicitações dos clientes.
♦ serverArgs (*) – argumentos para o Runform. Será tratado no grupo referente a parâmetros para o Runform.
♦ splashScreen – indica o nome do arquivo .GIF que deve ser apresentado antes da applet aparecer. Se não desejarmos esta
apresentação prévia, devemos preencher este argumento com NO. Se o deixarmos vazio será usada a default splash.
♦ background – indica o nome do arquivo .GIF que deve ser mostrado em background (fundo de tela). Se
preenchermos com NO, nenhuma imagem será apresentada. Se não preenchermos este argumento será
apresentada a imagem background default.
♦ clientDPI – especifica o número de pontos por polegada. Este parâmetro substitui o valor de DPI retornado pela
JVM. Isto permite que determinemos valores diferenciados por plataforma. A Oracle recomenda que utilizemos
valores inteiros entre 50 e 200 para este argumento.
♦ separateFrame – determina se a applet deve ser apresentada em um frame separado. Os valores válidos são True
ou False.
♦ lookAndFeel – determina a aparência da aplicação. Os valores válidos são Oracle ou Generic.
♦ colorScheme – indica o esquema de cores a ser usado pela aplicação. Os valores válidos são: Teal, Titanium, Red,
Khaki, Blue, Olive ou Purple. Válidas quando o LookAndFeel = Oracle.
♦ serverApp – podemos substituir o valor preenchido (“default”) pelo nome de uma classe. O uso de Application
Classes pode ser útil para determinar o mapeamento de fontes específicas e diretórios de ícones.
♦ heartBeat – este parâmetro determina de quanto em quanto tempo a applet no cliente deve enviar um indicador
de que ainda se acha em execução. O valor é dado em minutos e pode ser fracionário.
♦ imageBase – este parâmetro indica onde os arquivos de ícones estão armazenados. Podemos preenchê-lo com
“codebase”, indicando que o caminho é relativo ao diretório que contém as classes Java ou podemos preenchê-
lo com “documentBase” (default).
♦ registryPath – este parâmetro indica o diretório virtual onde o arquivo da aplicação nomeado pelo parâmetro
serverApp está localizado.
A Listagem 9.02 mostra os valores defaults presentes no arquivo formsweb.cfg definidos ao tempo de instalação do
Forms Server.
CONSIDERAÇÕES GERAIS
A lista a seguir se refere ao desenho de qualquer tipo de aplicação para a Web e não apenas a aplicações Forms:
♦ Uma das primeiras atitudes que devemos tomar é avaliar os fatores que venham a afetar a performance da
aplicação, tais como freqüentes idas ao banco de dados para obtenção de informações (aplicação – database) ou
apresentação de grande quantidade de informação ao usuário (cliente – aplicação).
♦ Outra preocupação grande deve ser com as imagens apresentadas. Cada vez que uma imagem é apresentada (seja
em um Forms ou Report), ela deve ser “download” do servidor de aplicação (ou extraída do banco de dados).
♦ Se num ambiente cliente-servidor a otimização das consultas é importante, num ambiente web esta preocupação
deve ser ainda maior.
♦ Se não houver impacto na utilização dos objetos, é uma recomendação da Oracle que coloquemos objetos
similares (botões com botões, text itens com text itens, etc.) juntos no Object Navigator. A ordenação de objetos
similares faz com que as propriedades enviadas para o cliente para apresentação da aplicação possam utilizar
um algoritmo (message diff-ing) de compressão de dados de forma eficiente diminuindo a quantidade de
informação trafegada e, conseqüentemente, melhorando a performance. Da mesma forma, se viermos a modificar
propriedades de diversos itens dinamicamente, devemos ordenar estas modificações pela propriedade e não
pelo item. Isto significa que, se vamos modificar a propriedade Label dos itens IA, IB e IC e a propriedade
Font_Weight do item IA, devemos, primeiramente, alterar a propriedade Label dos 3 itens e posteriormente a
propriedade Font Weight. Ainda em relação às propriedades temos que, quanto mais similares forem as
propriedades dos itens, mais eficiente se torna o algoritmo message diff-ing. Desta forma sugere-se:
♦ Usarmos os valores padrões das propriedades e modificarmos somente aqueles atributos indispensáveis ao objeto.
♦ Usarmos Smart Classes para descrevermos grupos de objetos.
♦ Determinarmos a aparência ideal de apresentação em um determinado número de atributos visuais (quanto
menor este número, melhor).
♦ Preencher, sempre que possível a propriedade Prompt em vez de usar um boilerplate de texto.
♦ Reduzir o uso de boilerplates dos tipos arco, círculos e polígonos. Todos os boilerplates são carregados na fase de
inicialização da aplicação (aumentando o seu tempo). Estes, especificamente, tomam mais tempo da carga
inicial sejam eles usados ou não. Os boilerplates comuns (retângulos e linhas) são otimizados, não precisando
de maiores preocupações.
♦ Realizar a menor quantidade possível de navegações. Um Event Bundle é enviado ao servidor cada vez que
um evento de navegação termina. Se conseguirmos dimiuir a navegação preenchendo o conteúdo dos cam-
pos com valores defaults, estaremos obtendo um ganho de performance. Outra observação se faz no sentido
de a aplicação encorajar o usuário a, rapidamente, encerrar a aplicação (quando acabar a tarefa desejada), o
que fará com que todos os demais eventos associados à navegação sejam disparados em conjunto, enviando
um único Event Bundle.
♦ Devemos tentar reduzir o tempo necessário para a construção da tela inicial. Para que seja possível a apresentação
desta tela, todos os objetos têm de ser carregados e inicializados antes de a apresentação ser feita. Desta forma a
recomendação é que nesta primeira tela façamos a redução da quantidade de objetos para o mínimo indispensável
(por exemplo título, logo, username e password).
♦ A propriedade RAISE ON ENTRY = YES (para Canvas) junto com VISIBLE = NO, pode ser usada para que os objetos
que não forem visíveis de imediato não sejam carregados. Isso pode ser especialmente útil para canvas do tipo
TAB, onde todos os elementos de todas as pastas são carregados quando esta se torna visível, independentemente
da pasta que ficar visível. Se houver uma grande necessidade de diminuição do tempo de carga, uma alternativa é
dividir a canvas TAB em diversas canvas Stacked, que são independentes umas das outras.
♦ A utilização de triggers do tipo When-Validate-Item, se possível, também deve ser reduzida uma vez que ele é
processado pelo Form Services. Devemos avaliar o custo x benefício de substituirmos a funcionalidade default
dos itens presentes no ambiente cliente com componentes Java. Desta forma a validação do item seria enviada
para o cliente, pois estaria contida no item.
♦ Como sugestão final, recomenda-se que grandes aplicações sejam divididas em pequenas aplicações, a fim de que
o tempo de apresentação de cada tela seja reduzido, uma vez que nem todos os objetos precisarão ser inicializados.
Por default os ícones devem ser instalados no diretório do documento base, isto é, do HTML. Se desejarmos que
eles residam em outro local, deveremos customizar o arquivo Registry.dat para indicar o novo local.
Neste arquivo encontramos dois parâmetros que podem ser preenchidos para indicar o local onde os ícones residirão
e a extensão escolhida.
No exemplo acima consideramos que os ícones estarão em um subdiretório icones, subordinado ao diretório onde
se acha o HTML, ou seja, usamos endereçamento relativo. Na Listagem 9.06 indicamos, ainda, que os ícones terão
a extensão GIF.
Para usarmos endereçamento absoluto, devemos preencher o parâmetro iconpath com /<nome do diretório> ou
<URL>/<nome do diretório>.
O arquivo Registry.dat pode ser modificado diretamente ou podemos criar um novo arquivo (com um outro
nome), específico por sistema. Para tal, devemos indicar no HTML base qual o nome do arquivo e sua localização.
O parâmetro que indica o nome e localização do arquivo correspondente é o parâmetro serverApp.
Se você tiver muitos arquivos imagem ou ícones ou se em todas as telas forem apresentados diversos ícones,
podemos reduzir o tráfego se agruparmos os arquivos envolvidos em um arquivo .JAR. Desta forma, somente o
download do arquivo .JAR será necessário.
Para a criação deste arquivo .JAR, devemos executar o utilitário jar.exe presente no diretório c:\oraforms\jdk\bin
no prompt do DOS, preferencialmente no diretório onde se acham os arquivos que desejamos agrupar. Por exemplo
jar –cvf teste.jar splash.git bgnd.gif frame.gif paste.gif criará o arquivo teste.jar contendo todos os arquivos .GIF
mencionados na seqüência.
Posteriormente, deveremos indicar no HTM base que estamos utilizando um arquivo .JAR. Isto deve ser feito com
o uso do parâmetro archive cujo valor identificará o arquivo .JAR e o parâmetro imageBase cujo valor indicará se
o arquivo .JAR deve ser procurado no DocumentBase directory ou no CodeBase directory. Neste caso a Oracle
determina que utilizemos CodeBase como valor do segundo parâmetro, pois, caso não seja informado, o default
DocumentBase será usado e o arquivo .JAR não será transferido.
EXERCÍCIOS
9.01) Crie uma aplicação Forms para cadastramento de departamentos. Todos os campos da tabela Depto devem
ser utilizados. O formato da aplicação deverá ser Tabular com 5 registros na tela. Inclua barra de rolagem. Esta
aplicação também deve acionar um relatório que apresente todos os departamentos cadastrados. Inclua um botão
que acione o relatório. Ainda neste item construa o relatório.
9.02) Acione a aplicação default fornecida pelo Oracle. Não realize modificações no arquivo de configuração.
9.03) Acione a aplicação construída por você utilizando o Form Services. Realize diferentes testes com relação à
aparência da tela, tamanho de janela, parâmetros para a aplicação, etc. Utilize o botão apropriado no Forms
Developer ou siga o passo-a-passo apresentado na resposta deste exercício.
9.04) Construa um HTML base com um novo layout para apresentação das aplicações de um sistema.
CONSIDERAÇÕES INICIAIS
Já estudamos anteriormente a execução de um relatório através do Forms. Esta é a forma clássica de uso de relatórios
num ambiente cliente servidor. Num ambiente de três camadas, no entanto, a Oracle disponibilizou uma forma de
acionarmos um relatório diretamente de um browser usando uma sintaxe URL. Esta forma de utilização é totalmente
independente do Forms e poderia causar a execução de um relatório através de uma página de HTML.
Os relatórios gerados podem usar formato HTMLCSS (HTML com Cascading Style Sheets) ou PDF (Adobe Portable
Document Format). Uma vantagem adicional desta forma de trabalho é que não há necessidade da instalação de
diversos produtos no ambiente cliente.
QUANTO À ARQUITETURA
O Oracle Reports Services pode ser configurado de formas diferentes de acordo com a arquitetura que estivermos usando.
Em uma arquitetura Web trabalhamos com 4 componentes ou ambientes: o ambiente cliente, o ambiente servidor
Web, o ambiente do Oracle Reports Services e o ambiente do banco de dados. A quantidade de equipamentos
envolvidos nesta configuração é totalmente variável. Poderemos utilizar todos os componentes em um único
equipamento (que será o nosso caso para efeito de teste) ou poderemos distribuí-los em máquinas diferentes.
Em uma arquitetura não Web o número de componentes diminuiria para 3 pois não teríamos a participação do
servidor Web. A diferença básica entre as duas arquiteturas é que nesta não há a participação do browser (no ambiente
cliente), e a solicitação do usuário é feita através do Oracle Reports Launcher ou da linha de comando do RWCLI60.
Considerando-se os aspectos de configuração, as principais diferenças entre a utilização de uma arquitetura Web e
uma arquitetura não Web são:
♦ Em uma arquitetura não Web precisaremos instalar nas máquinas-cliente um software para comunicação com
o ambiente servidor, isto é, o Net8 e o Oracle Reports Thin Client, que é composto do Oracle Reports Launcher,
do Oracle Reports Queue Manager e do RWCLI60.
♦ Em uma arquitetura Web, no ambiente cliente, utilizaremos um Web browser, porém no ambiente servidor
teremos necessidade de instalar e configurar o Oracle Reports Server CGI ou Servlet para estabelecer a comunicação
entre o browser do cliente e o Oracle Reports Services.
A arquitetura Web é, claramente, mais eficiente uma vez que reduz significativamente os custos de manutenção no
ambiente cliente. O Oracle Reports Services suporta ambas as arquiteturas indiferentemente, ou seja, podemos
optar por uma delas ou utilizá-las simultaneamente.
O browser passa, então, esta URL para o servidor Web. Para atender à requisição o servidor Web aciona o Oracle
Reports Server CGI ou Servlet (de acordo com a configuração escolhida).
Se a requisição incluir o argumento TOLERANCE, o Oracle Reports Services verifica em seu cache de saída se a
mesma requisição já foi executada anteriormente (dentro do tempo determinado pelo argumento) e, em vez de
reexecutar o relatório, ele obtém a saída gerada anteriormente e envia o resultado para o Oracle Reports Server.
Caso a requisição não inclua o argumento ou o tempo especificado seja excedido, a solicitação é incluída em uma
fila para execução. Quando o momento da execução chegar, o Oracle Reports Services envia a linha de comando
para execução pela Runtime Engine.
O resultado do relatório é recebido pelo Oracle Reports Server que o envia para o servidor Web que, por sua vez,
devolve o resultado para o usuário que fez a requisição.
Se estivermos usando um servidor Web baseado em Java, então nossa escolha deverá ser o formato Servlet.
TÉCNICA
♦ Desenvolvimento de exemplos de teste.
CUSTOMIZANDO O PRODUTO
Seguiremos, basicamente, os mesmos passos que fizemos anteriormente na configuração do Forms Services. Antes
de iniciarmos as configurações, propriamente ditas, verificaremos se o serviço do Oracle Reports Server está ativo.
Na Figura 9.04 vemos o produto Serviços com o Oracle Reports Server ativo. Para que isto aconteça o Listener deve
estar configurado adequadamente.
A Listagem 9.07 nos mostra o conteúdo do arquivo SQLNET.ORA presente no diretório <oracle
home>\NET80\ADMIN. Uma vez que instalamos o Reports em Oracle Home diferente do Forms, encontraremos
o arquivo no diretório C:\ORAREP\NET80\ADMIN.
Para este arquivo, devemos verificar se no arquivo TNSNAMES.ORA encontraremos o trecho mostrado pela Listagem
9.08 a seguir.
Observe que o nome REPSERVER foi dado por nós no momento da instalação (verifique na Figura 6.10), da mesma
forma que o número da porta 1949. O número do HOST 127.0.0.1 indica que é à nossa própria máquina que
faremos conexão. Se tivéssemos utilizado o parâmetro NAMES.DEFAULT_DOMAIN no arquivo SQLNET.ORA,
deveríamos ter acrescentado à string de conexão esta extensão (por exemplo, se NAMES.DEFAULT_DOMAIN fosse
preenchido com WORLD, deveríamos nomear a string com REPSERVER.WORLD).
Se o serviço não estiver ainda ativo, devemos ativá-lo neste momento.
O quadro abaixo apresenta estes caminhos virtuais com seus caminhos físicos correspondentes (default).
Como instalamos apenas o Reports Server (e não o IAS), os diretórios relativos aos softwares estão subordinados ao
<Oracle_Home> que escolhemos durante a etapa de instalação (C:\ORAREP). Os diretórios físicos apresentados,
portanto, se referem a esta escolha. Se estivéssemos configurando o Oracle9i IAS usaríamos como diretório físico o
valor C:\Program Files\Apache Group\Apache\cgi-bin.
♦ Report60_CgiDiagHeadTags – para o Oracle Reports Server CGI especifica tags HTML a serem incluídas entre
<HEAD>...</HEAD>, no resultado do RWCGI60 diagnostic/debugging.
♦ Reports60_CgiHelp – para o Oracle Reports Server CGI especifica a URL e URI do arquivo de ajuda do RWCGI60,
que será acionado quando houver um acionamento sem parâmetros. Se preenchermos com um nome de arquivo
HTM, será acionado o endereço de URL http://<nome do servidor web/<nome do arquivo htm>. Se preenchermos
com um endereço URL, este endereço será usado. Esta variável deverá ser incluída, se desejarmos.
♦ Reports60_CgiMap – para o Oracle Reports Server CGI, determina o diretório físico e o nome do arquivo Map,
se esta configuração for usada.
Para efeito de teste, utilizaremos esta variável, porém somente no tópico referente a formas de acionamento do
relatório faremos sua configuração.
♦ Reports60_Reports_Server – especifica o nome default do Oracle Reports Services para requisições CGI. Se esta
variável de ambiente for utilizada, poderemos omitir o parâmetro SERVER da linha de comando.
Esta variável deve ser incluída com o valor REPSERVER.
♦ Reports60_SSLPort – Se estivermos usando SSL e desejarmos usar uma porta diferente da 443 (que é a default),
podemos usar esta variável para determinar uma porta alternativa.
♦ Reports60_Sys_Auth – especifica o template a ser usado para autenticar o usuário quando a requisição é direcionada
a um Oracle Reports Server restrito.
♦ Reports60_Path – especifica todos os diretórios onde serão armazenados os relatórios (extensão .RDF ou .REP).
Esta variável já está presente na lista de variáveis de ambiente; incluiremos, apenas, o diretório onde armazenaremos
os relatórios D:\RepCap9.
Os valores dos parâmetros alfanuméricos devem ser incluídos, sempre, entre aspas duplas.
♦ FailNoteFile – determina um nome de arquivo (caminho completo) de mensagem padrão a ser enviado para um e-mail
específico referente a requisições que tenham falhado na execução. Por exemplo failnote=”d:\repCap9\failnote.dat”
♦ Identifier – é um valor interno (criptografado) que contém o username e password do administrador de filas.
Não devemos tentar modificá-lo diretamente.
Se removermos este parâmetro do arquivo, ao utilizarmos o Queue Manager, este aceitará qualquer usuário e senha
(válidos no banco de dados) que informarmos como sendo o usuário do administrador e o armazenará de forma
criptografada neste parâmetro.
♦ InitEngine – determina o número inicial de Runtime Engines. O valor default é 1.
♦ Logoption – determina o tipo de informação de log que desejamos incluir no arquivo de log. As opções são
ALLJOB, FAILEDJOB e SUCCEEDEDJOB.
♦ MailProfile – se o parâmetro DESTYPE do relatório for MAIL, o Oracle Reports Services envia o mail para um destino
específico. Este parâmetro permite que especifiquemos o mail profile e a password para ser usada quando enviarmos
relatórios mailing usando o Oracle Reports Services. Este parâmetro somente é aplicável ao Windows NT.
♦ MaxConnect – determina o número máximo de processos que podem estabelecer comunicação com o processo
servidor simultaneamente. Este valor corresponde à soma do número de Engines e Clients (deve ser maior que
dois). O valor default é 20.
♦ MaxEngine – determina o número máximo de Engines disponíveis para o Oracle Reports Services. O valor
default é 1.
♦ MaxIdle – determina o tempo máximo que uma Engine pode ficar idle antes de encerrar (shut down). A Engine
não será desativada se a quantidade de Engines ativas ficar inferior a MinEngine.
♦ MinEngine – determina o número mínimo de Engines ativas. O valor default é zero.
♦ PersistFile – determina a localização do arquivo (.DAT) que contém detalhes das requisições em fila (schedule).
Se este parâmetro não for especificado, o valor default é <oracle home>\report60\server.
♦ RepositoryConn – determina a string de conexão que permite que o oracle Reports Services estabeleça conexão
com o banco de dados. Por exemplo repositoryconn=”username/password@conexao”.
♦ Security – determina o nível de segurança (0, 1, 2 ou 3) para acesso aos arquivos de saída em cache através do
Oracle Reports Queue Manager. O valor zero indica que ninguém pode ter acesso a estes arquivos. O valor 1
indica que somente um usuário com userid idêntico ao que executou o relatório pode ter acesso ao resultado. O
valor 2 indica que somente o mesmo processo que enviou a solicitação pode ter acesso ao resultado. O valor 3
indica que o resultado não pode ser obtido do cache. O valor default é 1.
♦ Securitytnsname – determina o tnsname do Oracle WebDB que será usado para autenticação dos usuários para
o Oracle Reports Services.
♦ SourceDir – indica um caminho a ser pesquisado (antes do REPORTS60_PATH) para arquivos de relatório. Isto
pode ser útil quando usamos mais de um Oracle Reports Services que compartilhem o mesmo Oracle Home,
permitindo que cada Oracle Reports Services tenha seus próprios diretórios de executáveis.
♦ SuccNoteFile – determina o nome do arquivo (caminho completo) contendo mensagem de notificação a ser enviado
para um endereço de e-mail específico relativo a resquisições bem-sucedidas.
♦ TempDir – determina um diretório que será usado em vez do REPORTS60_TMP para criação de arquivos temporários.
Para que os novos parâmetros sejam utilizados devemos interromper e acionar o serviço novamente.
O Oracle Reports Services permite, também, que gravemos a fila de requisições no banco de dados, como um
Snapshot. Desta forma, podemos consultar as informações diretamente, verificar o que já foi executado, guardar
informações históricas, etc.
Para atualizarmos o banco de dados com as atividades da fila de requisições, devemos criar esta fila em um
determinado usuário e atualizar o parâmetro REPOSITORYCONN do Oracle Reports Services.
Desta forma devemos acionar o SQL*Plus, estabelecer conexão com o usuário DESENV e executar o script
rw_server.sql que se acha presente no diretório C:\ORAREP\REPORT60\SQL.
Este script criará uma tabela para armazenamento da fila de requisições e um package para manutenção desta fila.
Toda vez que o serviço for interrompido e restabelecido, a fila de jobs é esvaziada (observe a rotina clean_up_queue
presente no package).
Se desejarmos, podemos modificar este package para que esta limpeza não seja realizada, assim como podemos
manter as informações das requisições nas filas pelo tempo que considerarmos necessário.
Após a execução deste script, devemos incluir o parâmetro REPOSITORYCONN no arquivo de configuração do
Reports Services com o valor “desenv/desenv@desenv”.
Nossa próxima tarefa é retirar o serviço de atividade e restabelecê-lo. Utilize a opção Serviços do submenu Ferramentas
Administrativas do menu Painel de Controle.
Para que possamos testar todas as informações estudadas até aqui, no próximo tópico veremos diversas formas de
acionar e executar um relatório.
ACIONANDO UM RELATÓRIO
Existem diferentes formas de acionarmos um relatório utilizando o Reports Services.
A primeira delas é utilizando a linha de comandos do RWCLI60. A Figura 9.05 nos mostra como realizar esta
operação. Esta forma de acionamento não utiliza a arquitetura Web, o que significa que a comunicação entre o
usuário final e servidor onde o RepServer está executando deve ser via Net8.
Outra forma de acionamento é o uso do Oracle WebDB. O Oracle WebDB component permite a adição de um link
que estabeleceria nossa comunicação com o site Oracle WebDB. Este link estaria associado a uma rotina de um
pacote que conteria informações sobre a requisição de relatório. Os usuários autorizados, que fizessem acesso ao
site WebDB, simplesmente fariam um click no link para executar o relatório. Esta forma de acionamento não será
estudada neste material pois exigiria um detalhamento do uso do Oracle WebDB.
Outras duas formas de utilização seriam a execução da rotina SRW.RUN_REPORT (já nossa conhecida), na qual
poderíamos acrescentar o parâmetro SERVER para indicar a qual serviço desejaríamos associar o relatório, ou o uso
de um ActiveX control (esta forma também já foi comentada no uso de ActiveX no Forms), na qual poderíamos
não só acionar um relatório imediatamente como também poderíamos determinar quando o relatório deveria ser
acionado. Esta forma de uso será revista no tópico sobre o Queue Manager mais adiante.
A última forma (e mais explorada neste tópico) será o acionamento através de um browser. Neste método podemos
adotar várias alternativas de acionamento: diretamente através de uma URL, através de um link em uma página
HTML ou através de um arquivo de mapeamento.
Esta forma de requisição pode ser feita diretamente na linha de comandos do browser, como vemos na Figura 9.06.
<CENTER><B><FONT SIZE=+1>Autenticação</FONT></B></CENTER>
<FORM name=”reports” action=”http://lucia/cgi-bin/rwcgi60.exe” method=”post”>
<CENTER><TABLE COLS=2 width=”100%”>
<TR>
Neste exemplo disponibilizamos para o usuário apenas o nome do relatório (na verdade, como só temos um
relatório REP901, o mesmo é acionado em todos os casos), o tipo de destino e o formato de saída. Poderíamos
sofisticar o HTML como desejássemos incluindo diversas outras opções.
Para cada uma destas chaves, os parâmetros foram fixados diretamente dentro do arquivo de mapeamento ou
foram complementados com informações do usuário.
Para a chave N01 todos os parâmetros estão especificados dento do arquivo de mapeamento, não havendo
necessidade de nenhum parâmetro adicional. Desta forma, a URL correspondente a esta chave seria http://lucia/
cgi-bin/rwcgi60.exe?n01.
Para a chave N02 o usuário deverá informar o userid, que não se encontra presente na lista de argumentos
predefinidos. Quando usamos a URL http://lucia/cgi-bin/rwcgi60.exe?n02 uma tela de autenticação é enviada ao
usuário para que ele informe o userid. Isto é obtido porque usamos o parâmetro %D na lista de argumentos da
chave N02. Esta opção torna a transferência do username e password segura pois é totalmente criptografada.
Para a chave N03 não informamos userid. Esta informação será obtida do cookie presente na máquina do usuário.
A URL necessária para seu acionamento é http://lucia/cgi-bin/rwcgi60.exe?n03 .
Para a chave N04 consideramos que para alguns dos parâmetros obtidos da URL receberemos apenas o valor e para
outros receberemos a sintaxe completa, composta de nome do parâmetro e valor. Uma chamada típica para esta
opção seria a seguinte URL http://lucia/cgi-bin/rwcgi60.exe?n04+rep901.rdf+ cache+desformat=pdf .
Para a chave N05 alguns parâmetros estão especificados diretamente no arquivo e indicamos que a tela de parâmetros
deverá ser apresentada com formato HTML. É isto que indica o parâmetro %P apresentado na lista de argumentos.
Finalmente, para a chave N06 aceitamos os parâmetros oriundos da URL do usuário, porém indicamos que a tela
de parâmetros deverá ser apresentada em formato HTML.
A utilização de mapeamento favorece a padronização, pode tornar a URL menor, permite que omitamos
determinados parâmetros e restringe os parâmetros que um usuário poderá usar para executar um relatório.
Os parâmetros especiais(%) utilizados na configuração de mapeamento são os seguintes:
♦ %0 – %9 – indica que argumentos posicionais serão recebidos (observe a chave N04). O parâmetro %0 corresponde
à própria chave de mapeamento.
♦ %* – indica que tanto o nome do argumento quanto seu valor virão diretamente da URL. Observe as chaves N04 e N06.
♦ %P – indica que a tela de parâmetros deverá ser mostrada em formato HTML.
♦ %PT – indica que a tela de parâmetros deverá ser mostrada no formato HTMLTABLE.
♦ %PC – indica que a tela de parâmetros deverá ser mostrada no formato HTMLCSS.
♦ %D – indica que o usuário deverá informar o userid a cada execução do relatório. A ausência deste parâmetro
permite que a pesquisa do userid seja feita no cookie.
O uso de mapeamento não impede, pelo contrário favorece, o uso de um HTML com as opções agora montadas
considerando-se a utilização do arquivo de mapeamento. O usuário poderá apenas completar os parâmetros faltantes
que poderemos listar na página HTML previamente preparada.
Este utilitário estabelece conexão com um dos serviços em uso no ambiente e passa a ter acesso à fila de requisições
deste serviço. Quando estabelecemos conexão nos é solicitado um nome de fila, que na verdade corresponde a um
nome de serviço em uso.
A Figura 9.07 mostra a tela de conexão ao utilitário. Para que ela seja apresentada precisamos acionar o Queue
Manager da seguinte forma: Iniciar -> Programas -> Oracle Reports 6i – Reports Home -> Reports Queue Manager.
Após a conexão, no exemplo feito ao serviço RepServer, a tela mostrada na Figura 9.08 nos é apresentada. Na barra
de ferramentas encontramos a possibilidade de estabelecer conexão a outro serviço (primeira caixa de opções), de
visualizar a lista de tarefas concluídas (em destaque) ou a lista de tarefas em execução (botão seguinte) ou a lista de
tarefas agendadas. Em seguida podemos optar por visualizar apenas as tarefas do usuário atual ou todas as tarefas.
O próximo botão, quando acionado, relê a fila de requisições e “refresca” as informações apresentadas.
Podemos modificar algumas das características do serviço (Reports Services) dinamicamente. Para tal devemos
estabelecer conexão como administrador da fila. No menu Opções encontramos a opção Logon do Administrador.
Se tivermos removido o parâmetro “identifier” do arquivo RepServer.ora ou se esta for a primeira vez que utilizamos
o Queue Manager, este utilitário aceitará e considerará como administrador de fila qualquer usuário válido do
banco de dados. Posteriormente, se desejarmos, podemos modificar a senha deste usuário (apenas para o Queue
Manager). Quando indicamos o usuário e senha pela primeira vez, o parâmetro “identifier” é gravado no arquivo
RepServer.ora de forma criptografada. Em execuções posteriores para estabelecermos login como administrador de
fila devemos informar o usuário e senha gravados neste arquivo.
Após o login como administrador, podemos escolher a opção Propriedades do menu Fila (Figura 9.08) e modificar
os parâmetros que aparecem habilitados no fim da página: MinEngine e MaxEngine, MaxIdle e CacheSize (Figura
9.09). Quando um destes parâmetros é modificado, o arquivo RepServer é modificado simultaneamente para que,
quando o serviço for desativado e reativado, estes novos valores já sejam considerados.
Através do Queue Manager podemos, também, agendar a execução de uma tarefa. Para isto, devemos escolher a
opção Novo do menu Tarefa. O Oracle Reporting ActiveX Control é acionado, conforme mostrado na Figura 9.10.
♦ Autenticação do Sistema – Nesta pasta indicamos usuário e senha para autenticação da solicitação junto ao
Reports Services (AUTHID).
♦ Opções de Runtime – Nesta pasta informamos outros parâmetros do Report: READONLY, AUTOCOMMIT,
NONBLOCKSQL, ONSUCESS, ONFAILURE no primeiro quadro e CURRENCY, THOUSANDS, DECIMAL no
segundo quadro e ARRAYSIZE, LONGCHUNK no terceiro quadro.
♦ Opções de Depuração – Nesta pasta informamos no primeiro quadro o valor para os parâmetros ERRFILE,
PROFILE, TRACEFILE e TRACEMODE. No segundo quadro informamos as opções para Trace: TRACE_ERR,
TRACE_PRF, TRACE_APP, TRACE_PLS, TRACE_SQL e TRACE_TMS.
♦ Opções do Servidor – Finalmente, nesta pasta, passamos parâmetros relativos à forma como o relatório será
submetido ao Reports Services: o relatório poderá ser executado em background, sincronamente ou
assincronamente (as três opções são mutuamente exclusivas), a freqüência com que o acompanhamento do
relatório deverá ser feito e um limite (timeout) para execução do relatório. Podemos, também, informar um
nome para a tarefa na fila.
Todas as vezes que no valor de um parâmetro aparecer a opção InReport indica que o valor será obtido da especificação deste parâmetro dentro
do relatório que será executado.
EXERCÍCIOS
9.05) Baseado no relatório construído no Exercício 9.1, acrescente uma tela de parâmetros para que seja informada
a quantidade de cópias do resultado e o tipo de saída desejada pelo usuário. Acione este relatório usando uma URL.
9.06) Acione os relatórios criados usando um arquivo de HTML.
Observe a Figura-resposta 9.01 com o resultado do layout. Esta figura foi obtida com o uso do botão Executar Form
Web. Observe que a execução da aplicação é feita por uma applet Java. Para testarmos a execução do programa,
layout, execução na Web, etc., este botão é suficiente. Porém, a execução desta aplicação usando diretamente o
Form Services permitirá modificações na aparência, customização de fontes, uso de parâmetros na linha de comando
e outras configurações.
Nosso próximo passo será adicionar um botão na tela (com ícone) para que possamos acionar o relatório com o
RUN_REPORT.
Em seguida devemos preparar o relatório, bastante simplificado, utilizando os assistentes de tal forma que o resultado
seja apresentado na tela (Destype).
Com o relatório pronto fazemos uma execução para verificar se o acionamento está correto e se o relatório executa
adequadamente. Se tudo estiver funcionando a contento podemos passar para o Exercício 9.02, onde faremos a
configuração do Servidor Web e do Form Services para simulação de um ambiente Web.
9.02) Acione a aplicação default fornecida pela Oracle. Não realize modificações no arquivo de configuração.
Nossa primeira tarefa é realizar a configuração do servidor Web. Escolhi utilizar o IIS, não só por sua simplicidade
de configuração, como também por poder ser executado localmente. Se você estiver utilizando o IIS também,
acompanhe os procedimentos de configuração. Caso você possua outro servidor Web, nossa tarefa será apenas a de
relacionar os caminhos virtuais aos reais (leia o que faremos a seguir e repita estas ações no seu servidor Web).
No IIS, devemos acionar a execução do Gerenciador do Internet Services (Iniciar -> Painel de Controle -> Ferramentas
Administrativas -> Gerenciador ...), apresentado na Figura 9.02A.
Nesta primeira tela encontramos a situação geral do Site: seu Estado, endereço de IP, porta e status. Ao selecionarmos,
no quadro à esquerda, o item Site da Web padrão, do lado direito, será apresentada a lista de caminhos virtuais
deste Site. Para incluirmos um novo caminho devemos usar o menu Ação -> Novo -> Pasta virtual. Será acionado
um assistente que nos ajudará na montagem do relacionamento caminho virtual X caminho real. Devemos incluir
todos os caminhos mostrados no quadro presente no tópico: Configurando o Servidor Web. Em adição à lista do
quadro devemos criar um caminho virtual com o nome de Forms associado a um diretório de trabalho, onde
colocaremos os nossos arquivos FMX (no meu caso foi associado D:\FORMSCAP9).
Após a criação de todos os caminhos virtuais, podemos expandir o nó Site da Web padrão e visualizar (do lado
esquerdo) o nome dos diretórios virtuais criados. Quando clicamos sobre um desses nós, no quadro à direita
encontraremos os arquivos subordinados ao caminho físico correspondente. Confira!
Com o diretório virtual Forms selecionado, obtenha a opção Propriedades, usando o botão direito do mouse para
que a tela apresentada na Figura-resposta 9.02B seja apresentada. Confira as opções marcadas e clique, em seguida,
na aba da pasta Documentos. Nesta tela encontramos um campo chamado Ativar documento padrão, o qual
marcaremos, e pressionando o botão adicionar poderemos preencher o nome de nosso aplicativo EX901.fmx
(confira na Figura-resposta 9.02C).
O objetivo desta ativação é indicarmos o arquivo padrão a ser executado quando, no Browser, usarmos o endereço
http://<servidor>/forms, onde forms é o nome do nosso diretório virtual. Não precisaremos indicar o nome do
aplicativo a ser executado. Isto é muito útil pois poderemos indicar o nome da aplicação de abertura do nosso
sistema, para que o usuário estabeleça login, etc. Porém, somente esta configuração não é suficiente. Temos de
avisar ao servidor Web que programa deve ser usado para executar um arquivo com extensão .FMX.
Para tal retornaremos à aba Pasta virtual e pressionaremos o botão Configuração. O diálogo é apresentado na
Figura-resposta 9.02D. Neste diálogo faremos o mapeamento do aplicativo, isto é, associaremos a extensão.FMX
ao programa indicado pelo Oracle. Para realizar esta operação clique no botão Adicionar para que o diálogo
correspondente seja apresentado. No campo “executável” preencha com c:\oraforms\tools\web60\cgi\ifcgi60.exe
(onde c:\oraforms corresponde ao diretório de instalação da ferramenta). No campo “extensão” preencha com
.fmx. Com esta especificação indicamos que todos os arquivos com extensão FMX serão executados (ou abertos)
pelo programa IFCGI60.EXE.
Com esta etapa resolvida, passaremos às variáveis de ambiente. Execute o regedit e confirme o valor das seguintes variáveis:
♦ Forms60_Path – devemos adicionar o diretório que escolhemos para inclusão de nossos programas Forms (d:\formscap9).
♦ Forms60_Output – aqui serão gerados os arquivos temporários referentes aos relatórios que viermos a executar
através do Forms. O diretório atual é c:\oraforms\tools\web60\temp. Se você desejar, este diretório pode ser
alterado para uma área onde haja mais espaço em disco, pois é um diretório de output.
♦ Forms60_Repformat – nesta variável indicamos o formato do relatório gerado. Inicialmente usaremos HTML.
Antes de realizarmos nosso primeiro teste, devemos instalar o Jinitiator na máquina-cliente. Esta tarefa poderia ser
feita automaticamente na primeira chamada, mas já que estamos usando uma única máquina faremos,
manualmente, esta execução.
Faça um doubleclick no arquivo jnit.exe, presente no diretório c:\oraforms\jinit. O instalador fará a descompactação
inicial de alguns arquivos e, em seguida, iniciará o processo de instalação. Durante este processo, um dos diálogos
apresentados é o que está mostrado na Figura-resposta 9.02E onde escolhemos o local (diretório) para instalação.
Após esta tela a instalação é realizada e, ao término, será feita uma solicitação de fechamento e abertura do browser,
portanto esta será nossa próxima tarefa.
Para acompanharmos o startup do Runform, a participação do Listener e checarmos as informações sobre nossa
instalação do Form Services, faremos a ativação do log no serviço. Para isto devemos executar o aplicativo Services
(iniciar -> Configurações -> Painel de Controle -> Ferramentas Administrativas -> Serviços).
Selecionaremos a linha correspondente ao Oracle Forms Server e abriremos a tela de propriedades. Para que possamos
preencher o campo Parâmetros de inicialização, o serviço deve estar inativo. Clique, portanto, no botão Parar. Em
seguida preenchemos o campo Parâmetros de inicialização com o texto log=d:\formscap9\fserv.log (ou outro
diretório e nome de log desejado) e iniciamos o serviço novamente. Após esta etapa já podemos achar o arquivo de
log no diretório especificado. Podemos abri-lo e olhar seu conteúdo, que deverá ser similar ao texto da Listagem-
resposta 9.02A a seguir.
Abra seu browser e digite o texto http://<nome da sua máquina>/forms. Se tudo ocorrer conforme o planejado, a
Applet deve ser acionada e a aplicação Forms de nome test.fmx será acionada.
Você poderá ter a necessidade de informar a porta onde se acha o servidor Web. No caso do exemplo ele foi
instalado na porta 80, que é a porta default. Caso isto não tenha acontecido com você, o texto para execução da
aplicação deverá contemplar a porta, ou seja, http://<nome da sua máquina>:<número da porta>/forms.
Outra observação que podemos fazer é que o programa EX901.FMX que indicamos ao servidor Web que seria
nosso arquivo de startup não foi executado. Isto aconteceu porque quando o servidor Web iniciou o programa
IFCGI60.EXE associado à extensão FMX, este programa leu as instruções presentes no arquivo de configuração, no
qual indicamos que a aplicação de startup é TEST.FMX (é o default). No próximo exercício já estaremos configurando
este arquivo e fazendo as modificações que acharmos mais interessantes.
9.03) Acione a aplicação contruída por você utilizando o Form Services. Realize diferentes testes com relação à
aparência da tela, tamanho de janela, parâmetros para a aplicação, etc.
Após a execução anterior faremos modificações no arquivo de configuração para que nossa aplicação seja executada.
Como primeira etapa salvaremos o arquivo de configuração original com o nome de formsweb.old e modificaremos
o original com as informações apresentadas na listagem.
Com a parametrização acima, o resultado apresentado na execução da aplicação está presente na Figura-resposta
9.03A a seguir.
A cada modificação que fizermos no arquivo formsweb.cfg, precisaremos que um novo HTML (incorporando estas modificações) seja gerado. Desta
forma, para garantir que esta ação seja efetuada devemos pressionar o botão Atualizar na barra de ferramentas do Browser. Se você tiver dúvidas
quanto ao arquivo em execução utilize no menu Exibir a opção Código-Fonte e confira se as modificações foram incorporadas ao HTML base.
Partindo deste arquivo de configuração que salvaremos como formsweb.v01 proporemos algumas modificações
que afetem o layout para que você possa estabelecer aquele mais adequado à sua instalação. Nas listagens a seguir
incluiremos apenas as linhas modificadas.
Nesta versão testaremos a apresentação de um Splashscreen (basta retirar o valor no do parâmetro), que nada mais
é que a apresentação de uma imagem inicial enquanto a tela está sendo preparada. Esta imagem não pode ser grande
uma vez que a intenção é apresentar uma “distração” para o usuário enquanto aguarda a montagem da primeira
página do sistema. Incluímos, ainda, a apresentação da janela da aplicação em um frame (janela) em separado.
separateFrame=true
splashScreen=
; select default background by not specifying a value
background=no
lookAndFeel=Generic
colorScheme=Khaki
serverApp=default
Nesta versão atribuímos valores à tag Body da janela independente aberta para a aplicação (gerada pelo parâmetro
separateFrame=true). Determinamos que o tamanho desta nova janela seja 800 pixels por 550 pixels (este tamanho
foi diminuído em função da área das duas barras do Windows). Modificamos, também, a aparência (lookandFeel)
para Generic e o esquema de cores (colorScheme para Khaki).
Com estes exemplos você está apto a fazer diversos outros testes para determinar a aparência mais adequada à sua instalação.
9.04) Construa um HTML base com um novo layout para apresentação das aplicações de um sistema.
Para realizarmos esta tarefa basta que utilizemos no menu do Explorer a opção Exibir -> Código-Fonte, para que
seja apresentado o fonte da página em execução (esta ação deve ser feita na janela em que executamos http://
<máquina>:<porta>/forms). Este arquivo pode ser salvo no diretório desejado. Neste exemplo o arquivo foi salvo
no diretório onde se acham os executáveis do Forms, ou seja d:\formsCap9 com o nome de Forms.htm.
A salva neste diretório tem um efeito prático. Podemos modificar o arquivo default a ser executado (na configuração
do servidor Web) para este arquivo HTM, de tal forma que nosso usuário acione diretamente o HTM previamente
preparado (apresentado na Listagem-resposta 9.04A).
serverPort=”9000"
serverHost=””
connectMode=”Socket”
serverArgs=”module=EX901.fmx userid=DESENV/DESENV@DESENV “
separateFrame=”true”
splashScreen=””
background=”no”
lookAndFeel=”Generic”
colorScheme=”Khaki”
serverApp=”default”
>
<NOEMBED>
</COMMENT>
</NOEMBED></EMBED>
</OBJECT>
<!— Forms applet definition (end) —>
</BODY>
</HTML>
Observe que neste arquivo não existem mais variáveis com %, os valores são atribuídos diretamente aos parâmetros
da Applet.
Neste exemplo aproveitamos, também, para alterar o arquivo Registry.dat. Salvamos este arquivo no diretório d:\formsCap9
com o nome de Cap9.dat. Você poderá observar na Listagem-resposta 9.04A que o parâmetro serverApp na tag PARAM
está preenchido com /forms/Cap9, indicando que o arquivo Cap9.dat está localizado no diretório virtual /forms.
Dentro deste arquivo indicamos a localização dos arquivos de ícones e imagens. Uma vez que desejamos criar
arquivos de ícones e imagens específicos por sistema, criamos um subdiretório de nome “icons” subordinado ao
diretório d:\formsCap9 e copiamos aqueles ícones (com extensão .GIF) que desejávamos.
#
# Default Font Face mapping.
#
# appFontname represents a comma delimited list of Application Font Names.
# javaFontname represents a comma delimited list of Java Font Names.
#
# The number of entries in the appFontname list should match the number in
# the javaFontname list. The elements of the list are comma separated and
# *all* characters are taken literally, leading and trailing spaces are
#
# The Application Level icon files are relative to the DOCUMENTBASE
# example: icons/
# or an absolute URL.
# example: http://www.forms.net/~luser/d2k_project/
#
default.icons.iconpath=/forms/icons
default.icons.iconextension=gif
No trecho apresentado na Listagem 9.04B, fizemos algumas modificações no arquivo. Estas modificações indicam
que a fonte default é Helvetica e que qualquer outra fonte encontrada no Forms será sempre traduzida (em Java)
para Helvetica. Encontramos também a indicação da localização dos ícones e imagens, ou seja, /forms/icons,
indicando que abaixo do diretório virtual /forms foi incluído um diretório “icons” para armazenamento dos
ícones. Poderíamos, também, ter definido um outro diretório virtual com caminho físico totalmente independente
da localização dos arquivos .FMX. Observe que a extensão escolhida para os ícones foi gif. Como teste, o botão que
aciona o relatório pode ter sua propriedade “icônico” modificada para Sim e a propriedade “nome do arquivo de
ícones” preenchida com o nome de um arquivo .GIF incluído no diretório criado.
Com este exercício encerramos os testes relativos ao uso do Forms Server. Você poderá, ainda, realizar diversas
combinações e modificações no conjunto de arquivos estudados para chegar à melhor equação para sua instalação.
9.05) Baseado no relatório construído no Exercício 9.1, acrescente uma tela de parâmetros para que seja informada
a quantidade de cópias do resultado e o tipo de saída desejada pelo usuário. Acione este relatório usando uma URL.
Como primeira etapa devemos abrir o arquivo REP901.RDF e salvá-lo como REP905. Em seguida devemos criar
uma tela de parâmetros, usando o assistente, para os parâmetros de sistema DESFORMAT e COPIES.
Em seguida, a fim de testarmos a possibilidade de usarmos HTML na tela de parâmetros, faremos as seguintes modificações:
O boilerplate que contém o texto “Parâmetros do Relatório” será substituído pelo texto apresentado na Listagem-
resposta 9.05A. As propriedades de Formato podem ser modificadas para Estilo da Fonte igual a Normal e tamanho
8 (use a opção Fonte do menu Formatar).
Na tela de propriedades deste boilerplate, modificaremos a propriedade Contém Tags HTML para Sim.
Em seguida, o boilerplate que contém o texto “Informe valores para os parâmetros” será substituído pelo texto
apresentado na Listagem-resposta 9.05B. As propriedades de Formato também podem ser modificadas para Estilo
da Fonte igual a Normal e tamanho 8 (use a opção Fonte do menu Formatar).
Na tela de propriedades deste boilerplate, modificaremos a propriedade Contém Tags HTML para Sim.
Para os títulos de campo “Formato de Destino” e “Número de Cópias” substituiremos, respectivamente, pelos
textos mostrados na Listagem-resposta 9.05C.
Na tela de propriedades destes boilerplates, modificaremos a propriedade Contém Tags HTML para Sim.
Para que possamos apresentar uma lista de opções referente ao formato de destino, criaremos um parâmetro de
usuário com o nome P_FORMATO com tipo CHARACTER de 20 caracteres. No campo do form de parâmetro
associado ao Formato de Destino, modificaremos a propriedade Origem, inicialmente preenchida com DESFORMAT
para P_FORMATO. Isto fará com que a propriedade Lista de Valores seja habilitada. Nela preencheremos 3 valores
estáticos para este parâmetro (PDF, HTML e HTMLCSS) e manteremos a propriedade Restringir Lista a Valores
Predeterminados marcada. Para que a escolha do usuário seja atribuída ao parâmetro DESFORMAT, criaremos um
Gatilho de Validação com o código mostrado na Listagem-resposta 9.05D.
Como último passo devemos compilar e gerar o executável do relatório, tomando o cuidado de armazená-lo em
nosso diretório de trabalho dos relatórios (D:\REPCAP9).
Ao requisitarmos a execução deste relatório receberemos a tela apresentada na Figura-resposta 9.05A. Não se esqueça
de indicar o parâmetro PARAMFORM=HTML para que a tela de parâmetros seja mostrada.
Para resolução deste exercício utilizaremos o HTML criado, anteriormente, durante os testes e modificaremos para
que seja acionado o novo relatório e incluiremos uma nova opção na lista de chamada referente à apresentação da
tela de parâmetros. Esta pode parecer uma forma “preguiçosa” de resolver o problema, mas como nosso estudo
não é de HTML, e sim das opções do Reports Server, as modificações realizadas visam apenas facilitar a chamada do
resultado e não fazer testes complexos de HTML. Veja o resultado na Listagem-resposta 9.06A.
Neste arquivo incluímos três opções para executarmos o relatório REP901 e duas para executarmos o relatório
REP905. Observe que usamos o parâmetro %D, indicando que devem ser solicitados ao usuário o userid, password
e string de conexão para todas as execuções do relatório REP901. Na chamada do relatório REP905 usamos o
parâmetro P_FORMATO e não o parâmetro DESFORMAT na chave N05. Isto foi necessário pois o relatório esperava
receber este parâmetro. Seu valor é, internamente, atribuído ao parâmetro DESFORMAT. Teste!
Em seguida, modificaremos o valor da variável de ambiente REPORTS60_CGIMAP (use o regedit) para o valor
D:\REPCAP9\MAPCAP9.DAT.
Quando você estiver preparando seu ambiente de produção, observe que todas as opções ficarão dentro de um
único arquivo. No nosso caso criamos um arquivo de exemplo anteriormente (durante o estudo) e, agora, estamos
criando o nosso arquivo real de produção.
O HTML será bastante simplificado para permitir estes acionamentos. Veja o resultado na Listagem-resposta 9.07B.
Parte III
REFERÊNCIA
Capítulo 10
GUIA DE REFERÊNCIA DO SQL
Neste tópico, apresentaremos em ordem alfabética a sintaxe dos comandos de DML, uma parte da sintaxe dos
comandos de DCL e alguns comandos de DDL.
ALTER SESSION
Este comando possui um amplo espectro de modificações que pode realizar. Veremos algumas dessas modificações
e suas conseqüências.
COMMIT IN PROCEDURE
Habilita ou desabilita (Enable ou Disable) a execução do comando Commit (e Rollback) em stored procedures
ou functions.
Quando um comando Commit ou Rollback é executado em uma sessão, isso afeta todos os comandos executados
na sessão. Quando desejamos garantir que as rotinas que executamos na sessão não efetivem a transação, podemos
utilizar esse comando.
SQL_TRACE
Habilita ou desabilita (True ou False) a facilidade de trace para a sessão.
Essa opção aparentemente não muda o comportamento da sessão, porém passa a ser gerado em disco (no ambiente
servidor) um arquivo contendo informações sobre a execução de cada um dos comandos de DML ocorridos du-
rante a sessão (ou até que essa opção seja desabilitada). Isto ajuda o DBA a verificar a existência de comandos com
problemas de performance.
FLAGGER
Indica que os comandos de SQL executados na sessão deverão passar pelo crivo de validação sintática de acordo
com o padrão Ansi (Entry, Intermediate, Full ou Off).
NLS_LANGUAGE
A opção Nls_Language é mais geral, pois modifica simultaneamente as seguintes características da sessão:
♦ A linguagem usada para as mensagens do Oracle.
♦ A linguagem usada para nomes de dias, nomes de meses e suas respectivas abreviações.
♦ Símbolos equivalentes usados na linguagem para A.M., P.M., A.D. e B.C.
♦ Seqüência de ordenação dos caracteres (Group By utiliza Binary, a menos que especifiquemos Order By).
♦ Direção de impressão.
♦ Strings de resposta afirmativa (Yes / Sim) ou negativa (No / Não).
A tabela a seguir apresenta a lista de linguagens válidas para o Oracle9i. As linguagens listadas com (*) indicam
aquelas para as quais as mensagens de erro do Oracle foram traduzidas.
continua
NLS_TERRITORY
O parâmetro Nls_Territory também afeta um conjunto de características da sessão:
♦ Formato de data default.
♦ Indicação de decimal e separação de milhar.
♦ Símbolo financeiro ISO.
♦ Símbolo financeiro local.
♦ Símbolo financeiro Dual default (segunda moeda, por exemplo: Euro).
♦ Primeiro dia da semana para o formato D.
♦ Símbolos para crédito e débito.
O formato L mostra o símbolo financeiro local, o símbolo C mostra o símbolo financeiro ISO e o formato U mostra
o Dual.
NLS_DATE_FORMAT
O parâmetro Nls_Date_Format especifica explicitamente um novo formato default para datas, a ser usado nas
funções TO_CHAR e TO_DATE. O valor default para este parâmetro é determinado pelo Nls_Territory.
NLS_DATE_LANGUAGE
O parâmetro Nls_Date_Language determina a linguagem a ser usada para os nomes de dias e meses e suas respectivas
abreviaturas. Não há necessidade de arquivo específico, e portanto podemos efetuar a alteração para qualquer linguagem
válida (para linguagens que usem caracteres multibyte, há necessidade de o terminal suportar este tipo de código).
NLS_NUMERIC_CHARACTERS
O parâmetro Nls_Numeric_Characters explicitamente especifica o caracter a ser usado como separador decimal e o
caracter a ser usado como separador de milhar. Esses caracteres devem ser informados na ordem <d> (decimal) e
<g> (grupo, milhar). Os valores devem ser diferentes, não podem ser numéricos nem um dos seguintes caracteres:
“+”, “-“, “<”, “>”.
NLS_CURRENCY / NLS_ISO_CURRENCY
O parâmetro Nls_Currency permite que façamos a modificação do símbolo financeiro local e o parâmetro
Nls_Iso_Currency permite que determinemos o território de onde o símbolo ISO será usado. O valor default para
este parâmetro é obtido dp Nls_Territory.
Observe que só podemos modificar diretamente o símbolo local. O símbolo ISO é determinado indiretamente pelo território.
NLS_DUAL_CURRENCY
Suporte a dupla moeda (segunda moeda do país, por exemplo: Euro). Para utilização em uma máscara de formato,
foi implementado o símbolo U.
NLS_SORT
O parâmetro Nls_Sort altera a seqüência na qual o Oracle ordena os caracteres.
A tabela a seguir apresenta a lista de linguagens válidas para o parâmetro Nls_Sort.
NLS_COMP
Utilização de características da língua para efeito de comparação. Normalmente, a comparação na cláusula Where
é binária. Para que a comparação obedecesse às características específicas da linguagem era necessário o uso da
função NLSSORT. Essa nova opção (utilizada em nível de sessão – Alter Session) indica que as comparações devem
obedecer às características da sessão do usuário. Desta forma, se na sessão for feita alteração do parâmetro NLS_SORT
(para uma linguagem válida nesse parâmetro), as comparações efetuadas na cláusula Where respeitarão essas
características específicas.
NLS_CALENDAR
O parâmetro Nls_Calendar especifica um novo calendário para a sessão. Quando modificamos um calendário, as
seguintes informações são modificadas: o primeiro dia da semana, regra para a primeira semana do ano (por
exemplo se dia 1 do ano cai numa sexta-feira, a primeira semana é a que começa no dia 3 – domingo), número de
dia do ano, primeiro dia da Era (o que afetará o ano atual).
A tabela a seguir apresenta a lista de calendários válidos para o Oracle9i.
NLS_LENGTH_SEMANTICS
Permite a criação de colunas CHAR ou VARCHAR2 usando o comprimento da coluna com semântica CHAR ou
BYTE, isto é, podemos informar o comprimento em CHAR ou BYTE. As colunas existentes não são afetadas. O
valor default é BYTE.
NLS_NCHAR_CONV_EXCP
Indica se a perda de dados durante uma conversão explícita ou implícita de tipo de dado deve ou não reportar um erro.
NLS_TIMESTAMP_FORMAT
Determina o format default de Timestamp a ser usado com as funções TO_CHAR e TO_TIMESTAMP.
NLS_TIMESTAMP_TZ_FORMAT
Determina o format default de Timestamp zonado a ser usado com as funções TO_CHAR e TO_TIMESTAMP_TZ.
TIME_ZONE
Determina a forma de apresentação e a zona (meridiano) para a sessão corrente. Este parâmetro está associado à
sessão (não é um parâmetro de inicialização).
Ao usarmos o formato ‘+/- hh:mm’, indicamos que o valor deverá ser fornecido em relação ao meridiano de
Greenwich. Os valores válidos variam de –12:00 a + 14:00.
Se especificarmos LOCAL, será usado o valor estabelecido quando a sessão teve início. Se especificarmos
DBTIMEZONE, desejamos que o valor seja igualado à especificação do banco de dados.
Na última opção informamos um nome de região. Para sabermos os nomes de regiões existentes devemos consultar a
coluna TZNAME da view V$TIMEZONE_NAMES. Neste caso a função SESSIONTIMEZONE retornará um nome de região.
CURRENT_SCHEMA
Possibilidade de alteração do schema corrente sem alteração do usuário corrente.
A alteração de schema faz com que as referências feitas sem qualificação sejam direcionadas para o schema especificado
no comando. Isso é uma forma prática de acesso a dados que estão em outro usuário.
Essa característica, no entanto, não dá privilégios especiais ao usuário. Para que o acesso seja possível, ele deve ter
os privilégios necessários sobre o objeto desejado.
CONSTRAINTS
Este comando tem a finalidade de modificar o momento de verificação das restrições de integridade.
Com a opção Immediate, indicamos que as condições especificadas por uma Constraint Deferrable serão verificadas
imediatamente após cada comando de DML (similar ao Set Constraints All Immediate marcado no início de cada
transação). A opção Deferred indica que as condições especificadas por uma Constraint Deferrable serão verificadas
quando a transação for Committed (similar ao Set Constraints All Deferred marcado no início de cada transação).
Finalmente, a opção Default restaura todas as Constraints, no início de cada transação, ao seu estado inicial
(Deferred ou Immediate).
COMMIT
O Oracle possui dois comandos para que indiquemos ao banco de dados o momento em que concluímos a transação
da aplicação. A indicação de que a transação deve ser efetivada é feita com o comando Commit e de que a transação
deve ser desmanchada é feita com o comando Rollback.
A cláusula Work é mantida apenas para compatibilidade com o SQL padrão. Commit e Commit Work são
equivalentes. A cláusula Comment faz com que um comentário (de até 255 bytes) seja associado com a transação
corrente. Se a transação ficar pendente este comentário é gravado no dicionário de dados (view DBA_2PC_PENDING).
A cláusula Force se aplica a uma transação distribuída em que “forçamos” que o Commit seja realizado.
Até que uma transação seja encerrada e efetivada com o uso do comando Commit, nenhuma das alterações feitas
por ela sobre a base de dados fica visível por qualquer outra sessão que estabeleça conexão com o banco de dados,
qualquer que seja o usuário conectado.
Isso significa que as linhas modificadas por uma transação ficam bloqueadas, impedidas de uso por qualquer
usuário do banco de dados, até que a transação seja concluída. Este mecanismo de bloqueio chama-se Lock. Esse
mecanismo torna as transações independentes uma vez que, estando o acesso para atualização impedido, não
corremos o risco de tomar decisões em relação a modificações ainda pendentes, não efetivadas.
Após a execução do Commit e conseqüente efetivação da transação, podemos estar seguros de que as modificações
foram refletidas no banco de dados e não mais poderão ser desfeitas.
Uma transação se inicia quando o primeiro comando de SQL DML é encontrado no programa ou após um Com-
mit ou Rollback.
Uma transação termina quando:
♦ Executamos um Commit ou Rollback.
♦ Um comando de DDL é executado. Quando executamos um dos comandos de DDL, o Oracle executa um
Commit implícito antes de iniciar a execução do comando. Isso encerra a transação que estava em andamento
anteriormente e inicia uma outra contendo o comando de DDL.
♦ Um comando de DDL é concluído. Após a execução do comando de DDL, o Oracle implicitamente executa um
Commit. Isso encerra a transação que continha o comando. Observe que não podemos desfazer um comando
de DDL com Rollback. Após solicitarmos sua execução, a transação em uso é fechada, aberta uma outra, feita a
execução do comando, a transação atual é encerrada e aberta outra. Quando novamente temos acesso à
informação, a transação do comando de DDL já foi concluída.
♦ O usuário se desconecta do Oracle. Se o término da transação foi normal, isto é, não ocorreram erros, o Oracle
efetiva os comandos da última transação (Commit). Se o término foi anormal, com erros, o Oracle desmancha
todos os comandos relativos à última transação (Rollback).
Para transações terminadas normalmente em um programa Oracle Precompiler, não há efetivação da transação, o compilador não monta um comando de
Commit. Neste caso, o Oracle fará um Rollback. Quando trabalhamos com aplicativos ou utilitários da Oracle e a transação termina normalmente, o
utilitário ou aplicativo envia um Commit para o banco de dados. No caso de falha, envia um Rollback.
É recomendação da Oracle que o usuário explicitamente informe ao banco de dados qual a ação desejada também para a última transação da
aplicação, antes de encerrar a conexão com o banco de dados.
Como recomendação adicional, temos que um programa que altere o conteúdo de uma ou mais linhas em uma ou mais tabelas deve periodicamente
fixar essas modificações (Commit). Isso deve ocorrer, pois cada uma das linhas modificadas fica bloqueada, impedida de ser atualizada por outra
aplicação (Locked). Desta forma, quanto mais linhas Locked uma aplicação mantiver, menor a possibilidade de concorrência e maior a necessidade
de controle por parte do Oracle e, portanto, maior gasto de CPU.
A palavra Work é mantida para compatibilidade com o SQL padrão. Os comandos Commit e Commit Work são equivalentes.
CONCLUSÕES
♦ Uma leitura nunca é interrompida por um processo de atualização, ela sempre prossegue.
♦ Uma leitura não bloqueia os dados. Não faz Lock.
♦ Uma leitura “enxerga” o dado com a imagem que ele tinha antes de a leitura se iniciar. Ela vê todos os dados
Commited antes do início da consulta e vê todas as modificações feitas por sua própria transação.
♦ Após um comando Commit, todos os bloqueios (Locks) são liberados.
O comando Commit possui sintaxe específica para forçar ou comentar a execução de transações distribuídas, que não serão vistas neste material.
<CONDITION>
Uma condição é uma combinação de uma ou mais expressões e operadores lógicos (And, Or, Not) que determinam
se uma ação irá ou não ocorrer, dependendo do resultado True ou False.
As condições podem ser usadas na cláusula Where dos comandos Delete, Select ou Update e nas cláusulas Start
With, Connect By e Having do comando Select.
<CONSTRAINTS>
A claúsula <constraint> é utilizada nos comandos Create Table e Alter Table para estabelecer restrições sobre o
armazenamento de dados no banco de dados. Sua finalidade é garantir regras que garantam a integridade lógica do
negócio que o usuário está modelando.
♦ References – determina a coluna corrente (ou atributo) como FK e identifica a tabela-pai e a coluna ou combinação
de coluna que forma a chave referenciada. Se identificarmos somente a tabela-pai e omitirmos a coluna, a FK,
automaticamente, faz referência à PK da tabela-pai. As colunas correspondentes da FK e da RK (referenced key)
devem combinar em número e tipo. Para colunas REF a referência deve ser a uma Object Table ou View.
♦ On Delete – determina como o Oracle, automaticamente, mantém a integridade referencial se tentarmos remover a PK
ou UK referenciada. Se omitirmos esta cláusula, o ORACLE não permite que venhamos a remover os valores da RK na
tabela-pai se houver linhas associadas na tabela-filha.
♦ A opção Cascade indica que o Oracle deve remover as FKs dependentes.
♦ A opção Set Null indica que o Oracle deve converter os valores das FKs dependentes em null.
♦ Check – especifica uma condição que cada linha na tabela deve satisfazer. Para que a condição seja considerada
satisfeita, a expressão deve retornar true ou unknown (quando o valor é null).
♦ Deferrable – indica que a validação da restrição pode ser adiada até o fim da transação através do uso do
comando Set Constraint.
♦ Not Deferrable – indica que esta restrição deve ser verificada ao fim de cada comando DML. Esta é a opção default.
♦ Initially Immediate – indica que, a princípio, o default é verificar esta restrição ao fim de cada comando de
DML. Esta é a opção default.
♦ Initially Deferred – indica que, a princípio, o default é verificar esta restrição somente ao fim de cada transação.
♦ Rely | Norely – indica se uma restrição que está no modo Novalidate deve ser considerada para o mecanismo de
Query Rewrite. Se usarmos Rely estaremos ativando o uso desta restrição para o mecanismo de Query Rewrite.
O default é Norely.
♦ <using index> – especifica parâmetros para o índice que o Oracle cria para garantir uma constraint do tipo
Unique ou Primary Key. O nome do índice é o mesmo nome da restrição. Podemos determinar valores de
initrans, maxtrans, tablespace, storage, pctfree, logging e nologging para o índice.
♦ Enable – especifica que a restrição será aplicada a todos os novos dados na tabela. Antes de habilitarmos uma
integridade referencial, sua restrição referenciada (isto é UK ou PK) deve estar habilitada.
♦ A opção Validate indica que os dados velhos também deverão ser compatíveis com a restrição.
♦ A opção Novalidate assegura que todas as novas operações de DML nos dados restringidos sejam compatíveis com a
restrição, mas não assegura que os dados existentes na tabela o sejam.
♦ Disable – desabilita a restrição de integridade. Se não especificarmos esta cláusula na criação da restrição, ela
será habilitada, automaticamente.
♦ Validate desabilita a restrição e remove o índice associado, mas mantém a restrição válida. Esta característica
é muito útil em ambientes Data Warehouse, onde necessitamos carregar em uma tabela particionada uma
quantidade de dados com um intervalo distinto de valores na chave única. Nestas situações, esta opção
permite a carga usando exchange_partition_clause do comando Alter Table, mas as demais modificações
feitas por comandos de SQL são impedidas.
♦ Novalidate significa que o Oracle não faz nenhum esforço de manter a restrição.
♦ Scope – em uma tabela com uma coluna REF, cada valor REF na coluna pode associar um objeto em Object
Tables diferentes. A cláusula SCOPE restringe o escopo da referência a uma única tabela indicada por
scope_table_name. Os valores na coluna ou atributo REF apontam para objetos na scope_table_name, na qual
instâncias do objeto (de mesmo tipo daquele indicado pela coluna REF) são armazenadas. Só podemos especificar
uma tabela escopo por coluna REF.
♦ Exceptions Into – especifica uma tabela na qual o Oracle colocará os rowids de todas as linhas que violarem a
restrição. Esta tabela deverá ser criada com o script utlexcpt1.sql. Esta cláusula só é válida quando estivermos
validando uma restrição.
CREATE DIRECTORY
Este comando cria um objeto diretório no banco de dados e o associa a um diretório existente no sistema operacional.
Esse objeto será usado para indicação do diretório de armazenamento de arquivos associados às colunas do tipo Bfile.
CREATE SEQUENCE
Seqüências são objetos atualizados pelo Oracle Server com o objetivo de fornecer um número seqüencial. Esse
número pode ser usado para a geração de primary keys em tabelas. Quando não especificamos nenhum parâmetro,
o valor inicial é 1, incrementado de 1 e sem limite superior.
♦ Start With – Especifica o primeiro número de seqüência a ser gerado.
♦ Increment By – Especifica o intervalo entre os números gerados. Pode ser negativo, mas não pode ser zero.
♦ MaxValue / NoMaxvalue – Determina o maior valor gerado para números seqüenciais crescentes ou valor inicial
default para números seqüenciais decrescentes.
♦ MinValue / NoMinvalue – Determina o menor valor gerado para números seqüenciais decrescentes ou valor
inicial default para números seqüenciais crescentes.
♦ Cycle / NoCycle – Indica que a geração de números continuará após a seqüência ter atingido seu valor máximo
(ou mínimo, para seqüências decrescentes). O próximo número a ser gerado será o valor mínimo para seqüências
crescentes e o valor máximo para seqüências decrescentes.
♦ Cache / NoCache – Especifica uma quantidade de números que o Oracle pré-aloca e mantém em memória para
acesso mais rápido.
♦ Order / NoOrder – Garante que a numeração de seqüência é fornecida em ordem de requisição. Esta cláusula pode ser
útil se estivermos utilizando o número de seqüência para determinar a ordem de ocorrência dos elementos gravados.
De um modo geral, a utilização mais comum é para geração de PK e a ordem de requisição não é importante. A
utilização desta cláusula somente causa diferença em ambientes com mais de uma instância em paralelo.
Existe um risco potencial de perda de numeração seqüencial em caso de falha no sistema, em que a memória é
perdida, e quando ocorre uma falha de programa e desmanchamos a transação sem, efetivamente, utilizar os
números seqüenciais solicitados. O sequence não volta a disponibilizar os números perdidos, pois não tem controle
sobre o uso dado à seqüência. Esta situação é agravada com o uso de Cache.
CREATE TYPE
O comando Create Type cria um tipo Object, Varray ou Nested Table que pode ser usado na declaração de outros
tipos ou de uma tabela.
As seguintes cláusulas se acham presentes na Sintaxe 10.07:
♦ As Object – Cria um tipo objeto. As variáveis que formam a estrutura são chamadas de atributos. Os subprogramas
que definem as ações são chamados de métodos.
♦ As Table – Cria um tipo Nested Table referente ao tipo de dado especificado.
♦ As Varray (<limite>) – Cria um tipo Varray de elementos ordenados, todos do mesmo tipo de dado. A especificação
do <limite> é obrigatória. O tipo de dado de um Varray pode ser um escalar, um Ref, um tipo objeto (inclusive
contendo um atributo Varray). O tipo de dado de um Varray não pode ser um tipo objeto com uma Nested
Table, um tipo Varray ou um tipo Table.
♦ Ref <tipo objeto> – Associa uma instância de um objeto-origem a uma instância de um objeto-destino (não é
integridade referencial). Um Ref identifica e localiza (aponta) o objeto específico.
♦ Wnps – Indica que o corpo da função não deve conter comandos que modifiquem o valor de variáveis em pacotes.
♦ Rnds – Indica que o corpo da função não deve conter comandos que façam consultas a tabelas do banco de dados.
♦ Rnps – Indica que o corpo da função não deve conter comandos que façam referência a variáveis de pacotes.
♦ Trust – Indica que o compilador deve “acreditar” nas demais especificações feitas para a pragma e que não é
necessário realizar uma validação a tempo de compilação.
♦ AuthId – A cláusula indica ao Oracle como verificar (a tempo de execução) os privilégios e como resolver as
referências externas. A opção Definer (Default) indica que as verificações serão realizadas usando-se o schema
do dono da rotina. Para a opção Current_User, os privilégios do executor da rotina são usados a tempo de
execução e as referências externas são resolvidas no schema deste executor, presentes em:
a) Comandos que manipulam os dados: Select, Insert, Update e Delete.
b) Comando para controle de transações: Lock Table.
c) Comandos para controle de Cursores: Open e Open-For.
d) Comandos de SQL dinâmicos: Execute Immediate e Open-For-Using.
e) Comandos de SQL “parseados” pela rotina Parse do pacote Dbms_Sql.
Para os outros comandos, os privilégios do dono da rotina são usados a tempo de compilação e as referências
externas são resolvidas no schema do dono da rotina.
♦ Under <supertipo> – determina a criação de um subtipo a partir de um tipo preexistente (que deve ser Object).
O subtipo herda as propriedades do supertipo e deve (em sua definição) substituir algumas das propriedades ou
adicionar outras para diferenciá-lo do supertipo.
♦ <tipo SQLJ> – com esta definição estaremos criando um objeto SQLJ. Neste caso associamos ou mapeamos uma
classe Java para um tipo definido pelo usuário. A mesma classe Java pode ser mapeada para diversos tipos SQLJ,
porém existem algumas restrições:
♦ Um subtipo deve ser mapeado para uma classe que seja uma subclasse imediata da classe para a qual seu
supertipo foi mapeado.
♦ Dois subtipos de um supertipo comum não podem ser mapeados para a mesma classe.
Se existir um subtipo ou supertipo de um tipo SQLJ, ele também deve ser SQLJ object type, ou seja, todos os tipos
na hierarquia devem ser tipos SQLJ.
♦ <java external name> – especifica o nome de uma classe Java. Se a classe existir, ela deve ser pública. O nome
(incluindo o schema) será validado.
♦ SQLData ou CustomDataum ou OraData – são três tipos de interface que determinam o mecanismo que será
usado para a criação da instância Java. Estas interfaces estão documentadas no manual de JDBC da Oracle
(Oracle9i JDBC Developer’s Guide and Reference).
♦ External Name ‘<nome campo> ‘ – esta cláusula só é válida se estivermos especificando um tipo SQLJ. Estaremos,
neste caso, indicando o campo Java que corresponde ao atributo do tipo objeto SQLJ. O campo Java já deve
existir na classe. Não podemos mapear um mesmo campo Java para mais de um atributo do tipo objeto SQLJ na
mesma hierarquia. Esta cláusula é opcional quando criamos um tipo objeto SQLJ.
♦ [Not] Final – quando usamos cláusula Final indicamos que nenhum subtipo poderá ser criado a partir deste
tipo. Final é o default.
♦ [Not] Instantiable – quando usamos Instantiable indicamos que podemos criar instâncias de objeto a partir
deste tipo. Instantiable é o default.
♦ <Herança> – este grupo de opções determina o relacionamento entre o supertipo e os subtipos.
♦ Overriding – determina que este método substitui um método definido no supertipo. O default é Not Over-
riding. A cláusula Overriding não é válida para um tipo SQLJ.
♦ Final – especifica que este método não pode ser substituído em qualquer subtipo deste tipo. O default é Not Final.
♦ Instantiable – podemos especificar Not Instantiable se o tipo não fornecer implementação para este método.
Por default todos os métodos são Instantiable. Se especificarmos Not Instantiable, não podemos especificar
Final ou Static.
CREATE VIEW
Uma view corresponde a um comando Select armazenado no banco de dados associado a um nome.
Uma view relacional é visualizada pelo usuário como tabela. Na verdade, não são tabelas capazes de armazenar
dados. Fazem referência a uma ou mais tabelas, outras views ou uma combinação de tabelas e views. Correspondem
a um comando Select armazenado na base de dados, que é obtido quando realizamos uma operação de DML
fazendo referência à view. Adicionalmente, permitem a modificação do nome das colunas das tabelas originárias
para nomes mais amigáveis.
As Views Objeto correspondem a tabelas objeto virtuais. Essas views podem ser criadas a partir de tabelas e views
relacionais simulando tabelas objeto. Essa forma de utilização permite a criação de um ambiente de transição entre
as tabelas relacionais e as tabelas objeto. As aplicações já escritas continuam vendo o ambiente apenas como
relacional. As novas aplicações já podem considerar a existência de objetos utilizando, no entanto, o mesmo
conjunto de tabelas.
As views possuem uma grande utilização em um banco de dados: Podemos armazenar queries complexas que
sejam muito utilizadas; podemos armazenar queries que contenham restrições, alterando o acesso aos dados através
apenas das views no lugar das tabelas básicas, podemos armazenar queries que contenham cálculos; colunas
constantes que decodifiquem a forma real como a informação está armazenada e, ainda, simular tabelas objeto.
Quando realizamos uma consulta utilizando na cláusula From o nome da view, o Oracle junta as restrições existentes
nos dois Selects e realiza a consulta à tabela básica (pois é nela que estão armazenados os dados).
Uma view pode ser usada tanto para Select quanto para Insert, Update ou Delete.
♦ With Read Only – Se desejarmos impedir que sejam feitas atualizações utilizando a view. Neste caso, qualquer
tentativa de atualização (Insert, Update ou Delete) através da view resulta em erro.
♦ Force / NoForce – Indica que a view deve ser criada mesmo que a tabela (ou objeto) referenciada não exista ou
que não tenhamos privilégio para uso. O default é NoForce.
♦ With Object Identifier – Especifica os atributos do tipo objeto que serão usados para identificar inequivocamente
cada linha da view objeto. Se a view objeto for baseada em uma Object Table ou em outra Object View, essa
cláusula pode ser omitida ou podemos especificar Default. A partir da versão 8i, devemos usar With Object
Identifier, apesar de a sintaxe anterior (With Object OID) ainda ser suportada.
♦ Default – Indica que o Oid da Object View ou Object Table na qual a view está baseada será usado como Oid da View.
♦ Constraint – Indica o nome da constraint a ser criada em função da cláusula With Check Option. Se esse nome
não for fornecido, o nome-padrão (Sys_Cn) será usado.
♦ Under – Especifica uma Subview baseada em uma Object Superview.
<DATATYPES>
Cada valor manipulado pelo Oracle tem um Datatype que determina as propriedades do valor (ou elemento). Para
o Oracle9i os datatypes estão subdivididos em quatro categorias: Oracle Built-in Datatypes, Ansi, DB2 e SQL/DS
Datatypes, User-Defined Types e Oracle Suplied Types.
♦ Char – é uma string de caracteres de tamanho fixo (máximo de 2000 bytes). Tamanho default e mínimo é de 1
byte. A palavra Byte indica que o tamanho será considerado em bytes enquanto Char indica caracteres. Para
ambientes multi-bytes o uso desta informação faz diferença.
♦ Varchar2 – é uma string de tamanho variável (máximo de 4000 bytes). O tamanho é obrigatório. A palavra Byte
indica que o tamanho será considerado em bytes enquanto Char indica caracteres. Para ambientes multi-bytes
o uso desta informação faz diferença.
♦ Nchar – é uma string de caracteres de tamanho fixo (máximo de 2000 bytes). Tamanho default e mínimo é de
1 byte. O conteúdo armazenado deve ser compatível com o national charset definido para o banco de dados.
♦ Nvarchar2 – é uma string de tamanho variável (máximo de 4000 bytes). O tamanho é obrigatório. O conteúdo armazenado
deve ser compatível com o national charset definido para o banco de dados.
♦ Number(p,s) – dados numéricos, onde P varia de 1 a 38 dígitos. A escala S pode variar de –84 a 127.
♦ Long – é uma string de caracteres de tamanho variável com até 2Gb de comprimento. Só é possível a definição
de uma coluna do tipo long por tabela.
♦ Long Raw – é uma string de dados binários com comprimento variável até o limite de 2Gb de tamanho.
♦ Raw – armazena dados binários. O tamanho é obrigatório. Comprimento máximo de 2000 bytes.
♦ Date – armazena data e hora. Consideradas válidas no intervalo de 01/01/4712 AC. até 31/12/9999 DC. O
formato default é dd-mes-aa.
♦ Blob – armazena um locator para uma área que contenha dados binários (tam. máximo de 4Gb).
♦ Clob – armazena um locator para uma área que contenha dados alfanuméricos de comprimento máximo de
4Gb. Usa o database character set.
♦ Nclob – armazena um locator para uma área que contenha dados alfanuméricos de comprimento máximo de
4Gb. O conteúdo armazenado deve ser compatível com o national charset definido para o banco de dados.
♦ Bfile – armazena um locator para um arquivo do sistema operacional (tam. máximo de 4Gb).
♦ Rowid – string hexadecimal representando um endereço único de uma linha na tabela. O tipo é usado para
valores retornados pela pseudocoluna ROWID.
♦ Urowid (n) – string hexadecimal representando o endereço lógico de uma linha em uma IOT. O tamanho é opcional
e corresponde ao tamanho de uma coluna do tipo UROWID. O comprimento máximo e default é de 4000 bytes.
♦ Timestamp – Ano, mês e dia assim como hora, minuto, segundo e fração de segundo. O parâmetro <prc> indica
o número de dígitos da parte fracionária do segundo. Os valores podem variar de 0 a 9. O default é 6.
♦ A cláusula With Time Zone inclui a apresentação da zona de tempo. Onde a zona de tempo corresponde à
diferença (em horas e minutos) entre a hora local e UTC (hora de Greenwich).
♦ Se usarmos With Local Time Zone, são válidos todos os valores. A diferença entre esta opção e a anterior é
que a zona de tempo não é armazenada no banco de dados. O dado, quando armazenado, é normalizado
para a Dbtimezone e, quando recuperado, é visualizado pelo usuário com a Time Zone da sessão (ocorre uma
Segunda conversão).
♦ Interval Year – armazena um período de tempo em anos e meses, onde <prc> corresponde ao número de dígitos
do campo Year. São aceitos valores de 0 a 9. O default é 2.
♦ Interval Day – armazena um período de tempo em dias, horas, minutos e segundos. O primeiro <prc> determina
o número máximo de dígitos no campo Day. São aceitos valores de 0 a 9, sendo o default 2. O segundo <prc>
determina o número máximo de dígitos na parte fracionária do campo Second. Os valores válidos variam de 0
a 9. O default é 2.
♦ Sys.AnyData – contém uma instância de um determinado tipo com dado e descrição do tipo. Pode ser usado
como parâmetro de rotina onde esta flexibilidade é necessária. O valor pode ser um buit-in datatypes ou user-
defined types.
♦ Sys.AnyType – este tipo pode conter uma descrição de qualquer tipo SQL nomeado ou transiente.
♦ Sys.AnyDataSet – contém uma descrição de um determinado tipo mais um conjunto de instâncias de dados
daquele tipo. Pode ser usado como coluna para uma tabela onde armazenamos valores heterogêneos em uma
única coluna. O valor pode ser um buit-in datatypes ou user-defined types.
♦ Sys.XMLType – pode ser usado para armazenamento de dados XML no banco de dados. Tem funções membro
que podemos usar para acesso, extração e consulta. Internamente, a informação é armazenada em Clobs.
♦ Sys.UriType – corresponde a um supertipo que pode ser especializado em HttpUriType ou DbUriType. O subtipo
HttpUriType armazena URLs para páginas Web externas ou para arquivos usando o protocolo Http. O subtipo
DbUriType faz referências a dados (Uri) dentro do DB.
♦ Sys.UriFactoryType – é um tipo para fatoração. Pode criar e retornar outros tipos de objetos. Quando uma string
URL é atribuída a um tipo UriFactoryType podemos obter instâncias dos vários subtipos dos UriTypes. Ele
analisa a string URL e identifica o tipo da URL e cria uma instância do subtipo adequado (Http, Dburi, etc.).
♦ Mdsys.SDO_Geometry – é uma coluna objeto para armazenamento da descrição geométrica de um objeto do
tipo spatial. Não pode ser a única coluna da tabela.
♦ Ordsys.OrdAudio – é um tipo objeto para armazenamento de áudio.
♦ Ordsys.OrdImage – é um tipo objeto para armazenamento de imagem.
♦ Ordsys.OrdVideo – é um tipo objeto para armazenamento de vídeo.
DELETE
O comando Delete é o responsável pela remoção de linhas (ou instâncias de objetos) cadastradas no banco de dados.
A cláusula Where é a responsável por determinar que linhas poderão ser removidas. Caso essa cláusula não seja
informada, o comando tentará remover todas as linhas da tabela informada.
♦ Subpartition – Especifica uma subpartição da tabela em que desejamos efetuar a deleção. Não há necessidade de
especificarmos nem partição nem subpartição, mas em determinadas situações pode ser mais eficiente (que a
utilização de cláusulas Where complexas, por exemplo).
♦ Only – esta cláusula é aplicável somente quando fazemos referência a views. Esta cláusula é útil se a view
referenciada na cláusula From pertence a uma hierarquia de views e não desejamos remover linhas de quaisquer
das subviews.
♦ Table – Indica ao Oracle que a coluna retornada pela subquery será uma Nested Table e não um valor escalar.
♦ <coleção> – É uma <subquery> que seleciona uma coluna de uma tabela ou view.
♦ Returning – Obtém alguma informação das linhas afetadas pelo comando Delete. A informação obtida deve ser
um escalar, Lob, Rowid ou Ref. Essa cláusula não pode ser usada com Parallel DML ou com objetos remotos.
São usadas em funções e comandos SQL. As expressões têm vários formatos. O Oracle não aceita todos os formatos
em todas as partes de um comando SQL, de forma que, nas sintaxes apresentadas neste livro, poderemos usar estas
expressões onde encontrarmos <expressão> ou <expr>. Neste tópico, veremos as restrições aplicáveis.
Uma expressão pode ser:
♦ um texto, um número, Nextval de uma seqüência, CurrVal de uma seqüência, Null (explícito), uma coluna de uma
tabela, view ou materialized view. As pseudocolunas Level, Rowid e Rownum (as quais se aplicam exclusivamente às
tabelas, não sendo válidas para views ou materialized views).
♦ uma função predefinida (built-in).
♦ uma função criada pelo usuário.
♦ uma combinação de outras expressões unidas pelos operadores (+, -, *, / ou ||).
♦ uma chamada a um tipo construtor (constructor type). Os argumentos são separados por vírgulas.
♦ um cursor embutido (similar ao Ref Cursor de PL/SQL). Cursores só podem ser usados no comando Select que
não esteja embutido em outro, exceto quando a subquery é do próprio cursor. Cursores só podem aparecer na
lista de especificação do Select mais externo. Não podem aparecer em views e, ainda, não podemos usar operações
Bind e Execute em cursores embutidos.
♦ uma expressão envolvendo a cláusula Case, que permite uma estrutura do tipo IF..THEN …ELSE dentro de um
comando de SQL sem que tenhamos de usar uma rotina.
♦ uma combinação de uma ou mais expressões envolvendo tempo (datetime).
♦ uma conversão para o intervalo de tempo desejado.
♦ uma referência a um método. Os argumentos são separados por vírgulas.
Uma lista de expressões (também referenciada nas sintaxes) corresponde a diversas (mais de uma) expressões
separadas por vírgulas e entre parênteses.
FUNÇÕES ESCALARES
Funções são programas que realizam determinadas ações, podem receber parâmetros e retornam pelo menos
um resultado.
As funções de que trataremos neste item são as escalares. Uma função é dita escalar quando se aplica a um valor (e
não a um conjunto, como as funções de grupo). Podem também ser chamadas de funções de linha pois são
executadas uma vez para cada linha, retornada da query por exemplo.
Dentre as funções predefinidas pelo SQL do Oracle9i, o maior conjunto se refere às funções escalares. Essas built-ins se
aplicam à(s) coluna(s) de uma única linha, desta forma produzindo um resultado por linha.
Podemos subdividir esse grupo de funções de acordo com o tipo de parâmetro e resultado gerado, da seguinte forma:
♦ Numéricas – São aquelas que recebem parâmetros numéricos e geram resultados numéricos. Podem ser
subdivididas em Trigonométricas e Numéricas Simples.
♦ Alfanuméricas – Geram resultados alfanuméricos. Recebem parâmetros alfanuméricos e (algumas) numéricos.
♦ Alfanuméricas que retornam Valores Numéricos – Recebem parâmetros alfanuméricos e geram resultados numéricos.
♦ Datas – Realizam a manipulação de datas.
♦ Conversão – Realizam conversão de tipo.
♦ Outras – Características diversas.
No tópico Modificando o Resultado com Funções (Capítulo 2) obteremos detalhes de utilização, exemplos e valores
válidos para os parâmetros. A seguir, apresentaremos apenas a sintaxe básica.
NUMÉRICAS SIMPLES
Recebem parâmetros numéricos e geram resultados numéricos. Foram, para efeito de sintaxe, grupadas de acordo
com a quantidade de parâmetros recebidos.
Uma das novidades está na função Width_Bucket que é capaz de calcular, para a expressão fornecida como parâmetro
(que deve ser numérica ou datetime), faixas de valores. Para cada linha a expressão é calculada e classificada dentro
de uma das faixas de valor. Os parâmetros <menor_valor> e <maior_valor> indicam o intervalo de cálculo e o
parâmetro <num_buckets> indica a quantidade de faixas. Desta forma se passássemos como parâmetro os valores
1 e 30 para o intervalo e 3 para o número de faixas, teríamos a faixa 1 com valores reais entre 1 (inclusive) e 10
(exclusive), a faixa 2 com valores reais entre 10 (inclusive) e 20 (exclusive) e a faixa 3 com valores entre 20 (inclu-
sive) e 30 (exclusive). Caso fosse passado para esta função (no parâmetro <expressão)) o valor 12, o retorno da
função seria 2, indicando que este valor estaria compreendido na segunda faixa calculada.
O outro acréscimo foi o da função BitAnd que calculará uma operação AND bit a bit entre os argumentos passados
como parâmetros.
TRIGONOMÉTRICAS
Recebem parâmetros numéricos e geram resultados numéricos. Estão relacionadas a cálculos matemáticos de
trigonometria. Levam em consideração que o círculo trigonométrico tem o tamanho de 1. Os argumentos relativos
a ângulos são fornecidos em radianos.
Para transformarmos um ângulo (em graus) para radianos, devemos dividi-lo por 57.29578.
ALFANUMÉRICAS
Recebem parâmetros alfanuméricos e/ou numéricos e geram resultados alfanuméricos.
A sintaxe foi organizada de acordo com a quantidade e tipo dos parâmetros recebidos.
Nesta versão 9i encontramos uma nova função chamada Treat que permite que modifiquemos o tipo declarado de
uma expressão. Suponhamos, portanto, que a <expressão> seja do tipo X; desta forma, <type> poderá ser um
supertipo ou um subtipo de X, porém tem de estar na mesma hierarquia. Caso isso não seja respeitado, o retorno
da função é Null. Da mesma forma, se a <expressão> é uma referência (REF) ao tipo X; o parâmetro <type> deverá
ser um supertipo ou subtipo de X, caso contrário o retorno da função será Null.
Você poderá observar que Substr ganhou três novas variações. A função Substr original considera o parâmetro
<tamanho> fornecido em caracteres, SubstrB em bytes, SubstrC em caracteres Unicode Complete, Substr2 em
UCS2 Codepoints e Substr4 em UCS4 Codepoints.
Neste grupo as funções Length e Instr também ganharam variações para Bytes, Unicode Complete, UCS2 Codepoints
e UCS4 Codepoints.
DATAS
Realizam manipulação de datas.
A sintaxe foi organizada de acordo com a quantidade e tipo dos parâmetros recebidos.
Em algumas das funções de data, podemos passar um texto no lugar do parâmetro <data>. O Oracle fará a conversão
usando a função To_Date com o formato de acordo com o padrão em uso na estação do usuário. Nas funções Trunc
e Round, essa ação não é possível.
Todas as funções deste grupo retornam valores de data ou intervalo de data, exceto Months_Between, que retorna
um número.
As funções, nesta versão, ganharam mais precisão pois podemos determinar precisão em relação aos segundos
(Localtimestamp e Current_Timestamp) e, ainda, podem trabalhar com zona de tempo em relação ao meridiano
de Greenwich. No Capítulo 2 você encontrará exemplos que esclarecerão as alternativas de uso.
CONVERSÃO
A sintaxe foi organizada de acordo com a quantidade e tipo dos parâmetros recebidos.
Neste grupo diversas funções foram incluídas na versão 9i, principalmente associadas a timestamp. Retorne ao
Capítulo 2 para verificar a descrição destas funções e exemplos de uso.
OUTRAS
Neste grupo, veremos algumas funções que não se enquadram na classificação anterior.
Neste grupo também foram incluídas novas funções na versão 9i, dentre elas encontramos funções para tratamento de
Null tais como Coalesce, Nullif e NVL2, rotinas para detalhamento do caminho de uma querie hierárquica
(Sys_Connect_By_Path), rotinas para manipulação de documentos XML e geração de URL.
FUNÇÕES DE GRUPO
São programas que têm a finalidade de efetuar cálculos sobre um conjunto de linhas e retornam um valor. Elas se
aplicam a um grupo de linhas e retornam um único valor relativo a todo o grupo selecionado.
O argumento para essas funções pode ser o nome de uma coluna ou uma expressão (combinação de nomes de
colunas, constantes ou outras funções).
♦ Avg – Retorna a média dos valores de <expressão>.
♦ Corr – Retorna o coeficiente de correlação de um conjunto de pares de números.
♦ Covar_Pop – Retorna a covariância populacional relativa a um conjunto de pares de números.
♦ Covar_Samp – Retorna a covariância simples em relação a um conjunto de pares de números.
♦ Cume_Dist – Calcula a distribuição cumulativa de um valor em um grupo de valores.
♦ Dense_Rank – Calcula a posição (rank) de uma linha em um grupo ordenado de linhas.
♦ First – Opera em um conjunto de linhas que foram classificadas (Rank) como First com relação a uma
determinada ordenação.
♦ Group_Id – Distingue grupos duplicados resultantes de uma especificação Group By.
♦ Grouping – Tem a finalidade de distinguir um valor Null que representa um subgrupo (de uma das agregações
produzidas pelo Rollup ou Cube) de um valor Null real. Essa função somente poderá ser utilizada quando na
cláusula Group By usarmos a extensão Rollup ou a extensão Cube. A expressão a ser incluída na função Group-
ing deve corresponder a uma das expressões da cláusula Group By. Essa função retornará 1 se o valor da expressão
representar um subgrupo, e caso contrário retornará zero. O tipo de valor retornado é Number.
♦ Grouping_Id – retorna um número correspondente ao vetor Grouping associado à linha. Essa função somente poderá
ser utilizada quando na cláusula Group By usarmos a extensão Rollup ou a extensão Cube e a função Grouping.
♦ Last – Opera em um conjunto de linhas que foram classificadas (Rank) como Last com relação a uma
determinada ordenação.
♦ Max – Retorna o maior valor de <expressão>.
♦ Min – Retorna o menor valor de <expressão>.
♦ Percentile_cont – é uma função de distribuição inversa que assume um modelo de distribuição contínuo.
♦ Percentile_Dist – é uma função de distribuição inversa que assume um modelo de distribuição discreto.
♦ Percent_Rank – similar à Cume_Dist.
♦ Rank – Calcula a posição de um valor em um grupo de valores.
♦ Regr_ – Neste grupo encontramos diversas funções de regressão linear.
♦ Stddev – Retorna o desvio padrão de <expressão>.
♦ Stddev_Pop – calcula o desvio padrão populacional e retorna a raiz quadrada da variância populacional.
♦ Stddev_Samp – calcula o desvio padrão cumulativo e retorna a raiz quadrada da variância simples.
♦ Sum – Retorna o somatório dos valores de <expressão>.
♦ Variance – Retorna a variância dos valores de <expressão>.
♦ Var_Pop – Retorna a variância populacional de um conjunto de números após descartar os nulls do conjunto.
♦ Var_Samp – Retorna a variância simples de um conjunto de números após descartar os nulls do conjunto.
♦ Count – Retorna o número de linhas que satisfaça a query.
Para todas as funções (exceto Count(*)), as linhas em que <expressão> está sem valor (Null) não são contabilizadas
para cálculo do resultado.
FUNÇÕES ANALÍTICAS
As funções analíticas calculam um valor agregado baseado em um grupo de linhas. Elas diferem das funções de
agregação vistas anteriormente pelo fato de poderem retornar diversas linhas para cada grupo. O grupo de linhas
é chamado de Window e é definido por uma cláusula analítica.
As funções de grupo que possuem uma variação analítica não foram repetidas na sintaxe acima, excetuando-se os
casos em que ocorre diferença sintática.
GRANT
O propósito do comando Grant é ceder privilégios. Temos dois tipos de privilégios: sobre os objetos (que deve ser
cedido pelos usuários “donos” dos objetos) e de sistema (cedido pelo DBA), que autorizam determinadas ações dos
usuários no banco de dados.
♦ Delete – Permite que sejam removidas linhas da tabela. Aplicável a tabelas, views e views materializadas (que
sejam atualizáveis).
♦ Execute – Permite a execução da rotina especificada ou o acesso a qualquer programa especificado no package
nomeado. Aplicável a procedures, funções, pacotes, libraries, tipo definido pelo usuário, operator e Index Type.
♦ Index – Permite a criação de índices para a tabela. Aplicável a tabelas.
♦ Insert – Permite a inclusão de linhas na tabela. Aplicável a tabelas, views e views materializadas (que sejam atualizáveis).
♦ On Commit Refresh – Permite a atualização das views materializadas associadas à tabela quando ocorre um
Commit. Aplicável a tabelas usadas por views materializadas.
♦ Query Rewrite – Permite que um comando de pesquisa executado sobre uma tabela seja reescrito pelo otimizador
se ele encontrar uma View Materializada que responda à pergunta de forma mais eficaz. Aplicável a tabelas
usadas por views materializadas.
♦ Read – Permite a leitura de arquivos no diretório. Aplicável a Directories.
♦ References – Permite a criação de restrições de integridade que façam referência à tabela ou view. Aplicável a tabelas.
♦ Select – Permite que a tabela seja consultada. Aplicável a tabelas, seqüências, views e views materializadas.
♦ Under – Permite a criação de uma subview para a view ou um subtipo subordinado ao tipo. Aplicável a views e
tipos definidos pelo usuário.
♦ Update – Permite que sejam feitas alterações nos dados da tabela. Aplicável a tabelas, views e views materializadas
(que sejam atualizáveis).
♦ Write – Permite a gravação no diretório. Aplicável a Directories. Não permite que o usuário (ou role) que receber
os privilégios grave Bfiles.
Audit Any, Audit System, Backup Any Table, Become User, Comment Any Table, Create Any Cluster, Create Any
Directory, Create Any Index, Create Any Library, Create Any Procedure, Create Any Sequence, Create Any Snap-
shot, Create Any Synonym, Create Any Table, Create Any Trigger, Create Any Type, Create Any View, Create
Cluster, Create Database Link, Create Library, Create Procedure, Create Profile, Create Public Database Link, Cre-
ate Public Synonym, Create Role, Create Rollback Segment, Create Sequence, Create Session, Create Snapshot,
Create Synonym, Create Table, Create Tablespace, Create Trigger, Create Type, Create User, Create View, Delete
Any Table, Drop Any Cluster, Drop Any Directory, Drop Any Index, Drop Any Library,Drop Any Procedure, Drop
Any Role, Drop Any Sequence, Drop Any Snapshot, Drop Any Synonym, Drop Any Table, Drop Any Trigger, Drop
Any Type, Drop Any View, Drop Profile, Drop Public Database Link, Drop Public Synonym, Drop Rollback Seg-
ment, Drop Tablespace, Drop User, Execute Any Library, Execute Any Procedure, Execute Any Type, Force Any
Transaction, Force Transaction, Grant Any Privilege, Grant Any Role, Insert Any Table, Lock Any Table, Manage
Tablespace, Restricted Session, Select Any Sequence, Select Any Table, Update Any Table.
♦ Exp_Full_Database – Backup Any Table, Execute Any Procedure, Select Any Table.
♦ Imp_Full_Database – Alter Any Table, Alter Any Type, Audit Any, Become User, Comment Any Table, Create
Any Cluster, Create Any Directory, Create Any Index, Create Any Library, Create Any Procedure, Create Any
Sequence, Create Any Snapshot, Create Any Synonym, Create Any Table, Create Any Trigger, Create Any Type,
Create Any View, Create Database Link, Create Profile, Create Public Database Link, Create Public Synonym,
Create Role, Create Rollback Segment, Create Tablespace, Create User, Drop Any Cluster, Drop Any Directory,
Drop Any Index, Drop Any Library, Drop Any Procedure, Drop Any Role, Drop Any Sequence, Drop Any Snap-
shot, Drop Any Synonym, Drop Any Table, Drop Any Trigger, Drop Any Type, Drop Any View, Drop Profile,
Drop Public Database Link, Drop Public Synonym, Drop Rollback Segment, Drop Tablespace, Drop User, Ex-
ecute Any Procedure, Insert Any Table, Select Any Table.
As roles DBA, Connect e Resource estão mantidas nesta versão apenas para compatibilidade. A Oracle recomenda
que criemos nossas próprias roles para determinarmos privilégios e segurança do banco de dados. Estas roles
predefinidas podem não ser mais criadas em futuras versões do Oracle.
INSERT
O comando Insert tem a finalidade de incluir linhas (ou instâncias de objetos) em tabelas do banco de dados.
Podemos incluir linhas, em tabelas locais, de outros schemas e ainda de outros bancos de dados (@<dblink>). A inclusão
pode ser feita linha a linha ou os valores podem ser obtidos de outra(s) tabela(s) do banco de dados de tal forma que a
inclusão de diversas linhas pode ser feita com um único comando Insert.
Podemos definir que os valores sejam cadastrados em uma determinada partição de uma tabela específica ou em
uma Nested Table.
As cláusulas a seguir descrevem sintaticamente o comando:
♦ <Hint> – Corresponde a um comentário que passa instruções para o otimizador a respeito da forma como a
instrução deve ser executada.
♦ Partition – Identifica uma partição da tabela específica. A inclusão será realizada nesta partição se as restrições
estabelecidas para a partição forem respeitadas.
♦ Subpartition – Especifica uma subpartição da tabela. Não há necessidade de especificarmos nem partição nem
subpartição, mas em determinadas situações pode ser mais eficiente (que a utilização de cláusulas Where
complexas, por exemplo).
♦ All <cláusula Insert Into> – Indica que o Oracle fará uma inclusão incondicional. Será incluída uma linha para
cada cláusula Insert definida para cada linha retornada pela subquery.
♦ When – Indica que será feita uma filtragem. Podemos incluir até 127 cláusulas When. Elas indicarão qual dos
inserts será realizado.
♦ All When – Todas as cláusulas When serão verificadas e, para cada uma delas em que a condição for verdadeira,
a linha será incluída.
♦ First When – As cláusulas When serão verificadas na ordem estabelecida no comando e quando a primeira for
verdadeira a linha será incluída e as demais descartadas.
♦ Else – Se nenhuma cláusula When for verdadeira para uma determinada linha, a cláusula Else será executada.
Caso contrário nenhuma ação será realizada para aquela linha.
♦ Table – Indica ao Oracle que a coluna retornada pela subquery será uma Nested Table e não um valor escalar. A
sintaxe The (utilizada na versão 8) está sendo desaconselhada.
♦ <coleção> – É uma <subquery> que seleciona uma coluna de uma tabela ou view.
♦ <dblink> – Identifica um database link que permitirá a conexão com outro banco de dados.
♦ Returning – Obtém alguma informação das linhas afetadas pelo comando Delete. A informação obtida deve ser
um escalar, Lob, Rowid ou Ref. Essa cláusula não pode ser usada com Parallel DML ou com objetos remotos.
♦ Values – Especifica os valores de uma única linha (ou instância de objeto) a ser incluída.
♦ <subquery> – Indica uma query a ser usada como indicação de uma Nested Table ou de um conjunto de linhas
a serem incluídas. Observe que podemos utilizar uma subquery dentro da cláusula Values.
Quando não possuímos valor para uma determinada coluna, podemos utilizar a palavra-chave Null, indicando
que a coluna específica não será gravada no banco de dados.
MERGE
O comando tem a função de obter linhas de uma determinada tabela para atualizar ou incluir linhas em
outra tabela.
Como restrição temos que não podemos atualizar múltiplas vezes a mesma linha da tabela destino em um mesmo
comando Merge.
<RETURNING>
Em algumas situações, pode ser interessante obter informações da linha ou linhas alteradas, incluídas ou excluídas,
tais como dados das colunas, Rowid ou Refs. A cláusula Returning se aplica aos comandos Insert, Update e Delete.
Quando o retorno se refere a uma única linha, os valores podem ser armazenados em variáveis. Quando são
retornadas informações de diversas linhas, o resultado deve ser armazenado em um Bind Array.
Tanto os valores quanto as variáveis são separados por vírgulas.
BULK COLLECT
A opção Bulk Collect indica à SQL Engine para preparar toda a coleção de saída (Bulk Bind) antes de retorná-la para
a PL/SQL Engine.
REVOKE
O comando Revoke retira um privilégio previamente fornecido.
Da mesma forma que o Grant, o comando Revoke se refere a privilégios de sistema e privilégios para os objetos.
ROLLBACK
O comando Rollback tem a finalidade de concluir uma transação desmanchando todas as modificações efetuadas
desde o último Savepoint ou Commit.
A cláusula Work tem finalidade de estabelecer compatibilidade com o padrão Ansi e não traz qualquer modificação
ao comando. Já a cláusula To Savepoint indica que nem todos os comandos da transação serão desmanchados e
sim aqueles ocorridos após o Savepoint. Esse comando não efetiva os comandos anteriores ao Savepoint. Estes
continuam pendentes até que ocorra um Commit.
A cláusula Force tem a finalidade de indicar (<texto>) a transação distribuída pendente a ser desmanchada.
Nesta sintaxe, somente a transação distribuída é afetada. O <texto> deve conter o ID local ou global da transação
distribuída. Para obtermos este valor devemos consultar a view DBA_2PC_PENDING.
SAVEPOINT
Savepoints são utilizados junto com o comando Rollback. Têm a finalidade de marcar um ponto intermediário
na transação.
Savepoints podem ser úteis quando temos uma transação que executa diversos programas. Antes de cada programa,
podemos marcar um Savepoint e, caso ocorra um erro no programa, podemos realizar um Rollback somente até o
ponto marcado, desfazendo todas as modificações realizadas pelo programa e, então, executá-lo novamente com
as correções necessárias.
Quando ocorre um Rollback para Savepoint, todas as modificações ocorridas após o Savepoint são desmanchadas e
todos os locks adquiridos após este ponto também são liberados. A transação, porém, não é efetivada. Todas as modificações
ocorridas antes do Savepoint continuam “locked” sem efetivação aguardando que o usuário realize um Commit.
SELECT
O objetivo do comando Select é recuperar dados de uma ou mais tabelas, tabelas objeto, views, views objeto ou
views materializadas.
SET CONSTRAINT
Este comando tem a finalidade de modificar o momento de verificação das restrições de integridade.
Normalmente, tão logo enviemos um comando de atualização para a base de dados, as regras de integridade são
verificadas (esta é a situação mais comum e o que era disponível até a release 7.3).
A partir da release 8 do Oracle, podemos determinar que uma restrição de integridade seja verificada apenas no
momento em que a transação for encerrada com Commit.
Estabelecemos o modo como a restrição irá trabalhar no momento da criação da regra de integridade. Esta condição
poderá ser fixa ou variável. Caso especifiquemos que uma constraint é Deferrable, ela poderá ter sua condição de
verificação alterada a tempo de transação.
SET ROLE
O comando Set Role adquire para a sessão, dinamicamente, os privilégios das roles informadas.
Na sintaxe observamos que o comando pode adquirir todas as roles que o usuário tem autorização de usar, com a
cláusula All.
Se for nomeada uma role, todas as demais roles não nomeadas e que não estejam previamente habilitadas são
desabilitadas para a sessão.
A cláusula None desabilita todas as roles para a sessão corrente.
SET TRANSACTION
O mecanismo de consistência do Oracle garante que o resultado de um comando seja consistente. Pode ser necessário,
porém, que ampliemos esta consistência a diversos comandos. Por exemplo, desejamos executar várias leituras na
mesma tabela ou em tabelas diferentes, todas relativas ao mesmo momento de tempo.
O comando Set Transaction Read Only garante que a consistência seja considerada em relação ao momento da
execução do comando Set Transaction e não de cada comando individualmente.
O uso do comando Set Transaction determina algumas regras:
♦ Deve ser o primeiro comando da transação (caso contrário, ocorrerá um erro).
♦ Somente consultas são permitidas na transação.
♦ Um Commit, Rollback ou qualquer outro comando de DDL (possuem Commits implícitos) encerram o efeito
do comando Set Transaction.
Durante a transação (Read Only), todas as consultas se referem ao momento da execução do SET. Desta forma,
todas as modificações feitas na base de dados após a execução do comando SET não serão vistas por essa transação.
Somente as transações concluídas (Commited) antes de seu início serão visíveis.
Esse processo não impede a atualização do banco de dados pelas outras transações.
Devemos, no entanto, avaliar com cuidado a necessidade de utilizar este comando, pois transações Read Only
muito longas podem receber erro (Snapshot Is Too Old), indicando que a base de dados já sofreu muitas modificações
desde que o comando foi executado. Quando isso ocorre, podemos encerrar a transação e reexecutar o comando
Set Transaction, se necessário.
O nível de isolamento da transação (Isolation Level) identifica como transações que possuam modificações para o
banco de dados serão manipuladas.
A opção Read Committed é a forma padrão de trabalhar do Oracle, ou seja, se uma transação precisa adquirir linhas
bloqueadas por outra transação (locked), esta transação aguarda a liberação destas linhas.
Com a opção Serializable, indicamos que a transação em estado de serialização somente atualiza transações que
tenham sido commited antes do início da transação serializada, ou seja, supondo-se que uma transação A tenha
entrado em estado de serialização, após este momento uma transação B realiza uma modificação na matrícula 1 da
tabela Func e realiza um Commit. Se a transação A tentar modificar esta mesma linha ocorrerá um erro indicando
que não é possível serializar o acesso para esta transação.
O comando Set Transaction também permite a indicação do segmento de rollback a ser usado para aquela transação
específica. Isso pode ser muito útil para transações especialmente longas em que desejamos direcionar a alocação
de rollback para uma área específica (um segmento maior).
A cláusula Read Write do comando é a situação default para todas as transações.
<SUBQUERY>
Uma subquery é um comando Select que aparece em outros comandos de DML.
UPDATE
O comando Update tem a finalidade de alterar informações já gravadas na base de dados. Diferentemente do
comando Insert, o comando Update possui uma cláusula Where, a qual determinará que linhas serão modificadas.
Para determinar essas linhas, o Oracle faz um Select implícito no banco de dados, uma pesquisa para determinar
que linhas atendem à cláusula Where presente no comando. Caso não seja informada nenhuma cláusula Where,
todas as linhas serão modificadas.
Na sintaxe são apresentadas algumas cláusulas que veremos a seguir:
♦ <Hint> – Corresponde a um comentário que passa instruções para o otimizador a respeito da forma como a
instrução deve ser executada.
♦ Partition – Identifica uma partição da tabela específica. A atualização será realizada nesta partição se as restrições
estabelecidas para a partição forem respeitadas. Se não mencionarmos a partição, todas as partições serão consultadas
para verificação da condição de seleção. Quando mencionamos a partição, a restrição presente na cláusula Where
somente será verificada para essa partição.
♦ Subpartition – Especifica uma subpartição da tabela. Não há necessidade de especificarmos nem partição nem
subpartição, mas em determinadas situações pode ser mais eficiente (que a utilização de cláusulas Where
complexas, por exemplo).
♦ Table – Indica ao Oracle que a coluna retornada pela subquery será uma Nested Table e não um valor escalar. A
sintaxe THE (utilizada na versão 8) está sendo desaconselhada.
♦ Only – Somente aplicável a views. Indica que, se a view mencionada pertence a uma hierarquia, não desejamos
que as linhas das subviews sejam atualizadas.
♦ <coleção> – É uma <subquery> que seleciona uma coluna de uma tabela ou view.
♦ <dblink> – Identifica um database link que permitirá a conexão com outro banco de dados.
♦ Returning – Obtém alguma informação das linhas afetadas pelo comando Delete. A informação obtida deve ser
um escalar, Lob, Rowid ou Ref. Essa cláusula não pode ser usada com Parallel DML ou com objetos remotos.
♦ Set – Indica as colunas que serão modificadas.
♦ <subquery> – Indica uma query a ser usada para obtenção dos valores a serem atribuídos às colunas. Esse
comando Select deve retornar exatamente uma linha.
Capítulo 11
GUIA DE REFERÊNCIA DO SQL*PLUS
Neste capítulo, apresentaremos a sintaxe e pequenos comentários sobre os comandos do SQL*Plus. Não serão
reapresentados os exemplos.
Para facilidade de pesquisa, os comandos serão apresentados em ordem alfabética.
SOBRE O SQL*PLUS
ABRINDO UMA SESSÃO
O SQL*Plus é uma ferramenta que nos possibilita a interação com o banco de dados Oracle. Funciona como um
intermediário entre o usuário e o banco de dados.
Ao acionarmos a execução da ferramenta (botão Iniciar, pasta Programas, pasta Oracle – OraHome9i, pasta Appli-
cation Development), será apresentado um diálogo de login a fim de que possamos fornecer o nome do usuário e
senha para estabelecer conexão com o banco de dados. Nosso usuário-padrão para testes será DESENV (criado no
item Criando um Usuário Padrão do Capítulo 1).
A terceira informação deste diálogo corresponde à string de conexão (String do Host), ou seja, um parâmetro que
indica a que máquina e a que banco de dados desejamos estabelecer conexão. Se você estiver estabelecendo conexão
com um banco de dados instalado na mesma máquina (local), este valor não precisa ser preenchido; caso isto não
aconteça, consulte seu DBA para obter o nome adequado para preenchimento. Em todo este livro estaremos
usando o Personal Oracle9i (versão 9.0.1.1.1) para realização dos testes. A instalação deste produto se encontra
descrita no Capítulo 1 (Instalando o Personal Oracle9i no Windows 2000).
Quando a conexão é estabelecida, obtemos permissão do banco de dados para enviar comandos e receber respostas.
O intervalo de tempo entre o momento em que uma conexão é estabelecida até o momento em que ela é encerrada
é chamado de Sessão.
O SQL BUFFER
No SQL*Plus, a tela apresentada mostra uma linha com o texto SQL> à esquerda do vídeo, indicando que poderemos
digitar o comando que desejamos executar.
Ao digitarmos um comando na linha de prompt (SQL>), a ferramenta identifica este comando e verifica se se trata de
um comando de SQL. Em caso afirmativo, o coloca numa área de memória chamada SQL Buffer (ver Figura 11.03).
Quando terminamos a digitação, esta área de memória, que só pode conter 1(um) comando de SQL (ou um bloco
de PL/SQL), é transmitida para o banco de dados. Quando o banco de dados retorna o resultado, o SQL*Plus recebe
a informação, a formata e apresenta.
OS COMANDOS DO SQL*PLUS
No esquema da Figura 11.03, observamos que nem todos os comandos digitados são colocados na área de Buffer
para transmissão ao banco de dados. Isto ocorre porque o SQL*Plus também possui comandos próprios com a
finalidade de:
♦ Editar o comando SQL armazenado no Buffer.
♦ Formatar os resultados retornados pelo banco de dados.
♦ Armazenar os comandos de SQL para disco e recuperá-los para execução.
♦ Modificar o modo de trabalhar do SQL*Plus.
♦ Enviar mensagens e receber respostas de outros usuários.
♦ Listar a definição de qualquer tabela.
♦ Fazer acesso e copiar dados entre banco de dados.
DIGITANDO NO SQL*PLUS
A digitação na linha de prompt pode ser contínua (uma única linha) ou pode ocupar mais de uma linha, bastando
que teclemos Enter para que seja mostrada uma numeração seqüencial no lado esquerdo do vídeo, indicando que
o SQL*Plus considerou continuação do estado de digitação.
Para encerrarmos a digitação de um comando, temos quatro opções, cada uma delas indicando ações diferentes.
A primeira opção é digitar um ponto-e-vírgula (;) seguido de Enter, indicando fim de digitação e ao mesmo tempo
solicitação de execução.
Outra opção que causa o mesmo resultado é pressionarmos a tecla Enter e na nova linha digitarmos a barra ( / ),
como primeiro caracter da linha, seguida de Enter. Novamente, o SQL*Plus considerará fim de digitação e dará
início à execução do comando.
Se não desejarmos que o comando seja executado, podemos teclar Enter duas vezes seguidas (deixando uma linha
vazia) ou podemos teclar Enter uma vez, colocar um ponto (.) como primeiro caracter da nova linha e pressionar
Enter novamente. Nestas duas situações, o SQL*Plus apenas registrará o comando no SQL Buffer, mas não o executará.
Havendo um comando de SQL armazenado no SQL Buffer, poderemos alterá-lo, listá-lo ou substituí-lo com alguns
comandos básicos, próprios do SQL*Plus.
♦ S[ilent] – Indica que a execução será em batch. Não é aberta janela para o SQL*Plus.
♦ M[arkup] – Este comando indica que a saída (ou resposta) da consulta realizada deve ser preparada em formato
HTML. Pode ser útil quando usada junto com Silent para a geração em batch de um resultado HTML. Este
comando possui alguns argumentos, que veremos a seguir:
♦ HTML – este argumento é obrigatório e indica se a saída gerada será ou não em formato HTML.
♦ HEAD – com este argumento podemos especificar textos para a tag HEAD. Por default text tem o conteúdo
<TITLE>SQL*Plus Report</TITLE>. Se o texto contiver espaços, ele deve ser informado entre aspas. O SQL*Plus
não faz validação sintática do HTML.
♦ BODY – com este argumento podemos especificar textos para a tag BODY. Por default text não tem conteúdo. Se
o texto contiver espaços, ele deve ser informado entre aspas. O SQL*Plus não faz validação sintática do HTML.
♦ TABLE – com este argumento podemos especificar textos para a tag TABLE. Por default text tem o conteúdo
WIDTH=90% BORDER=1 (são argumentos da tag TABLE). Se o texto contiver espaços, ele deve ser informado
entre aspas. O SQL*Plus não faz validação sintática do HTML.
♦ ENTMAP – com este argumento indicamos se o SQL*Plus deve ou não substituir os caracteres <, >, “ e &
respectivamente por <, >, " e &.
♦ SPOOL – com este argumento indicamos se o SQL*Plus deve ou não gerar as tags <HTML>, <BODY>, </
HTML> e </BODY> a serem adicionadas no início e fim de cada arquivo gerado pelo comando SPOOL (visto
posteriormente).
♦ PREFORMAT – com este argumento indicamos se o SQL*Plus deve utilizar a tag <PRE> ou a tag <TABLE>. O
default para este argumento é OFF, o que indica que a tag <TABLE> será usada.
Alguns comandos do SQL*Plus adquirem significação diferente quando usamos o argumento MARKUP:
♦ PAGESIZE passa a indicar o número de linhas da tabela HTML. Uma linha de tabela pode conter múltiplas linhas.
♦ LINESIZE pode ter efeito se WRAPPING estiver habilitado ou para dados muito longos.
♦ O conteúdo de TTITLE e BTITLE podem ser alinhados para três posições de linha: Left, Center ou Right, sendo que
o tamanho máximo da linha é de 90% da janela do browser. O resultado pode não seguir o alinhamento esperado,
uma vez que o texto é manuseado por um browser.
♦ Se usarmos um título no relatório, o SQL*Plus iniciará uma nova tabela HTML a cada conjunto de linhas que
aparecer após o título. O browser poderá gerar tamanhos de colunas diferentes para cada tabela, de acordo
com seu conteúdo.
♦ SET COLSEP e RECSEP somente produz efeito quando usamos PREFORMAT ON.
♦ /Nolog – indica que o SQL*Plus deve ser iniciado, porém sem conexão com o banco de dados.
♦ username ou / – identifica o usuário, password e string de conexão ou a / (barra), que estabelece conexão no
usuário default (Ops$<username do sistema operacional>) ou com o usuário determinado no arquivo de
inicialização do banco de dados init.ora.
♦ As {Sysdba|Sysoper} – indica que a conexão ao banco de dados será feita com um usuário privilegiado. O uso de
AS SYSDBA ou AS SYSOPER não dá os privilégios ao usuário. Este privilégio deve ter sido fornecido anteriormente.
É utilizado por DBAs ou operadores para inicializar o banco de dados ou fechá-lo.
♦ @<arquivo> – Onde informamos o nome do script que desejamos executar. Se o arquivo não estiver local, todo
o caminho (diretório) deve ser informado. Adicionalmente, podemos passar os parâmetros necessários à execução
do script (veja o comando start e @). Nesta versão o nome do arquivo pode ser informado usando a sintaxe URI,
ou seja, o arquivo pode estar em um servidor Web (apenas em plataformas Windows, por enquanto).
COMANDOS
@ E @@
Veja o comando Start / @ / @@ mais adiante.
/
Quando digitamos uma barra na linha de prompt e em seguida teclamos Enter, o SQL*Plus envia o conteúdo do
SQL Buffer para execução pelo banco de dados, porém não apresenta o texto enviado, isto é, não lista o SQL Buffer.
Esta é a diferença entre o comando Run e a barra.
ACCEPT
Este comando cria uma variável de substituição e, opcionalmente, formata uma mensagem para o usuário.
Quando criamos a variável de substituição com este comando, ela pode ser de tipo Number, Char ou Date, havendo
crítica se o valor informado não for compatível com o tipo definido. Os formatos válidos para uso são os mesmos
do comando Col e ainda são suportados os formatos SQL de data quando o tipo da variável for Date. Podemos
informar um valor default (para o caso de o usuário não fornecer nenhum), apresentar uma mensagem ou não
(com as opcões Prompt/Noprompt) e esconder o valor digitado pelo usuário (Hide).
APPEND
Com este comando, podemos adicionar um trecho de texto ao fim da linha corrente. Sua sintaxe é apresentada em
11.04 a seguir.
O texto é adicionado imediatamente após o texto existente na linha corrente, mesmo havendo um branco entre o
comando e o texto. Após a execução do comando, o SQL*Plus apresenta a linha modificada para verificação.
Se desejarmos incluir um branco (ou mais) entre o texto antigo e o novo, devemos digitar o comando append, dois
brancos (ou mais) e o texto a ser adicionado.
Tente usar este comando para incluir um ponto-e-vírgula ao final de alguma linha. Isto não é possível, uma vez
que o ponto-e-vírgula não faz parte da sintaxe do SQL e tem uma conotação especial para o SQL*Plus, pois indica
término de digitação e solicitação de execução. Se, porém, o trecho que estivermos digitando não for de SQL, e sim
de PL/SQL, teremos necessidade de incluir o ponto-e-vírgula no texto. Para que isto seja possível, devemos repetir
a ação realizada com o branco, ou seja, para a inclusão de um ponto-e-vírgula ao fim do texto, devemos digitar dois
ponto-e-vírgulas seguidos.
ARCHIVE LOG
Este comando tem a finalidade de manusear com arquivos online redo log do banco de dados. É um comando de
uso exclusivo de DBAs e não será estudado neste material.
ATTRIBUTE
Este comando especifica atributos de apresentação (display) para um determinado atributo de uma coluna Object Type.
Os formatos válidos são os mesmos do comando Column.
BREAK
O comando Break define quais são os elementos de quebra e que ação deve ser tomada quando ocorrer a mudança
de valor (quebra) em cada um deles. Este comando não ordena os dados recebidos do banco de dados. Para que o
resultado seja adequado, no comando Select devemos incluir a cláusula Order By com as mesmas colunas nas
quais desejamos que o SQL*Plus avalie quebra.
Só podemos ter ativo um comando Break em cada sessão. Um segundo comando desabilita o primeiro; desta forma, o
último comando Break que executarmos passa a determinar as quebras válidas. Não é cumulativo.
O comando Break executado sem parâmetros apresenta a situação de quebra em vigor.
BTITLE
Veja TTitle.
CHANGE
Este comando de edição tem o objetivo de substituir parte do texto (ou todo) por outro. O separador (<sepchar>)
pode ser qualquer caracter especial (não alfanumérico) que não esteja presente no texto <old> nem no texto <new>.
Observe que os separadores apresentados são iguais. Podemos utilizar qualquer caracter especial não presente nos
textos, porém dentro de um comando só podemos usar um deles.
Este comando efetua apenas uma substituição por linha, isto é, a linha é analisada da esquerda para a direita e
quando for encontrado um trecho de texto igual ao texto <old> é feita a substituição pelo texto <new> e o comando
é encerrado. Se desejarmos repetir a substituição para outro trecho da linha, devemos digitar o comando novamente.
Para que não precisemos digitar repetidamente o mesmo comando, podemos “pintá-lo” com o botão esquerdo do mouse (pressionar o mouse sobre
o primeiro caracter que desejamos copiar, mantê-lo pressionado e arrastá-lo até o último caracter desejado) e sem soltar o botão esquerdo clicar o
botão direito do mouse. Esta ação fará com que o trecho pintado seja copiado para a linha de prompt. Experimente.
CLEAR
O comando Clear tem por finalidade limpar o valor atual da opção especificada.
COLUMN
Podemos executar este comando sem coluna identificada para que ele apresente a formatação existente em vigor
no SQL*Plus. Se o executarmos informando um nome de coluna ou expressão, ele apresentará a formatação em
vigor para o elemento específico.
Cada uma das opções do comando afetará uma característica da coluna ou expressão, de acordo com a lista a seguir:
♦ Alias – Associa um alias para a coluna (ou expressão), que pode ser utilizado em um comando Break, Compute
ou até mesmo em outro comando Column.
♦ Clear – Desfaz os formatos especificados para a coluna.
♦ Entmap – Quando utilizamos HTML no relatório gerado pelo SQL*Plus, os símbolos <, >, “ e & podem ser substituídos
pelos valores <, >, " e &. A conversão ou não do conteúdo das colunas (ou expressões) que
incluímos em nosso comando Select é determinado pelo valor do parâmetro Entmap dentro do comando Markup
Html. Pode acontecer, porém, de desejarmos que para uma determinada coluna o padrão seja diferente. Neste caso
especificamos o parâmetro Entmap diretamente no comando Column para a coluna cujo padrão desejamos alterar.
♦ Fold (After ou Before) – Associa um carriage return antes (before) ou depois (after) do cabeçalho e coluna em
cada linha. Isto força uma quebra na linha na posição em que o carriage return é colocado. O SQL*Plus não
adiciona um carriage return extra ao final da linha listada.
♦ Format – Determina um formato de edição para as colunas numéricas e um tamanho de coluna para as demais
colunas. O <formato> não pode ser substituído por uma variável, deve ser um valor constante e pode ser composto
pelos caracteres { 9 0 , . $ L G D C B MI S PR V EEEE RN rn DATE }, com a mesma funcionalidade dos formatos
numéricos da função To_Char. Para os formatos alfanuméricos ou de data, podemos especificar An, onde n
indica a largura da coluna.
♦ Heading – Determina o cabeçalho da coluna.
♦ Justify – Determina o alinhamento para o cabeçalho da coluna. Se não especificado, o alinhamento-padrão para
colunas numéricas é à direita e para as alfanuméricas, à esquerda.
♦ Like – Copia os atributos de outra coluna definida anteriormente. A opção Like não recobre as características já
definidas para a coluna; só acrescenta aqueles não definidos.
♦ NewLine – Quebra a linha antes de o valor ser apresentado. Tem o mesmo efeito de Fold_Before.
♦ New_Value – Atribui ao parâmetro <variável> o novo valor desta coluna toda vez que houver mudança de valor.
♦ Print/NoPrint – Apresenta (Print) ou não (NoPrint) a coluna na listagem resultado (cabeçalho e todos os valores).
♦ Null – Indica o <texto> a ser apresentado quando o conteúdo da coluna for indeterminado (Null).
♦ Old_Value – Atribui ao parâmetro <variável> o valor anterior desta coluna toda vez que houver mudança de valor.
♦ On/Off – Habilita ou desabilita os atributos de apresentação para a coluna.
♦ Wrapped – Determina como será feito o controle de quebra quando o conteúdo da coluna for maior que a
largura especificada para ela. A opção Wrapped indica que o texto será cortado na largura especificada e continuará
na próxima linha. Word_wrapped indica que o texto será cortado em final de palavra. Truncated indica que o
texto apresentado será apenas aquele que couber na primeira linha.
O comando COL é muito utilizado dentro de arquivos de comandos. Após a execução do comando desejado,
desfazemos a formatação de cada coluna, retornando aos valores padrões.
COMPUTE
O comando Compute efetua um cálculo em relação a um elemento de quebra. Se desejarmos efetuar um cálculo
quando houver quebra da coluna cd_depto, esta coluna deve estar referenciada no comando Break. Se desejarmos
um determinado cálculo ao término do relatório, a palavra Report deve estar mencionada no comando Break, e
assim por diante. O cálculo só é efetuado em relação a um elemento presente no comando de quebra.
Podemos especificar um ou mais cálculos por elemento e, ainda, especificar um label que identifique o tipo de
cálculo efetuado.
CONNECT/DISCONNECT
Permite a troca de sessão do SQL*Plus com o banco de dados ou encerra uma sessão com o banco de dados. A
opção “As Sysdba/Sysoper” somente é aplicável a DBAs. Esta opção permitirá o uso dos comandos administrativos
do banco de dados (Startup, Shutdown, Recover, etc.).
COPY
Copia os dados de uma query para uma tabela em um banco de dados local ou remoto.
DEFINE
Este comando especifica uma variável de substituição e associa um valor alfanumérico a ela. Quando este comando
é executado sem parâmetros, o nome e valor de todas as variáveis de substituição são apresentados. Quando
informamos o nome de uma variável, apenas seu valor é apresentado.
O valor desta variável permanece no sistema até que modifiquemos seu valor através de outro comando Define,
um comando Accept ou Col com New_Value/Old_Value ou, ainda, façamos a destruição da variável com o comando
Undefine ou encerremos o SQL*Plus.
DEL
Exclui uma determinada linha da área do SQL Buffer. Caso não sejam informados parâmetros que indiquem a
linha a ser removida, será excluída a linha corrente.
DESCRIBE
Esse comando tem a finalidade de apresentar a definição de um objeto criado na base de dados Oracle. O objeto
pode ser uma table, view, synonym, function, procedure ou package.
A Sintaxe 11.15 indica que podemos obter informações de objetos pertencentes ao usuário que estabeleceu a
conexão, objetos de outros usuários (informando-se <schema>) ou objetos existentes em outros bancos de dados
(informando-se <database_link_name>).
Por default, o banco de dados procura o objeto no próprio schema do usuário conectado.
DISCONNECT
Veja Connect/Disconnect anteriormente.
EDIT
Este comando aciona um editor registrado no Windows e passa como parâmetro o nome de um arquivo ou o texto
presente no SQL Buffer, de acordo com o comando executado.
Quando omitimos o nome do arquivo a ser editado, o SQL*Plus aciona o editor do sistema passando como parâmetro
o texto do SQL Buffer.
Quando desejamos editar um determinado arquivo, seu nome pode ser informado com ou sem a extensão. A
extensão default é SQL.
O editor em uso pode ser obtido através da variável de sistema chamada _EDITOR. Para sabermos seu valor podemos
digitar na linha de prompt DEFINE _EDITOR ou apenas DEFINE. No primeiro caso, o SQL*Plus nos mostrará o valor
apenas da variável solicitada. No segundo caso, serão apresentadas todas as variáveis de sistema existentes até o momento.
O editor-padrão no Windows é o bloco de notas (Notepad). Antes de substituirmos o editor-padrão por outro de
nossa escolha, devemos nos lembrar que o editor escolhido deve aceitar um parâmetro correspondente ao arquivo
a ser editado.
O diretório do Windows onde serão gravados (ou lidos) os arquivos de trabalho pode ser controlado por nós
(default é C:\<Oracle Home>\BIN). Se criarmos um atalho para o SQL*Plus (o executável se encontra na pasta
C:\<Oracle Home>\Bin e se chama SqlPlusw.exe) basta que modifiquemos o diretório “Iniciar em” da pasta “Atalho”
(ver Figura 11.06), obtida ao pressionarmos o botão direito do mouse sobre o ícone do SQL*Plus e escolhermos a
opção Propriedades.
Podemos, também, modificar o diretório de trabalho default do atalho presente na pasta Oracle para Windows da
seguinte forma: clicar o botão Iniciar (do Windows), opção Configurações, opção Barra de Tarefas, pasta Programas do
menu Iniciar, clicar no botão Avançado, expandir o nó Programas, expandir o nó Oracle – OraHome9i e fazer um duplo
clique no ícone da pasta Application Development, pressionar o botão direito do mouse sobre o ícone do SQL*Plus e
escolher a opção Propriedades. Novamente, será mostrada a tela de propriedades e, na pasta Atalho, poderemos alterar
o diretório “Iniciar em” (ver Figura 11.06). Para que a modificação tenha efeito, o SQL*Plus deve ser reiniciado.
Com esta modificação, qualquer arquivo a ser lido ou gravado pelo SQL*Plus o será no novo diretório default.
Se desejarmos efetuar a leitura ou gravação de arquivos em outros diretórios, podemos incluir o caminho onde se
encontra o arquivo ao usarmos o comando EDIT.
EXECUTE
Veja o tópico Password, Execute, Host e Remark mais adiante.
EXIT/QUIT
Os comandos Exit e Quit são equivalentes e têm a finalidade de encerrar a sessão do SQL*Plus. Isto significa que a
conexão com o banco de dados e simultaneamente o próprio programa serão encerrados.
De acordo com a Sintaxe 11.17, observamos que podemos determinar como deve ser considerado o término do
programa, isto é, com sucesso ou não e com efetivação ou não das modificações realizadas no banco de dados.
Quando digitamos apenas Quit (ou apenas Exit) ficam valendo as opções sublinhadas. O término do programa é
considerado normal e a conexão se encerra também normalmente com Commit.
As demais opções indicam a ocorrência de uma falha na execução do SQL*Plus; isto pode ser útil quando executamos
o SQL*Plus dentro de um arquivo de comandos para o sistema operacional em que devemos determinar como foi
o término do programa anterior para que o próximo comando do arquivo seja executado ou não.
Podemos informar um valor numérico fixo, o valor de uma variável de sistema ou o valor de uma variável Bind
(variável para troca de informações com um programa PL/SQL).
A utilização destes parâmetros pode ser útil quando executamos o SQL*Plus em um arquivo de comandos. Desta
forma, poderemos transferir o valor para o arquivo de comandos a fim de controlar a execução do comando seguinte.
A conexão com o banco pode ser encerrada independentemente do tipo de término do SQL*Plus (Commit ou Rollback).
A execução de um comando Commit indica ao banco de dados que todos os comandos que modificaram informações do banco de dados devem
ser considerados válidos e as alterações devem ser efetivadas. Já um comando Rollback indica que as modificações devem ser desconsideradas.
GET
A recuperação de um texto para o SQL Buffer é feita por meio do comando Get. Todo o conteúdo do arquivo é
copiado para o SQL Buffer; portanto, este arquivo deve conter apenas um comando.
A extensão só precisa ser mencionada se for diferente do padrão (SQL). O padrão pode ser mudado com o uso da
variável de sistema Suffix.
Todo o conteúdo do arquivo é carregado para o SQL Buffer; desta forma, se o arquivo contiver mais de um comando,
ocorre um erro na execução, porque o SQL*Plus envia todo o buffer para o banco de dados como se fosse um único
comando e, portanto, não reconhecido pelo banco de dados.
Caso o nome do arquivo seja composto das palavras List ou File, seu nome deve ser mencionado entre aspas.
Por default, o conteúdo do arquivo é listado após ser carregado para o SQL Buffer. Se esta ação não for desejada,
devemos usar a opção Nolist.
HELP
Este comando aciona o mecanismo de Help do SQL*Plus mostrando a sintaxe desejada. Podemos usar HELP IN-
DEX (ou HELP TOPICS) para que seja mostrada a lista de tópicos disponíveis. A apresentação da sintaxe depende
de o DBA haver instalado e preenchido a tabela Help no banco de dados.
HOST
Veja os tópicos Password, Execute, Host e Remark mais adiante.
INPUT
Este comando adiciona uma ou mais linhas após a linha corrente (no SQL Buffer). Este comando difere do comando
Append uma vez que pode voltar ao estado de digitação, abrindo uma nova linha para digitação imediatamente
após à linha corrente.
Quando digitamos o comando juntamente com um texto, é criada uma nova linha imediatamente após a linha
corrente, sendo seu conteúdo o texto informado. Quando digitamos apenas o comando, o SQL*Plus volta ao
estado de digitação, apresentando uma linha vazia com a numeração à esquerda seqüencial à da linha corrente,
anexada da letra i.
Para concluirmos a digitação desta(s) linha(s), devemos deixar uma linha vazia (teclando <Enter> duas vezes) ou
devemos incluir um ponto como primeiro e único caracter da última linha.
LIST
Este comando tem a finalidade de listar uma ou mais linhas do SQL Buffer. A última linha listada pelo comando se
tornará a linha corrente.
A Sintaxe 11.21 indica como podemos listar parte do SQL Buffer e transformar em linha corrente quaisquer das
linhas digitadas.
PAUSE
Este comando envia uma linha em branco ou uma linha com texto para a tela do usuário e aguarda que este tecle
Enter para que o script tenha prosseguimento.
PRINT
Este comando apresenta o valor de uma variável Bind ou de todas as variáveis deste tipo declaradas (se for executado
sem argumentos).
PROMPT
Envia uma mensagem ou uma linha em branco para a tela do usuário. Pode ser útil para scripts longos, a fim de
informar o passo executado.
QUIT
Veja o tópico Exit/Quit anteriormente.
RECOVER
Este comando tem a finalidade de iniciar uma recuperação física do banco de dados, tablespaces ou datafiles. É um
comando de uso exclusivo de DBAs e não será estudado neste material.
REMARK
Veja o tópico Password, Execute, Host e Remark anteriormente.
REPHEADER/REPFOOTER
Os comandos RepHeader e RepFooter têm a finalidade de formatar um título geral para o início ou fim do relatório.
Somente serão apresentados na primeira página (RepHeader) ou na última página do relatório (RepFooter).
A utilização de um dos comandos sem parâmetros faz com que o SQL*Plus liste o header ou footer em vigor.
♦ Col – Estabelece posicionamento na coluna <número> da linha de impressão atual (avança ou recua).
♦ Skip – Pula para o início da próxima linha <número> vezes. Se o parâmetro <número> for omitido, 1 vez é
assumido. Se o parâmetro <número> possuir o valor 0, fará com que haja o posicionamento na linha atual.
♦ Tab – Pula <número> de colunas para a frente ou para trás (se o valor for negativo).
♦ Left/Center/Right – Estabelece o posicionamento dos textos que o seguem à esquerda, centralizados ou à direita,
respectivamente. Os textos são tratados como um único elemento.
♦ Bold – Realiza impressão em negrito. No vídeo a linha será repetida três vezes.
♦ Format – Utiliza os mesmos formatos válidos para o comando Column. A palavra Format não pode ser abreviada.
♦ <texto> – Corresponde a uma única palavra ou a um conjunto de palavras (se entre aspas).
♦ <variável> – Corresponde a uma variável de sistema criada pelo usuário.
♦ Sql.Pno – Corresponde a uma variável de sistema que indica a página corrente.
♦ Sql.Lno – Corresponde a uma variável de sistema que indica a linha corrente.
♦ Sql.Release – Corresponde a uma variável de sistema que indica a release do Oracle.
♦ Sql.Sqlcode – Corresponde a uma variável de sistema que indica o último código de erro ocorrido.
♦ Sql.User – Corresponde a uma variável de sistema que indica o usuário da sessão.
♦ On/Off – Torna o header (ou footer) habilitado ou desabilitado sem afetar sua definição.
O comando RepHeader (assim como os demais comandos do SQL*Plus) pode ocupar diversas linhas. Será considerado
um único comando se incluirmos o símbolo – (hífen) ao fim de cada linha para indicar continuação de comando
(para o SQL*Plus).
RUN
Este comando envia o conteúdo do SQL Buffer para o banco de dados e ao mesmo tempo apresenta no vídeo as
linhas enviadas (lista o SQL Buffer).
SAVE
Este comando salva o conteúdo do SQL Buffer em um arquivo do sistema operacional.
A sintaxe acima permite que o conteúdo do SQL buffer seja salvo em um arquivo novo (default), substitua um
arquivo existente ou seja adicionado a um arquivo existente.
A extensão do arquivo é fornecida por .<ext> . Caso seja omitida será usado SQL como extensão padrão. O padrão
pode ser mudado com o uso da variável de sistema Suffix.
Se desejarmos efetuar a salva recobrindo o que está em disco, complementamos o comando com a opção Replace,
indicando que desejamos a substituição do arquivo.
SET
Este comando, que pode ser incluído em um script, modifica o valor de uma das variáveis de sistema.
A Tabela 11.01 a seguir apresenta a lista e significados das variáveis de sistema do SQL*Plus.
Variável Descrição
APPI[NFO]{ON|OFF|text} Indica que os comandos executados com @, @@ e Start devem ser registrados pelo pacote
DBMS_APPLICATION_INFO a fim de terem sua execução monitorada pelo DBA. O valor default para texto é
“SQL*Plus”.
ARRAY[SIZE] {15|n} Determina o número de linhas que o SQL*Plus deve obter do banco de dados a cada leitura (Fetch).
AUTO[COMMIT] {OFF | ON | IMM[EDIATE] | n} Indica se o ORACLE efetiva as modificações pendentes para o database. A opção ON faz com que seja
executado um COMMIT após cada comando SQL ou bloco PL/SQL. A opção IMM funciona de forma
semelhante a ON. A opção n indica que o comando COMMIT deve ser executado após n comandos de
atualização bem-sucedidos.
AUTOP[RINT] {OFF|ON} Apresenta, automaticamente, o valor das variáveis BIND após a execução de um PL/SQL.
AUTORECOVERY [ON | OFF] Esta opção pode ser utilizada pelo DBA durante um processo de recuperação do banco de dados.
AUTOT[RACE] {OFF|ON|TRACE[ONLY]} Apresenta um relatório sobre a execução dos comandos de SQL DML (Select, Insert, Update ou Delete) bem-
[EXP[LAIN]] [STAT[ISTICS]] sucedidos. O relatório pode incluir a apresentação de estatísticas e o caminho de execução (Explain). A opção
TraceOnly apresenta o relatório sem apresentar os dados da Query. Se Statistics for solicitado a execução do
comando é realizada, porém sem a apresentação dos resultados. Para que a opção Explain possa ser
executada deve ser criada a tabela Plan_Table para a geração do caminho de acesso.
BLO[CKTERMINATOR] { . |c} Determina um caracter não-alfanumérico a ser usado para indicar fim de blocos PL/SQL.
CMDS[EP] {;|c|OFF|ON} Determina um caracter não alfanumérico usado para separar múltiplos comandos de SQL*Plus digitados na
mesma linha. Se usarmos a opção ON, o caracter default será ponto-e-vírgula ( ; ).
COLSEP {_|text} Determina o texto a ser impresso entre colunas selecionadas (Select). Se o valor tiver brancos ou caracteres
de pontuação, deve ser informado entre aspas simples. O valor default é um único espaço em branco.
COM[PATIBILITY] {V7|V8|NATIVE} Especifica a versão do banco de dados com a qual estamos nos conectando.
continua
continuação
Variável Descrição
CON[CAT] { . |c|OFF|ON} Determina o caracter para terminar uma variável de substituição se desejarmos seguir imediatamente a
variável com um caracter que o SQL*Plus deva interpretar como valor, e não como parte do nome da
variável de substituição.
COPYC[OMMIT] {0|n} Controla o número de linhas após as quais o comando COPY deve efetivar (Commit) as linhas para o banco
de dados. Se optarmos por 0 (zero), o commit só será executado ao final da cópia.
COPYTYPECHECK {OFF|ON} Determina que a verificação de compatibilidade de tipos de dados deve ser suprimida durante uma inclusão
ou adicionamento de linhas para tabelas usando-se o comando COPY. Esta é uma facilidade para DB2, que
necessita que um CHAR seja copiado para um DB2 DATE.
DEF[INE] {&|c|OFF|ON} Determina o caracter a ser usado para prefixar variáveis de substituição. ON ou OFF controla se o SQL*Plus
irá ou não pesquisar no texto a procura de variáveis de substituição para substituí-las por valores. Ao
usarmos ON, o valor atribuído é &. Esta opção tem precedência sobre SCAN.
DESCRIBE [DEPTH{1|n|ALL}] Determina o nível de profundidade para o qual desejamos recursivamente descrever um objeto. Os valores
[LINENUM {ON|OFF}] [INDENT{ON|OFF}] válidos variam de 1 a 50. Aplicável a partir do SQL*Plus 8.1.5.
ECHO {OFF|ON} Controla quando o comando Start lista cada comando presente no arquivo de comandos quando realiza a
sua execução.
EDITF[ILE] file_name[.ext] Determina o nome default para o comando Edit (no Windows, o nome default é Afiedt.buf). Podemos incluir
caminho e/ou extensão para o arquivo.
EMB[EDDED] {OFF|ON} Controla onde cada nova página do relatório começa. OFF força cada relatório a começar no topo de uma
nova página. ON permite que um relatório inicie em qualquer parte da página.
ESC[APE] { \ |c|OFF|ON} Define qual o caracter a ser usado como escape. ON altera o valor <c> para o default “\”. Este caracter é
utilizado antes do caracter indicado para variáveis de substituição para indicar que o texto a seguir deve ser
considerado normal e não uma substituição.
FEED[BACK] { 6 | n } Mostra o número de registros retornados por uma query se forem selecionados mais de n registros (default 6).
FEED[BACK] { ON | OFF } Determina o estado da variável FEEDBACK (default ON).
FLAGGER {OFF|ENTRY|INTERMED[IATE]|FULL} Verifica sintaticamente o comando SQL informado com o padrão ANSI/ISO SQL92. Este comando pode ser
executado mesmo que não estejamos conectados ao banco de dados. Ficará acionado através de todas as
conexões que estabelecermos, até que seja desabilitado ou que encerremos (EXIT) o SQL*Plus.
FLUSH {ON | OFF} Indica se as respostas (outputs) e prompts dos comandos devem ou não ser mostrados no vídeo. Usado para
execução em batch.
HEA[DING] {ON | OFF} Determina se os cabeçalhos de coluna devem ser apresentados (default ON).
HEADSEP {“|” | ON | OFF} Determina qual o caracter indicador de quebra de linha para o texto dos cabeçalhos de coluna.
INSTANCE [instance_path | LOCAL] Permite a modificação da instância para a sessão. Somente podemos definir uma nova instância se não
estivermos conectados a uma determinada instância no momento. Podemos utilizar qualquer identificador
do Oracle Net como instance_path.
LIN[ESIZE] {80 | n} Indica o número de caracteres por linha (default 80).
LOBOF[FSET] { n | 1} Determina a posição inicial para apresentação de informações para colunas Clob e Nclob.
LOGSOURCE [pathname] Especifica a localização dos arquivos de log arquivados. Este comando pode ser utilizado por DBAs durante
um processo de recuperação.
LONG {80|n} Determina a largura máxima em bytes para apresentação de valores LONG, CLOB e NCLOB e para cópia de
valores LONG. O valor máximo é de 2GB.
LONGC[HUNKSIZE] {80|n} Determina o tamanho (em bytes) dos incrementos nos quais o SQL*Plus recupera um valor LONG, CLOB ou
NCLOB. Quando obtemos valores CLOB ou NCLOB podemos desejar obter os valores em pedaços em vez do
tamanho total em função de restrições de memória.
continua
continuação
Variável Descrição
MARK[UP] HTML [ON | OFF] [HEAD text] Indica que o relatório a ser gerado a partir deste momento o será em formato HTML. Veja o tópico
[BODY text] [TABLE text] [ENTMAP {ON | OFF}] Acionando o SQL*Plus em batch para verificar o detalhamento desta sintaxe.
[SPOOL {ON | OFF}] [PRE[FORMAT] {ON | OFF}]
NEWPAGE { 1 | n | none} Determina o número de linhas em branco a serem impressas entre o início da página e o primeiro título.
Zero (0) coloca formfeed no topo.
NULL {“” | <texto>} Indica qual o texto a ser apresentado na coluna quando seu conteúdo, em uma determinada linha, for
indeterminado (Null).
NUMFORMAT {“” | <formato>} Determina o formato default para apresentação das colunas numéricas.
NUM[WIDTH] {10 | n} Indica a largura default para apresentação de números.
PAGES[ IZE ] {24 | n} Indica o número de linhas para cada página do relatório (default 24).
PAU[ SE ] <mensagem> Mostra a mensagem após o preenchimento da página de tela.
PAU[ SE ] ON | OFF Indica se o mecanismo de pausa após o preenchimento de uma página deve ser acionado (default OFF).
RECSEP {WR[APPED]|EA[CH]|OFF} Mostra ou imprime separadores de registros. A variável RECSEPCHAR define o caracter a ser apresentado
para separação de registros. O valor default é um branco. Esta variável indica quando o SQL*Plus deve
efetuar a separação dos registros. Se escolhermos WRAPPED, o SQL*Plus imprime um separador somente
após as linhas quebradas. Se escolhermos EACH, a impressão se dará a cada linha.
RECSEPCHAR {_|c} Define o caracter separador de registros. O default é um branco.
SERVEROUT[PUT] {OFF|ON} [SIZE n] Controla a apresentação das informações geradas através do pacote DBMS_OUTPUT em stored procedures
[FOR[MAT] {WRA[PPED] ou blocos de PL/SQL. O parâmetro Size determina o número de bytes que podem ser buferizados dentro
| WOR[D_WRAPPED] | TRU[NCATED]} ] do Oracle Server (o valor deve variar entre 2000 e 1.000.000). O default é 2000. Quando WRAPPED é
habilitado a quebra de linha ocorre a cada LINESIZE caracteres. Quando WORD_WRAPPED é utilizado a
quebra de linhas ocorre a cada LINESIZE caracteres, porém em final de palavra. Quando TRUNCATED é
habilitado, cada linha é truncada em LINESIZE caracteres.
SHIFT[INOUT] {VIS[IBLE]|INV[ISIBLE]} Permite o alinhamento correto para terminais que mostrem caracteres shift junto com os dados (por
exemplo IBM 3270).
SHOW[MODE] {OFF|ON} Indica se o SQL*Plus mostra o valor antigo e o novo de uma variável de sistema quando esta é modificada
com o comando SET.
SPACE {1 | n} Indica o número de espaços entre as colunas do relatório. O valor máximo é 10 (default 1).
SQLBL[ANKLINES] {ON|OFF} Indica se desejamos preservar ou não os brancos dentro de um comando de SQL.
SQLC[ASE] {MIX[ED] | LO[WER] | UP[PER]} Converte os textos dos comandos SQL e PL/SQL de acordo com a opção escolhida, inclusive os textos
constantes (entre plics). (default MIXED)
SQLCO[NTINUE] { > |text} Determina o caracter que o SQL*Plus mostra como prompt se quebrarmos uma linha de comando do
SQL*Plus usando o hífen ( - ).
SQLN[UMBER] {OFF|ON} Determina o prompt para a segunda (e subseqüentes) linha quando estamos efetuando a digitação de
comandos SQL ou PL/SQL. ON indica que o prompt deve ser uma numeração seqüencial. OFF indica que o
valor deve ser SQLPROMPT.
SQLPLUSCOMPAT[IBILITY] {x.y[.z]} Determina a compatibilidade do SQL*Plus com relação ao comando VARIABLE (por enquanto somente este
comando é afetado). O parâmetro x representa version, o parâmetro y representa release e o parâmetro z
representa update. Se colocarmos um valor inferior a 9.0.0 (no arquivo Glogin.sql o valor default é 8.1.7), o
tamanho das variáveis de tipo Nchar e Nvarchar2 estará associado ao National Character Set em uso (que
determinará se o valor é expresso em bytes ou caracteres).
SQLP[ROMPT] {SQL> | text } Indica o texto de prompt para o SQL*PLUS.
continua
continuação
Variável Descrição
SQLPRE[FIX] { # |c} Indica um prefixo. Durante a digitação de um comando de SQL podemos, em uma linha separada prefixada
pelo caracter escolhido, digitar um comando de SQL*Plus, que será executado imediatamente após o
<enter> da linha. Deve ser um caracter não alfanumérico.
SQLT[ERMINATOR] { ; | c | OFF | ON} Indica qual caracter o SQL*PLUS reconhecerá como fim de linha e execução. OFF indica que não existe
caracter associado, o fim do comando é reconhecido por uma linha inteira em branco. A opção ON retorna
ao valor default de;
SUF[FIX] {SQL | text} Indica a extensão default para arquivos de comandos do SQL*PLUS.
TAB {OFF|ON} Determina como o SQL*Plus formata espaços no resultado. OFF usa brancos para formatar espaços no
resultado. ON usa o caracter TAB. Esta opção é aplicável apenas a terminais. TABs não são colocados em arquivos.
TERM[OUT] {OFF|ON} Controla a apresentação dos resultados gerados por comandos executados a partir de um arquivo de
comandos. OFF suprime a apresentação do resultado no vídeo, mas o spool do resultado é gerado. TERMOUT
OFF não afeta a apresentação de comandos interativos.
TI[ME] {OFF|ON} Controla a apresentação da hora atual. ON mostra a hora corrente antes do prompt.
TIMI[NG] {OFF|ON} Controla a apresentação de estatísticas de tempo. ON mostra as estatísticas em cada comando SQL ou bloco
de PL/SQL.
TRIM[OUT] {OFF|ON} Determina se o SQL*Plus deixa os brancos finais de cada linha ou remove-os. ON remove os brancos ao fim
de cada linha aumentando a performance, especialmente útil quando executamos o SQL*Plus de um
equipamento lento. Não afeta Spool.
TRIMS[POOL] {ON|OFF} Determina se o SQL*Plus retira os brancos ao final de cada linha enviada para Spool. ON remove os brancos
finais. Não afeta o resultado para o terminal.
UND[ERLINE] { - | c | ON | OFF} Determina o caracter usado para sublinhar cabeçalhos de colunas. ON altera o valor para o padrão “-“. <c>
não pode ser um caracter alfanumérico.
VER[ IFY ] {ON | OFF} Determina se o texto do comando SQL será apresentado antes e após o SQL*PLUS ter efetuado a
substituição do parâmetro pelo valor real (default ON).
WRA[P] {OFF|ON} Controla se o SQL*PLUS trunca a apresentação de linhas selecionadas se o comprimento a ser apresentado é
muito longo para a largura atual da linha. OFF trunca a linha. ON permite a quebra de linha.
SHOW
Apresenta informações sobre o elemento especificado.
Dentre os parâmetros do comando Show apresentados na sintaxe, temos:
♦ <variável> – Apresenta informações sobre a variável de sistema nomeada no comando.
♦ All – Apresenta informações sobre todas as variáveis de sistema.
♦ Parameters – Apresenta informações sobre os parâmetros de inicialização do banco de dados. É uma opção para
uso por DBAs.
♦ SGA – Apresenta a alocação de memória feita para o banco de dados. É uma opção para uso por DBAs.
♦ Errors – Apresenta informações sobre o último comando de PL/SQL compilado ou sobre uma rotina específica
nomeada no comando.
SHUTDOWN
Este comando tem a finalidade de encerrar a execução do banco de dados. É um comando de uso exclusivo de
DBAs e não será estudado neste material.
SPOOL
Este comando armazena o resultado de uma consulta em um arquivo do sistema operacional e, opcionalmente,
envia o arquivo para a impressora default do sistema.
Nesse arquivo, são gerados não só o resultado do(s) comando(s) executado(s), como também as mensagens enviadas,
o texto do comando, enfim, uma reprodução de tudo que é mostrado no vídeo. Podemos alterar esse resultado
através das variáveis de sistema.
START / @ / @@
Esse comando executa o conteúdo de um arquivo de comandos existente no sistema operacional ou, com a sintaxe
padrão URI (Uniform Resource Identifier), em um servidor Web. Neste caso os protocolos suportados são HTTP,
FTP e Gopher.
Cada comando de SQL ou de SQL*Plus é lido e tratado individualmente. Num arquivo executado por Start, podemos
incluir diversos comandos de SQL.
O comando @ é sinônimo de Start e o @@ é semelhante, com a diferença de que, se esse comando for incluído em
um arquivo de comandos, ele pesquisará o arquivo associado no diretório do arquivo de comandos e não no
diretório local, como seria o caso do @ e do Start.
A Sintaxe 11.32 do comando Start permite a passagem de parâmetros. Esses parâmetros são variáveis de substituição
que são utilizadas para a substituição de trechos do comando de SQL.
Quando executamos o comando Start passando parâmetros na linha de comando, o SQL*Plus define uma variável
de substituição com o nome de cada um dos parâmetros passados, de tal forma que uma segunda execução do
mesmo comando não precisa da passagem dos parâmetros.
As variáveis de substituição não precisam ter nomes numéricos, podemos dar qualquer nome a elas, porém
neste caso não podem ser utilizadas como parâmetro para o comando Start. Ao executarmos um comando de
SQL ou de SQL*Plus contendo uma referência a variáveis de substituição, o SQL*Plus solicita que o valor da
variável seja informado.
Quando o comando contém a variável de substituição com nome alfanumérico precedido por um &, o SQL*Plus
não define uma variável de sistema com este nome. Se for desejada esta ação, devemos preceder a variável de
substituição com && e teremos o mesmo efeito que no caso do Start com parâmetros numéricos.
Quando desejamos que o valor da variável de substituição seja concatenado com outro valor, devemos usar um
ponto (.) para separar seu nome do valor.
STARTUP
Este comando tem a finalidade de inicializar a instância Oracle e, adicionalmente, o banco de dados. É um comando
de uso exclusivo de DBAs e não será estudado neste material.
STORE
O comando Store gera um arquivo contendo todas as variáveis de sistema e seus valores defaults para que possamos
gerar um script com aquelas que desejamos alterar.
Quando o SQL*Plus começa a executar, ele procura por um arquivo de nome Login.Sql e, caso encontre, executa os
comandos existentes neste arquivo.
Desta forma, podemos criar um arquivo com esse nome no diretório default do SQL*Plus contendo atribuições a
variáveis de sistema, títulos, formatação de colunas, enfim, todos os padrões que quisermos estabelecer para nossa
sessão. Toda vez que iniciarmos o SQL*Plus, esse arquivo será executado automaticamente.
TIMING
Registra dados de tempo para um determinado intervalo. O parâmetro <texto> corresponde ao nome do timer
criado. Se executado sem parâmetros, lista a quantidade de timers ativos. A opção Show mostra o valor acumulado
para o timer corrente e a opção Stop interrompe a contagem para o timer ativo.
TTITLE/BTITLE
Os comandos Ttitle e Btitle formatam títulos a serem apresentados no topo (Ttitle) ou rodapé (Btitle) de cada
página do relatório.
A sintaxe desses dois comandos é semelhante à dos comandos RepHeader e RepFooter, excetuando-se a opção
Page, que não existe para Ttitle e Btitle.
UNDEFINE
Destrói a definição de uma determinada variável de substituição.
VARIABLE
Esse comando cria uma variável Bind, que pode ser usada em programas de PL/SQL.
WHENEVER OSERROR/SQLERROR
Com este comando, podemos determinar que ação tomar quando ocorrer um erro de sistema operacional (Oserror)
ou de SQL (Sqlerror). No caso de escolhermos encerrar o SQL*Plus, podemos ainda fornecer uma informação para
o sistema operacional. Esse tipo de procedimento é interessante quando colocamos a execução do SQL*Plus em
um arquivo de comandos do sistema operacional. O encerramento com um valor permite que o script tome uma
ação associada a cada valor retornado.
Capítulo 12
GUIA DE REFERÊNCIA DE PL/SQL
Neste capítulo, apresentaremos de forma resumida os comandos de PL/SQL e de SQL necessários à criação de
rotinas e pacotes armazenados no banco de dados e, ainda, a sintaxe das rotinas pertencentes aos pacotes vistos no
tópico desenvolvido. Não constarão exemplos e nem exercícios.
Se você ficar com dúvidas sobre a sintaxe apresentada, pesquise detalhes no manual Oracle9i PL/SQL User’s Guide
and Reference, pois lá você encontrará as sintaxes completas de todos os comandos de PL/SQL, e para SQL consulte
o manual Oracle9i SQL Reference.
Para facilitar a pesquisa, os comandos são apresentados em ordem alfabética.
SOBRE A PL/SQL
ESTRUTURA
A PL/SQL é estruturada em blocos. Cada bloco pode conter outros blocos. Em cada um destes blocos, podemos
declarar variáveis que deixam de existir quando o bloco termina.
A Sintaxe 12.01 apresenta a estrutura de um bloco PL/SQL, que é composto de três partes:
♦ Uma parte declarativa, onde definimos as variáveis locais àquele bloco.
♦ Uma parte de lógica, onde definimos a ação que aquele bloco deve realizar, incluindo a declaração de outros
blocos subordinados (ou embutidos) a este.
♦ Uma parte de tratamento de erros, que permite que tenhamos acesso ao erro ocorrido e à determinação de uma
ação de correção. Nesta parte, também podemos declarar outros blocos subordinados.
IDENTIFICADORES
Um identificador consiste em uma letra seguida de outras letras, números, $ (dólar), _ (sublinhado) e # (símbolo
numérico). Possui um limite máximo de 30 caracteres.
As letras podem ser maiúsculas ou minúsculas indiscriminadamente, pois a linguagem não é sensível à forma.
Opcionalmente os identificadores podem ser declarados (e usados) entre aspas, quando desejamos, por exemplo,
usar no identificador caracteres não incluídos na lista de símbolos válidos.
PALAVRAS RESERVADAS
Alguns identificadores possuem um significado especial em PL/SQL e não devem ser utilizados na declaração de variáveis.
LITERAIS
Corresponde à representação explícita de um número, caracter, string ou booleano.
COMENTÁRIOS
Um comentário em PL/SQL pode ser informado de duas formas:
FIM DE LINHA
A indicação de fim de linha de comando em PL/SQL é feita com um ponto-e-vírgula (;).
TIPOS DE DADOS
Podem ser subdivididos nos seguintes grupos: Escalares, Compostos, Reference e Lob.
ESCALARES
São um conjunto de tipos de dados predefinidos e que não possuem componentes internos (não são subdivididos).
♦ Binary_Integer – Tipo de dado numérico para armazenamento de inteiros válidos no seguinte intervalo de
valores: de -231 + 1 (-2147483647) e 231 - 1 (2147483647). Possui os seguintes subtipos:
♦ Natural – valores não negativos. Intervalo entre 0 e 231 - 1 (2147483647).
♦ NaturalN – valores não negativos. Intervalo entre 0 e 231 - 1 (2147483647). Não admite Null.
♦ Positive – valores positivos. Intervalo entre 1 e 231 - 1 (2147483647).
♦ PositivelN – valores positivos. Intervalo entre 1 e 231 - 1 (2147483647). Não admite Null.
♦ Signtype – somente os valores –1, 0 e 1.
♦ Number – Tipo de dado numérico para armazenamento de valores fixos ou em ponto flutuante com precisão de
até 38 dígitos e magnitude de 1.0E-130 a 9.99E125. Podemos especificar precisão e escala. Se não especificarmos
precisão, o default é 38 (ou o maior tamanho válido para o sistema operacional, o que for menor). Escala pode
variar de -84 a 127. Escalas negativas causam o arredondamento da parte inteira. Possui os seguintes subtipos:
♦ Decimal, Dec e Numeric – armazenamento em ponto fixo com uma precisão máxima de 38 dígitos decimais.
♦ Double Precision, Float – armazenamento em ponto flutuante com uma precisão máxima de 126 dígitos
binários, o que equivale a 38 dígitos decimais.
♦ Real – armazenamento em ponto flutuante com uma precisão máxima de 63 dígitos binários, o que equivale
a 18 dígitos decimais.
♦ Integer, Int e Smallint – armazenamento de inteiros com uma precisão máxima de 38 dígitos.
♦ Pls_Integer – Tipo de dado numérico para armazenamento de inteiros válidos no seguinte intervalo de valores: de
-231 + 1 (-2147483647) e 231 - 1 (2147483647). É similar ao tipo Binary_Integer, porém é mais rápido para efetuar
cálculos que um Binary_Integer ou um Number, pois utiliza machine arithmetic, enquanto os demais usam library
arithmetic. Possui uma outra diferença em relação ao Binary_Integer no que se refere à detecção de Overflow.
Quando efetuamos um cálculo usando variáveis Pls_Integer e o valor ultrapassa a capacidade máxima da variável,
ocorre um erro de Overflow mesmo que a área receptora tenha capacidade de armazenamento (seja um Number,
por exemplo). Já com Binary_Integer não ocorrerá qualquer erro se atribuirmos o resultado a um Number.
♦ Char – Tipo de dado alfanumérico de tamanho fixo com comprimento de até 32.767 bytes. Podemos especificar
o tamanho máximo na declaração de uma variável com este tipo. Caso isto não seja especificado, o comprimento
default é de 1. O comprimento pode ser especificado em bytes ou em caracteres. Isto é importante quando
armazenamos valores multibyte. O conjunto de valores válidos para armazenamento depende do charset do
banco de dados. A definição de uma coluna do tipo Char no banco de dados está limitada a 2.000 bytes. Possui
um subtipo Character, que é semelhante ao Char. Quando não informamos a unidade do comprimento (bytes
ou caracteres), o default é dado pela variável Nls_Lenght_Semantics.
♦ Varchar2 – Tipo de dado alfanumérico de tamanho variável com comprimento de até 32.767 bytes. A especificação
de tamanho é obrigatória para uma variável declarada com este tipo. O comprimento pode ser especificado em
bytes ou em caracteres. Isto é importante quando armazenamos valores multibyte. O conjunto de valores válidos
para armazenamento depende do charset do banco de dados. A definição de uma coluna do tipo Varchar2 no
banco de dados está limitada a 4.000 bytes. Possui dois subtipos Varchar e String, até agora equivalentes a
Varchar2. Quando não informamos a unidade do comprimento (bytes ou caracteres), o default é dado pela
variável Nls_Lenght_Semantics.
♦ Long – Tipo de dado alfanumérico de tamanho variável com comprimento de até 32.760 bytes. Podemos
especificar o tamanho máximo na declaração de uma variável com este tipo. Uma coluna Long no banco de
dados armazena até 2 GB (2.147.483.647 bytes). Podemos fazer referência a colunas Long em comandos de
DML Insert, Update e muitos comandos Select, mas não em expressões, chamadas de funções SQL, ou em certas
cláusulas tais como Where, Group By e Connect By.
♦ Raw – Tipo de dado binário de tamanho variável com comprimento de até 32.767. A especificação de tamanho
na declaração de uma variável com este tipo é obrigatória. São semelhantes a colunas Varchar2, porém a PL/SQL
não interpreta seu conteúdo. O SQL*Net não realiza conversão entre charsets quando transmitimos dados Raw
de um sistema para outro. Uma coluna Raw no banco de dados armazena até 2.000 bytes.
♦ Long Raw – Tipo de dado binário de tamanho variável com comprimento de até 32.760 bytes. A especificação
de tamanho na declaração de uma variável com este tipo é obrigatória. São semelhantes a colunas Long, porém
a PL/SQL não interpreta seu conteúdo. Uma coluna Long Raw no banco de dados armazena até 2 GB
(2.147.483.647 bytes).
♦ Rowid – Para armazenamento de valores Rowid do banco de dados. Cada tabela criada no banco de dados possui
uma pseudocoluna Rowid que armazena valores hexadecimais que correspondem ao endereço de cada linha (row).
♦ Urowid – Armazena um Rowid lógico. Usado para captura do Rowid (lógico) de tabelas Index Organized.
♦ Nchar – Tipo de dado alfanumérico de tamanho fixo com comprimento de até 32.767 bytes. Podemos especificar
o tamanho máximo na declaração de uma variável com este tipo. Caso isto não seja especificado, o comprimento
default é de 1 byte. O comprimento é especificado em caracteres. Isto é importante quando armazenamos
valores multibyte. O conjunto de valores válidos para armazenamento depende do national charset definido
para o banco de dados. As colunas alfanuméricas Nchar e Nvarchar2 obedecem ao national charset, e as colunas
Char, Varchar2 e Long ao database charset.
A definição de uma coluna do tipo Nchar no banco de dados está limitada a 2.000 bytes. Podemos intercambiar
valores entre colunas Nchar e Char, porém pode haver perda de informação se o charset da coluna Char não
puder representar todo o conteúdo da coluna Nchar (aparecerão caracteres com ?).
♦ Nvarchar2 – Tipo de dado alfanumérico de tamanho variável com comprimento de até 32.767 bytes. A
especificação de tamanho é obrigatória para uma variável declarada com este tipo. O comprimento é especificado
em caracteres. Isto é importante quando armazenamos valores multibyte. O conjunto de valores válidos para
armazenamento depende do national charset definido para o banco de dados. As colunas alfanuméricas Nchar
e Nvarchar2 obedecem ao national charset e as colunas Char, Varchar2 e Long ao database charset. A definição
de uma coluna do tipo Nvarchar2 no banco de dados está limitada a 4.000 bytes. Podemos intercambiar valores
entre colunas Nvarchar2 e Varchar2, porém pode haver perda de informação se o charset da coluna Varchar2
não puder representar todo o conteúdo da coluna Nvarchar2 (aparecerão caracteres com ?).
♦ Boolean – É um tipo de dado para variáveis (não podem ser definidas como colunas em uma base de dados). Armazena
valores lógicos True e False e a ausência de valor Null. Não possuem tamanho e nem qualquer tipo de parâmetro.
♦ Date – Tipo de dado para armazenamento de valores de data e hora. Os valores válidos variam de 01 de janeiro
de 4712 A.C. até 31 de dezembro de 9999 D.C.
♦ Timestamp – Extensão ao tipo Date. Ano, mês e dia assim como hora, minuto, segundo e fração de segundo.
Podemos indicar o número de dígitos da parte fracionária do segundo.
♦ Timestamp with time zone – Extensão ao tipo Timestamp. Inclui a apresentação da zona de tempo. Onde a zona
de tempo corresponde à diferença (em horas e minutos) entre a hora local e UTC (hora de Greenwich).
♦ Timestamp with local time zone – Extensão ao tipo Timestamp. A diferença entre esta opção e a anterior é que a zona
de tempo não é armazenada no banco de dados. O dado, quando armazenado, é normalizado para a Dbtimezone e,
quando recuperado, é visualizado pelo usuário com a Time Zone da sessão (ocorre uma Segunda conversão).
♦ Interval Day to Second – Armazena um período de tempo em dias, horas, minutos e segundos.
♦ Interval Year to Month – Armazena um período de tempo em anos e meses.
LOBS
São um conjunto de tipos de dados predefinidos e que armazenam valores chamados locators, os quais especificam
a localização dos lobs (large objects) armazenados na linha ou fora dela.
Armazenam valores com comprimento de até 4 GB. Permitem o acesso randômico a trechos do dado.
♦ Blob – O tipo Blob tem a capacidade de armazenar grandes valores binários. O tamanho máximo não pode
exceder 4GB. O armazenamento da informação pode ser feito na própria linha ou em outro espaço específico.
♦ Clob – O tipo Clob tem a capacidade de armazenar grandes volumes de dados alfanuméricos no charset do
banco de dados. O tamanho máximo não pode exceder 4GB. O armazenamento da informação pode ser feito
na própria linha ou em outro espaço específico.
♦ Nclob – O tipo Nclob tem a capacidade de armazenar grandes volumes de dados alfanuméricos no national
charset. O tamanho máximo não pode exceder 4GB. O armazenamento da informação pode ser feito na própria
linha ou em outro espaço específico.
♦ Bfile – O tipo Bfile tem a capacidade de armazenar grandes volumes de dados binários fora do banco de dados.
O locator de um Bfile inclui um diretório que especifica o caminho completo do arquivo no servidor.
Bfiles são read-only. Não podemos modificá-los.
COMPOSTOS
São aqueles tipos que têm componentes internos que podem ser manuseados individualmente.
Neste grupo se encontram os tipos definidos pelo usuário: Table, Record e Varray.
REFERENCE
São aqueles tipos que armazenam valores chamados ponteiros, que apontam para outros itens do programa ou do
banco de dados. Fazem parte deste grupo os tipos Ref Cursor e Ref <object>.
CONVERSÃO IMPLÍCITA
Quando atribuímos uma variável de um determinado tipo a uma outra variável de outro tipo, ocorre uma conversão
implícita de tipo de dado.
A conversão implícita é possível em PL/SQL, mas não é recomendada, porque pode dificultar a performance e,
ainda, sofrer modificações de uma versão para outra do software.
Tipo B_Integer Blob Char CLOB Date Long Number P_Integer Raw Urowid Varchar2
B_Integer S S S S S
Blob S
Char S S S S S S S S S
Clob S S
Date S S S
Long S S S
Number S S S S S
P_Integer S S S S S
Raw S S S S
Urowid S S
Varchar2 S S S S S S S S S
Devemos tomar cuidado adicional com as conversões implícitas, pois o PL/SQL utiliza as funções de SQL, porém,
com os parâmetros de formato defaults. Assim, a execução de uma rotina em um servidor pode produzir um
resultado, enquanto em outro poderá produzir outro em função de parâmetros de ambiente (Nls, por exemplo).
DECLARAÇÕES
A parte declarativa do bloco precede a parte executiva e deve conter todas as variáveis necessárias à execução do
bloco, uma vez que a PL/SQL não declara implicitamente variáveis (como ocorre em outras linguagens).
VARIÁVEIS E CONSTANTES
Podemos declarar variáveis e constantes na parte declarativa de qualquer bloco, subprograma ou pacote.
A Sintaxe 12.02 apresenta a declaração de variáveis e constantes. Observe que uma constante, obrigatoriamente,
deve ter um valor inicial; no entanto, seu valor não poderá ser alterado ao longo do programa.
O valor inicial poderá ser fixo ou uma expressão, inclusive utilizando funções.
As variáveis podem receber ou não valor inicial. Caso a declaração da variável receba a cláusula Not Null, a atribuição
de valor inicial se torna obrigatória. Quando não informamos valor inicial para uma variável, seu valor é considerado
desconhecido, ou seja, Null.
ATRIBUIÇÃO
A atribuição de valor a uma variável é feita com a notação :=.
As variáveis e constantes são criadas e recebem seu valor inicial cada vez que for iniciado o bloco no qual estão declaradas.
%TYPE
O atributo %Type copia o tipo de dado de uma variável ou coluna do banco de dados.
Podemos, desta forma, declarar outra variável baseados na definição de uma coluna do banco de dados ou outra variável.
ESCOPO E VISIBILIDADE
O escopo de uma variável é a região (bloco, subprograma ou pacote) onde a referência a ela é válida. Dentro de um
mesmo escopo, todas as variáveis devem ter nomes únicos.
Uma variável declarada em um bloco é visível naquele bloco e em todos os blocos subordinados a este. Se uma
variável é redefinida em um sub-bloco, ambas são acessíveis. No sub-bloco, porém, qualquer referência não
qualificada fará acesso à variável de nível mais interno.
QUALIFICAÇÃO
Para controlarmos a visibilidade e termos acesso às variáveis dos blocos de nível superior, devemos qualificar
qualquer referência às variáveis externas nos blocos internos.
RESTRIÇÕES
A PL/SQL não admite referências a variáveis não declaradas, mesmo que elas venham a ser declaradas posteriormente.
Para que utilizemos uma variável (mesmo sendo na declaração de outra), devemos ter efetuado sua declaração primeiro.
COMANDOS
CASE
A cláusula Case permite a montagem de uma estrutura similar a IF..THEN …ELSE. Ao observarmos a Figura 12.03
veremos que existem duas formas sintáticas de utilizarmos o comando.
Na primeira forma usamos uma expressão que será comparada em cada uma das cláusulas When, funcionando
como um “seletor” indicativo dos comandos a serem executados. Caso não venhamos a definir uma cláusula Else
e nenhuma das expressões for compatível com a expressão seletora, o retorno será Null.
Na segunda forma não temos uma expressão de comparação; neste caso, cada cláusula When conterá uma condição
a ser verificada. Cada cláusula When é executada uma única vez e em ordem de apresentação. Quando uma condição
é satisfeita, os comandos subordinados são executados e as cláusulas When subseqüentes não são avaliadas. Caso
nenhuma condição seja satisfeita e não tenhamos definido uma cláusula Else, ocorrerá a exception Case_Not_Found.
CURSOR
%ROWTYPE
A fim de facilitar a recepção de informações das linhas da tabela, a PL/SQL implementa o atributo %Rowtype, que
gera uma área (registro) capaz de armazenar, exatamente, uma linha com o layout da linha de uma tabela do
banco de dados ou com o layout apenas das colunas (ou expressões) referenciadas no Select associado a um cursor.
ATRIBUTO %FOUND
É um atributo de cursor que indica se a última operação de Fetch foi bem-sucedida (para cursores explícitos), ou se
alguma linha foi afetada pelo último comando Insert, Update ou Delete, ou, ainda, se o comando Select Into
retornou uma ou mais linhas (para cursores implícitos).
Antes do primeiro Fetch, o valor do atributo é Null para cursores explícitos e também é Null antes de o comando
(Insert, Update, Delete ou Select Into) ser executado, para cursores implícitos.
ATRIBUTO %ISOPEN
Permite que se verifique se um cursor está aberto ou não. Para cursores implícitos, o resultado será sempre False,
uma vez que o Oracle abre o cursor imediatamente antes de a operação e o fecha imediatamente após a operação
e antes de a ação retornar ao programa.
ATRIBUTO %NOTFOUND
É um atributo de cursor com lógica inversa ao atributo %Found. %Notfound retornará False se o último comando
Fetch retornar uma linha (para cursores explícitos) ou se o último comando Insert, Update ou Delete não afetar
nenhuma linha ou, ainda, se o último comando Select Into não retornar nenhuma linha (para cursores implícitos).
Antes do primeiro Fetch, o valor do atributo é Null para cursores explícitos e também é Null antes de o comando
(Insert, Update, Delete ou Select Into) ser executado, para cursores implícitos.
ATRIBUTO %ROWCOUNT
Indica o número de linhas já lidas (Fetched) para os cursores explícitos ou o número de linhas afetadas por um
comando Insert, Update ou Delete ou, ainda, o número de linhas retornadas por um comando Select Into (para
cursores implícitos).
Quando o cursor é aberto, o atributo %Rowcount é zerado. Antes do primeiro Fetch, o atributo continua com zero.
O valor só é incrementado após o fetch ter sido efetuado com sucesso.
Até que o primeiro comando de DML seja executado, o valor do atributo é Null para cursores implícitos.
ATRIBUTO %BULK_ROWCOUNT
Este atributo é semelhante ao atributo %Rowcount, porém para utilização conjunta com o comando ForAll. Sua
utilização está associada ao uso de coleções.
Ele indica o resultado do processamento de cada elemento da coleção.
Quando processamos uma coleção usando o comando ForAll, para cada índice da coleção o atributo %Bulk_RowCount
indica quantas linhas da tabela foram processadas.
Como restrição, temos que %Bulk_RowCount não pode ser associado (atribuído) a outras coleções, além de não
poder ser passado como parâmetro para subprogramas.
ATRIBUTO %BULK_EXCEPTIONS
Durante a execução de um comando For All podemos decidir interromper a execução do comando quando a primeira
exception for encontrada ou podemos prosseguir e armazenar todas as exceptions ocorridas para posterior tratamento.
Para esta segunda forma devemos incluir a cláusula Save Exceptions na execução do comando For All. A presença
da cláusula Save Exceptions fará com que a execução prossiga até o fim e todas as exceptions sejam armazenadas
(em ordem de ocorrência) em uma coleção.
O acesso a esta coleção é feito com o atributo %Bulk_Exceptions. Nesta coleção encontraremos um registro para
cada erro adquirido. O índice desta coleção navega seqüencialmente pela lista de erros encontrados. A propriedade
Count do atributo %Bulk_Exceptions indica a quantidade total de erros; desta forma o primeiro erro é obtido com
SQL%Bulk_Exceptions(1) e o último com SQL%Bulk_Exceptions(SQL%Bulk_Exceptions.Count).
Cada registro da coleção possui dois campos:
♦ O primeiro, %Bulk_Exceptions(i).ERROR_INDEX, indica a iteração que recebeu a exception.
♦ O segundo, %Bulk_Exceptions(i).ERROR_CODE, contém o código do erro.
CLOSE CURSOR
Para fecharmos um cursor, devemos utilizar o verbo Close. Este verbo libera a área reservada para a montagem do
conjunto de dados selecionados.
CURSOR LOOP
Este comando é similar ao comando For Loop, mas é específico para utilização com cursores.
O registro presente na sintaxe é declarado implicitamente pelo Oracle (como um registro tipo <cursor>%rowtype)
e tem vida útil até o End ser atingido. Este comando realiza todas as operações vistas relativas a cursor: quando a
iteração se inicia, o cursor é aberto e feito Fetch na primeira linha. Se a operação (de leitura) for bem-sucedida, é
executada a seqüência de comandos presente entre o Loop e o End Loop. Este processo se repete até que a última
linha seja processada. Após este processamento, o cursor é automaticamente fechado.
O cursor pode ser declarado previamente e utilizado no comando ou pode ser incluído o comando Select desejado
no próprio comando.
Este comando permite até a passagem de parâmetros, caso o comando Select associado ao cursor seja executado
em relação a um valor parametrizado.
DECLARAÇÃO DE CURSOR
Na declaração de um cursor, já é feita a associação com o comando Select capaz de obter as linhas do banco de dados.
O cursor deve ser criado antes de ser usado; por isso é necessário que a declaração esteja presente no bloco em que
usaremos o cursor ou em um bloco mais externo.
O tipo do retorno deve representar um registro correspondendo às colunas trazidas pelo comando Select.
A manipulação de um cursor é semelhante àquela usada para arquivos convencionais: abrir (Open), ler uma linha
(Fetch into) e fechar (Close).
Precisamos garantir que a linha a ser removida esteja bloqueada contra atualizações concorrentes antes de efetuarmos
o comando Delete. Desta forma, a cláusula For Update deve ser usada no comando Select do cursor.
A cláusula For Update adicionada ao comando Select indica que todas as linhas escolhidas através da condição
presente na cláusula Where devem sofrer bloqueio (Lock) contra atualizações concorrentes.
FETCH CURSOR
Associa os valores da linha atual às variáveis do programa e, posteriormente, posiciona o cursor na próxima linha
do conjunto de linhas resultantes da operação de Select.
As variáveis devem ser informadas no Fetch na mesma ordem das expressões correspondentes no comando Select. Para
cada expressão deve haver uma variável receptora. Os tipos de dado da variável e da expressão devem ser compatíveis.
A cláusula Bulk Collect apresentada na sintaxe indica à SQL Engine para preparar toda a coleção de saída (Bulk
Bind) antes de retorná-la para a PL/SQL Engine. Esta cláusula pode ser usada junto com a cláusula Into nos comandos
Select Into, Fetch Into e Returning Into.
OPEN CURSOR
A abertura de um cursor é realizada com o comando Open. Os parâmetros devem ser fornecidos a tempo de Open
para que seja possível a execução do comando Select.
Os parâmetros declarados com valor inicial podem, a tempo de Open, não receber nenhum valor e utilizar os
valores iniciais previamente declarados.
Para a passagem dos parâmetros, podemos usar a notação posicional ou a notação nomeada.
A cláusula For Update adicionada ao comando Select indica que todas as linhas escolhidas através da condição
presente na cláusula Where devem sofrer bloqueio (Lock) contra atualizações concorrentes.
TRATAMENTO DE ERRO
PRAGMA EXCEPTION_INIT
A lista de exceptions predefinidas é limitada e muitas vezes desejamos controlar a ocorrência de outros erros
conhecidos do ambiente, tais como: deadlock ou constraint error.
Como não temos condições de erro predefinidas para tratamento destas situações, é muito comum encontrarmos
nos programas o uso de testes do código do erro ocorrido para efetuar uma ou outra ação (Sqlcode e When Others).
As pragmas são diretivas de compilação, isto é, são instruções fornecidas ao compilador, que modificam a forma de
execução do programa.
A pragma Exception_Init nos proporciona uma forma mais legível de realizarmos o controle dos erros previstos,
mas sem condições de erro predefinidas.
A diretiva Pragma é definida na parte declarativa do bloco, pois será usada pelo compilador e não a tempo de execução.
EXCEPTION
Cada bloco de PL/SQL possui uma área específica para tratamento de erro. Toda vez que ocorre um erro no programa, a
seqüência de execução é interrompida e o controle é transferido para esta área especial do bloco onde o erro foi adquirido.
Quando criamos um programa PL/SQL, são incorporadas a ele algumas condições de erro predefinidas, que
conheceremos a seguir:
Access_into_null ORA-06530 -6530 É causada se ocorrer uma associação de valores a atributos de um objeto não-inicializado (Null).
Case_not_found ORA-6592 -6592 É causada se nenhuma das opções da cláusula When for satisfeita e não houver sido declarada
nenhuma cláusula Else.
Collection_is_null ORA-06531 -06531 É causada se forem aplicados métodos (exceto Exists) ou associação de valores a uma Nested
Table ou Varray não-inicializados.
Cursor_already_open ORA-06511 -6511 É causada se for executado um Open para um cursor já aberto.
Dup_val_on_index ORA-00001 -1 É causada se for tentada a inclusão de valores duplicados em uma coluna do banco de dados
que contém uma restrição de unicidade.
Invalid_cursor ORA-01001 -1001 É causada se for tentada uma operação ilegal com um cursor. Como, por exemplo, fechar um
cursor não aberto.
Invalid_number ORA-01722 -1722 É causada se algum comando de SQL tentou uma conversão de string para numérico quando a
string não representava um número válido. Em comandos procedurais, a exception adquirida é
Value_Error.
Login_denied ORA-01017 -1017 É causada se houver uma tentativa de conexão ao Oracle com um user/password inválidos.
No_data_found ORA-01403 +100 É causada se num comando Select Into nenhuma linha foi retornada ou foi feita referência a
um elemento inexistente (deletado) de uma Nested Table ou uma referência a um elemento
não-inicializado em uma tabela PL/SQL.
Not_logged_on ORA-01012 -1012 É causada se um programa de PL/SQL tenta fazer acesso ao banco de dados sem estabelecer conexão.
continua
continuação
RAISE
Este verbo causa a exception no momento em que é aplicado. Isto pode ser feito tanto para uma exception definida
pelo usuário quanto para uma exception predefinida.
RAISE_APPLICATION_ERROR
Esta procedure permite que seja feito o fornecimento de mensagens de erro a partir de subprogramas armazenados
no banco de dados ou de database triggers.
Onde:
♦ <erro> – Corresponde ao número do erro, podendo variar de -20.000 a -20.999. Deve ser um número inteiro.
Nesse intervalo de valores não existem erros do Oracle. Esse intervalo foi reservado para erros do usuário.
♦ <mensagem> – Corresponde à mensagem que desejamos enviar. Pode ser uma string de até 2.048 bytes de
comprimento.
♦ TRUE / FALSE – O terceiro parâmetro é opcional. Se for enviado True, indica que o erro será colocado na pilha de
erros anteriores. Caso o valor seja False (default), o erro substituirá todos os erros anteriores.
WHEN OTHERS
Podemos utilizar a sintaxe When Others se desejarmos capturar, dentro do programa, qualquer outra ocorrência
não prevista dentro da lista de exceptions (predefinidas ou do usuário).
É muito comum a utilização conjunta da sintaxe When Others e das funções SqlCode e SqlErrm.
ITERAÇÕES
EXIT
O comando Exit tem a finalidade de encerrar um Loop (qualquer das formas). Quando o comando Exit é executado,
o loop é completado incondicionalmente e o controle passa para o próximo comando.
A presença do Label indica que o comando também é qualificável com a utilização de um Label precedente e, desta
forma, o processo repetitivo pode ser nomeado.
FORALL
Este comando indica à PL/SQL Engine para preparar toda a coleção de entrada (Bulk Bind) antes de enviá-la à SQL Engine.
FOR LOOP
O comando For Loop determina que a seqüência de comandos seja executada um número fixo de vezes. O número
de iterações é conhecido (determinado) antes de o Loop ter início.
Na sintaxe, observamos que deve ser fornecido um valor inferior e um valor superior que corresponderão, respectiva-
mente, ao valor inicial e ao valor final de contador, que é incrementado de 1 a cada iteração. Caso a palavra
Reverse seja utilizada na sintaxe, o valor inicial de contador será o valor superior e a cada iteração o contador será
decrementado de 1 até atingir o valor inferior.
A variável contador é implicitamente declarada como variável local ao Loop e com tipo de dado Integer. Não pode
ser utilizada fora da iteração, porque sua declaração se extingue quando o processamento executar o End Loop.
Os valores referentes a valor inferior e valor superior podem ser fornecidos por constantes ou variáveis.
GOTO
O comando GoTo efetua um desvio incondicional para um Label. O Label deve ser único dentro do escopo e deve
preceder um comando ou um bloco PL/SQL. Além de ser usado para desvios, um Label também serve como
qualificador de variáveis, como foi comentado no item Qualificação, do tópico Declarações.
A PL/SQL possui diversas estruturas de iteração, e raramente teremos necessidade de utilizar um comando GoTo.
Existem algumas situações em que o comando GoTo não pode ser usado:
♦ Desvio para dentro de um IF ou Loop (GoTo Proximo_IF).
♦ Desvio para dentro de um sub-bloco (GoTo Subbloco).
♦ Desvio para fora de um subprograma (GoTo Para_Fora).
♦ Desvio para dentro de um bloco a partir da área de exceção (GoTo Inicio).
LOOP
A seqüência de comandos é executada um número infinito de vezes ou até que seja interrompida por um comando Exit.
WHILE
O comando While corresponde a uma outra forma de Loop, em que estabelecemos uma condição de interrupção
na própria sintaxe do comando.
DEMAIS COMANDOS
EXECUTE IMMEDIATE
Comandos de SQL dinâmico são armazenados em strings e construídos pelo programa a tempo de execução. Estas
strings devem conter um comando SQL ou um bloco de PL/SQL válidos. Podem, ainda, conter argumentos (Bind)
a serem supridos durante a execução.
O comando Execute Immediate é um comando de SQL Dinâmico para o qual podemos montar, a tempo de
execução, o comando de SQL (exceto Select que retorne múltiplas linhas) que desejamos executar.
Onde:
♦ <string com comando dinâmico> – É uma expressão que representa um comando SQL qualquer (exceto queries
que retornem múltiplas linhas) sem terminação ou um bloco de PL/SQL com terminação. Esta string pode
conter referências a argumentos Bind. Não podemos, porém, usar argumentos Bind para substituir nomes de
objetos dentro da string.
♦ <variável> – É uma variável que armazena o valor de uma coluna selecionada.
♦ <registro> – Corresponde a um Record definido pelo usuário ou um %Rowtype que armazenará uma linha
(row) selecionada.
♦ <argumento Bind> – É uma expressão cujo valor é passado dinamicamente para o comando SQL ou bloco de
PL/SQL (o hint NoCopy não é permitido em um Execute Immediate). Se não for especificado o modo do
parâmetro, o default é IN.
SQL dinâmico suporta todos os tipos de dados de SQL (coleções, Lobs, Refs, objetos), mas não suporta tipos específicos de PL/SQL (booleanos e
tabelas Index-By). Desta forma, tanto <variável> quanto <argumento Bind> devem obedecer a esta regra.
FUNÇÕES
Em PL/SQL, podemos utilizar quase todas as funções de SQL diretamente nos comandos de atribuição ou em IFs.
A lista a seguir apresenta as funções de SQL válidas em PL/SQL:
♦ Numéricas Simples – Abs, Bitand, Ceil, Exp, Floor, Ln, Log, Mod, Power, Round, Sign, Sqrt, Trunc.
♦ Trigonométricas – Acos, Asin, Atan, Atan2, Cos, Cosh, Sin, Sinh, Tan, Tanh.
♦ Alfanuméricas – Chr, Concat, Initcap, Lower, Lpad, Ltrim, Nls_Initcap, Nls_Lower, Nls_Upper, Replace, Rpad,
Rtrim, Soundex, Substr, Substrb, Translate, Upper, Trim.
♦ Alfanuméricas que retornam Valores Numéricos – Ascii, Instr, Instrb, Length, Lengthb, Nlssort.
♦ Datas – Sysdate, Add_Months, Current_Date, Current_Timestamp, DBTimezone, Extract, From_Tz, Last_Day,
LocalTimestamp, Months_Between, New_Time, Next_Day, NumToDsInterval, NumToYmInterval, Round,
SessionTimeZone, Sysdate, SysTimestamp, To_DsInterval, To_Timestamp, To_Timestamp_Ltz, To_Timestamp_Tz,
To_YmInterval, Tz_Offset, Trunc.
♦ Conversão – CharToRowid, Convert, HexToRaw, RawToHex, RowidToChar, To_Blob, To_Char, To_Clob, To_Date,
To_Multi_Byte, To_Nclob, To_Number, To_Single_Byte, Translate Using.
IF
O comando IF verifica uma condição e, dependendo do resultado, realiza uma ou outra ação. Permite a execução
condicional de uma determinada ação.
Sintaxe 12.18 – IF
A Sintaxe 12.18 apresenta a forma básica de um comando IF. Observamos que a presença de um End If para
encerrar o comando é necessário. Mesmo quando utilizamos diversos Elseifs, apenas um End If é necessário.
Devemos considerar que o End If encerra o IF isolado.
NULL
Esse comando, explicitamente, indica que não há ação a ser feita. Serve para compor certas situações em que um
comando é exigido, mas nenhuma ação é, realmente, necessária.
SELECT INTO
Dentro da PL/SQL, o comando Select ganha a cláusula Into a fim de obter dados da linha lida para variáveis do
programa. Desta forma poderemos manusear os dados obtidos.
A cláusula Into segue imediatamente a lista de variáveis da cláusula Select e precede a cláusula From.
Devemos informar uma área de recepção capaz de comportar todos os dados lidos; caso contrário receberemos erro
na execução.
O comando Select Into somente faz leitura de uma row. Caso venhamos a selecionar mais de uma usando este
comando, ocorrerá um erro (Too Many Rows) indicando o excesso. A leitura de diversas rows é feita com o uso do
cursor ou com o acréscimo da cláusula Bulk Collect.
CURSO COMPLETO00✦ 1289
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE III: REFERÊNCIA
COLEÇÕES E REGISTROS
Uma coleção é um grupo ordenado de elementos, todos do mesmo tipo. Cada elemento possui um único subscrito
que determina o posicionamento do elemento na coleção.
A PL/SQL trabalha com três tipos de coleções: Nested Tables, Varrays e Index-by Tables.
NESTED TABLES
Dentro da PL/SQL, as Nested Tables são como arrays. Possuem, porém, duas diferenças significativas:
♦ Arrays possuem fronteiras (limite), já Nested Tables não possuem. Desta forma, o tamanho de uma Nested Table
cresce dinamicamente.
♦ Arrays devem ser densos, isto é, ter subscritos consecutivos. Não podemos remover elementos de um array.
Nested Tables podem ter elementos removidos, deixando de ser densa.
O <tipo> presente na sintaxe pode corresponder a qualquer tipo válido em PL/SQL, exceto Boolean, Nchar, Nclob,
Nvarchar2, um tipo objeto com atributo Table ou Varray, Ref Cursor, Table ou Varray.
VARRAYS
Um Varray possui um tamanho máximo, que deve ser especificado a tempo de definição. Seu índice possui,
implicitamente, a fronteira inferior de 1. A fronteira superior é dada pelo limite estabelecido na definição.
INDEX-BY TABLES
Index-By Tables são semelhantes a Nested Tables em diversos pontos. São mantidos para compatibilidade com a
versão 2 da PL/SQL. Em aplicações antigas, devemos continuar usando Index-By Tables para compatibilidade. Em
novas aplicações, devemos usar sempre Nested Tables para flexibilidade.
♦ As procedures Extend e Trim podem ser aplicadas a Nested Tables, mas não a Index-By Tables.
MANIPULANDO COLEÇÕES
As coleções possuem métodos, que são funções predefinidas com ações específicas que agem sobre as coleções
facilitando sua manipulação.
Os seguintes métodos são aplicáveis a coleções:
Exception Condição
Collection_is_null É causada se forem aplicados métodos (exceto Exists) ou associação de valores a uma Nested Table ou Varray não
inicializados.
No_data_found É causada se foi feita referência a um elemento inexistente (deletado) de uma Nested Table ou uma referência a um
elemento não inicializado em uma Index-By Table.
Subscript_beyond_count É causada se for feita uma referência a um elemento de uma coleção usando um índice maior que o número de elementos
da coleção.
Subscript_outside_limit É causada se for feita uma referência a um elemento de uma Nested Table ou Varray usando um número fora do intervalo
legal (por exemplo –1).
Value_error É causada se um subscrito é Null ou não-inteiro.
REGISTROS
Um registro nada mais é que uma área estruturada. Um grupo de itens de dados relacionados e armazenados em
campos contendo seu próprio nome e tipo de dado.
O atributo %Rowtype permite a declaração de um registro com o layout de uma tabela definida no banco de dados
ou das colunas selecionadas em um cursor.
A definição de registro permite total flexibilidade na declaração da área. Podemos definir nomes próprios e tipos e
tamanhos que desejarmos.
Na declaração de um registro, podemos associar nesta estrutura elementos com os tipos escalares, Varrays, Nested
Tables e objetos.
A declaração de tipo não cria uma área para recepção dos dados. Apenas cria o layout da área. É indispensável a
criação da variável com o tipo definido para que seja possível a utilização da área.
SUBPROGRAMAS E PACOTES
SUBPROGRAMAS
Subprogramas são blocos de PL/SQL que têm nome e, portanto, podem ser chamados de outros blocos. Além desta
característica, os subprogramas podem receber parâmetros formais em vez das variáveis de substituição.
A PL/SQL possui dois tipos de subprogramas: Procedures e Functions.
De um modo geral, são bastante semelhantes as características dos dois tipos de subprogramas da PL/SQL. As
semelhanças e diferenças estão relacionadas a seguir:
♦ Os subprogramas, como todos os blocos de PL/SQL, também possuem uma área para declaração de variáveis,
uma área para desenvolvimento da lógica e uma área opcional para tratamento de erros.
♦ Os subprogramas podem ser armazenados no banco de dados e acionados por qualquer programa aplicativo
que tenha autorização de execução.
♦ Os subprogramas podem receber um ou mais parâmetros formais.
♦ Uma Function sempre retorna um valor para o bloco de PL/SQL de onde foi acionada.
♦ Uma Procedure pode retornar ou não um valor para o bloco de PL/SQL de onde foi acionada.
♦ Uma Function armazenada no banco de dados pode ser acionada em comandos de SQL. Uma Procedure, nas
mesmas condições, não pode.
♦ Uma Procedure é acionada como um comando de PL/SQL, isto é, isolada. Não faz parte de expressões.
♦ Uma função, para ser acionada, deve fazer parte de uma expressão PL/SQL (por exemplo, uma atribuição a
uma variável).
♦ Uma função deve, obrigatoriamente, executar o comando Return para transferir a informação de volta para o
programa acionador.
PARÂMETROS
Os subprogramas recebem informação dos blocos que os acionaram através de parâmetros. Estes parâmetros são
chamados de formais.
Como apresentado na Sintaxe 12.24, um parâmetro pode ser definido de três formas:
♦ IN – Indica um parâmetro de entrada. Dentro do subprograma, um parâmetro do tipo IN funciona como uma
constante, isto é, podemos ler seu valor, porém não podemos fazer qualquer tipo de atribuição a eles. Caso o
modo não seja informado, este é o modo default.
A transferência de informações entre o bloco principal e a procedure pode ser feita de duas formas: com o valor ou
através de uma variável. Estas duas sintaxes são válidas, porque o parâmetro é de entrada.
♦ OUT – Indica um parâmetro de saída. Dentro do subprograma, um parâmetro do tipo OUT pode receber
atribuições, porém não pode ter seus valores consultados de nenhuma forma.
Um parâmetro OUT só pode ser passado através de uma variável porque o valor que atribuirmos ao parâmetro no
subprograma será atribuído à variável que for passada como parâmetro.
Outra característica do modo OUT é que, ao iniciar o subprograma, o Oracle associa Null ao parâmetro OUT. Desta
forma, se associarmos, dentro do subprograma, um valor ao parâmetro, ao encerrarmos a rotina o valor atribuído
será retornado ao bloco chamador, porém, se esta ação não for feita, será retornado Null.
♦ IN OUT – Indica um parâmetro que será usado simultaneamente como entrada e como saída. Dentro do
subprograma, poderemos ler seu valor e atribuir um novo valor a ele.
Para passarmos valor do bloco principal para o subprograma, obrigatoriamente, devemos passar o parâmetro
através de uma variável, porque o valor, apesar de ser lido, também receberá uma atribuição. E para que o resultado
seja transferido para o bloco principal há necessidade de se informar uma variável.
Quando definimos um parâmetro com o modo IN, podemos atribuir um valor default para o caso de o parâmetro
não ser informado.
♦ Hint NOCOPY – O Hint NOCOPY indica ao Oracle que a passagem dos parâmetros de saída (OUT ou IN OUT)
deve ser feita por referência.
DECLARAÇÕES FORWARD
A PL/SQL exige que se declare um subprograma antes de podermos utilizá-lo. Se desejássemos criar dois
procedimentos mutuamente recursivos, esta regra impediria essa forma de utilização.
Como solução de contorno para este tipo de situação, a PL/SQL fornece uma forma de declaração parcial chamada
de declaração forward que interrompe a declaração da procedure ou função após a definição dos parâmetros (para
as procedures) ou do tipo de retorno (para as funções), permitindo que o compilador realize a validação da chamada
do subprograma mesmo sem ter informações sobre o corpo (ou lógica) deste.
Posteriormente, repete-se a definição do subprograma, agora contendo a chamada e a lógica.
CLÁUSULA AUTHID
A cláusula AuthId tem a finalidade de indicar ao Oracle de que usuário devem ser obtidos os privilégios e resolvidas
as referências externas a tempo de execução. Quando especificamos AuthId Definer (default), os privilégios e as
referências externas são resolvidos no schema do dono da rotina. Quando especificamos a cláusula AuthId
Current_User, os privilégios do executor da rotina são verificados a tempo de execução e as referências externas são
resolvidas no schema deste executor, presentes em:
♦ Comandos que manipulam os dados: Select, Insert, Update e Delete.
♦ Comando para controle de transações: Lock Table.
♦ Comandos para controle de Cursores: Open e Open-For.
♦ Comandos de SQL dinâmicos: Execute Immediate e Open-For-Using.
♦ Comandos de SQL “parseados” pela rotina Parse do pacote Dbms_Sql.
Para os outros comandos, os privilégios do dono da rotina são verificados a tempo de compilação e as referências
externas também são resolvidas no schema do dono da rotina.
CLÁUSULA AS LANGUAGE
Esta cláusula indica ao Oracle que a rotina, na verdade, não está escrita em PL/SQL e sim na linguagem especificada (C
ou Java). Na versão 8, tínhamos a cláusula As External; no entanto, a Oracle recomenda que seu uso seja descontinuado.
CLÁUSULA DETERMINISTIC
Indica ao Oracle que a rotina produzirá sempre um mesmo resultado para cada valor de parâmetro, ou seja, se
repetirmos os mesmos parâmetros para a função ela produzirá o mesmo resultado. Esta cláusula é indispensável
para a criação de um índice baseado na função.
TABLE FUNCTIONS
São funções que produzem uma coleção de linhas (Nested Table ou Varray) como resultado (cláusula Return) e que
podem ser consultadas como se fossem uma tabela, isto é, usando-se a cláusula From do Comando Select.
CLÁUSULA PIPELINED
Indica que o resultado da Table Function pode ser obtido à medida que este for produzido, ou seja, as linhas são
retornadas iterativamente em vez de ocorrerem somente ao término da execução.
A opção Using <implementation type> indica que deve será feita interface com uma ODCITable.
CLÁUSULA PARALLEL
É um hint de otimização que indica que a função pode ser executada a partir de um servidor paralelo em uma operação
paralela. Funções deste tipo não podem fazer uso de estados da sessão tais como variáveis de pacote e variáveis que não
possam ser compartilhadas através de servidores paralelos. Paralelismo não faz parte do estudo deste material.
CLÁUSULA AGREGATE
Identifica esta função como uma função de agregação. Na cláusula Using devemos especificar o nome do tipo de
implementação da função associado a ODCIAggregate routines.
OVERLOADING
A PL/SQL permite a definição de dois subprogramas com o mesmo nome desde que seus parâmetros formais sejam
diferentes em número, ordem ou grupo familiar (por exemplo Integer e Real são tipos diferentes, porém pertencem
ao mesmo grupo familiar). Esta característica é chamada de Overloading.
Como restrição, temos que essa técnica só se aplica a subprogramas locais ou subprogramas definidos em pacotes
(serão vistos em outro tópico). Além disso, não podemos “overload” dois subprogramas se seus parâmetros diferirem
apenas em relação aos nomes ou aos modos dos parâmetros. E, finalmente, não podemos “overload” duas funções
em que haja diferença apenas no tipo de retorno (mesmo que estejam em grupos familiares diferentes).
STORED SUBPROGRAM
O objetivo de armazenarmos uma procedure ou function no banco de dados é permitir que a rotina seja
compartilhada por diversas aplicações.
A sintaxe para a criação de uma rotina no banco de dados é semelhante à sintaxe para criação de uma rotina
dentro de um bloco principal. A diferença está na cláusula Create, que estabelece o armazenamento da rotina no
banco de dados.
CALL
Executa uma rotina (procedure ou função isolada, de pacote ou de tipo) de dentro do SQL. A cláusula INTO indica
uma variável para receber o retorno da função (só aplicável a funções) e a cláusula INDICATOR especifica o valor
ou condição da variável host.
Esta sintaxe pode ser usada em Triggers.
PACKAGES
Um package é uma área para armazenamento de subprogramas, tipos, constantes, cursores e variáveis de PL/SQL.
Um package é definido em duas partes: uma parte de especificação e uma parte de corpo.
ESPECIFICAÇÃO
A especificação é a interface com as aplicações. É nela que declaramos os tipos, variáveis, constantes, exceções,
cursores e subprogramas que desejamos que sejam visíveis e compartilháveis pelas aplicações. Tudo que for definido
na parte de especificação pode ser compartilhado.
A definição dos subprogramas e cursores não é completa; fazemos apenas uma definição do tipo Forward, uma vez
que as aplicações só necessitam saber quais os parâmetros a serem passados para a rotina (ou cursor) e quais os
retornos fornecidos. Não há necessidade de se saber como a rotina efetua a operação.
Na Sintaxe 12.26 está definida a parte de especificação de um pacote. Apesar de a sintaxe do pacote lembrar a
sintaxe de definição de rotinas, os pacotes diferem das rotinas nos seguintes aspectos: não podem ser chamados,
não podem ser parametrizados e não podem ser definidos dentro de outros pacotes.
O objetivo de empacotar é primeiramente organizacional. O pacote oferece a possibilidade de juntarmos itens e
subprogramas que realizam ações associadas.
Observe que as informações declaradas no pacote determinam quais os nomes das rotinas e itens, os parâmetros
recebidos e o retorno esperado. Não definimos detalhes de implementação. Isto será feito no corpo.
Na parte de corpo do pacote, definimos por completo todas as rotinas. Não só aquelas declaradas na parte de
especificação, como também todas aquelas rotinas que serão chamadas pelas outras, mas que não desejamos
disponibilizar diretamente para as aplicações.
Definimos também, agora, os cursores por completo, além de todas as variáveis que venham a ser usadas pelas
rotinas e que não desejamos disponibilizar para as demais aplicações.
Observe a presença da cláusula AuthId na parte de especificação. Ela indica que para todas as rotinas do pacote
serão utilizados os privilégios e resolvidas referências externas a tempo de execução no schema do autor do pacote
ou no schema do executor, de acordo com o que tiver sido definido.
CORPO DO PACOTE
O corpo implementa detalhes e declarações privadas que são invisíveis pelas aplicações.
Na Sintaxe 12.27, observamos que, sintaticamente, a definição da especificação e do corpo do pacote são similares.
A diferença é que na parte de especificação as definições são do tipo Forward, enquanto na parte de corpo as
definições são completas.
No corpo, aparece ainda a possibilidade de definirmos uma área de lógica (<inicialização>) que será executada na
primeira vez que o pacote for utilizado em uma sessão do usuário. Nessa área, podemos estabelecer ações para
inicialização de variáveis, cursores, etc.
Uma vez que apenas a parte de especificação é utilizada para compilação dos programas que façam uso dos pacotes,
podemos alterar o corpo do pacote sem haver necessidade de recompilar os programas que o usam.
O PACOTE DBMS_FLASHBACK
Este pacote tem a finalidade de habilitar ou desabilitar um ponto específico do tempo para acesso a informações já
modificadas no banco de dados.
Podemos obter informações de uma versão (ou momento) do banco de dados anterior ao momento atual. Quando
habilitamos este pacote, a sessão do usuário utiliza uma versão Flashback do banco de dados
Este pacote pode ser usado para recuperarmos dados removidos (Delete) incorretamente, versão original de dados
que foram modificados, etc.
Para realizarmos estas ações com sucesso, o DBA deve ser informado, para que tenhamos autorização de uso do
pacote e para habilitar a retenção das informações pelo período de tempo de que viermos a necessitar.
Enable_At_Time Procedure Habilita a sessão para o modo de Flashback. O controle do tempo é feito em relação ao SCN mais
próximo da data e hora informados como parâmetro.
Enable_At_System_Change Procedure Habilita a sessão para o modo de Flashback. Passamos como parâmetro, diretamente, o SCN desejado.
Get_System_Change_Number Function Retorna o SCN atual.
Disable Procedure Encerra o modo Flashback para a sessão.
Quando uma transação que modifica o banco de dados é encerrada com sucesso, ela recebe um número de controle
chamado SCN (System Change Number). Este número é gravado no arquivo de Log e era usado, até esta versão,
apenas para o controle do processo de recuperação.
Na versão 9i, podemos usar o SCN, também, para identificar um ponto dentro do arquivo de Log onde desejamos
estabelecer uma imagem do banco de dados para obtenção de informações do passado. Este pacote se utiliza desta
informação para determinação deste ponto no tempo.
O PACOTE DBMS_LOB
Large Objects ou Lobs são tipos de dados que podem armazenar informações de até 4GB de dados binários (imagens,
sons, vídeos, etc.) ou caracteres.
A tabela a seguir apresenta as rotinas, condições de erro e constantes componentes do pacote Dbms_Lob.
Call Constante Lobs Temporários Indica que o Lob é válido somente durante aquela execução.
File_readonly Constante Bfiles Determina se o arquivo deve ser usado somente para leitura. O valor atual é 0, indicando que
somente leituras são permitidas.
Lobmaxsize Constante Todos Determina o tamanho máximo de um Lob. Atualmente seu valor é 4 GB (4294967295).
Read_Only Constante Todos Indica que o modo de abertura é leitura.
Read_Write Constante Todos Indica que o modo de abertura é gravação.
Session Constante Lobs Temporários Indica que o Lob é mantido até o fim da sessão.
Access_Error Exception Todos Tentativa de leitura ou gravação de um Lob com tamanho superior ao permitido (-22925).
Invalid_argval Exception Todos Indica que o parâmetro informado é inválido, fora do intervalo possível ou Null (-21560).
Invalid_directory Exception Todos Diretório inválido (-22287).
Invalid_operation Exception Todos Falha na execução da operação (-22288).
No_Data_Found Exception Todos Fim de arquivo em uma operação de leitura (-1403).
Noexist_Directory Exception Todos Diretório não existe. (-22285).
Nopriv_Directory Exception Todos Privilégios insuficientes para o diretório (-22286).
Open_TooMany Exception Todos Número limite de arquivos abertos atingido (-22290).
Unopened_file Exception Todos A operação não pode ser efetuada em um arquivo que não foi aberto. (-22289).
Compare Function Compara o conteúdo de dois Lobs.
continua
continuação
As funções do pacote Dbms_Lob retornam NULL se quaisquer dos valores dos parâmetros para estas rotinas forem NULL ou inválidos. Já as
procedures causam exceptions.
O Oracle9i suporta a criação, liberação, acesso e atualização de Lobs temporários. Seu tempo de vida padrão é uma
sessão, porém podem ser liberados a qualquer momento pela aplicação. São ideais como áreas de trabalho temporárias
para manipulação de dados. Como não são logados nem são armazenadas informações para redo, eles possuem
uma performance melhor que Lobs persistentes.
O PACOTE DBMS_OUTPUT
Este pacote tem a finalidade de enviar mensagens a partir de procedures, packages ou triggers. Ele se utiliza de um
buffer em memória para transferência das mensagens.
Quando um programa envia mensagens através do pacote Dbms_Output, essas mensagens são armazenadas na
área de buffer e somente apresentadas ao término do programa.
Caso estejamos executando o programa no SQL*Plus ou Server*Manager, basta que executemos o comando Set
Serveroutput On para que todas as mensagens enfileiradas pelo programa sejam apresentadas.
Se estivermos executando rotinas encadeadas ou blocos anônimos, podemos obter as linhas geradas pelo programa
anterior usando a rotina Get_Line do próprio pacote.
No quadro abaixo, apresentamos os componentes do pacote.
continuação
A Sintaxe 12.31 mostra as rotinas que compõem o pacote com seus respectivos parâmetros.
O PACOTE DBMS_PIPE
O pacote DBMS_PIPE permite que duas ou mais sessões na mesma instância se comuniquem. As informações são
enviadas através de uma área de memória chamada Pipe. Estas áreas são armazenadas na SGA.
De acordo com os requisitos de segurança de nossa instalação, podemos usar pipes públicos ou privados.
Podemos criar um Pipe Público explicita ou implicitamente.
A criação implícita ocorre quando fizermos a primeira referência ao Pipe e desaparecerá quando não mais contiver dados.
A criação explícita ocorre quando utilizamos a função Create_Pipe e informamos o parâmetro Private com o valor
False. Sua destruição também deverá ser explícita com a rotina Remove_Pipe.
O domínio do Pipe Público é o schema no qual ele foi criado, implicita ou explicitamente.
Cada Pipe Público trabalha assincronamente. Qualquer número de usuários (schemas) poderá gravar para um Pipe
Público (se tiver permissão de Execute no pacote Dbms_Pipe e conhecer seu nome).
Qualquer usuário com os privilégios e conhecimentos apropriados poderá ler informações de um Pipe Público.
Porém, uma vez que a informação é lida, o Pipe é esvaziado e a informação não fica mais disponível para outros
leitores do mesmo Pipe.
O pacote Dbms_Pipe fornece as rotinas necessárias aos procedimentos de criação, leitura e gravação de informações
em um Pipe (seja ele público ou privativo).
A criação de um Pipe Privativo é explícita através da chamada da função Create_Pipe. Uma vez criado, o Pipe
Privativo permanece na memória compartilhada (SGA) até que seja explicitamente removido (Remove_Pipe ou
que a instância seja shutdown).
Não poderemos criar um Pipe Privativo se existir na memória um Pipe Público com o mesmo nome.
Inicialmente, usamos a procedure Pack_Message, que armazena a mensagem para a área de buffer local da sessão.
Após termos juntado todas as mensagens desejadas no buffer, podemos enviá-las com a procedure Send_Message.
Esta rotina envia todas as mensagens armazenadas no buffer local.
A leitura se processa de forma inversa, devemos obter a informação do Pipe, usando a procedure Receive_Message
e armazená-la no buffer local da sessão, e em seguida desmembrá-la com a procedure Unpack_Message.
O quadro a seguir apresenta os diversos componentes deste pacote.
O PACOTE DBMS_RANDOM
Este pacote tem a finalidade de gerar números randômicos. Este gerador produz números inteiros de 8 dígitos.
Para que a geração tenha sucesso, devemos, como primeira etapa, inicializar a geração fornecendo um número de
mais de 5 dígitos.
Ao término da etapa de obtenção dos números randômicos devemos encerrar a execução do pacote com o uso da
rotina Terminate.
continuação
Initialize Procedure Inicializa o gerador. Deve-se fornecer como parâmetro um número com mais de 5 dígitos.
Seed Procedure Reinicializa o processo de geração. Deve receber um valor numérico como parâmetro.
Random Function Obtém o número randômico. Inteiro. Positivo ou negativo.
Terminate Procedure Deve ser executada ao término do processo de geração.
Normal (*) Function Obtém o número randômico. Positivo ou negativo.
Seed (*) Procedure Reinicializa o processo de geração. Deve receber um valor alfanumérico como parâmetro.
String (*) Function Obtém a string randômica. Deve receber dois parâmetros. O primeiro corresponde a um caracter numérico ou
alfanumérico e o segundo a um número que indica o tamanho do resultado.
Value (*) Function Obtém o número randômico. Podem ser informados dois parâmetros indicativos do intervalo desejado para
geração do número randômico. O resultado é Number.
As rotinas marcadas com (*) não estão presentes na documentação da Oracle. Se viermos a dar um DESC no pacote elas aparecerão. Neste livro
não as usaremos nos exemplos; no entanto, você pode testá-las substituindo-as nos exemplos e exercícios.
O PACOTE DBMS_ROWID
Cada linha no banco de dados tem um endereço. Este endereço é fornecido pela pseudocoluna Rowid.
Ao consultarmos o valor de Rowid para uma determinada linha, obtemos uma informação que representa seu endereço.
A maioria das rotinas deste pacote é composta de funções. Essas funções podem ser usadas tanto em PL/SQL quanto em comandos de SQL.
Na Sintaxe 12.34, são apresentadas as sintaxes de todas as rotinas que compõem o pacote.
O PACOTE UTL_FILE
O pacote Utl_File possui um conjunto de rotinas que têm a finalidade de permitir o acesso ou geração de arquivos
externos ao banco de dados. As rotinas são similares aos processos de manipulação de arquivos convencionais.
Para utilização deste package, o DBA deve acrescentar o parâmetro UTL_FILE_DIR ao arquivo de inicialização INIT.ORA a fim de determinar
quais diretórios estão disponíveis para acesso.
Sabemos que a PL/SQL executa no ambiente Server; assim, os arquivos lidos ou gravados com o uso deste pacote serão lidos ou gerados no
ambiente servidor (no ambiente em que se acha o banco de dados).
Este pacote não declara apenas procedures e funções, são declaradas exceções e tipos também.
O quadro abaixo apresenta um resumo dos diversos objetos presentes no pacote.
continuação
A Sintaxe 12.35 a seguir apresenta as rotinas presentes no pacote e seus respectivos parâmetros.
Este pacote trabalha de forma semelhante ao pacote Dbms_Output no que se refere à area de trabalho. Ele se utiliza
de um buffer em memória para transferência dos dados a serem armazenados ou lidos do arquivo em disco.
Quando um programa envia linhas para gravação através do pacote Utl_File, estas linhas são armazenadas na área
de buffer e transferidas para disco quando o buffer se enche ou quando acionamos a rotina Fflush, que força a
gravação do buffer para disco.
PL/SQL WRAPPER
Muitas vezes, necessitamos enviar aplicações de PL/SQL para instalação em ambientes externos ao de nossa
instalação. O código enviado, de um modo geral, fica exposto e passível de modificações indesejáveis.
A rotina Wrapper tem a finalidade de criptografar o código-fonte de tal forma que somente o Oracle tenha condições
de ler e compilar o texto gerado.
A rotina Wrapper converte o código-fonte de PL/SQL em uma forma intermediária de código-objeto.
O código-objeto gerado é portável como se fosse o próprio código-fonte. O compilador PL/SQL reconhece e carrega
o código gerado pelo Wrapper automaticamente.
A rotina Wrapper não é executada pelo banco de dados; é uma rotina externa e deve ser executada no sistema
operacional em uso.
Caso o arquivo de saída não seja especificado, será gerado com o mesmo nome do arquivo de entrada, com a
diferença apenas da extensão.
Não deve haver espaço nem antes nem depois dos sinais de igual.
A extensão default para o arquivo de entrada é .SQL e para o arquivo de saída, .PLB.
VARIÁVEIS CURSOR
Uma variável cursor (como um cursor) aponta para a linha corrente da “tabela” resultante gerada por uma query
que retorne um número indefinido de linhas.
Uma variável cursor, porém, possui uma diferença marcante em relação a um cursor: não está associada a uma
query específica. Pode ser associada a diversas queries ao longo de sua existência. Elas podem, ainda, ser definidas
como parâmetros de procedimentos.
A criação de uma variável cursor é similar à declaração de outros tipos (Nested Table, Varray, Record); inicialmente
devemos definir o tipo e posteriormente as variáveis com aquele tipo.
Na Sintaxe 12.37, temos a definição de um tipo Cursor. O <tipo retorno> que aparece na sintaxe representa o
layout da área de retorno, podendo ser definido como um record ou uma row em uma tabela do banco de dados.
Observe que a cláusula Return é opcional, indicando que o tipo pode determinar ou não o layout do retorno.
A tempo de Open da variável cursor é que determinamos a query a ser associada à variável.
Na Sintaxe 12.38, vemos os três comandos para manipulação de variáveis do tipo Cursor. Para variáveis cursor não
temos o comando Cursor Loop.
Em um pacote podemos definir o tipo cursor, não a variável global. O que criamos na definição de uma variável
cursor é um ponteiro e não um item; desta forma não possui um estado persistente, não podendo, assim, ser
definida em pacotes.
Quando declaramos uma variável cursor como parâmetro formal de um subprograma que obtém linhas desta variável, devemos especificar o
parâmetro no modo IN (ou IN OUT). Se o subprograma também abrir a variável cursor, devemos especificar o modo IN OUT.
OPEN-FOR DINÂMICO
Para efetuarmos o processamento de uma consulta, que retorne diversas linhas, de forma dinâmica, deveremos
utilizar três comandos: Open uma variável cursor For uma consulta de múltiplas linhas, então, Fetch as linhas para
variáveis locais da aplicação e, finalmente, quando todas as linhas tiverem sido processadas, Close a variável cursor.
Na Sintaxe 12.39, apresentamos o comando Open For capaz de realizar uma consulta dinâmica.
Onde:
♦ <string dinâmica> – É uma string que contém um comando SQL Select que retorna diversas linhas.
♦ <Bind> – É uma expressão cujo valor é passado dinamicamente para o comando SQL.
Qualquer argumento Bind na consulta é avaliado somente quando o cursor é aberto. Desta forma, para obtermos dados do cursor usando
diferentes valores de argumento, devemos reabrir a variável cursor com os argumentos Bind contendo os novos valores desejados.
Os comandos Fetch e Close para uso com Open-For possuem a mesma sintaxe vista anteriormente. Não foram repetidos.
TRIGGERS
Triggers são códigos de PL/SQL armazenados no banco de dados, associados a uma tabela específica e executados
implicitamente pelo Oracle na ocorrência de um determinado evento.
A Oracle recomenda que limitemos o tamanho do código de PL/SQL do trigger para algo em torno de 60 linhas.
Caso tenhamos necessidade de definir um trigger mais complexo, devemos criar stored procedures com ações
específicas e acionar estas rotinas dentro do trigger.
A Sintaxe 12.40 apresenta a criação de um Database Trigger. Esta sintaxe é subdividida em três partes:
♦ Evento – O evento corresponde ao momento em que o database trigger deve ser acionado pelo Oracle.
♦ Tipo – Um trigger pode ser de dois tipos: Comando ou Linha.
Um trigger de comando é acionado de acordo com o evento, mas associado ao comando como um todo. Ou seja,
será acionado antes ou depois de um determinado comando, independente de o comando atualizar uma ou mais
linhas. Este tipo de trigger não tem acesso às linhas atualizadas.
Um trigger do tipo Row é acionado de acordo com o evento, mas uma vez para cada linha afetada pelo comando
disparado pelo usuário.
Sintaticamente, para indicação deste tipo de trigger, basta que especifiquemos a cláusula For Each Row.
♦ Ação – A última parte de um trigger é composta do bloco de PL/SQL associado ao evento.
Quando criamos um trigger associado a mais de um comando de DML (Insert, Update ou Delete), muitas vezes
temos necessidade, dentro do código de PL/SQL, de saber qual o evento causador da execução do trigger. Isto é
possível se usarmos os predicados condicionais:
♦ Inserting – Retorna True se o trigger foi disparado por causa de um comando Insert.
♦ Updating – Retorna True se o trigger foi disparado por causa de um comando Update.
♦ Deleting – Retorna True se o trigger foi disparado por causa de um comando Delete.
Além dos tradicionais eventos associados a DML, o DBA pode efetuar o controle sobre eventos de DDL tais como:
♦ Create (o trigger é disparado quando um comando Create adiciona um novo objeto ao dicionário de dados).
♦ Alter (o trigger é disparado quando um objeto do dicionário de dados é modificado).
♦ Drop (o trigger é disparado quando um objeto do dicionário de dados é removido).
♦ Analyze (o trigger é disparado quando o Oracle colecionar ou deletar estatísticas ou validar a estrutura de um
objeto do dicionário de dados).
♦ Associate Statistics (o trigger é disparado quando houver associação de estatísticas de determinado tipo a um
objeto do dicionário de dados).
♦ Audit (o trigger é disparado quando ocorrer a auditoria sobre um objeto do dicionário de dados).
♦ Comment (o trigger é disparado quando forem adicionados comentários a um objeto do dicionário de dados).
♦ Disassociate Statistics (o trigger é disparado quando houver desassociação de estatísticas de um objeto do dicionário
de dados).
♦ Grant (o trigger é disparado quando um usuário der autorização a outro usuário ou role).
♦ Noaudit (o trigger é disparado quando houver interrupção do processo de auditoria sobre um objeto do dicionário
de dados).
♦ Rename (o trigger é disparado quando um objeto do dicionário de dados mudar de nome).
♦ Revoke (o trigger é disparado quando um usuário revogar autorizações de outro usuário ou role).
♦ Truncate (o trigger é disparado quando uma tabela tiver todos os dados removidos).
Para esse tipo de evento, temos como restrição os eventos disparados através de rotinas PL/SQL, que não podem
ser controlados.
O controle também pode ser efetuado para eventos do banco de dados, tais como:
♦ Servererror (é disparado quando é gravada uma mensagem de erro do servidor).
♦ Logon (é disparado quando uma aplicação cliente estabelece conexão com o banco de dados).
♦ Logoff (é disparado quando uma aplicação cliente fecha a conexão com o banco de dados).
♦ Startup (é disparado quando o banco de dados é aberto).
♦ Shutdown (é disparado quando uma instância do Oracle é fechada).
Capítulo 13
PROPRIEDADES DO FORMS
As propriedades serão apresentadas com seu nome em português e entre parênteses com seu nome em inglês.
Estão associadas aos objetos aos quais pertencem e subdivididas de acordo com o grupo correspondente na tela de
propriedades do Forms.
ALERTA (ALERT)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
TÍTULO (TITLE)
Especifica o título a ser apresentado para o objeto.
MENSAGEM (MESSAGE)
Determina a mensagem que será apresentada pelo alerta.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
objeto é apresentado com a cor da camada de fundo – Background), Clear (None – o objeto é transparente e não é
afetado pelas cores das camadas).
Para os demais padrões, o desenho em preto é apresentado com a cor da primeira camada (Foreground) e o desenho
branco é apresentado com a cor da camada de fundo (Background).
O padrão Clear (ou None) não está disponível para itens e nem canvas. Para os dois objetos, o melhor padrão é Transparent.
Na paleta de padrões apresentada pelo editor de layout, o padrão sólido é representado pelo quadrado preto (segundo
a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro a partir do
canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando selecionamos a opção
Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
FONTE (FONT)
NOME DA FONTE (FONT NAME)
Esta propriedade determina o nome da fonte a ser usada para textos no objeto.
INTERNACIONAL (INTERNATIONAL)
DIREÇÃO (DIRECTION)
Esta propriedade é útil apenas para aplicações bidirecionais (National Language Support).
Especifica a direção de desenvolvimento do objeto. Três valores são válidos para esta propriedade: Default, Da
Direita para a Esquerda (para linguagens mostradas da direita para a esquerda) e Da Esquerda para a Direita (para
linguagens mostradas da esquerda para a direita).
Para a maioria dos objetos, excetuando-se itens de texto e itens de display (os itens da lista – List items possuem
também a propriedade Estado Inicial do Teclado), esta é a única propriedade bidirecional.
A propriedade Direction do Form é herdada das variáveis NLS definidas no ambiente se seu valor no Form for Default.
Todos os objetos da aplicação (exceto os itens) herdam essa propriedade diretamente do módulo Form se receberem o
valor default. Os itens herdam essa propriedade da canvas (que herda do módulo Form).
Os itens de texto e de display, a tempo de desenvolvimento (no Form Builder), não possuem a propriedade Direc-
tion e sim as propriedades Justificação, Ordem de Leitura e Estado Inicial do Teclado, porém, na programação,
podemos definir Direction para todos os objetos, inclusive itens.
Para cada tipo de objeto esta propriedade pode ter uma forma específica de afetar a apresentação. Por exemplo,
para um item do tipo Caixa de Verificação (Check Box), essa propriedade afeta a posição da caixa em relação ao
texto, a ordem de leitura da etiqueta (label) do objeto e o estado inicial do teclado quando o objeto recebe o foco.
Para detalhes específicos de cada elemento acione a opção Tópicos de Ajuda do Form Builder no menu Ajuda e
pesquise pelo tópico Language Direction.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
Para os demais padrões, o desenho em preto é apresentado com a cor da primeira camada (Foreground) e o desenho
branco é apresentado com a cor da camada de fundo (Background).
O padrão Clear (ou None) não está disponível para itens e nem canvas. Para os dois objetos, o melhor padrão é
Transparent.
Na paleta de padrões apresentada pelo editor de layout, o padrão sólido é representado pelo quadrado preto (segundo
a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro a partir do
canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando selecionamos a opção
Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
FONTE (FONT)
NOME DA FONTE (FONT NAME)
Esta propriedade determina o nome da fonte a ser usada para textos no objeto.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
NAVEGAÇÃO (NAVIGATION)
ESTILO DE NAVEGAÇÃO (NAVIGATION STYLE)
Esta propriedade determina o que ocorre quando o foco está sobre o último item (relativamente à seqüência de
navegação) de um bloco e o usuário aciona a ação de Próximo Item (Next Item), ou, inversamente, quando o foco
está posicionado sobre o primeiro item (relativamente à seqüência de navegação) de um bloco e o usuário aciona
a ação de Item Anterior (Previous Item).
Existem três opções de valor válidas:
♦ Mesmo Registro (Same Record) – Corresponde à opção default. Uma operação de Próximo Item (Next Item) movimenta
o foco para o primeiro item navegável deste mesmo bloco sem mudar de registro.
♦ Alterar Registro (Change Record) – Uma operação de Próximo Item (Next Item) movimenta o foco para o
primeiro item navegável deste mesmo bloco, porém, no próximo registro.
♦ Alterar Bloco de Dados (Change Block) – Uma operação de Próximo Item (Next Item) movimenta o foco para o
primeiro item navegável do próximo bloco. Caso o foco esteja posicionado no primeiro item navegável de um
bloco e for realizada uma operação de Item Anterior (Previous Item), o foco será movido para o último item
navegável do bloco anterior.
REGISTROS (RECORDS)
GRUPO DE ATRIBUTOS VISUAIS DO REGISTRO ATUAL (CURRENT RECORD VISUAL ATTRIBUTE GROUP)
Esta propriedade determina o nome de um grupo de atributos visuais que será utilizado quando o item for parte do
registro corrente.
Essa propriedade pode ser definida em nível de módulo, bloco ou item. O nível mais específico se sobrepõe ao
nível mais genérico.
Este valor pode afetar a performance da sua aplicação. Valores maiores para esta propriedade dão uma perfor-
mance melhor. Valores menores utilizarão menos memória, em compensação farão uma quantidade maior de
operações de I/O para leitura em disco.
Devemos considerar a existência de itens grandes no bloco e, neste caso, diminuir esse número ou a existência de
intensa atividade de digitação (inclusão/alteração) para esse bloco e itens pequenos, sendo preferível, neste caso,
aumentar esse número.
Esse valor é herdado por todos os itens destes bloco por default. A exibição dos itens será múltipla.
Se essa propriedade receber um valor maior que 1, diremos que o bloco é multi-record.
Devemos marcar essa propriedade com Sim para um bloco de controle que contenha um sumário calculado a
partir de um item ou um controle VBX ou ActiveX. A esta propriedade deve ser atribuído Não para um bloco de
controle que contenha itens a serem sumariados e mostrados num item de cálculo em outro bloco de controle, o
qual deve receber Sim.
Quando essa propriedade recebe Sim, devemos determinar a origem dos dados (table, procedure, transacional
trigger ou Sub-query).
Quando essa propriedade recebe Não, o Forms ignora as propriedades relativas à origem dos dados.
Se a propriedade “Tipo de Origem de Dados de Consulta” for Tabela, deveremos preencher essa propriedade com
o nome da tabela; se for Procedimento, preencheremos com o nome do procedimento (de consulta) no banco de
dados e, se for Consulta da Cláusula From, com o nome da sub-query.
Essa propriedade não é válida para Gatilhos Transacionais (Transactional Triggers).
Só é válido quando o tipo de origem de dado do bloco (Query Data Source Type) for procedimento (Procedure).
APELIDO (ALIAS)
Estabelece um alias para a tabela à qual o bloco de dados está associado. Por default, o Form Builder associa a
primeira letra correspondente ao nome da tabela. Essa propriedade é de preenchimento obrigatório para blocos de
dados que contenham colunas do tipo Ref.
Podemos fazer referência aos seguintes objetos: colunas da tabela (exceto do tipo Long), itens do bloco (formato
:<nome do bloco>.<nome do item>), variáveis globais (formato :Global.<nome da variável>) e parâmetros (formato
:Parameter.<nome do parâmetro>).
Quando esta opção recebe o valor Não, o Form reaproveita o mesmo comando SQL para diversas atualizações, sem ter de
refazer a fase de Parse a cada comando. Ao modificarmos este valor para Sim, cada comando significará um novo Parse.
O banco de dados não permitirá a atualização da coluna se o usuário não tiver privilégio para tal, independente da opção definida no Forms.
Essa opção só é utilizada quando a opção Consultar Todos os Registros (Query All Records) estiver marcada.
INSERIR COLUNAS DE CONJUNTOS DE RESULTADOS DE PROCEDIMENTO (INSERT PROCEDURE RESULT SET COLUMNS)
Especifica o nome, tipo, tamanho e indicação de obrigatoriedade do conjunto de colunas associadas com o resultado
do procedimento para inclusão de dados oriundos do Bloco de Dados. Esta propriedade só é válida se o tipo de
destino é procedimento (Procedure).
ATUALIZAR COLUNAS DE CONJUNTOS DE RESULTADOS DE PROCEDIMENTO (UPDATE PROCEDURE RESULT SET COLUMNS)
Especifica o nome, tipo, tamanho e indicação de obrigatoriedade do conjunto de colunas associadas com o resultado
do procedimento para atualização de dados oriundos do Bloco de Dados. Esta propriedade só é válida se o tipo de
destino é procedimento (Procedure).
DELETAR COLUNAS DE CONJUNTOS DE RESULTADOS DE PROCEDIMENTO (DELETE PROCEDURE RESULT SET COLUMNS)
Especifica o nome, tipo, tamanho e indicação de obrigatoriedade do conjunto de colunas associadas com o resultado
do procedimento para exclusão de dados oriundos do Bloco de Dados. Esta propriedade só é válida se o tipo de
destino é procedimento (Procedure).
BLOQUEAR COLUNAS DE CONJUNTOS DE RESULTADOS DE PROCEDIMENTO (LOCK PROCEDURE RESULT SET COLUMNS)
Especifica o nome, tipo, tamanho e indicação de obrigatoriedade do conjunto de colunas associadas com o resultado
do procedimento para bloqueio de dados oriundos do Bloco de Dados. Esta propriedade só é válida se o tipo de
destino é procedimento (Procedure).
Quando aumentamos este valor, estamos aumentando a performance; em compensação, também estamos
aumentando a memória necessária para as operações de atualização no banco de dados.
O valor ideal para este parâmetro seria igual à quantidade média de registros que um usuário modifica a cada transação.
Quando este valor for maior que 1 e o bloco admitir inclusões, devemos definir as colunas PK para este bloco.
Quando o Forms faz uma inclusão individual de linha, este processo obtém o Rowid da linha a fim de permitir
futuras atualizações ou exclusões. Quando, porém, aumentamos a quantidade de linhas a serem incluídas em um
único passo, o Rowid não é retornado, sendo necessária, então, a identificação da PK do bloco. A PK é utilizada para
bloqueio da linha modificada e conseqüente obtenção do Rowid. O Rowid é utilizado para a atualização e a exclusão.
Quando esta opção recebe um valor maior que 1, a propriedade “Atualizar somente as colunas alteradas” (Update Changed
Columns Only) recebe o valor Não a tempo de execução, mesmo que tenhamos marcado como Sim no Form Builder.
Se houver no bloco um item do tipo Long Raw (imagem, som ou OLE), esta propriedade será modificada para 1 a
tempo de execução.
Esta propriedade é especialmente útil quando temos triggers associados à tabela que modificam o valor de
determinadas colunas a tempo de exclusão ou alteração.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
Para os demais padrões, o desenho em preto é apresentado com a cor da primeira camada (Foreground) e o desenho
branco é apresentado com a cor da camada de fundo (Background).
O padrão Clear (ou None) não está disponível para itens e nem canvas. Para os dois objetos, o melhor padrão é Transparent.
Na paleta de padrões apresentada pelo editor de layout: o padrão sólido é representado pelo quadrado preto (segundo
a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro a partir do
canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando selecionamos a opção
Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
INTERNACIONAL (INTERNATIONAL)
DIREÇÃO (DIRECTION)
Esta propriedade é útil apenas para aplicações bidirecionais (National Language Support).
Especifica a direção de desenvolvimento do objeto. Três valores são válidos para esta propriedade: Default, Da
Direita para a Esquerda (para linguagens mostradas da direita para a esquerda) e Da Esquerda para a Direita (para
linguagens mostradas da esquerda para a direita).
Para a maioria dos objetos, excetuando-se itens de texto e itens de display (os itens da lista – List items possuem
também a propriedade Estado Inicial do Teclado), esta é a única propriedade bidirecional.
A propriedade Direction do Form é herdada das variáveis NLS definidas no ambiente se seu valor no Form for
Default. Todos os objetos da aplicação (exceto os itens) herdam essa propriedade diretamente do módulo Form se
receberem o valor default. Os itens herdam esta propriedade da canvas (que herda do módulo Form).
Os itens de texto e de display, a tempo de desenvolvimento (no Form Builder), não possuem a propriedade Direc-
tion e sim as propriedades Justificação, Ordem de Leitura e Estado Inicial do Teclado, porém, na programação,
podemos definir Direction para todos os objetos, inclusive itens.
Para cada tipo de objeto esta propriedade pode ter uma forma específica de afetar a apresentação. Por exemplo,
para um item do tipo Caixa de Verificação (Check Box), essa propriedade afeta a posição da caixa em relação ao
texto, a ordem de leitura da etiqueta (label) do objeto e o estado inicial do teclado quando o objeto recebe o foco.
Para detalhes específicos de cada elemento acione a opção Tópicos de Ajuda do Form Builder no menu Ajuda e
pesquise pelo tópico Language Direction.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
ATIVADO (ENABLED)
Esta propriedade indica se o objeto poderá receber foco, seja através da navegação-padrão (tecla Tab) ou através de
rotinas predefinidas (Next_Item, Go_Item, etc.).
O quadro a seguir mostra a relação entre a propriedade Ativado (Enabled) e a propriedade Navegável com Teclado
(Keyboard Navigable).
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
ETIQUETA (LABEL)
Esta propriedade armazena o texto que será apresentado na etiqueta para um botão, caixa de checagem (Check
Box), botão de rádio (Radio Button), página Tab (usuário poderá clicar no label para que a página de Tab
correspondente seja apresentada), item de menu ou que será apresentado ao usuário para o preenchimento do
parâmetro de substituição (do menu).
O caracter que servirá como chave de acesso é mostrado no vídeo sublinhado no texto da etiqueta (Label).
REGISTROS (RECORDS)
DISTÂNCIA ENTRE REGISTROS (DISTANCE BETWEEN RECORDS)
Esta propriedade determina a distância entre as instâncias dos itens em um bloco multi-record.
FÍSICO (PHYSICAL)
VISÍVEL (VISIBLE)
Esta propriedade determina se o objeto em questão ficará visível quando a aplicação for inicialmente executada.
Essa propriedade pode ser modificada posteriormente por programação.
Como restrição temos que não podemos esconder uma canvas que contenha o item corrente, da mesma forma que
não podemos esconder uma janela que contenha o item corrente.
POSIÇÃO X (X POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é da esquerda para a direita, ou seja, o valor 0 corresponde exatamente à
posição da linha esquerda da tela ou da canvas. A partir deste ponto e em direção ao lado direito da tela ou canvas,
esse valor é crescente.
POSIÇÃO Y (Y POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é de cima para baixo, ou seja, o valor 0 corresponde exatamente à posição da linha
superior da tela ou da canvas. A partir deste ponto e em direção à parte inferior da tela ou canvas, esse valor é crescente.
LARGURA (WIDTH)
Especifica a largura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
ALTURA (HEIGHT)
Especifica a altura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
FONTE (FONT)
NOME DA FONTE (FONT NAME)
Esta propriedade determina o nome da fonte a ser usada para textos no objeto.
PROMPT (PROMPT)
PROMPT (PROMPT)
Especifica o texto que será mostrado para o item.
CANVAS (CANVAS)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
AUMENTAR NA ENTRADA (RAISE ON ENTRY)
Esta propriedade especifica como o Forms deve mostrar a canvas quando o usuário navega para um item em outra
canvas apresentada na mesma janela.
Se essa propriedade receber o valor Não, o Forms coloca a canvas na frente de todas as outras canvas presentes na
janela somente se o item para o qual o usuário navegou estiver escondido por trás da outra canvas.
Se esta propriedade receber o valor Sim, basta que o usuário navegue para qualquer item de outra canvas (mesmo
que seja um item visível atualmente) para que esta canvas seja colocada na frente de todas as outras.
VISUALIZADOR (VIEWPORT)
POSIÇÃO X DO VISOR (VIEWPORT X POSITION)
Especifica a coordenada X para o canto esquerdo superior de uma canvas do tipo Stacked em relação ao canto
esquerdo superior da canvas Content que preenche a janela.
FÍSICO (PHYSICAL)
VISÍVEL (VISIBLE)
Esta propriedade determina se o objeto em questão ficará visível quando a aplicação for inicialmente executada.
Esta propriedade pode ser modificada posteriormente por programação.
Como restrição temos que não podemos esconder uma canvas que contenha o item corrente, da mesma forma que
não podemos esconder uma janela que contenha o item corrente.
JANELA (WINDOW)
Especifica a janela na qual a canvas será mostrada a tempo de execução. Esta propriedade, caso não seja especificada,
mostra a canvas na janela principal(Root_Window), se existir; caso contrário, na primeira janela do nó Janelas (Windows).
LARGURA (WIDTH)
Especifica a largura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
ALTURA (HEIGHT)
Especifica a altura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
BEVEL (BEVEL)
Especifica a aparência da borda do objeto. Os valores válidos para esta propriedade são: Diminuído (Lowered),
Aumentado (Raised), Nenhum (None), Inset ou Outset.
Esta propriedade é aplicável a itens do tipo Chart, Custom, Text e canvas do tipo Stack, mas apenas em ambientes
Microsoft Windows.
Os valores válidos para esta propriedade são: Topo (Top), Base (Bottom), Esquerda (Left), Direita (Right), Inicial
(Initial), Final (Final).
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
Para os demais padrões, o desenho em preto é apresentado com a cor da primeira camada (Foreground) e o desenho
branco é apresentado com a cor da camada de fundo (Background).
O padrão Clear (ou None) não está disponível para itens e nem canvas. Para os dois objetos, o melhor padrão é
Transparent.
Na paleta de padrões apresentada pelo editor de layout, o padrão sólido é representado pelo quadrado preto (segundo
a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro a partir do
canto esquerdo superior) e o padrão Clear (None na paleta de propriedades) é utilizado quando selecionamos a opção
Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
FONTE (FONT)
NOME DA FONTE (FONT NAME)
Esta propriedade determina o nome da fonte a ser usada para textos no objeto.
INTERNACIONAL (INTERNATIONAL)
DIREÇÃO (DIRECTION)
Esta propriedade é útil apenas para aplicações bidirecionais (National Language Support).
Especifica a direção de desenvolvimento do objeto. Três valores são válidos para esta propriedade: Default, Da
Direita para a Esquerda (para linguagens mostradas da direita para a esquerda) e Da Esquerda para a Direita (para
linguagens mostradas da esquerda para a direita).
Para a maioria dos objetos, excetuando-se itens de texto e itens de display (os itens da lista – List items possuem
também a propriedade Estado Inicial do Teclado), esta é a única propriedade bidirecional.
A propriedade Direction do Form é herdada das variáveis NLS definidas no ambiente se seu valor no Form for Default.
Todos os objetos da aplicação (exceto os itens) herdam essa propriedade diretamente do módulo Form se receberem o
valor default. Os itens herdam essa propriedade da canvas (que herda do módulo Form).
Os itens de texto e de display, a tempo de desenvolvimento (no Form Builder), não possuem a propriedade Direc-
tion e sim as propriedades Justificação, Ordem de Leitura e Estado Inicial do Teclado, porém, na programação,
podemos definir Direction para todos os objetos, inclusive itens.
Para cada tipo de objeto esta propriedade pode ter uma forma específica de afetar a apresentação. Por exemplo,
para um item do tipo Caixa de Verificação (Check Box), essa propriedade afeta a posição da caixa em relação ao
texto, a ordem de leitura da etiqueta (label) do objeto e o estado inicial do teclado quando o objeto recebe o foco.
Para detalhes específicos de cada elemento acione a opção “Tópicos de Ajuda do Form Builder” no menu Ajuda e
pesquise pelo tópico Language Direction.
EDITOR (EDITOR)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
TÍTULO (TITLE)
Especifica o título a ser apresentado para a janela do editor.
FÍSICO (PHYSICAL)
POSIÇÃO X (X POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é da esquerda para a direita, ou seja, o valor 0 corresponde exatamente à
posição da linha esquerda da tela ou da canvas. A partir deste ponto e em direção ao lado direito da tela ou canvas,
esse valor é crescente.
POSIÇÃO Y (Y POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é de cima para baixo, ou seja, o valor 0 corresponde exatamente à posição
da linha superior da tela ou da canvas. A partir deste ponto e em direção à parte inferior da tela ou canvas, esse
valor é crescente.
LARGURA (WIDTH)
Especifica a largura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
ALTURA (HEIGHT)
Especifica a altura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
FONTE (FONT)
NOME DA FONTE (FONT NAME)
Esta propriedade determina o nome da fonte a ser usada para textos no objeto.
GATILHO (TRIGGER)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
ESTILO DE GATILHO (TRIGGER STYLE)
Indica se um gatilho (Trigger) está escrito em linguagem PL/SQL ou no estilo V2. A Oracle Corporation recomenda
que todos os gatilhos sejam escritos em PL/SQL. O Estilo V2 foi mantido nesta versão apenas para compatibilidade
com versões anteriores. Esta propriedade não é mutável.
Esta propriedade só é aplicável aos seguintes gatilhos (triggers): Key-*, On-Error, On-Message, When-* (exceto
When-Database-Record, When-Image-Activated, When-New-Block-Instance, When-New-Form-Instance, When-
Create-Record, When-Remove-Record, When-Validate-Record e When-Validate-Item)
AJUDA (HELP)
EXIBIÇÃO NA ‘AJUDA DO TECLADO’ (DISPLAY IN ‘KEYBOARD HELP’)
Esta propriedade determina se a descrição do gatilho (somente para gatilhos do tipo Key-*) será mostrada na janela
de ajuda (Teclas – Keys).
Se não desejarmos que seja apresentado um nome ou descrição para esta tecla na janela de ajuda (Teclas), devemos
preencher esta propriedade com o valor Não (default).
Se desejarmos que o texto default para esta tecla seja apresentado, devemos preencher esta propriedade com Sim e
deixar a descrição em branco. Caso desejarmos substituir a descrição default por outra, devemos também preencher
a propriedade Descrição (a seguir).
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
TIPO DE GRUPO DE REGISTROS (RECORD GROUP TYPE)
Esta propriedade determina o tipo do Grupo de Registros (Record Group).
Os valores válidos para esta propriedade são:
♦ Estático (Static) – Especifica que o grupo de registros (Record Group) é constituído de colunas, linhas e valores
construídos a tempo de desenvolvimento, que não podem ser modificados a tempo de execução.
♦ Consulta (Query) – Especifica que o grupo de registros (Record Group) está associado a um comando Select e
que será preenchido a tempo de execução.
ITEM (ITEM)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
Deste grupo de opções, dois tipos não têm associação com colunas do banco de dados: Chart Item e Button.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
O quadro a seguir mostra a relação entre a propriedade Ativado (Enabled) e a propriedade Navegável com Teclado
(Keyboard Navigable).
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
ETIQUETA (LABEL)
Esta propriedade contém o texto que será apresentado na etiqueta para um botão, caixa de checagem (Check Box), botão
de rádio (Radio Button), página Tab (usuário poderá clicar no label para que a página de Tab correspondente seja apresentada),
item de menu ou que será apresentado ao usuário para o preenchimento do parâmetro de substituição (do menu).
O caracter que servirá como chave de acesso é mostrado no vídeo sublinhado no texto da etiqueta (Label).
MAPEAMENTO DE OUTROS VALORES DA CAIXA DE SELEÇÃO (CHECK BOX MAPPING OF OTHER VALUES)
Esta propriedade determina como qualquer valor lido ou atribuído a este item deve ser interpretado. Os valores
válidos para esta propriedade são:
♦ Não Permitido (Not Allowed) – Qualquer registro que contenha um valor diferente daqueles mapeados nas
propriedades anteriores será rejeitado, isto é, não será lido do banco de dados. Se for feita uma tentativa de
associação de um valor não mapeado para este item, causa erro.
♦ Assinalado (Checked) – Qualquer valor diferente daqueles mapeados nas propriedades anteriores será mostrado
para o usuário como assinalado.
♦ Seleção Cancelada (Unchecked) – Qualquer valor diferente daqueles mapeados nas propriedades anteriores será
mostrado para o usuário como não assinalado.
♦ Final (End) – Indica que o texto será alinhado à direita ou esquerda, dependendo do valor da propriedade
Ordem de Leitura – Reading Order. Por exemplo, se a propriedade Ordem de Leitura receber o valor Esquerda
para Direita, o valor Final indicará que o texto será alinhado à direita.
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
Os valores válidos para esta propriedade são: BMP, CALS, GIF, JFIF, PICT, RAS, TIFF, TPIC.
O formato default Oracle para imagens não é mais válido.
O valor que especificarmos para esta propriedade irá se sobrepor ao formato original de uma imagem quando o registro
contendo a imagem for armazenado no banco de dados. Suponhamos que tivéssemos preenchido um item imagem com
uma imagem do tipo TIFF, mas esta propriedade estivesse preenchida com o valor GIF. A tempo de execução, a imagem
seria convertida para GIF e armazenada no banco de dados neste formato.
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
Lembre-se, porém, de que em memória o item continua com o valor originalmente lido; não é feita nenhuma
modificação no valor presente na memória.
♦ Misto (Mixed) – Não ocorre conversão. O que for digitado é armazenado sem alteração.
♦ Superior (Upper) – Qualquer texto digitado em minúsculas é convertido para maiúsculas.
♦ Inferior (Lower) – Qualquer texto digitado em maiúsculas é convertido para minúsculas.
Esta propriedade é válida tanto para os textos digitados quanto para os textos atribuídos ao item por programação,
ou através de leitura do banco de dados.
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
O quadro a seguir mostra a relação entre a propriedade Ativado (Enabled) e a propriedade Navegável com Teclado
(Keyboard Navigable).
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
Ela especifica se, nesta situação, podemos abrir mais de um objeto simultaneamente (do mesmo tipo). Quando
trabalhamos com Word ou Excel, é comum abrirmos mais de um documento ao mesmo tempo.
O quadro a seguir mostra a relação entre a propriedade Ativado (Enabled) e a propriedade Navegável com Teclado
(Keyboard Navigable).
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
ETIQUETA (LABEL)
Esta propriedade armazena o texto que será apresentado na etiqueta para um botão, caixa de checagem (Check
Box), botão de rádio (Radio Button), página Tab (usuário poderá clicar no label para que a página de Tab
correspondente seja apresentada), item de menu ou que será apresentado ao usuário para o preenchimento do
parâmetro de substituição (do menu).
ICÔNICO (ICONIC)
Indica se o botão será representado por um ícone.
Quando por programação ou através de leitura do banco de dados for lido um valor de dado não presente na lista, o
Form Runtime apresentará o texto correspondente ao valor informado nesta propriedade.
Lembre-se, porém, de que em memória o item continua com o valor originalmente lido; não é feita nenhuma
modificação no valor presente na memória.
O quadro a seguir mostra a relação entre a propriedade Ativado (Enabled) e a propriedade Navegável com Teclado
(Keyboard Navigable).
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
continua
continuação
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
A rotina Write_Sound_File para efetuar a gravação de um arquivo de som para o sistema operacional possui um
parâmetro (channels) para que possamos determinar o número de canais.
COMPACTAR (COMPRESS)
Especifica se um arquivo de som lido para um item deve ser comprimido quando convertido para o formato
interno do Oracle.
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
JUSTIFICAÇÃO (JUSTIFICATION)
Esta propriedade especifica a justificação do texto dentro do item. Pode ser preenchida com os seguintes valores:
♦ Esquerda (Left) – Faz a justificação pela esquerda, independente do valor da propriedade Ordem de Leitura
(Reading Order).
♦ Centralizado (Center) – Faz a justificação pelo centro, independente do valor da propriedade Ordem de Leitura
(Reading Order).
♦ Direita (Right) – Faz a justificação pela direita, independente do valor da propriedade Ordem de Leitura (Reading Order).
♦ Inicial (Start) – O texto é alinhado por uma das laterais, de acordo com o valor da propriedade Ordem de Leitura
(Reading Order). Seu alinhamento será pela direita se Ordem de Leitura (Reading Order) estiver preenchida com
Direita para Esquerda (Right To Left) e será pela esquerda se Ordem de Leitura (Reading Order) estiver preenchida
com Esquerda para Direita (Left To Right).
♦ Final (End) – O texto é alinhado por uma das laterais, de acordo com o valor da propriedade Ordem de Leitura
(Reading Order). Seu alinhamento será pela esquerda se Ordem de Leitura (Reading Order) estiver preenchida com
Direita para Esquerda (Right To Left) e será pela direita se Ordem de Leitura (Reading Order) estiver preenchida com
Esquerda para Direita (Left To Right).
♦ Misto (Mixed) – Não ocorre conversão. O que for digitado é armazenado sem alteração.
♦ Superior (Upper) – Qualquer texto digitado em minúsculas é convertido para maiúsculas.
♦ Inferior (Lower) – Qualquer texto digitado em maiúsculas é convertido para minúsculas.
Essa propriedade é válida tanto para os textos digitados quando para os textos atribuídos ao item por programação
ou através de leitura do banco de dados.
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
O quadro a seguir mostra a relação entre a propriedade Ativado (Enabled) e a propriedade Navegável com Teclado
(Keyboard Navigable).
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
ETIQUETA (LABEL)
Esta propriedade contém o texto que será apresentado na etiqueta para um botão, caixa de checagem (Check Box),
botão de rádio (Radio Button), página Tab (usuário poderá clicar no label para que a página de Tab correspondente
seja apresentada), item de menu ou que será apresentado ao usuário para o preenchimento do parâmetro de
substituição (do menu).
ICÔNICO (ICONIC)
Indica se o formato do item deve ser um ícone.
MULTISSELEÇÃO (MULTI-SELECTION)
Indica se o usuário poderá ou não selecionar mais de um elemento na árvore.
GRÁFICO (CHART)
EIXO X DA ORIGEM DE DADOS (DATA SOURCE X AXIS)
Determina o nome do item que será usado no eixo X para a montagem do gráfico.
NAVEGAÇÃO (NAVIGATION)
NAVEGÁVEL COM TECLADO (KEYBOARD NAVIGABLE)
Determina se, a tempo de execução, o item poderá receber foco (ou seja, se o usuário poderá posicionar o cursor
sobre este item usando o teclado). Se preenchermos esta propriedade com o valor Não (No), o Form pulará este
item e navegará para o próximo item na seqüência de navegação (que, por default, é determinada pela ordem do
Navegador de Objetos – Object Navigator).
Só válida para itens do tipo tecla (button), caixa de verificação (check box), item da lista (list item) ou grupo de
rádios (radio group).
Para que a ação associada a um botão seja executada, não é necessário que ocorra a navegação para ele; basta que
a propriedade Ativado (Enabled) esteja marcada para que isto ocorra.
No caso do botão devemos considerar deixar esta propriedade (Mouse Navigate) desmarcada se desejarmos que a
ação associada ao botão seja efetuada sobre o item que detém o foco atualmente (e não o item do botão).
DADOS (DATA)
TIPO DE DADOS (DATA TYPE)
Nesta propriedade devemos especificar o tipo de dado a ser armazenado. A Oracle recomenda que a partir do
Form Builder 5.0 passemos a utilizar somente Car (Character), Número (Number), Data (Date) ou Extenso (Long).
As demais opções de valores (possíveis apenas para itens de texto) foram mantidas para compatibilidade com
versões anteriores.
O tipo de dado de um item deve ser compatível com o tipo de dado da coluna correspondente no banco de dados.
Para coluna Varchar2 no banco de dados devemos especificar o item como Car (Character).
OBRIGATÓRIO (REQUIRED)
Esta propriedade indica que o preenchimento do item é obrigatório. Quando esta propriedade está marcada (Sim),
o Form Runtime impede que o usuário navegue para fora desse item sem que um valor seja preenchido, a menos
que a propriedade Defer_Required_Enforcement esteja ativada, o que fará com que a validação seja adiada para o
momento de validação do registro, permitindo que o usuário navegue livremente por todos os itens do bloco.
Esta verificação, a princípio, não é feita quando fazemos uma leitura do banco de dados, pois presume-se que os
dados gravados no banco são válidos.
CÁLCULO (CALCULATION)
MODO DE CÁLCULO (CALCULATION MODE)
Esta propriedade determina o modo de avaliação dos valores a serem calculados para o item atual. As opções válidas são:
♦ Fórmula (Formula) – Indica que o cálculo será feito através de uma fórmula definida pelo usuário.
♦ Sumário (Summary) – Indica que o cálculo será feito através de uma função de grupo sobre um determinado item.
♦ Nenhum (None) – Este item não é resultado de cálculo.
FÓRMULA (FORMULA)
No caso de a propriedade Modo de Cálculo (Calculation Mode) ser preenchida com Fórmula (Formula). Devemos
definir, agora, o texto da fórmula.
REGISTROS (RECORDS)
GRUPO DE ATRIBUTOS VISUAIS DO REGISTRO ATUAL (CURRENT RECORD VISUAL ATTRIBUTE GROUP)
Esta propriedade determina o nome de um grupo de atributos visuais que será utilizado quando o item for parte do
registro corrente.
Essa propriedade pode ser definida em nível de módulo, bloco ou item. O nível mais específico sobrepõe o mais genérico.
Esta propriedade pode afetar o resultado da performance uma vez que o Form Runtime acrescentará à cláusula
Where do comando Select montado para este bloco restrições de leitura sobre colunas que podem ou não ter
índices de acesso. Verifique com seu DBA o impacto da utilização dessa propriedade.
EDITOR (EDITOR)
EDITOR (EDITOR)
Determina o nome do editor a ser apresentado para este item. Podemos escolher entre nenhum, editor de sistema
(System_Editor) ou um editor específico criado na aplicação. Quando esta propriedade é preenchida, o usuário
poderá acionar o editor neste item usando a tecla Editor (Ctrl+E).
FÍSICO (PHYSICAL)
VISÍVEL (VISIBLE)
Esta propriedade determina se o objeto em questão ficará visível quando a aplicação for inicialmente executada.
Essa propriedade pode ser modificada posteriormente por programação.
Como restrição, temos que não podemos esconder uma canvas que contenha o item corrente, da mesma forma
que não podemos esconder uma janela que contenha o item corrente.
CANVAS (CANVAS)
Indica o nome da canvas onde o item será apresentado. Se esta propriedade não for preenchida, indica que o item
não ficará visível para o usuário. É dito ser um Null Canvas Item.
POSIÇÃO X (X POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do
módulo Form.
O desenvolvimento desta propriedade é da esquerda para a direita, ou seja, o valor 0 corresponde exatamente à
posição da linha esquerda da tela ou da canvas. A partir deste ponto e em direção ao lado direito da tela ou canvas,
esse valor é crescente.
POSIÇÃO Y (Y POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do
módulo Form.
O desenvolvimento desta propriedade é de cima para baixo, ou seja, o valor 0 corresponde exatamente à posição
da linha superior da tela ou da canvas. A partir deste ponto e em direção à parte inferior da tela ou canvas, esse
valor é crescente.
LARGURA (WIDTH)
Especifica a largura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
ALTURA (HEIGHT)
Especifica a altura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
BEVEL (BEVEL)
Especifica a aparência da borda do objeto. Os valores válidos para esta propriedade são: Diminuído (Lowered),
Aumentado (Raised), Nenhum (None), Inset ou Outset.
Esta propriedade é aplicável a itens dos tipos Chart, Custom, Text e canvas do tipo Stack, mas apenas em ambientes
Microsoft Windows.
FINALIZADO (RENDERED)
Esta propriedade informa ao Form Runtime que, quando este objeto não tiver o foco, os recursos de sistema são
desnecessários. Apenas quando o item receber o foco é que os recursos de sistema serão ativados para ele. Se a
tempo de execução esta propriedade for marcada com Não, isto permitirá que este item se sobreponha a outro, o
que, de um modo geral, não é possível.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
O padrão Clear (ou None) não está disponível para itens e nem canvas. Para os dois objetos, o melhor padrão é
Transparent.
Na paleta de padrões apresentada pelo editor de layout: o padrão sólido é representado pelo quadrado preto (segundo
a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro a partir do
canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando selecionamos a opção
Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
FONTE (FONT)
NOME DA FONTE (FONT NAME)
Esta propriedade determina o nome da fonte a ser usada para textos no objeto.
PROMPT (PROMPT)
PROMPT (PROMPT)
Especifica o texto que será mostrado para o item.
Por exemplo, se a propriedade Alinhamento do Prompt (Prompt Alignment) tiver o valor Inicial, significa que o prompt
estará alinhado pelo topo em relação ao botão (ambos com o mesmo alinhamento superior).
A propriedade atual define um distanciamento para este alinhamento.
Suponhamos, então, que o valor escolhido tenha sido 5. Neste caso, se o botão possui coordenada Y igual a 35, o
prompt possuiria coordenada Y igual a 40, ou seja, um distanciamento de 5.
AJUDA (HELP)
DICA (HINT)
Nesta propriedade, especificamos um texto informativo para o usuário. Esse texto será apresentado na linha de
mensagem quando este item receber o foco.
Para que esse texto seja apresentado, a propriedade Exibir Dica Automaticamente (Display Hint Automatically)
deve receber o valor Sim (True).
INTERNACIONAL (INTERNATIONAL)
ESTADO INICIAL DO TECLADO (INITIAL KEYBOARD STATE)
Esta propriedade determina o estado do teclado quando o item recebe o foco. Os valores válidos para essa propriedade são:
♦ Default – O estado é baseado no valor da propriedade Reading Order.
♦ Local – Indica o valor direita para a esquerda.
♦ Roman – Indica o valor esquerda para a direita.
DIREÇÃO (DIRECTION)
Esta propriedade é útil apenas para aplicações bidirecionais (National Language Support).
Especifica a direção de desenvolvimento do objeto. Três valores são válidos para esta propriedade: Default, Da
Direita para a Esquerda (para linguagens mostradas da direita para a esquerda) e da Esquerda para a Direita (para
linguagens mostradas da esquerda para a direita).
Para a maioria dos objetos, excetuando-se itens de texto e itens de display (os itens da lista – List items possuem
também a propriedade Estado Inicial do Teclado), esta é a única propriedade bidirecional.
A propriedade Direction do Form é herdada das variáveis NLS definidas no ambiente se seu valor no Form for
Default. Todos os objetos da aplicação (exceto os itens) herdam esta propriedade diretamente do módulo Form se
receberem o valor Default. Os itens herdam esta propriedade da Canvas (que herda do módulo Form).
Os itens de texto e de display, a tempo de desenvolvimento (no Form Builder), não possuem a propriedade Direc-
tion e sim as propriedades Justificação, Ordem de Leitura e Estado Inicial do Teclado, porém, na programação,
podemos definir Direction para todos os objetos, inclusive itens.
Para cada tipo de objeto, essa propriedade pode ter uma forma específica de afetar a apresentação. Por exemplo,
para um item do tipo Caixa de Verificação (Check Box), essa propriedade afeta a posição da caixa em relação ao
texto, a ordem de leitura da etiqueta (label) do objeto o estado inicial do teclado quando o objeto recebe o foco.
Para detalhes específicos de cada elemento, acione a opção “Tópicos de Ajuda do Form Builder” no menu Ajuda e
pesquise pelo tópico Language Direction.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
ATIVADO (ENABLED)
Especifica se o item de menu deve ser apresentado normalmente (habilitado) ou desabilitado (cinza).
ETIQUETA (LABEL)
Esta propriedade contém o texto que será apresentado na etiqueta para um botão, caixa de checagem (Check Box),
botão de rádio (Radio Button), página Tab (usuário poderá clicar no label para que a página de Tab correspondente
seja apresentada), item de menu ou que será apresentado ao usuário para o preenchimento do parâmetro de
substituição (do menu).
Clear, Copy, Cut, Paste Nenhum Estes itens executam as operações default indicadas para seus nomes.
Quit Nenhum Por default, este comando encerra a aplicação após perguntar ao operador se deseja salvar as
modificações efetuadas.
Window NULL ou MENU Este comando irá mostrar um submenu default que lista todas as janelas abertas. O operador poderá ativar uma
outra janela selecionando-a do submenu. Se definirmos um submenu (em vez de NULL), o Form Runtime fará
uma combinação entre os itens do submenu com a lista de janelas abertas para criar um submenu único. A
ordem dos itens no menu resultante é indefinida.
Essa propriedade deve ser preenchida apenas com o nome do ícone, sem diretório e sem extensão.
Por exemplo, suponha que o nome do ícone completo fosse c:\windows\abrir.ico.
A propriedade deve ser preenchida com Abrir. O diretório deve ser incluído na variável de ambiente, isto é, UI_ICON,
presente no registrador do Windows (usar RegEdit para manutenção).
FÍSICO (PHYSICAL)
VISÍVEL (VISIBLE)
Esta propriedade determina se o objeto em questão ficará visível quando a aplicação for inicialmente executada.
Pode ser modificada posteriormente por programação.
Como restrição, temos que não podemos esconder uma canvas que contenha o item corrente, da mesma forma
que não podemos esconder uma janela que contenha o item corrente.
FONTE (FONT)
NOME DA FONTE (FONT NAME)
Esta propriedade determina o nome da fonte a ser usada para textos no objeto.
AJUDA (HELP)
DICA (HINT)
Esta propriedade é aplicável a menus que sejam apresentados no formato Tela Cheia (Full Screen).
LOV (LOV)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
TÍTULO (TITLE)
Especifica o título a ser apresentado para a janela da lista de valores.
FÍSICO (PHYSICAL)
POSIÇÃO X (X POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é da esquerda para a direita, ou seja, o valor 0 corresponde exatamente à
posição da linha esquerda da tela ou da canvas. A partir deste ponto e em direção ao lado direito da tela ou canvas,
esse valor é crescente.
POSIÇÃO Y (Y POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é de cima para baixo, ou seja, o valor 0 corresponde exatamente à posição
da linha superior da tela ou da canvas. A partir deste ponto e em direção à parte inferior da tela ou canvas, este
valor é crescente.
LARGURA (WIDTH)
Especifica a largura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
ALTURA (HEIGHT)
Especifica a altura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando selecionamos a opção
Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
FONTE (FONT)
NOME DA FONTE (FONT NAME)
Esta propriedade determina o nome da fonte a ser usada para textos no objeto.
INTERNACIONAL (INTERNATIONAL)
DIREÇÃO (DIRECTION)
Esta propriedade é útil apenas para aplicações bidirecionais (National Language Support).
Especifica a direção de desenvolvimento do objeto. Três valores são válidos para esta propriedade: Default, Da
Direita para a Esquerda (para linguagens mostradas da direita para a esquerda) e da Esquerda para a Direita (para
linguagens mostradas da esquerda para a direita).
Para a maioria dos objetos, excetuando-se itens de texto e itens de display (os itens da lista – List items possuem
também a propriedade Estado Inicial do Teclado), esta é a única propriedade bidirecional.
A propriedade Direction do Form é herdada das variáveis NLS definidas no ambiente se seu valor no Form for
Default. Todos os objetos da aplicação (exceto os itens) herdam esta propriedade diretamente do módulo Form se
receberem o valor Default. Os itens herdam esta propriedade da Canvas (que herda do módulo Form).
Os itens de texto e de display, a tempo de desenvolvimento (no Form Builder), não possuem a propriedade Direc-
tion e sim as propriedades Justificação, Ordem de Leitura e Estado Inicial do Teclado, porém, na programação,
podemos definir Direction para todos os objetos, inclusive itens.
Para cada tipo de objeto, essa propriedade pode ter uma forma específica de afetar a apresentação. Por exemplo,
para um item do tipo Caixa de Verificação (Check Box), essa propriedade afeta a posição da caixa em relação ao
texto, a ordem de leitura da etiqueta (label) do objeto e o estado inicial do teclado quando o objeto recebe o foco.
Para detalhes específicos de cada elemento, acione a opção “Tópicos de Ajuda do Form Builder” no menu Ajuda e
pesquise pelo tópico Language Direction.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
MENU TIRAR (TEAR-OFF MENU)
É um submenu que os operadores podem retirar da barra de menu e reposicionar em qualquer lugar da tela. Pode-
se habilitar a funcionalidade Tear-Off para qualquer submenu, porém somente no estilo pull-down e quando o
gerenciador de janelas suportar esta característica.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
MENU TIRAR (TEAR-OFF MENU)
É um menu que os operadores podem reposicionar em qualquer lugar da tela. Pode-se habilitar a funcionalidade
Tear-Off para qualquer menu Pop-up, porém somente quando o gerenciador de janelas suportar esta característica.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
TÍTULO (TITLE)
Especifica o título a ser apresentado para o objeto.
NAVEGAÇÃO (NAVIGATION)
LIMITE DE NAVEGAÇÃO DO MOUSE (MOUSE NAVIGATION LIMIT)
Esta propriedade indica qual ação de navegação o usuário poderá fazer com o mouse. Os valores válidos são:
♦ Form (permite ao operador navegar para qualquer item no Form corrente, mudando de bloco, de registro, etc.,
com o mouse).
♦ Bloco de Dados – Data Block (permite ao operador navegar para qualquer item dentro de um mesmo bloco; não
é possível a troca de bloco com o mouse).
♦ Registro – Record (neste caso, o usuário poderá navegar apenas entre itens de um mesmo registro; não é possível
a troca de registros com o mouse).
♦ Item (esta opção impede que o usuário navegue para fora do item com o mouse, ou seja, impede o uso do mouse).
REGISTROS (RECORDS)
GRUPO DE ATRIBUTOS VISUAIS DO REGISTRO ATUAL (CURRENT RECORD VISUAL ATTRIBUTE GROUP)
Esta propriedade determina o nome de um grupo de atributos visuais que será utilizado quando o item for parte do
registro corrente.
Essa propriedade pode ser definida em nível de módulo, bloco ou item. O nível mais específico sobrepõe o nível
mais genérico.
indica que em uma leitura consistente serão vistas todas as modificações Commited antes do início da leitura e todas
as modificações realizadas pela transação atual.
FÍSICO (PHYSICAL)
SISTEMA COORDENADO (COORDINATE SYSTEM)
Indica a unidade de trabalho no Form, que pode ser Caracter ou Real (ponto, píxel, centímetro, etc.).
Quando acionamos esta propriedade, é apresentado um diálogo para que determinemos a unidade em que são
fornecidos os valores de coordenadas (tamanhos, posicionamento, etc.) dos objetos.
Quando escolhemos na propriedade Sistema de Coordenadas o valor Real, a propriedade Unidade Real (Real Unit) pode
ser escolhida e a propriedade Célula de Caracter fica habilitada para que venhamos a determinar o tamanho de um
caracter na fonte-padrão. Esse tamanho será utilizado pelo Form Builder quando tiver de dimensionar o espaço de
apresentação de um objeto (por exemplo, na construção do layout de um bloco) cujo tamanho seja fornecido em caracteres
(uma coluna do banco de dados, por exemplo).
Quando escolhemos na propriedade Sistema de Coordenadas o valor Caracter, a propriedade Escalonamento de
Fonte Default (Default Font Scaling) fica habilitada. Essa propriedade indica que, a tempo de execução, a fonte
indicada para uso na aplicação deve ser escalada para o tamanho de caracter correspondente no vídeo em uso.
Se ela receber o valor Sim (Yes), qualquer canvas que tenha a propriedade Visual Attribute Group preenchida com
Default será, automaticamente, apresentada em cinza e a propriedade Bevel para cada item é, automaticamente,
apresentada como se estivesse preenchida com Lowered (mesmo que no item esta propriedade esteja com outro valor).
INTERNACIONAL (INTERNATIONAL)
DIREÇÃO (DIRECTION)
Esta propriedade é útil apenas para aplicações bidirecionais (National Language Support).
Especifica a direção de desenvolvimento do objeto. Três valores são válidos para esta propriedade: Default, Da
Direita para a Esquerda (para linguagens mostradas da direita para a esquerda) e Da Esquerda para a Direita (para
linguagens mostradas da esquerda para a direita).
Para a maioria dos objetos, excetuando-se itens de texto e itens de display (os itens da lista – List items possuem
também a propriedade Estado Inicial do Teclado), esta é a única propriedade bidirecional.
A propriedade Direction do Form é herdada das variáveis NLS definidas no ambiente se seu valor no Form for
Default. Todos os objetos da aplicação (exceto os itens) herdam esta propriedade diretamente do módulo Form se
receberem o valor Default. Os itens herdam esta propriedade da Canvas (que herda do módulo Form).
Os itens de texto e de display, a tempo de desenvolvimento (no Form Builder), não possuem a propriedade Direc-
tion e sim as propriedades Justificação, Ordem de Leitura e Estado Inicial do Teclado, porém, na programação,
podemos definir Direction para todos os objetos, inclusive itens.
Para cada tipo de objeto, essa propriedade pode ter uma forma específica de afetar a apresentação. Por exemplo,
para um item do tipo Caixa de Verificação (Check Box), essa propriedade afeta a posição da caixa em relação ao
texto, a ordem de leitura da etiqueta (label) do objeto e o estado inicial do teclado quando o objeto recebe o foco.
Para detalhes específicos de cada elemento, acione a opção “Tópicos de Ajuda do Form Builder” no menu Ajuda e
pesquise pelo tópico Language Direction.
COMPATIBILIDADE (COMPATIBILITY)
MODO DE COMPATIBILIDADE EM RUNTIME (RUNTIME COMPATIBILITY MODE)
Determina se o modo de trabalhar o Form Runtime deve ser compatível com as versões 4.5 ou 5.0.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
MENU PRINCIPAL (MAIN MENU)
Nesta propriedade determinamos o nome de um menu (definido dentro deste módulo) que será o principal ou
inicial a tempo de execução.
Quando criamos um menu do tipo Pull-Down, essa propriedade é preenchida automaticamente com o nome do
primeiro menu que criarmos no módulo e atualizada todas as vezes que modificarmos o nome deste menu.
Quando, porém, apresentamos o menu com o formato de tela inteira, essa propriedade determina o limite de navegação
do usuário, isto é, garante que o usuário não poderá navegar para um menu acima deste especificado.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
ATIVADO (ENABLED)
Esta propriedade indica se o objeto poderá receber foco, seja através da navegação-padrão (tecla Tab) ou através de
rotinas predefinidas (Next_Item, Go_Item, etc.).
O quadro a seguir mostra a relação entre a propriedade Ativado (Enabled) e a propriedade Navegável com Teclado
(Keyboard Navigable).
ON ON O item é navegável e o Forms pode mover o foco para o item durante o processo de navegação-padrão
(default). O item é apresentado normalmente.
OFF ON O item não é navegável. Durante a navegação-padrão (default) o Forms pula o item para o próximo navegável
da seqüência. O item é mostrado normalmente e o operador pode navegar para ele e manipulá-lo com o mouse.
OFF OFF O item não é navegável e é apresentado com contraste reduzido para indicar que ele não está disponível para
entrada de dados ou manipulação com o mouse.
ETIQUETA (LABEL)
Esta propriedade contém o texto que será apresentado na etiqueta para um botão, caixa de checagem (Check Box), botão
de rádio (Radio Button), página Tab (usuário poderá clicar no label para que a página de Tab correspondente seja apresentada),
item de menu ou que será apresentado ao usuário para o preenchimento do parâmetro de substituição (do menu).
FÍSICO (PHYSICAL)
VISÍVEL (VISIBLE)
Esta propriedade determina se o objeto em questão ficará visível quando a aplicação for inicialmente executada.
Pode ser modificada posteriormente por programação.
Como restrição, temos que não podemos esconder uma canvas que contenha o item corrente, da mesma forma
que não podemos esconder uma janela que contenha o item corrente.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
O padrão Clear (ou None) não está disponível para itens e nem canvas. Para os dois objetos, o melhor padrão é Transparent.
Na paleta de padrões apresentada pelo editor de layout, o padrão sólido é representado pelo quadrado preto
(segundo a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro
a partir do canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando
selecionamos a opção Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
INTERNACIONAL (INTERNATIONAL)
DIREÇÃO (DIRECTION)
Esta propriedade é útil apenas para aplicações bidirecionais (National Language Support).
Especifica a direção de desenvolvimento do objeto. Três valores são válidos para esta propriedade: Default, Da
Esquerda para a Direita (para linguagens mostradas da direita para a esquerda) e Da Direita para a Esquerda (para
linguagens mostradas da esquerda para a direita).
CURSO COMPLETO00✦ 1391
Para uso pessoal. Este material não pode ser utilizado em Salas de Aula e para ministrar treinamentos.
ORACLE 9I PARA DESENVOLVEDORES CURSO COMPLETO – PARTE III: REFERÊNCIA
Para a maioria dos objetos, excetuando-se itens de texto e itens de display (os itens da lista – List items possuem
também a propriedade Estado Inicial do Teclado), esta é a única propriedade bidirecional.
A propriedade Direction do Form é herdada das variáveis NLS definidas no ambiente se seu valor no Form for
Default. Todos os objetos da aplicação (exceto os itens) herdam esta propriedade diretamente do módulo Form se
receberem o valor Default. Os itens herdam esta propriedade da Canvas (que herda do módulo Form).
Os itens de texto e de display, a tempo de desenvolvimento (no Form Builder), não possuem a propriedade Direc-
tion e sim as propriedades Justificação, Ordem de Leitura e Estado Inicial do Teclado, porém, na programação,
podemos definir Direction para todos os objetos, inclusive itens.
Para cada tipo de objeto, essa propriedade pode ter uma forma específica de afetar a apresentação. Por exemplo,
para um item do tipo Caixa de Verificação (Check Box), essa propriedade afeta a posição da caixa em relação ao
texto, a ordem de leitura da etiqueta (label) do objeto o estado inicial do teclado quando o objeto recebe o foco.
Para detalhes específicos de cada elemento, acione a opção “Tópicos de Ajuda do Form Builder” no menu Ajuda e
pesquise pelo tópico Language Direction.
PARÂMETRO (PARAMETER)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
DADOS (DATA)
TIPOS DE DADOS DE PARÂMETRO (PARAMETER DATA TYPE)
Nesta propriedade, definimos o tipo de dados a ser armazenado no parâmetro. Os valores válidos para essa
propriedade são: Caracter (Character), Número (Number) ou Data (Date).
QUADRO (FRAME)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
SHRINKWRAP (SHRINKWRAP)
Esta propriedade permite que o Form Builder aproxime o Frame dos objetos internos. Quando aumentamos o
tamanho do Frame e essa propriedade está preenchida com Sim, o Form Builder diminui o Frame para que este
fique próximo aos objetos.
REGISTROS (RECORDS)
NÚMERO DE REGISTROS EXIBIDOS (NUMBER OF RECORDS DISPLAYED)
Esta propriedade determina o número de registros exibidos simultaneamente. O valor default é 1.
Esse valor é herdado por todos os itens deste bloco por default. A exibição dos itens será múltipla.
Se esta propriedade receber um valor maior que 1, diremos que o bloco é multi-record.
Quando modificamos essa propriedade no Frame, automaticamente esse valor é alterado dentro das propriedades
do bloco correspondente (definido pela propriedade Bloco de Dados de Layout). O inverso não é verdadeiro.
Quando esta propriedade no Frame está preenchida com Não e no Bloco temos o valor Sim, a barra de rolagem
aparece fora do Frame.
FÍSICO (PHYSICAL)
POSIÇÃO X (X POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é da esquerda para a direita, ou seja, o valor 0 corresponde exatamente à posição da
linha esquerda da tela ou da canvas. A partir deste ponto e em direção ao lado direito da tela ou canvas, esse valor é crescente.
POSIÇÃO Y (Y POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é de cima para baixo, ou seja, o valor 0 corresponde exatamente à posição da linha
superior da tela ou da canvas. A partir deste ponto e em direção à parte inferior da tela ou canvas, esse valor é crescente.
LARGURA (WIDTH)
Especifica a largura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
ALTURA (HEIGHT)
Especifica a altura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
BEVEL (BEVEL)
Especifica a aparência da borda do objeto. Os valores válidos para esta propriedade são: Diminuído (Lowered),
Aumentado (Raised), Nenhum (None), Inset ou Outset.
Essa propriedade é aplicável a itens dos tipos Chart, Custom, Text e canvas do tipo Stack, mas apenas em ambientes
Microsoft Windows.
GRUPO DE ATRIBUTOS VISUAIS DO TÍTULO DO QUADRO (FRAME TITLE VISUAL ATTRIBUTE GROUP)
Esta propriedade determina como os atributos visuais (Nome da Fonte, Cor de Fundo, etc.) de um determinado
objeto serão derivados. Esta propriedade pode receber dois tipos de valores:
♦ A palavra-chave Default – Indica que os atributos individuais definidos para o objeto em questão refletem sua
situação atual.
♦ Nome de um Atributo Visual existente – Indica que os atributos definidos para este objeto são derivados do
Atributo Visual nomeado.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
COR DE FUNDO DO LIMITE (EDGE FOREGROUND COLOR) / COR DE FUNDO DO LIMITE (EDGE BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
Na paleta de padrões apresentada pelo editor de layout, o padrão sólido é representado pelo quadrado preto (segundo
a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro a partir do
canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando selecionamos a opção
Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
RELAÇÃO (RELATION)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
BLOCO DE DADOS DETALHADO (DETAIL DATA BLOCK)
Nesta propriedade, especificamos o nome do bloco detalhe em uma relação Master-Detail.
Esta definição deve ser repetida quantas vezes forem necessárias para que todos os itens que representem colunas
relacionadas sejam explicitamente associados.
Para que esta condição seja explicitada corretamente, devemos ter definidos em cada bloco todos os itens necessários
ao relacionamento uma vez que a relação se dá entre os itens e blocos da aplicação.
COORDENAÇÃO (COORDINATION)
Como restrição às propriedades deste grupo, temos que não surte efeito modificá-las a tempo de execução uma vez que
os textos dos triggers e unidades de programa incluídos na aplicação não podem ser modificados a tempo de execução.
Quando preenchemos as propriedades desse grupo, o Form Builder monta os trigger On-Clear-Details, On-Populate-
Details e as unidades de programa Check_Package_Failure, Clear_All_Master_Details e Query_Master_Details com os
textos adequados para a execução das ações definidas pelas propriedades. Isto não é modificado a tempo de execução.
DIFERIDO (DEFERRED)
Indica se a consulta no bloco-detalhe deve ou não ser adiada após a identificação do registro no bloco-mestre.
Quando esta propriedade recebe o valor Não, tão logo seja feita uma consulta ou navegação para o próximo
registro no bloco principal, ocorrerá a consulta no bloco-detalhe. Neste caso, a propriedade Consulta Automática
(Automatic Query) é ignorada.
Quando indicamos que desejamos o adiamento (Sim), a propriedade Consulta Automática (Automatic Query)
mostrará como será feita a consulta no detalhe.
JANELA (WINDOW)
GERAL (GENERAL)
NOME (NAME)
Identifica o nome interno do objeto. Deve respeitar a convenção de nomes do Oracle.
COMENTÁRIOS (COMMENTS)
Esta propriedade é de preenchimento livre do usuário. Pode ser usada para registrarmos informações relevantes relativas
ao objeto em questão, tais como: quem criou o objeto e por quê, data da alteração, etc.
FUNCIONAL (FUNCTIONAL)
TÍTULO (TITLE)
Especifica o título a ser apresentado para a janela.
Se não especificarmos um título para a janela da aplicação (exceto para a Root Window), o Forms utiliza a propriedade
Nome (Name) como título.
Se não especificarmos um título para a Root Window e o menu atual for o menu default, a mesma regra anterior é
válida. Se, porém, o menu em uso foi construído pelo usuário e estiver sendo apresentado no estilo Pull-down ou Bar,
o Forms utiliza a propriedade Menu Principal (Main Menu) do módulo de menu.
Essa propriedade só tem de ser preenchida no caso de janelas abertas por programação. Uma vez que sabemos
quando uma aplicação se torna ativa, a canvas Content a ser apresentada é aquela que contém os itens referentes
ao primeiro bloco navegável.
MODAL (MODAL)
Esta propriedade indica se a janela atual é Modal (Sim) ou Modeless (Não).
Uma janela Modeless permanece ativa até que o operador a encerre (ou o programa). Mais de uma Modeless pode
ser mostrada ao mesmo tempo e os operadores podem navegar através delas se a aplicação permitir. As janelas
Modeless podem ser apresentadas na frente ou atrás de outras janelas.
Uma janela Modal é mais restrita que uma janela Modeless, uma vez que o operador só poderá passar para outra
janela após encerrá-la. As aplicações, normalmente, só mostram uma janela Modal de cada vez, apesar de ser
possível chamar uma Modal a partir de outra.
Caso o usuário tente fechar a janela do Forms50 Runtime, o próprio Forms determina o fechamento da aplicação
subordinada executando um comando Do_key(‘exit_form’).
Deve ser preenchida apenas com o nome do ícone, sem diretório e sem extensão.
A propriedade deve ser preenchida com Abrir. O diretório deve ser incluído na variável de ambiente apropriada,
isto é, UI_ICON, presente no registrador do Windows (usar RegEdit para manutenção).
FÍSICO (PHYSICAL)
POSIÇÃO X (X POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é da esquerda para a direita, ou seja, o valor 0 corresponde exatamente à
posição da linha esquerda da tela ou da canvas. A partir deste ponto e em direção ao lado direito da tela ou canvas,
esse valor é crescente.
POSIÇÃO Y (Y POSITION)
Especifica onde o objeto aparece na tela. Para um item, especifica a posição do canto esquerdo superior deste em
relação ao canto esquerdo superior da canvas.
A unidade em que esta informação é fornecida é especificada pela propriedade Sistema Coordenado do módulo Form.
O desenvolvimento desta propriedade é de cima para baixo, ou seja, o valor 0 corresponde exatamente à posição
da linha superior da tela ou da canvas. A partir deste ponto e em direção à parte inferior da tela ou canvas, esse
valor é crescente.
LARGURA (WIDTH)
Especifica a largura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
ALTURA (HEIGHT)
Especifica a altura do objeto. A unidade em que esta informação é fornecida é especificada pela propriedade
Sistema Coordenado do módulo Form.
BEVEL (BEVEL)
Especifica a aparência da borda do objeto. Os valores válidos para esta propriedade são: Diminuído (Lowered),
Aumentado (Raised), Nenhum (None), Inset ou Outset.
Essa propriedade é aplicável a itens do tipo Chart, Custom, Text e canvas do tipo Stack, mas apenas em ambientes
Microsoft Windows.
COR (COLOR)
COR DE FUNDO (FOREGROUND COLOR) / COR DE FUNDO (BACKGROUND COLOR)
As cores são dadas em duas camadas: a primeira camada (Foreground Color) e a camada de fundo (Background
Color). Aliado a estas duas camadas, existe o padrão de preenchimento que afeta o resultado apresentado (veja
especificação de padrão de preenchimento).
Para os demais padrões, o desenho em preto é apresentado com a cor da primeira camada (Foreground) e o desenho
branco é apresentado com a cor da camada de fundo (Background).
O padrão Clear (ou None) não está disponível para itens e nem canvas. Para os dois objetos, o melhor padrão é
Transparent.
Na paleta de padrões apresentada pelo editor de layout, o padrão sólido é representado pelo quadrado preto (segundo
a partir do canto esquerdo superior), o padrão transparente é representado pelo quadrado branco (primeiro a partir do
canto esquerdo superior) e o padrão Clear (None, na paleta de propriedades) é utilizado quando selecionamos a opção
Nenhum Preenchimento (No Fill) ou Nenhuma Linha (No Line).
FONTE (FONT)
NOME DA FONTE (FONT NAME)
Esta propriedade determina o nome da fonte a ser usada para textos no objeto.
INTERNACIONAL (INTERNATIONAL)
DIREÇÃO (DIRECTION)
Esta propriedade é útil apenas para aplicações bidirecionais (National Language Support).
Especifica a direção de desenvolvimento do objeto. Três valores são válidos para esta propriedade: Default, Da
Direita para a Esquerda (para linguagens mostradas da direita para a esquerda) e Da Esquerda para a Direita (para
linguagens mostradas da esquerda para a direita).
Para a maioria dos objetos, excetuando-se itens de texto e itens de display (os itens da lista – List items possuem
também a propriedade Estado Inicial do Teclado), esta é a única propriedade bidirecional.
A propriedade Direction do Form é herdada das variáveis NLS definidas no ambiente se seu valor no Form for
Default. Todos os objetos da aplicação (exceto os itens) herdam esta propriedade diretamente do módulo Form se
receberem o valor Default. Os itens herdam esta propriedade da Canvas (que herda do módulo Form).
Os itens de texto e de display, a tempo de desenvolvimento (no Form Builder), não possuem a propriedade Direc-
tion e sim as propriedades Justificação, Ordem de Leitura e Estado Inicial do Teclado, porém, na programação,
podemos definir Direction para todos os objetos, inclusive itens.
Para cada tipo de objeto, essa propriedade pode ter uma forma específica de afetar a apresentação. Por exemplo,
para um item do tipo Caixa de Verificação (Check Box), essa propriedade afeta a posição da caixa em relação ao
texto, a ordem de leitura da etiqueta (label) do objeto e o estado inicial do teclado quando o objeto recebe o foco.
Para detalhes específicos de cada elemento, acione a opção “Tópicos de Ajuda do Form Builder” no menu Ajuda e
pesquise pelo tópico Language Direction.
Capítulo 14
VARIÁVEIS DE SISTEMA DO
FORMS E VARIÁVEIS DE AMBIENTE
Neste capítulo, apresentaremos a lista de variáveis de sistema do Forms e variáveis de ambiente aplicáveis tanto ao
Forms quanto ao Reports.
As variáveis de sistema capazes de sofrer modificações aparecem com o símbolo ( * ) ao lado de seu nome. As
demais são read-only.
VARIÁVEIS DE SISTEMA
SYSTEM.BLOCK_STATUS
Indica o estado do bloco em que o cursor está localizado ou o bloco corrente durante o processamento de um
gatilho (trigger). Pode assumir um dos seguintes valores:
♦ CHANGED – Indica que o bloco contém pelo menos um registro alterado.
♦ NEW – Indica que o bloco contém apenas registros novos.
♦ QUERY – Indica que o bloco contém somente registros válidos recuperados do banco de dados.
O conteúdo da variável é fornecido em letras maiúsculas.
SYSTEM.COORDINATION_OPERATION
Essa variável é utilizada pelo trigger On-Clear-Details juntamente com a variável System.Master_Block para
determinar que tipo de ação causou a execução do trigger e em que bloco Master de que relação Master-Detail.
SYSTEM.CURRENT_BLOCK
Essa variável foi incluída para compatibilidade com versões anteriores. A Oracle Corporation recomenda a utilização
das variáveis System. Cursor_Block e System.Trigger_Block no lugar desta.
SYSTEM.CURRENT_DATETIME
Essa variável contém a data e hora do sistema operacional. O valor é uma string no formato: DD-MON-YYYY
HH24:MI:SS.
SYSTEM.CURRENT_FORM
Contém o nome do Form que está sendo executado. O valor é sempre fornecido como uma string.
SYSTEM.CURRENT_ITEM
Essa variável foi incluída para compatibilidade com versões anteriores. A Oracle Corporation recomenda a utilização
das variáveis System.Cursor_Item e System.Trigger_Item no lugar desta.
SYSTEM.CURRENT_VALUE
Essa variável foi incluída para compatibilidade com versões anteriores. A Oracle Corporation recomenda a utilização
da variável System. Cursor_Value no lugar desta.
SYSTEM.CURSOR_BLOCK
O valor dessa variável depende da unidade de navegação corrente.
Se a unidade de navegação é bloco, registro ou item, como por exemplo nos triggers Pre- e Post- para Item, Registro
e Bloco, esta variável conterá o nome do bloco onde o cursor (foco) está posicionado.
Se a unidade de navegação é Form, como nos triggers Pre-Form e Post-Form, ela receberá Null.
SYSTEM.CURSOR_ITEM
Contém o nome do item onde o cursor (foco) está posicionado. O formato é <bloco>.<item>.
Se durante a execução de um trigger houver navegação de um item para outro, o valor desta variável será alterado,
acompanhando o cursor (foco).
SYSTEM.CURSOR_RECORD
Esta variável contém o número do registro onde o cursor está localizado. Esse número representa o registro corrente
na ordem física da lista de registros do bloco. O valor é uma string.
SYSTEM.CURSOR_VALUE
Contém o valor do item onde o cursor está localizado.
SYSTEM.CUSTOM_ITEM_EVENT
Armazena o nome do evento disparado por um controle VBX (ambiente Microsoft Windows 16-bits) ou ActiveX
(ambiente Microsoft Windows 32-bits).
SYSTEM.CUSTOM_ITEM_EVENT_PARAMETERS
Armazena argumentos suplementares de um evento disparado por um controle VBX (ambiente Microsoft Win-
dows 16-bits) ou ActiveX (ambiente Microsoft Windows 32-bits).
SYSTEM.DATE_THRESHOLD ( * )
Determina a freqüência com que o Form Runtime sincroniza as datas das variáveis locais relacionadas com o
Banco de Dados (Rdbms). Essa variável trabalha junto com as variáveis $$DBDATE$$, $$DBDATETIME$$ e
$$DBTIME$$. Seu valor tem o formato MI:SS.
O valor default para essa variável é 01:00 (1 minuto). Este valor não significa que seja feita uma leitura do banco de
dados a cada minuto. Indica que se houver necessidade (e só neste caso) de fornecer informações para as variáveis
de sistema (por exemplo $$Dbdate$$), o Form Runtime verificará se tem mais de um minuto que essa informação
foi obtida. Nesse caso, é feita uma nova leitura do banco de dados; caso contrário as variáveis de sistema são
atualizadas em função do tempo decorrido localmente.
Caso não tenha necessidade de fornecer o valor para estas variáveis, não é feito qualquer acesso ao banco de dados
com este fim.
Essa variável pode ser alterada, ou seja, podemos informar a freqüência que desejarmos.
SYSTEM.EFFECTIVE_DATE ( * )
Representa a última data e hora efetiva do banco de dados. Possui o formato DD-MON-YYYY HH24:MI:SS.
Essa variável pode ser alterada.
SYSTEM.EVENT_CANVAS
Informa o nome da canvas quando o trigger When-Tab-Page-Changed for acionado.
SYSTEM.EVENT_WINDOW
Representa o nome da última janela que foi afetada pela ação que causou o acionamento de um dos triggers de
janela. Se um dos triggers When-Window-Activated, When-Window-Closed, When-Window-Deactivated ou When-
Window-Resized for usado, a variável é modificada.
SYSTEM.FORM_STATUS
Representa o estado da aplicação em que o cursor está localizado. Pode assumir um dos seguintes valores:
♦ CHANGED – Indica que o Form contém pelo menos um bloco com registro alterado.
♦ NEW – Indica que o Form contém apenas registros novos.
♦ QUERY – Indica que existe uma consulta em andamento, ou seja, o Form contém pelo menos um bloco em
QUERY e nenhum bloco em CHANGED.
O conteúdo da variável é fornecido em letras maiúsculas.
SYSTEM.LAST_FORM
Essa variável contém o identificador (Form Document ID) do Form anterior (em aplicações Multi-Form) quando
múltiplos Forms são acionados usando-se OPEN_FORM. O valor pode conter uma das seguintes strings: o
identificador do Form ou NULL. Esta variável não é válida quando acionamos um Forms via CALL_FORM.
SYSTEM.LAST_QUERY
Contém o último comando Select que o Form utilizou para preencher um bloco.
SYSTEM.LAST_RECORD
Contém o valor True se o registro que detém o foco atualmente é o último registro do bloco. Contém o valor False
para os demais registros. O valor é fornecido como uma string com as letras em maiúsculas.
SYSTEM.MASTER_BLOCK
Essa variável é utilizada pelo trigger On-Clear-Details juntamente com a variável System.Coordination_Operation
para determinar que tipo de ação causou a execução do trigger e em que bloco Master de que relação Master-Detail.
SYSTEM.MESSAGE_LEVEL ( * )
Representa um nível de severidade para as mensagens. Durante a execução do Form Runtime, todas as mensagens
que tiverem nível de severidade igual ou inferior ao valor definido para essa variável não são apresentadas.
Os valores válidos são: 0, 5, 10, 15, 20, ou 25.
SYSTEM.MODE
Indica como se encontra o processamento do Form Runtime. Os valores podem ser:
a) NORMAL – Indica que a aplicação está no estado de digitação, entrada de dados, alteração.
b) ENTER_QUERY – Indica que a aplicação está aguardando que o usuário informe restrições para a consulta a ser realizada.
c) QUERY – Indica que a aplicação está lendo dados do banco de dados. Esse estado será perceptível nos triggers de
Post-Query, por exemplo.
SYSTEM.MOUSE_BUTTON_MODIFIERS
Indica as teclas (Shift, Alt ou Control) que estavam pressionadas durante o Click. O valor corresponde a uma
string. Por exemplo, Shift+Control+.
Essa variável deve ser usada no lugar da variável System.Mouse_Button_Shift_State.
Os valores possíveis são: Shift+, Caps Lock+, Control+, Alt+, Command+, Super+, e Hyper+.
SYSTEM.MOUSE_BUTTON_PRESSED
Indica o número do botão que foi pressionado (1, 2 ou 3) em um mouse de três botões.
SYSTEM.MOUSE_BUTTON_SHIFT_STATE
Essa variável indica a tecla que estava pressionada quando ocorreu o clique do mouse, tais como Shift, Alt ou
Control. O valor é uma string. Seu conteúdo depende do sistema operacional.
O uso desta variável deve ser substituído por System.Mouse_Button_Modifiers.
SYSTEM.MOUSE_ITEM
Indica o nome do item que está sob o mouse. O formato é <bloco>.<item>.
SYSTEM.MOUSE_CANVAS
Essa variável contém o nome de uma canvas. Se o mouse estiver sobre a canvas, conterá o nome desta canvas. Se
estiver sobre um item, conterá o nome da canvas onde este item está “pendurado”.
Se o mouse não estiver sobre uma canvas ou item, o valor da variável é Null.
SYSTEM.MOUSE_FORM
Essa variável contém o nome do documento Form sobre o qual o mouse está. Corresponde a uma string.
Se a plataforma não for GUI, essa variável contém Null.
SYSTEM.MOUSE_X_POS
Essa variável representa a coordenada do mouse na unidade em uso no Form. Se o mouse estiver posicionado sobre
um item, o valor é relativo ao canto superior esquerdo do item. Se o mouse estiver sobre uma canvas, o valor é
relativo ao canto esquerdo superior da canvas.
SYSTEM.MOUSE_Y_POS
Essa variável representa a coordenada do mouse na unidade em uso no Form. Se o mouse estiver posicionado sobre
um item, o valor é relativo ao canto superior esquerdo do item. Se o mouse estiver sobre uma canvas, o valor é
relativo ao canto esquerdo superior da canvas.
SYSTEM.MOUSE_RECORD
O número absoluto do registro onde o mouse está posicionado. Se ele não estiver sobre um registro o valor retornado
é 0 (zero).
SYSTEM.MOUSE_RECORD_OFFSET
Corresponde ao número relativo do registro onde o mouse está posicionado. O registro número 1 é o primeiro
registro visível na canvas.
SYSTEM.RECORD_STATUS
Indica o estado do registro em que o cursor está localizado. Pode assumir um dos seguintes valores:
a) CHANGED – Indica que o registro foi alterado e deve ser enviado para o banco de dados.
b) INSERT – Indica que um registro New foi modificado e deve ser incluído no banco de dados.
b) NEW – Indica que o registro foi criado no buffer, mas ainda não foi modificado.
c) QUERY – Indica que o registro é válido e foi recuperado do banco de dados.
SYSTEM.SUPPRESS_WORKING ( * )
Indica se a mensagem “Working ... “ deve ser suprimida (True) ou não (False). O valor é fornecido como string com
as letras em maiúsculas.
SYSTEM.TAB_NEW_PAGE
Especifica o nome da Tab Page para a qual a navegação ocorreu. Deve ser usada dentro do trigger When-Tab-Page-Changed.
SYSTEM.TAB_PREVIOUS_PAGE
Especifica o nome da Tab Page de onde a navegação ocorreu. Deve ser usada dentro do trigger When-Tab-Page-Changed.
SYSTEM.TRIGGER_BLOCK
Essa variável contém o nome do bloco onde o cursor estava localizado quando o trigger atual foi disparado. O valor
será Null se o trigger corrente é um Pre-Form ou Post-Form. O valor é sempre uma string.
SYSTEM.TRIGGER_ITEM
Indica o item, no formato <bloco>.<item>, no escopo do qual o trigger corrente foi acionado. Se o trigger é do tipo
Key, indica o item em que estava o cursor quando o trigger foi acionado. Seu valor permanece o mesmo durante
toda a execução do gatilho, independente de haver ou não navegação.
SYSTEM.TRIGGER_NODE
Indica o nó da árvore hierárquica onde o mouse estava posicionado quando o usuário efetuou um click. Retorna
um valor do tipo Nó.
SYSTEM.TRIGGER_RECORD
Representa o número do registro que está sendo processado. Esse número corresponde à ordem do registro em
relação à lista de registros do bloco.
VARIÁVEIS DE AMBIENTE
Quando realizamos a instalação de um produto Oracle em um ambiente Windows, o Oracle Installer adiciona
algumas variáveis, chamadas de “variáveis de ambiente” ao registrador do Windows. Estas variáveis são utilizadas
pelos produtos da Oracle (por exemplo Forms, Reports, SQL*Plus, etc.) como informações sobre o ambiente onde
o produto está instalado e orientações defaults sobre o comportamento a ser adotado pelo produto.
Muitas destas variáveis somente devem ser modificadas pelo DBA ou através do processo de instalação. Outras podem
ser modificadas por nós a fim de influirmos, a nosso gosto, no comportamento da aplicação.
Para obtermos acesso ao local onde se acham as variáveis, devemos executar o editor de registro do Windows.
Desta forma, pressione o botão Iniciar (Start) do Windows e escolha a opção Executar (Run). No diálogo apresentado
escreva REGEDIT e pressione o botão OK.
A Figura 14.01 a seguir nos apresenta o registrador já com os nós expandidos. Para obter este mesmo resultado,
expanda o nó HKEY-LOCAL-MACHINE, em seguida expanda o nó SOFTWARE e expanda, também, o nó Oracle.
Você encontrará tantos Homes quantos Oracle-Homes você tiver criado na instalação (verifique o passo-a-passo
para instalação no Capítulo 6). Selecione aquele pertencente ao Forms. Na janela à direita aparecem as variáveis de
ambiente do produto Oracle correspondente.
Neste tópico conheceremos aquelas variáveis que afetam diretamente o Forms e o Reports e para as quais podemos
alterar seu valor.
CA_GPREFS
Esta variável de ambiente indica a localização do arquivo de preferências global (CAGPREFS.ORA). Este arquivo é
utilizado como default pelos produtos do pacote Developer. Ele contém as preferências da ferramenta. Este arquivo
pode ser compartilhado pelos diversos usuários desenvolvedores, ou seja, pode ser instalado na rede.
Obs: A ferramenta pesquisa no diretório local a existência deste arquivo além do local especificado na variável de ambiente.
CA_UPREFS
À medida que modificamos as informações presentes no menu Ferramentas (Tools), item Preferências (Prefer-
ences), as modificações específicas de cada usuário são armazenadas no arquivo CAUPREFS.ORA. Neste arquivo
estão armazenadas preferências tanto do Form Builder quanto do Report Builder (ou das demais ferramentas do
pacote Developer, à medida que as criamos).
A variável de ambiente CA_UPREFS indica a localização deste arquivo.
Obs: A ferramenta pesquisa no diretório local a existência deste arquivo além do local especificado na variável de ambiente.
FORMS60_DEFAULTFONT
Esta variável especifica a fonte default a ser usada para “boilerplates” no editor de layout do Form Builder. Como
exemplo poderíamos ter: FORMS60_DEFAULTFONT=”Arial.8"
FORMS60_EDITOR
Esta variável determina o editor a ser acionado pelo Form Builder para itens multi-line, tanto ao tempo de
desenvolvimento quanto produção. Caso esta informação não seja fornecida, somente o editor interno do Forms
será utilizado. Como exemplo, teríamos: FORMS60_EDITOR=C:\windows\notepad.exe.
FORMS60_ERROR_DATE_FORMAT
Nesta variável informaremos o formato de data a ser utilizado pelo Forms para mostrar mensagens de erro quando
o usuário informar uma data com layout inválido. Como exemplo teríamos: FORMS60_ERROR_DATE_FORMAT
DD/MM/YYYY
FORMS60_ERROR_DATETIME_FORMAT
Nesta variável informaremos o formato de data e hora a ser utilizado pelo Forms para mostrar mensagens de erro
quando o usuário informar uma data com layout inválido. Como exemplo teríamos:
FORMS60_ERROR_DATETIME_FORMAT DD/MM/YYYY HH24:MI
FORMS60_JAVADIR
Este parâmetro determina a localização dos arquivos de execução Oracle Java necessários para uso de Java Beans e
para a visualização de Forms a serem usados na Web. O valor default é <oracle_home>\forms60\java
FORMS60_MAPPING
Para processar imagens na Web, o Forms Server transmite arquivos JPEG. Se viermos a usar imagens ou ícones nas
aplicações Forms na Web, devemos criar um diretório temporário e um diretório virtual que o Forms Server usará
para imagens e outros arquivos de trabalho.
A variável de ambiente Forms60_Mapping indica o nome do diretório virtual, por exemplo
FORMS60_MAPPING=http://myhost.com/webtemp. Esta variável deve ser criada na máquina onde o Forms Server
estiver executando.
FORMS60_OUTPUT
Para processar imagens na Web, o Forms Server transmite arquivos JPEG. Se viermos a usar imagens ou ícones nas
aplicações Forms na Web, devemos criar um diretório temporário e um diretório virtual que o Forms Server usará
para imagens e outros arquivos de trabalho.
A variável de ambiente Forms60_Output indica o nome do diretório real, por exemplo FORMS60_OUTPUT=
C:\ORANT\WEBTEMP\.
FORMS60_OUTPUT_DATE_FORMAT
Esta variável de ambiente estabelece um formato de data e hora a ser usado pelo Forms para apresentação de itens do
tipo “date” que não possuam suas máscaras específicas. Como exemplo temos: FORMS60_OUTPUT_DATE_FORMAT
DD/MM/YYYY.
FORMS60_OUTPUT_DATETIME_FORMAT
Esta variável de ambiente estabelece um formato de data e hora a ser usado pelo Forms para apresentação de itens do tipo
“datetime” que não possuam suas máscaras específicas. Como exemplo temos: FORMS60_OUTPUT_DATETIME_FORMAT
DD/MM/YYYY HH24:MI:SS.
FORMS60_PATH
Esta variável especifica os diretórios onde se encontram os módulos executáveis gerados pelo Form Builder: Forms
(.fmx), Menus (.mmx), Bibliotecas de PL/SQL(.pll) e outros objetos que a aplicação tente carregar de um arquivo ao
tempo de execução.
Nesta variável podemos especificar vários diretórios separados por ponto-e-vírgula (;). O Forms fará a pesquisa da
esquerda para a direita na lista de caminhos. Como exemplo, temos: FORMS60_PATH=C:\curso\forms;C:\teste
FORMS60_REPFORMAT
Esta variável especifica o formato de um relatório executado através da rotina RUN_PRODUCT, quando estivermos
usando um browser para esta execução. Como exemplo, temos: FORMS60_REPFORMAT=HTML
FORMS60_TIMEOUT
Esta variável determina o tempo (em minutos) que o Forms Server aguarda antes de encerrar se não houve
comunicações de um cliente.
FORMS60_USER_DATE_FORMAT
Esta variável de ambiente estabelece o formato de máscara que o Forms usará para obter valores de itens do tipo
“date” quando estes itens não tiverem máscaras próprias. Como exemplo, temos: FORMS60_USER_DATE_FORMAT
FXFMDD-MM-RRRR.
FORMS60_USER_DATETIME_FORMAT
Esta variável de ambiente estabelece o formato de máscara que o Forms usará para obter valores de itens do tipo “datetime”
quando estes itens não tiverem máscaras próprias. Como exemplo, temos: FORMS60_USER_DATETIME_FORMAT FXFMDD-
MM-RRRR HH24:MI:SS.
FORMS60_USEREXITS
Esta variável especifica uma lista de DLLs (diretório e nome do arquivo completos) que contenham Foreign Func-
tions que possam ser acionadas em um Forms (pacote ORA_FFI). Como exemplo, temos: FORMS60_USEREXITS =
C:\mathlib\add.dll;C:\mathlib\mult.dll. Observe que mais de uma DLL pode ser indicada quando separamos as
informações com ponto-e-vírgula (;).
OLECREATEOBJPOOLINMEMORY
Este parâmetro indica ao Report Builder se deve construir o pool de objetos OLE2 em memória (1) ou em arquivos
temporários (0). A utilização de memória incrementa a performance, uma vez que não há necessidade de operações
de I/O a disco. Para determinarmos a melhor opção devemos estar cientes de que um boilerplate OLE2 presente em
um Repeating Frame usará apenas um objeto OLE2 (contabilizando apenas uma vez seu tamanho em memória);
no entanto, um Field contabilizará um objeto para cada instância do Field.
OLEDONOTUPDATELINKS
Para o Report Builder, este parâmetro habilita (0) ou desabilita(1) a atualização de links (Linked OLE2) quando
abrimos o editor de Layout ou executamos o relatório.
Os objetos OLE2 linkados possuem uma representação armazenada (cached) dos seus objetos originais. Esta
representação é atualizada pelo servidor OLE2 correspondente. Estas atualizações podem ser desabilitadas (a fim
de aumentar a performance) se não desejarmos a ativação do servidor OLE2 (quando, por exemplo, não precisarmos
de uma atualização do objeto OLE2 correspondente).
OLEUPDATELINKSPROMPT
Para o Report Builder, este parâmetro indica se o usuário deve (0) ou não (1) ser questionado quando o objeto
linked não for encontrado.
REPORTS60_CGIDIAGBODYTAGS
Para o Reports Web CGI, especifica as tags HTML a serem incluídas como <BODY …> na saída de diagnóstico /
depuração do RWCGI60.
REPORTS60_CGIDIAGHEADTAGS
Para o Reports Web CGI, especifica as tags HTML a serem incluídas entre o <HEAD …> e o </HEAD> na saída de
diagnóstico / depuração do RWCGI60.
REPORTS60_CGIHLP
Para o Reports Web CGI, especifica a URL/URI do arquivo de ajuda RWCGI60 que será apresentado quando o
RWCGI60 for acionado com uma requisição vazia.
REPORTS60_CGIMAP
Para o Reports Web CGI, especifica o arquivo map (diretório e arquivo) se um arquivo de configuração for usado.
REPORTS60_CGINODIAG
Para o Reports Web CGI, determina que todas as saídas de depuração/diagnóstico devem ser desabilitadas.
REPORTS60_COOKIE_EXPIRE
Esta variável determina o tempo sem uso de um cookie. Os cookies armazenam os usuários e senhas (criptografados)
dos usuários na máquina-cliente. Quando solicitamos a execução de um relatório, o cookie é enviado para efeito de
autenticação. O CGI (no ambiente servidor) compara a data do cookie com a data do sistema. Se o tempo houver se
esgotado é retornada uma tela de autenticação para que o usuário, novamente, estabeleça conexão com o sistema.
REPORTS60_DB_AUTH
Esta variável especifica um template (de autenticação do banco de dados) a ser usado para conexão ao banco. É
recomendado que não modifiquemos este parâmetro.
REPORTS60_ENCRYPTION_KEY
Especifica uma chave de criptografia para usuários e senhas.
REPORTS60_PATH
Nesta variável podemos informar diversos diretórios separados por ponto-e-vírgula (;), os quais determinam as
localizações dos relatórios (.rep ou .rdf) e dos objetos externos (bibliotecas de PL/SQL, queries externas, boilerplates
externos, etc.) a serem usados no relatório. Podemos adicionar a estes diretórios a palavra-chave DB indicando que
o banco de dados também deve ser pesquisado. O tamanho limite deste parâmetro é de 256 caracteres.
REPORTS60_REPORTS_SERVER
Este parâmetro determina o nome do Report Server. Quando este parâmetro é informado podemos omitir o
argumento SERVER na linha de comando em uma solicitação de relatório Web.
REPORTS60_SYS_AUTH
Especifica o template de autenticação usado para validação de username e password quando os usuários executam os
relatórios em um Report Server restrito. É recomendado que não modifiquemos esta informação.
REPORTS60_TMP
Esta variável estabelece o diretório no qual serão armazenados os arquivos temporários criados durante a execução
dos relatórios. Devemos informar apenas um diretório neste parâmetro. Se este parâmetro não for informado, será
usado o diretório de trabalho corrente.
REPORTS60_USEREXIT
Esta variável especifica uma lista de DLLs (diretório e nome do arquivo completos) que possam ser acionadas pelo Report
Builder ou Runtime. Mais de uma DLL pode ser indicada quando separamos as informações com ponto-e-vírgula (;).
UI_ICON
Esta variável determina o diretório no qual se encontram os ícones utilizados nas aplicações Forms e Reports.
Somente um diretório pode ser informado aqui. Como exemplo, temos: UI_ICON=C:\icones
Capítulo 15
BUILT-INS DO FORMS
Neste capítulo, listamos as rotinas presentes no nó Pacotes Embutidos (Built-in Packages) do Form Builder e
incluiremos uma descrição resumida da ação da rotina. As rotinas sem documentação foram omitidas do capítulo.
As rotinas do pacote Extensões Standard (Standard Extensions) foram grupadas de acordo com seu escopo de
atuação (por exemplo, rotinas que afetam itens, blocos, relações, janelas, etc.) para que você encontre a função
desejada com mais facilidade.
Antes de utilizar determinada rotina, verifique informações complementares no Help da ferramenta: por exemplo,
se trata-se de uma procedure ou função, o que deve ser passado nos parâmetros, o que pode ser recebido, etc.
No Capítulo 16, referente aos triggers, incluímos algumas das rotinas presentes nesta lista, ou seja, aquelas que
podem realizar a funcionalidade default quando utilizamos triggers Key-* ou On.
♦ Função Get_Ole_Var(Obj, Memberid, Persistent) – Obtém o valor de uma determinada propriedade (do tipo variant).
♦ Procedure Get_Var_Bounds(Var, Bounds) – Obtém as fronteiras de um array OLE variant.
♦ Função Get_Var_Dims(Var) – Determina se um OLE variant é um array e, neste caso, retorna a quantidade de
dimensões do array.
♦ Função Get_Var_Type(Var) – Obtém o tipo de um OLE variant.
♦ Procedure Init_Oleargs(Num_Args) – Determina o número de parâmetros que serão definidos e passados para o
método de um objeto OLE.
♦ Função Last_Ole_Error – Retorna o número que identifica a mais recente (última) condição de erro OLE.
♦ Função Last_Ole_Exception(Source, Description, Helpfile, Helpcontextid) – Retorna o número que o OLE Server
associou a esta condição de erro.
♦ Função Ptr_To_Var(Pointer, Vtype) – Inicialmente cria um OLE variant do tipo VT_PTR que contenha o endereço
fornecido. Em seguida, passa essa variant e tipo através da função Varptr_To_Var.
♦ Procedure Release_Obj(Obj, Kill_Persistent) – Encerra a conexão do objeto OLE.
♦ Procedure Set_Ole(Obj, Memberid, Newval, Vtype) – Altera o valor de uma propriedade de um OLE.
♦ Procedure Set_Var(Var, Newval ou Data, Vtype, Arrspec) – Inicializa um recém-criado OLE variant ou substitui o
valor de um existente.
♦ Função To_Variant(Newval, Vtype, Persistent) – Cria um OLE variant e associa ao mesmo um valor.
♦ Função To_Variant(Var ou Newval, Vtype, Arrspec, Persistent) – Cria um OLE variant e associa ao mesmo um valor.
♦ Função Varptr_To_Var(Variant, Vtype) – Altera uma variant pointer em uma variant simples.
♦ Função Var_To_Char(Var, Arrspec) – Lê um OLE variant e transforma seu valor em um tipo PL/SQL equivalente.
♦ Função Var_To_Number(Var, Arrspec) – Lê um OLE variant e transforma seu valor em um tipo PL/SQL equivalente.
♦ Função Var_To_Obj(Var, Arrspec) – Lê um OLE variant e transforma seu valor em um tipo PL/SQL equivalente.
♦ Procedure Var_To_Table(Var, Data, Arrspec) – Lê um array OLE variant e preenche uma tabela PL/SQL a partir dele.
♦ Função Var_To_Varptr(Variant, Vtype) – Cria um OLE variant que aponta para uma variant existente.
ALERTA (ALERT)
♦ Procedure Change_Alert_Message (Alert_Id ou Alert_Name, Message) – Permite a alteração da mensagem de um alerta.
♦ Função Find_Alert (Alert_Name) – Retorna o ID do alerta passado como parâmetro.
♦ Função Id_Null(Alert_Id) – Retorna um booleano indicando se o ID do alerta passado como parâmetro é válido.
♦ Procedure Set_Alert_Button_Property (Alert_Name ou Alert_Id, Button, Property, Value) – Permite a alteração
de propriedades do botão de alerta.
♦ Procedure Set_Alert_Property (Alert_Name ou Alert_Id, Property, Message) – Permite a alteração do título ou da
mensagem de um alerta.
♦ Função Show_Alert (Alert_Name ou Alert_Id) – Apresenta a janela do alerta e retorna um numérico indicando
qual botão foi pressionado pelo operador.
APLICAÇÃO
♦ Procedure Do_Key(Key) – Executa o trigger do tipo Key que corresponda à built-in que se refere à ação-padrão.
♦ Função Get_Application_Property(Property) – Retorna um varchar2 referente à propriedade solicitada como parâmetro.
♦ Função Get_File_Name (Directory_Name, File_Name, File_Filter, Message, Dialog_Type, Select_File) – Mostra o diálogo-
padrão de abertura de arquivo para que o usuário especifique um arquivo preexistente ou defina um novo arquivo.
♦ Procedure Host(Syscmd, Kwd) – Envia um comando ao sistema operacional (o segundo parâmetro é opcional).
♦ Procedure Pause – Suspende a ação até que o operador indique o prosseguimento.
♦ Procedure Set_Application_Property(Property, Value) – Permite a modificação do valor de uma propriedade da aplicação.
♦ Procedure User_Exit(Command, Error) – Aciona a user exit determinada. O segundo parâmetro é opcional.
BLOCO
♦ Procedure Block_Menu – Apresenta a lista de blocos disponíveis para navegação da aplicação.
♦ Procedure Clear_Block(Kwd) – Limpa a área de buffer associada ao bloco corrente.
♦ Função Find_Block(Block_Name) – Retorna o ID do bloco passado como parâmetro.
♦ Função Get_Block_Property(Block_Name ou Block_Id, Property) – Retorna o valor da propriedade solicitada.
♦ Procedure Go_Block(Blk) – Desvia para o primeiro item navegável no bloco informado.
♦ Função Id_Null(Block_Id) – Retorna um booleano indicando se o ID do bloco passado como parâmetro é válido.
♦ Procedure Next_Block – Desvia para o primeiro item navegável no próximo bloco dentro da seqüência de navegação.
♦ Previous_Block – Desvia para o primeiro item navegável no bloco anterior dentro da seqüência de navegação.
♦ Procedure Set_Block_Property(Block_Name ou Block_Id, Property, Value) – Permite a alteração do valor da
propriedade informada.
♦ Procedure Table_From_Block (Block_Data, Block_Name, Start_Rec, End_Rec, Item_Data) – Preenche uma tabela
PL/SQL a partir de um bloco.
CANVAS-VIEW
CANVAS (CONTENT)
♦ Função Find_Canvas (Canvas_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Get_Canvas_Property (canvas_name ou canvas_id, property) – Retorna o valor da propriedade solicitada.
♦ Função Id_Null (Canvas_Id) – Retorna um booleano indicando se o ID da canvas passada como parâmetro é válido.
♦ Procedure Print – Imprime a janela corrente para um arquivo ou impressora.
♦ Procedure Replace_Content_View (Window_Id ou Window_Name, View_Name ou View_Id) – Substitui a can-
vas content associada à window passada como parâmetro.
♦ Procedure Set_Canvas_Property (Canvas_Id ou Canvas_name, Property, Value) – Permite a alteração do valor da
propriedade informada.
♦ Procedure Set_Canvas_Property (Canvas_Name ou Canvas_Id, Property, X, Y) – Permite a alteração do valor da
propriedade informada.
VIEW (STACKED)
♦ Função Find_View (View_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Get_View_Property (View_Name ou View_Id, Property) – Retorna o valor da propriedade solicitada.
♦ Procedure Hide_View (View_Name ou View_Id) – Esconde a canvas (stack) mencionada.
♦ Função Id_Null (View_Id) – Retorna um booleano indicando se o ID da canvas passada como parâmetro é válido.
TAB
♦ Função Find_Tab_Page(Page_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Get_Tab_Page_Property(Page_Name ou Page_Id, Property) – Retorna o valor da propriedade solicitada.
♦ Procedure Set_Tab_Page_Property(Page_Name ou Page_Id, Property, Value) – Permite a alteração do valor da
propriedade informada.
FORM
♦ Procedure Bell – Aciona o alarme sonoro quando ocorrer o sincronismo entre o estado do terminal e a tela.
♦ Procedure Break – Interrompe a execução e apresenta o Debugger quando a aplicação estiver executando no
modo de depuração.
♦ Procedure Call_Form (Formmodule_Name, Display, Switch_Menu, Query_Mode, Paramlist_Name ou
Paramlist_Id) – Inicia a execução da aplicação indicada.
♦ Procedure Call_Form (Formmodule_Name, Display, Switch_Menu, Query_Mode, Data_Mode, Paramlist_Id ou
Paramlist_Name) – Inicia a execução da aplicação indicada.
♦ Procedure Call_Form (Formmodule_Name, Display, Switch_Menu, Query_Mode, Data_Mode) – Inicia a execução
da aplicação indicada.
♦ Procedure Clear_Form (Kwd1, Kwd2) – Limpa todos os blocos presentes na aplicação corrente.
♦ Procedure Close_Form (Formmodule_Name ou Formmodule_Id) – Fecha a aplicação mencionada (caso seja a
corrente, realiza a mesma ação de Exit_Form).
♦ Procedure Commit_Form – Dispara a execução da etapa transacional da aplicação aplicando as pendências para
o banco de dados e enviando em seguida um Commit.
♦ Procedure Debug_Mode – Alterna o estado de debug entre on e off.
♦ Procedure Enter – Valida o dado na unidade de validação corrente.
♦ Procedure Erase (Globvar) – Destrói a variável global informada.
♦ Procedure Execute_Trigger (T) – Executa o trigger mencionado.
♦ Procedure Exit_Form (Kwd1, Kwd2) – Encerra a aplicação corrente.
♦ Função Find_Form (Formmodule_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Form_Failure – Retorna um booleano se a última rotina predefinida encerrou com erro.
♦ Função Form_Fatal – Retorna um booleano se a última rotina predefinida encerrou com erro fatal.
♦ Função Form_Success – Retorna um booleano se a última rotina predefinida encerrou com sucesso.
♦ Função Get_Form_Property (Formmodule_Name ou Formmodule_Id, Property) – Retorna o valor da
propriedade solicitada.
♦ Procedure Go_Form (Formmodule_Name ou Formmodule_Id) – Desvia para o Form indicado em um ambiente
com múltiplos Forms abertos simultaneamente.
♦ Procedure Help – Mostra a mensagem de Hint para o item corrente.
♦ Função Id_Null (Formmodule_Id) – Retorna um booleano indicando se o ID do módulo passado como parâmetro
é válido.
♦ Procedure Next_Form – Em ambiente com múltiplos Forms abertos simultaneamente, esta procedure permite a
navegação para o próximo Form aberto (de acordo com a seqüência de navegação). Este número é atribuído de
acordo com a ordem em que cada Form é acionado a tempo de execução.
♦ Procedure New_Form (Formmodule_Name, Rollback_Mode, Query_Mode, Data_Mode, Paramlist_Id ou
Paramlist_Name) – Encerra o Form corrente e aciona o módulo indicado.
♦ Procedure New_Form (Formmodule_Name, Rollback_Mode, Query_Mode, Paramlist_Name ou Paramlist_Id) –
Encerra o Form corrente e aciona o módulo indicado.
♦ Procedure New_Form (Formmodule_Name, Rollback_Mode, Query_Mode, Data_Mode) – Encerra o Form corrente
e aciona o módulo indicado.
♦ Procedure Open_Form (Formmodule_Name, Activate_Mode, Session_Mode, Data_Mode, Paramlist_Id ou
Paramlist_Name) – Abre uma nova aplicação Form sem encerrar a corrente. Permite a criação de um ambiente com
múltiplos Forms abertos simultaneamente. O Form a ser aberto pode estabelecer uma nova conexão com o banco de
dados independente do Form corrente original.
♦ Procedure Open_Form (Formmodule_Name, Activate_Mode, Session_Mode, Paramlist_Name ou Paramlist_Id) –
Abre uma nova aplicação Form sem encerrar a corrente. Permite a criação de um ambiente com múltiplos Forms
abertos simultaneamente. O Form a ser aberto pode estabelecer uma nova conexão com o banco de dados
independente do Form corrente original.
♦ Procedure Open_Form (Formmodule_Name, Activate_Mode, Session_Mode, Data_Mode) – Abre uma nova
aplicação Form sem encerrar a corrente. Permite a criação de um ambiente com múltiplos Forms abertos
simultaneamente. O Form a ser aberto pode estabelecer uma nova conexão com o banco de dados independente
do Form corrente original.
♦ Procedure Previous_Form – Em ambiente com múltiplos Forms abertos simultaneamente, essa procedure permite a
navegação para o Form anterior ao corrente (de acordo com a seqüência de navegação). Esse número é atribuído de
acordo com a ordem que cada Form é acionado a tempo de execução.
♦ Procedure Post – Inicia o processo transacional aplicando as pendências em cada bloco (inserts, updates e
deletes) para o banco de dados. Não faz Commit, o que permite que desfaçamos as modificações se desejarmos.
♦ Procedure Redisplay – Reapresenta a tela. As mensagens presentes na tela são apagadas.
♦ Procedure Set_Form_Property (Formmodule_Name ou Formmodule_Id, Property, Value) – Permite a alteração
do valor da propriedade informada.
♦ Procedure Show_Keys – Mostra o diálogo Keys contendo a função e as teclas correspondentes para seu
acionamento através do teclado.
♦ Procedure Synchronize – Sincroniza a tela do terminal com o estado interno do Form.
ITEM
GERAL
♦ Procedure Clear_Eol – Limpa o trecho de texto do item corrente a partir da posição atual do cursor para o fim da linha.
♦ Procedure Clear_Item – Limpa o texto do item corrente (atribui Null).
♦ Procedure Convert_Other_Value (Item_Name ou Item_Id) – Converte o valor corrente de um item do tipo
check box, radio group ou list item para o valor associado com o estado atual do check box (checado / não
checado) ou com o botão corrente do radio grupo ou com o elemento corrente da lista.
♦ Procedure Copy (Source, Destination) – Copia o valor (ou uma referência a um item ou variável global)
indicado pelo parâmetro Source para a variável (ou item) indicada pelo parâmetro Destination.
♦ Procedure Copy_Region – Copia o texto selecionado (sem apagá-lo da tela) para o clipboard até que façamos a
cópia para outra região.
♦ Procedure Cut_Region – Copia o texto selecionado, apagando-o da tela, para o clipboard até que façamos a
cópia para outra região.
♦ Procedure Default_Value (Val, Fie) – Copia o valor definido pelo parâmetro Val para a variável indicada pelo
parâmetro Fie se a variável de destino for Null. No caso de a variável de destino ser uma Global não criada, a
criação é feita neste momento.
♦ Procedure Display_Item (Item_Id ou Item_Name, Attribute) – Associa um atributo visual definido para o item indicado.
♦ Procedure Duplicate_Item – Copia o valor da instância anterior do item (no registro anterior) para o item corrente.
♦ Função Find_Item(Item_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Get_Item_Instance_Property(Item_Name ou Item_Id, Record_Number, Property) – Retorna o valor da
propriedade solicitada para a instância do item indicada pelo número do registro.
♦ Função Get_Item_Property (Item_Id, Property) – Retorna o valor da propriedade solicitada.
♦ Procedure Go_Item (Item_Name ou Item_Id) – Navega para o item indicado.
♦ Função Id_Null (Item_Id) – Retorna um booleano indicando se o ID item passado como parâmetro é válido.
♦ Função Name_In (F) – Retorna o valor do item referenciado pelo parâmetro F.
♦ Procedure Next_Item – Navega para o próximo item na seqüência de navegação.
♦ Procedure Next_Key – Navega para o próximo item primary key (enabled e navigable) com número de seqüência
superior ao do item corrente. Se não existir, a navegação é feita para o item pk com o menor número de seqüência.
Se não existir item pk para o bloco corrente, ocorre um erro.
♦ Procedure Paste_Region – Cola a informação (guardada previamente no clipboard) para a posição do cursor no
item corrente.
♦ Procedure Previous_Item – Navega para o item anterior da seqüência de navegação.
♦ Recalculate (Item_Name ou Item_Id) – Marca o valor do item de fórmula para recálculo. Essa built-in deve ser
executada quando a fórmula (ou função ou procedure que ela aciona) faz referência a uma variável ou função
que retornou um valor diferente agora.
♦ Procedure Select_All – Seleciona o texto no item corrente.
♦ Procedure Set_Item_Instance_Property (Item_Id ou Item_Name, Record_Number, Property, Value) – Permite a alteração
do valor da propriedade informada para uma determinada instância do item.
♦ Procedure Set_Item_Property (Item_Name ou Item_Id, Property, X, Y) – Permite a alteração do valor da propriedade
informada (para todas as instâncias do item simultaneamente).
♦ Procedure Set_Item_Property (Item_Name ou Item_Id, Property, Value) – Permite a alteração do valor da
propriedade informada (para todas as instâncias do item simultaneamente).
CHART
♦ Procedure Update_chart (Chart_Name ou Chart_Id, Param_List_id ou Param_List_Name) – Faz com que um
item do tipo chart seja considerado alterado mesmo que o bloco de dados no qual ele está baseado não seja
alterado. O segundo parâmetro é opcional.
CHECKBOX
♦ Função Checkbox_Checked (Item_Name ou Item_Id) – Retorna um booleano indicando o estado atual do item
(checado ou não).
EDITOR
♦ Procedure Edit_Textitem (X, Y, Width, Height) – Aciona o editor associado ao item corrente (caso não exista, usa
o editor default do Form).
♦ Procedure Edit_Textitem (X, Y) – Aciona o editor associado ao item corrente (caso não exista, usa o editor
default do Form).
♦ Procedure Edit_Textitem – Aciona o editor associado ao item corrente (caso não exista, usa o editor default do Form).
OLE
♦ Procedure Activate_Server (Item_Id ou Item_Name) – Ativa o servidor OLE associado com o container (item).
♦ Procedure Close_Server (Item_Id ou Item_Name) – Desativa o servidor OLE associado com o container (item).
♦ Procedure Exec_Verb (Item_Name ou Item_Id, Verb_Name ou Verb_Index) – Solicita a execução do verbo
identificado pelo nome ou índice.
♦ Função Find_Ole_Verb (Item_Id ou Item_Name, Verb_Name) – Retorna o índice correspondente ao nome do
verbo indicado.
♦ Função Get_Interface_Pointer (Item_Id ou Item_Name) – Retorna um handle para um objeto OLE2 automation.
♦ Função Get_Verb_Count (Item_Id ou Item_Name) – Retorna a quantidade de verbos que o servidor OLE reconhece.
♦ Função Get_Verb_Name (Item_Id ou Item_Name, Verb_Index) – Retorna o nome do verbo correspondente ao
índice informado.
♦ Procedure Initialize_Container (Item_Id ou Item_Name, File_name) – Insere um objeto OLE de um arquivo de
tipo compatível com o servidor OLE no container (item).
♦ Função Server_Active (Item_Id ou Item_Name) – Retorna um booleano indicando se o servidor está ou não
ativo (ou associado).
RADIO
♦ Função Get_Radio_Button_Property (Item_Name ou Item_Id, Button_Name, Property) – Retorna o valor da
propriedade solicitada do botão de radio.
♦ Procedure Set_Radio_Button_Property (Item_Id ou Item_Name, Button_Name, Property, X, Y) – Permite a alteração
do valor da propriedade informada para o botão de radio.
♦ Procedure Set_Radio_Button_Property (Item_Id ou Item_Name, Button_Name, Property, Value) – Permite a
alteração do valor da propriedade informada para o botão de radio.
IMAGE
♦ Procedure Image_Scroll (Item_Name ou Item_Id, X, Y) – Rola o item imagem para o offset especificado, se
possível. Esta rotina é útil quando a imagem é maior que o item na canvas.
♦ Procedure Image_Zoom (Item_Name ou Item_Id, Zoom_Type, Zoom_Factor) – Aumenta ou diminui o tamanho
da imagem usando o efeito especificado pelo parâmetro Zoom_Type e pela quantidade especificada por Zoom_Factor.
♦ Procedure Read_Image_File (File_Name, File_Type, Item_Name ou Item_Id) – Lê um arquivo imagem do disco e
o associa ao item image.
LIST
♦ Procedure Add_List_Element (Item_Name ou Item_Id, Item_Index, Label_Str, Value_Str) – Adiciona um elemento
a um List Item.
♦ Procedure Clear_List (Item_Name ou Item_Id) – Remove todos os elementos de um List Item. Após a execução
dessa rotina, apenas um elemento fica residente na lista (Null, mesmo que o item seja obrigatório).
♦ Procedure Delete_List_Element (Item_Name ou Item_Id, Item_Index) – Remove um elemento da lista.
♦ Função Get_List_Element_Count (Item_Id ou Item_Name) – Retorna a quantidade de elementos da lista inclu-
sive o elemento Null.
♦ Função Get_List_Element_Label (Item_Name ou Item_Id, Item_Index) – Retorna o label (texto visualizado pelo
usuário) do elemento indicado.
♦ Função Get_List_Element_Value (Item_Name ou Item_Id, Item_Index) – Retorna o valor associado ao elemento indicado.
♦ Procedure Populate_List (Item_Name ou Item_Id, Rg_Name ou Recgrp_Id) – Remove o conteúdo atual da lista e a
preenche novamente a partir dos valores presentes no record group. O record group deve ter sido criado a tempo
de execução e a estrutura deste deve conter, na primeira coluna, o label da lista e, na segunda, o valor da lista.
♦ Procedure Retrieve_List (Item_Id ou Item_Name, Rg_Name ou Recgrp_Id) – Copia o conteúdo de um List Item
para o record group referenciado. A estrutura do record group deve conter na primeira coluna o label da lista e
na segunda, o valor da lista.
SOUND
♦ Procedure Play_Sound (Item_Name ou Item_Id) – Toca o som associado ao item especificado.
♦ Procedure Read_Sound_File (File_Name, File_Type, Item_Name ou Item_Id) – Lê o arquivo contendo o som e o
armazena no item especificado.
♦ Procedure Write_Sound_File (File_Name, File_Type, Item_Name ou Item_Id, Compression, Sound_Quality,
Channels) – Grava o som armazenado no item no arquivo especificado.
MENU
♦ Procedure Application_Parameter – Mostra todos os parâmetros associados com o menu corrente e seus valores
correntes na caixa de diálogo Enter Parameter Values.
♦ Procedure Background_Menu {1|2|3|4|5|6|7|8|9|10} – Executa o item de menu especificado do background menu.
♦ Função Find_Menu_Item (Menuitem_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Get_Menu_Item_Property (Menuitem_Name Menuitem_Id, Property) – Retorna o valor da propriedade solicitada.
♦ Procedure Hide_Menu – Em plataformas Character Mode, faz o menu corrente desaparecer se estiver visível
atualmente, descobrindo qualquer parte do Form que o menu tenha coberto. O menu será reapresentado se a
rotina Show_Menu for acionada ou o operador pressionar Menu.
♦ Função Id_Null (Menuitem_Id) – Retorna um booleano indicando se o ID do item de menu passado como
parâmetro é válido.
♦ Função Item_Enabled (Mnunam, Itmnam) – Retorna um booleano indicando se o item de menu está ou não habilitado.
♦ Procedure Main_Menu – Navega para o menu principal da aplicação corrente.
♦ Procedure Menu_Clear_Field – Limpa o campo corrente a partir da posição do cursor na caixa de diálogo Enter
Parameter Values.
♦ Procedure Menu_Parameter – Mostra todos os parâmetros associados com o menu corrente e seus valores no
diálogo Enter Parameter Values.
♦ Procedure Menu_Previous_Field – Retorna para o campo anterior em um diálogo de entrada de parâmetros.
♦ Procedure Menu_Redisplay – Redesenha a tela.
♦ Procedure Menu_Show_Keys – Mostra a tela de teclas para o módulo menu a tempo de execução.
♦ Procedure Next_Menu_Item – Navega para o próximo campo no diálogo Enter Parameter Values.
♦ Procedure Previous_Menu – Navega para o item de menu anterior no menu anterior.
♦ Procedure Previous_Menu_Item – Navega para o campo anterior no diálogo Enter Parameter Values.
♦ Procedure Query_Parameter (parameter_string) – Mostra o diálogo Query Parameter mostrando os valores correntes
dos parâmetros de substituição especificados. O parâmetro especifica uma string contendo parâmetros de substituição
para um item de menu. A sintaxe obriga à presença de um “&” precedendo o nome de cada parâmetro.
♦ Procedure Replace_Menu (Menu_Application, Menu_Type, Starting_Menu, Group_Name, Use_File) – Substitui
o menu corrente pelo menu especificado, mas não o torna ativo.
♦ Procedure Set_Input_Focus (Kwd) – Coloca o foco no menu do Form corrente. Uma vez que o trigger em
processamento esteja completo, o Form Builder ativa o menu.
♦ Procedure Set_Menu_Item_Property (Menuitem_Id ou Menuitem_Name, Property, Value) – Permite a alteração
do valor da propriedade informada.
♦ Procedure Show_Background_Menu – Mostra o menu background.
♦ Procedure Show_Menu – Mostra o menu corrente se ele não estiver visível atualmente. Não o torna ativo.
♦ Procedure Terminate – Termina a entrada de dados relativa à caixa de diálogo Enter Parameter Values.
♦ Procedure Where_Display – Alterna entre On e Off a opção de navegação do menu. Em um menu apresentado em
Full Screen, a Where Option mostra informações sobre a localização corrente do operador na hierarquia do menu.
MENSAGEM
♦ Procedure Clear_Message – Remove a mensagem corrente da área de mensagens da tela.
♦ Função Dbms_Error_Code – Retorna o código do último erro de banco de dados ocorrido.
♦ Função Dbms_Error_Text – Retorna a mensagem relativa ao último erro de banco de dados ocorrido.
♦ Procedure Display_Error – Mostra o diálogo Display Error se um erro houver acontecido.
♦ Função Error_Code – Retorna o número do erro do último Form Builder Error.
♦ Função Error_Text – Retorna o texto do erro relativo ao último Form Builder Error.
♦ Função Error_Type – Retorna o tipo do erro relativo ao último Form Builder Error.
♦ Função Get_Message – Retorna a mensagem corrente, independente do tipo.
♦ Procedure Message (Message, User_Response) – Mostra o texto especificado na linha de mensagem.
♦ Função Message_Code – Retorna o número da última mensagem gerada pelo Form durante a execução.
♦ Função Message_Text – Retorna o texto relativo à última mensagem gerada pelo Form durante a execução.
♦ Função Message_Type – Retorna o tipo da última mensagem gerada pelo Form durante a execução.
CONTROLE DE TEMPO
♦ Função Create_Timer (Timer_Name, Milliseconds, Iterate) – Cria um Timer que será expirado no prazo de tempo
especificado.
♦ Procedure Delete_Timer (Timer_Name ou Timer_Id) – Remove o Timer especificado.
♦ Função Find_Timer (Timer_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Id_Null (Timer_Id) – Retorna um booleano indicando se o ID do timer passado como parâmetro é válido.
♦ Procedure Set_Timer (Timer_Name ou Timer_Id, Milliseconds, Iterate) – Altera as características de um Timer
existente. Pode-se alterar o tempo de expiração e/ou a condição de repetição.
EDITOR
♦ Procedure Edit_TextItem – Aciona o editor associado ao item e coloca o Form no modo de edição.
♦ Função Find_Editor (Editor_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Id_Null (Editor_Id) – Retorna um booleano indicando se o ID do editor passado como parâmetro é válido.
♦ Procedure Show_Editor (Editor_Id ou Editor_Name, Message_In, [X, Y,] Message_Out, Result) – Aciona o editor
nas coordenadas especificadas (opcional) e envia um texto a ser apresentado no editor, recuperando, em seguida,
o texto modificado pelo usuário e sua aceitação ou não do diálogo de edição.
LOV
♦ Função Find_Lov (Lov_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Id_Null (Lov_Id) – Retorna um booleano indicando se o ID da lov passada como parâmetro é válido.
♦ Função Get_Lov_Property (Lov_Name ou Lov_Id, Property) – Retorna o valor da propriedade solicitada.
♦ Procedure Set_Lov_Column_Property (Lov_Id ou Lov_Name, Colnum, Property, Value) – Permite a alteração do
valor da propriedade informada para uma determinada coluna da lov.
♦ Procedure Set_Lov_Property (Lov_Name ou Lov_Id, Property, X, Y) – Permite a alteração do valor da propriedade
informada para a lov.
♦ Função Show_Lov (Lov_Name ou Lov_Id [,X,Y] ) – Apresenta a janela da lov nas coordenadas especificadas e
retorna um booleano indicando se o operador selecionou um valor da lista (True) ou se o operador cancelou ou
fechou a lista.
VALIDAÇÃO
♦ Procedure Validate (Validation_Scope, Block_Or_Item, Record_Number) – Força o Form a executar o processo
de validação para o escopo definido.
♦ Função Get_Parameter_Attr (Name ou List, Key, Paramtype, Value) – Retorna o tipo e valor de um elemento da
lista de parâmetros.
♦ Função Get_Parameter_List (Name) – Retorna o identificador (ID) da lista de parâmetros nomeada.
♦ Função Id_Null (Paramlist_Id) – Retorna um booleano indicando se o ID da lista de parâmetros passada como
parâmetro é válido.
♦ Procedure Run_Product (Product, Document, Commmode, Execmode, Location, Paramlist_Name ou
Paramlist_Id, Display) – Executa uma aplicação Report, Forms, Graphics ou Oracle Book passando como parâmetro
a lista de parâmetros criada.
♦ Procedure Set_Parameter_Attr (Name ou List, Key, Paramtype, Value) – Atribui valor e tipo a um dos elementos
da lista de parâmetros.
QUERY
♦ Procedure Abort_Query – Fecha uma query que esteja aberta no bloco corrente.
♦ Procedure Count_Query – Aciona o processo do Form para identificar o número de linhas que a query retornará para
o bloco corrente. Somente válida em triggers que admitam procedures restritas.
♦ Enter_Query[(Kwd1[, Kwd2[, Kwd3]])] – Coloca o Form no modo de Enter Query para que o usuário possa
fornecer informações que restrinjam a query a ser realizada.
♦ Procedure Execute_Query[(Kwd1[, Kwd2[, Kwd3]])] – Executa a query de acordo com as restrições previamente
estabelecidas.
RECORD
♦ Procedure Check_Record_Uniqueness – Inicia o processo-padrão de verificação da unicidade da PK.
♦ Procedure Clear_Record – Remove o registro corrente do bloco (buffer) sem efetuar validação.
♦ Procedure Create_Queried_Record – Quando chamada a partir do trigger on-fetch, cria um registro na lista de
espera do bloco. Essa lista é uma área de registros intermediária (temporária), que contém registros que tenham
sido lidos do banco de dados (fetched), mas ainda não foram colocados na lista de registros ativos. Após a
inclusão nessa lista, o registro deve receber dados para que seja disponibilizado para a aplicação.
♦ Procedure Create_Record – Cria um novo registro no bloco corrente após o registro corrente.
♦ Procedure Delete_Record – Quando utilizada fora da trigger on-delete, retira o registro corrente do buffer e o
adiciona à lista dos registros a serem excluídos durante o próximo processo de Post e Commit. Se utilizada
dentro do trigger on-delete, gera o comando, padrão para remoção de um registro do banco de dados.
♦ Procedure Down – Navega para o item corrente no próximo registro. Caso o registro corrente seja o último
e o Form Builder venha a criar um novo registro, a navegação ocorrerá para o primeiro item navegável no
novo registro.
♦ Procedure Duplicate_Record – Copia o valor de cada item no registro anterior para o registro corrente.
♦ Procedure First_Record – Navega para o primeiro registro na lista de registros do bloco.
♦ Procedure Generate_Sequence_Number – Inicia o processo-padrão para geração de um número seqüencial. Para
tal, um item no bloco deve ter a propriedade Valor Inicial preenchida com :sequence.<sequencia>.nextval. Essa
rotina deve ser acionada na trigger on-sequence-number.
♦ Função Get_Record_Property (Record_Number, Block_Name, Property) – Retorna o valor da propriedade solicitada.
♦ Procedure Go_Record (Rn) – Navega para o número de registro informado.
♦ Procedure Insert_Record – Gera o comando-padrão de inclusão de registros no banco de dados. Deve ser acionada
dentro da trigger on-insert.
♦ Procedure Last_Record – Navega para o último registro do bloco. Se a query ainda estiver aberta, força o Form
Builder a obter o restante dos registros do banco de dados e fechar a query.
♦ Procedure Lock_Record – Quando utilizada dentro do trigger on-lock, gera o comando-padrão para bloqueio do
registro corrente no banco de dados.
♦ Procedure Next_Record – Navega para o próximo registro (número de registro superior).
♦ Procedure Next_Set – Obtém um novo conjunto de registro do banco de dados (fetch) e navega para o primeiro registro
nesse conjunto. Só é bem-sucedida se a query estiver aberta no bloco corrente.
♦ Procedure Previous_Record – Navega para o registro anterior (número de registro inferior).
♦ Procedure Scroll_Down – Rola os registros para a frente de acordo com a quantidade de registros do bloco. Se o
bloco for single-line, tem o mesmo efeito da rotina Down.
♦ Procedure Scroll_Up – Rola os registros para trás de acordo com a quantidade de registros do bloco. Se o bloco
for single-line, tem o mesmo efeito da rotina Up.
♦ Procedure Select_Records – Quando chamada de dentro do trigger on-select, inicia o processo default de Select
do Form Builder.
♦ Procedure Set_Record_Property (Record_Number, Block_Name, Property, Value) – Permite a alteração do valor
da propriedade informada.
♦ Procedure Up – Navega para o item corrente no registro anterior.
♦ Procedure Update_Record – Quando chamada de dentro da trigger on-update, inicia o processo default de
atualização de registros no banco de dados durante o Post e Commit.
RECORD GROUP
♦ Função Add_Group_Column (Recordgroup_Id ou Recordgroup_Name, Groupcolumn_Name, Column_Type [,
Column_Width ] ) – Adiciona uma coluna do tipo especificado ao record group mencionado.
♦ Procedure Add_Group_Row (Recordgroup_Name ou Recordgroup_Id, Row_Number) – Adiciona uma nova row
ao record group mencionado.
♦ Função Create_Group (Recordgroup_Name, Scope, Array_Size) – Cria um record group do tipo non-query. Esse
novo grupo não possui linhas ou colunas, até que sejam explicitamente adicionadas pelas rotinas
Add_Group_Column e Add_Group_Row.
♦ Função Create_Group_From_Query (Recordgroup_Name, Query, Scope, Array_Size) – Cria um record group
com um determinado nome, o qual contém colunas derivadas das colunas presentes na Select-List da query.
♦ Procedure Delete_Group (Recordgroup_Name ou Recordgroup_Id) – Remove o record group nomeado (criado
por programação).
♦ Procedure Delete_Group_Row (Recordgroup_Name ou Recordgroup_Id, Row_Number) – Remove uma linha
(ou todas) de um record group.
♦ Função Find_Column (Groupcolumn_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Find_Group (Recordgroup_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Get_Group_Char_Cell (Groupcolumn_Name ou Groupcolumn_Id, Row_Number) – Retorna o conteúdo
(varchar2) de uma determinada célula de um record group identificada pelo número da linha e pela coluna.
♦ Função Get_Group_Date_Cell (Groupcolumn_Name ou Groupcolumn_Id, Row_Number) – Retorna o conteúdo
(date) de uma determinada célula de um record group identificada pelo número da linha e pela coluna.
RELATION
♦ Função Find_Relation (Relation_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Get_Relation_Property (Relation_Id ou Relation_Name, Property) – Retorna o valor da propriedade solicitada.
♦ Função Id_Null (Relation_Id) – Retorna um booleano indicando se o ID do relation passado como parâmetro é válido.
♦ Procedure Set_Relation_Property (Relation_Name ou Relation_Id, Property, Value) – Permite a alteração do valor
da propriedade informada.
REPORT
♦ Procedure Cancel_Report_Object (Job_Handle) – Cancela a execução de um relatório assíncrono. O identificador
é obtido na execução da rotina Run_Report_Object.
TRANSACTION
♦ Procedure Check_Record_Uniqueness – Inicia o processo-padrão de verificação da unicidade da PK.
♦ Procedure Commit_Form – Faz com que o Form Builder execute as rotinas necessárias para atualizar os dados do
banco de dados para que fiquem compatíveis com o Form. Inicialmente, o Form Builder realiza a validação do
Form; em seguida, para cada bloco no Form, realiza a fase de Post e finalmente executa um database Commit.
♦ Procedure Delete_Record – Quando utilizada fora da trigger on-delete, retira o registro corrente do buffer e o
adiciona à lista dos registros a serem excluídos durante o próximo processo de Post e Commit. Se utilizada
dentro do trigger on-delete, gera o comando, padrão para remoção de um registro do banco de dados.
♦ Procedure Enforce_Column_Security – Executa o processo-padrão para verificar a segurança de uma coluna no
banco de dados, garantindo que o operador atual tenha privilégios de atualização para cada coluna quando o
bloco possuir a propriedade Impor Segurança de Coluna (Enforce Column Security) como Sim.
♦ Procedure Fetch_Records – Quando chamada de dentro do trigger on-fetch, inicia o processo-padrão para obtenção
(fetch) de registros que tenham sido identificados pelo Select.
♦ Função Forms_Ddl (Statement) – Permite o envio de comandos de SQL dinâmicos.
♦ Procedure Generate_Sequence_Number – Inicia o processo-padrão para geração de um número seqüencial. Para
tal, um item no bloco deve ter a propriedade Valor Inicial preenchida com :sequence.<sequencia>.nextval. Essa
rotina deve ser acionada na trigger on-sequence-number.
♦ Procedure Insert_Record – Gera o comando-padrão de inclusão de registros no banco de dados. Deve ser acionada
dentro da trigger on-insert.
♦ Procedure Issue_Rollback (Spname) – Quando acionada de um trigger on-rollback, inicia o processo-padrão de
desmanchar as ações realizadas desde o savepoint indicado.
♦ Procedure Issue_Savepoint (Spname) – Quando chamada de um trigger on-savepoint, inicia o processo-padrão
de criar um ponto de controle (savepoint).
♦ Procedure Logon (Username, Password, Logon_Screen_On_Error) – Executa o logon-padrão do Form Builder
com o username e password indicados. Essa rotina deve ser acionada a partir da trigger on-logon.
♦ Procedure Logon_Screen – Mostra a tela de logon-padrão e requisita um username e password válidos.
♦ Procedure Logout – Desconecta a aplicação do banco de dados Oracle.
♦ Procedure Select_Records – Quando chamada de dentro do trigger on-select, inicia o processo default de Select
do Form Builder.
♦ Procedure Update_Record – Quando chamada de dentro da trigger on-update, inicia o processo default de
atualização de registros no banco de dados durante o Post e Commit.
WINDOW
♦ Função Find_Window (Window_Name) – Retorna o ID do objeto passado como parâmetro.
♦ Função Get_Window_Property (Window_Name ou Window_Id, Property) – Retorna o valor da propriedade solicitada.
♦ Procedure Hide_Window (Window_Name ou Window_Id) – Esconde a janela especificada.
♦ Função Id_Null (Window_Id) – Retorna um booleano indicando se o ID da window passada como parâmetro é válida.
♦ Função Move_Window (Window_Name ou Window_Id, X, Y) – Movimenta a janela para as coordenadas especificadas.
♦ Procedure Resize_Window (Window_Name ou Window_Id, Width, Height) – Dimensiona a janela especificada
para o tamanho de largura e altura informado.
♦ Procedure Set_Window_Property (Window_Name ou Window_Id, Property, Value) – Permite a alteração do
valor da propriedade informada.
♦ Procedure Set_Window_Property (Window_Name ou Window_Id, Property, X, Y) – Permite a alteração do valor
da propriedade informada.
♦ Show_Window (Window_Id ou Window_Name[, X, Y]) – Mostra a janela especificada nas coordenadas correntes
ou naquelas informadas pela rotina.
♦ Go_Field(Fie)
♦ Hide_Page(P)
♦ Isnull(List)
♦ List_Values(Kwd)
♦ Menu_Failure
♦ Menu_Help
♦ Menu_Message(Message)
♦ Menu_Next_Field
♦ Menu_Previous_Field
♦ Menu_Success
♦ Move_View(P, X0, Y0)
♦ New_Application(Aplnam)
♦ New_User(Username)
♦ Next_Field
♦ No_Operation
♦ Null_Command
♦ Ohost(System_Command)
♦ Ohost(System_Command, Value)
♦ Os_Command(Cmnd)
♦ Os_Command1(Cmnd)
♦ Previous_Field
♦ Resize_View(P, Xs, Ys)
♦ Set_Field(F, Att, Kwd)
♦ Show_Page(P)
VBX
DESCRIÇÃO DO PACOTE
Este pacote contém um conjunto de rotinas relacionadas à interface com controles VBX, que podem ser anexadas
a uma aplicação de 16-bits.
ROTINAS DO PACOTE
♦ Procedure Vbx.Fire_Event (Item_Name ou Item_Id, Event_Name, Paramlist_Id ou Paramlist_Name) – Causa um
evento de um controle VBX.
♦ Function Vbx.Get_Property (Item_Name ou Item_Id, Property) – Obtém o valor de uma propriedade de um
controle VBX.
♦ Função Vbx.Get_Value_Property(Item_Name ou Item_Id) – Obtém a propriedade de valor do controle VBX.
TEXTO_IO
DESCRIÇÃO DO PACOTE
Este pacote permitirá que venhamos a ler ou gravar informações para um arquivo do ambiente. É equivalente ao
pacote Utl_File da PL/SQL, com a diferença de que o arquivo lido ou gravado se encontra no ambiente cliente.
ROTINAS DO PACOTE
♦ Procedure Text_Io.Fclose(File) – Fecha o arquivo.
♦ Função Text_Io.Fopen(Spec, Filemode) – Abre o arquivo no modo especificado e retorna o file handle do arquivo.
♦ Procedure Text_Io.Get_Line(File, Item) – Recupera a próxima linha de um arquivo previamente aberto.
♦ Função Text_Io.Is_Open(File) – Retorna um booleano indicando se o arquivo está aberto.
♦ Procedure Text_Io.New_Line([File,] N) – Concatena o número especificado de carriage return à linha corrente de um
arquivo previamente aberto. Caso o nome do arquivo não seja especificado, envia os caracteres para o Interpreter.
♦ Text_Io.Put([File,] Item) – Concatena o dado informado para a linha corrente de um arquivo previamente aberto. Caso
o nome do arquivo não seja especificado, envia o dado para o Interpreter.
♦ Procedure Text_Io.Putf([File,] Format[, Arg1[, Arg2[, Arg3[, Arg4[, Arg5]]]]]) – Formata e concatena um texto
para a linha corrente de um arquivo previamente aberto. Caso o nome do arquivo não seja especificado, envia
o texto para o Interpreter.
♦ Procedure Text_Io.Put_Line([File,] Item) – Concatena o dado informado para a linha corrente de um arquivo
previamente aberto. Caso o nome do arquivo não seja especificado, envia o dado para o Interpreter. Ao fim do
dado, é concatenado, automaticamente, um carriage return.
OLE2
DESCRIÇÃO DO PACOTE
Conjunto de rotinas PL/SQL APIs para criação, manipulação e acesso a atributos de objetos OLE2 Automation.
Os objetos OLE2 Automation encapsulam um conjunto de atributos e métodos que pode ser manipulado ou
invocado de um OLE2 Automation Client. O pacote OLE2 permite que façamos acesso aos objetos OLE2 Automa-
tion Servers diretamente do PL/SQL.
ROTINAS DO PACOTE
♦ Procedure Ole2.Add_Arg(List, Value) – Adiciona um argumento ao fim de uma lista de argumentos previamente criada.
♦ Procedure Ole2.Add_Arg_Obj(List, Value) – Adiciona um argumento do tipo objeto ao fim de uma lista de
argumentos previamente criada.
♦ Função Ole2.Create_Arglist – Cria uma lista de argumentos que pode ser passada como parâmetro para um
OLE2 Automation Server.
♦ Função Ole2.Create_Obj(Object) – Cria um OLE2 Automation Object.
♦ Procedure Ole2.Destroy_Arglist(List) – Destrói uma lista de argumentos previamente criada.
♦ Função Ole2.Get_Bool_Property(Object, Property, Arglist) – Obtém o valor de uma propriedade boleana.
♦ Função Ole2.Get_Char_Property(Object, Property, Arglist) – Obtém o valor de uma propriedade caracter.
♦ Função Ole2.Get_Num_Property(Object, Property, Arglist) – Obtém o valor de uma propriedade numérica.
♦ Função Ole2.Get_Obj_Property(Object, Property, Arglist) – Obtém o valor de uma propriedade do tipo objeto.
♦ Procedure Ole2.Invoke(Object, Method, Arglist) – Aciona um método do OLE2.
♦ Função Ole2.Invoke_Char(Object, Method, Arglist) – Obtém um valor caracter de um objeto OLE2 Automation
ao acionar o método especificado.
♦ Função Ole2.Invoke_Num(Object, Method, Arglist) – Obtém um valor numérico de um objeto OLE2 Automa-
tion ao acionar o método especificado.
♦ Função Ole2.Invoke_Obj(Object, Method, Arglist) – Obtém um valor do tipo objeto de um objeto OLE2 Auto-
mation ao acionar o método especificado.
♦ Função Ole2.Issupported – Indica se o pacote OLE2 é suportado na plataforma corrente.
♦ Função Ole2.Last_Exception[(Message)] – Retorna a última condição de erro OLE2 sinalizada por uma excep-
tion PL/SQL. A mensagem de erro pode ser retornada no parâmetro Message.
♦ Procedure Ole2.Release_Obj(Object) – Indica ao objeto OLE2 Automation que o PL/SQL client está encerrando
a comunicação.
♦ Procedure Ole2.Set_Property(Object, Property, Value, Arglist) – Atribui valor a uma propriedade de um objeto
OLE2 Automation.
DEBUG
DESCRIÇÃO DO PACOTE
O pacote Debug oferece um conjunto de rotinas, funções e condições de erro para realizarmos depuração em
aplicações Forms.
ROTINAS DO PACOTE
♦ Função Debug.Getc(Varname) – Obtém o valor da variável local (caracter) informada.
♦ Função Debug.Getd(Varname) – Obtém o valor da variável local (data) informada.
♦ Função Debug.Geti(Varname) – Obtém o valor da variável local (pls_integer) informada.
♦ Função Debug.Getn(Varname) – Obtém o valor da variável local (number) informada.
♦ Procedure Debug.Interpret(Input) – Executa o comando de PL/SQL ou o comando do Interpreter informado no parâmetro.
♦ Procedure Debug.Setc(Varname, Newvalue) – Atribui um valor para a variável local (caracter) informada.
♦ Procedure Debug.Setd(Varname, Newvalue) – Atribui um valor para a variável local (data) informada.
♦ Procedure Debug.Seti(Varname, Newvalue) – Atribui um valor para a variável local (pls_integer) informada.
♦ Procedure Debug.Setn(Varname, Newvalue) – Atribui um valor para a variável local (number) informada.
♦ Procedure Debug.Suspend – Suspende a execução da unidade de programa corrente e transfere o controle
para o Interpreter.
PECS
DESCRIÇÃO DO PACOTE
Este pacote fornece ao desenvolvedor ou ao administrador dos sistemas meios de análise da performance tanto do
Form Builder quanto das aplicações geradas.
ROTINAS DO PACOTE
♦ Função Pecs.Add_Class(Class_Name ou Class_Type) – Cria uma classe ou grupo de eventos no Pecs e retorna o
ID da classe criada.
♦ Função Pecs.Add_Event(Class_Id, Description ou Event_Type) – Adiciona um evento a uma classe especificada.
Retorna o ID do evento criado.
♦ Procedure Pecs.Collect(Collector_Status) – Habilita ou desabilita o Pecs. Essa rotina só pode ser acionada uma
vez por sessão.
♦ Procedure Pecs.Disable_Class(Class_Id[, Event_Id ou Event_Type]) – Desabilita um ou todos os eventos de uma classe.
♦ Procedure Pecs.Enable_Class(Class_Id[, Event_Id ou Event_Type]) – Habilita um ou todos os eventos de uma classe.
♦ Procedure Pecs.End_Event(Event_Id, Handle) – Determina o fim de um evento Pecs.
♦ Procedure Pecs.Point_Event(Event_Id, Comment) – Determina se um evento foi ocorrido durante a execução do código.
♦ Função Pecs.Start_Event([Event_Id,] Comment) – Marca o início de um evento Pecs. Retorna um identificador único
para esta ocorrência do evento, que é necessário para o encerramento do evento.
WEB
DESCRIÇÃO DO PACOTE
Este pacote, composto por uma única rotina, tem a finalidade de definir a URL do documento a ser carregado em
aplicações Web.
ROTINAS DO PACOTE
♦ Procedure Web.Show_Document(Url, Target) – Especifica a URL e janela de destino de uma aplicação Web.
ORA_FFI
DESCRIÇÃO DO PACOTE
Este pacote provê uma interface de uso de funções C (terceira geração) diretamente dentro do PL/SQL.
No ambiente Windows, as funções externas devem ser DLLs que, depois de registradas via funções ORA_FFI,
podem ser usadas em uma aplicação Forms.
Para utilização de uma DLL em uma aplicação Forms, devemos:
♦ Usar a função Load_Library para obter um handle da DLL, ou seja, uma identificação física (nome de diretório,
nome do arquivo, etc.).
♦ Usar a função Register_Function para obter um handle da função, ou seja, uma identificação no ambiente da
função (C) a ser usada. Devem-se especificar o nome da função e sua localização (o handle da DLL).
♦ Usar a função Register_Parameter para registrar cada parâmetro e estabelecer a paridade com os tipos de parâmetro
da PL/SQL.
♦ Usar a função Register_Return para registrar o tipo de retorno da função C e estabelecer a paridade com o
equivalente PL/SQL.
ROTINAS DO PACOTE
♦ Função Ora_Ffi.Find_Function(Libname, Funcname) – Localiza e retorna o function handle para a função
especificada. A função deve ter sido previamente registrada.
♦ Função Ora_Ffi.Find_Library(Libname) – Localiza e retorna o handle para a library especificada. A library deve
ter sido registrada previamente.
♦ Procedure Ora_Ffi.Generate_Foreign(Handle[, Pkgname]) – Gera um pacote de código de PL/SQL para todas as
funções definidas na biblioteca especificada. Deve-se inicialmente carregar a biblioteca, registrar todas as funções
que desejarmos acionar e registrar seus parâmetros e retornos.
♦ Função Ora_Ffi.Is_Null_Ptr(Handle) – Determina se uma biblioteca, função ou pointer (ponteiro do C) é Null.
♦ Função Ora_Ffi.Load_Library(Dirname, Libname) – Carrega a DLL especificada para que suas funções possam
ser registradas.
♦ Função Ora_Ffi.Register_Function(Libhandle, Funcname[, Callstd]) – Registra a função especificada.
♦ Função Ora_Ffi.Register_Library(Dirname, Libname) – Registra a biblioteca especificada.
♦ Procedure Ora_Ffi.Register_Parameter(Funchandle, Cargtype[, Plsargtype]) – Registra o tipo do argumento corrente
da função especificada.
♦ Procedure Ora_Ffi.Register_Return(Funchandle, Creturntype[, Plsreturntype]) – Registra o tipo de retorno da
função especificada.
♦ Procedure Ora_Ffi.Unload_Library(Libhandle) – Descarrega da memória a DLL especificada. As funções dessa
DLL não estarão mais acessíveis até que a biblioteca seja carregada novamente.
ORA_PROF
DESCRIÇÃO DO PACOTE
Este pacote contém procedimentos, funções e condições de erro que nos permitirão verificar o tempo de execução
de uma determinada unidade de programa.
ROTINAS DO PACOTE
♦ Procedure Ora_Prof.Create_Timer(Timer) – Aloca um contador de tempo com o nome especificado.
♦ Procedure Ora_Prof.Destroy_Timer(Timer) – Destrói o contador de tempo especificado.
♦ Função Ora_Prof.Elapsed_Time(Timer) – Retorna a quantidade de tempo acumulada desde a última chamada à
procedure Ora_Prof.Reset_Timer.
♦ Procedure Ora_Prof.Reset_Timer(Timer) – Zera o contador de tempo especificado.
♦ Procedure Ora_Prof.Start_Timer(Timer) – Determina o início da contagem de tempo.
♦ Procedure Ora_Prof.Stop_Timer(Timer) – Determina a interrupção da contagem de tempo sem zerar o contador.
ORA_NLS
DESCRIÇÃO DO PACOTE
Este pacote permite que obtenhamos informações sobre o ambiente corrente.
ROTINAS DO PACOTE
♦ Função Ora_Nls.American – Retorna um booleano indicando se o charset corrente é “American”.
♦ Função Ora_Nls.American_Date – Retorna um booleano indicando se o formato de data corrente é “American”.
♦ Função Ora_Nls.Get_Lang_Scalar(Attribute) – Retorna a informação requisitada sobre a linguagem corrente.
♦ Função Ora_Nls.Get_Lang_Str(Attribute) – Retorna a informação requisitada sobre a linguagem corrente.
♦ Função Ora_Nls.Linguistic_Collate – Retorna um booleano se os caracteres no charset corrente necessitam ser
organizados de acordo com informações especiais da linguagem.
♦ Função Ora_Nls.Linguistic_Specials – Retorna um booleano indicando se existem características lingüísticas em uso.
♦ Função Ora_Nls.Modified_Date_Fmt – Retorna um booleano que indica se o formato de data foi modificado.
♦ Função Ora_Nls.Right_To_Left – Retorna um booleano que indica se a direção de impressão da linguagem
corrente é “right-to-left”.
♦ Função Ora_Nls.Simple_Cs – Retorna um booleano indicando se o charset corrente é simples, ou seja, single-
byte, sem caracteres especiais, etc.
♦ Função Ora_Nls.Single_Byte – Retorna um booleano que indica se todos os caracteres no charset corrente podem
ser representados em um byte.
TOOL_RES
DESCRIÇÃO DO PACOTE
Este pacote fornece um mecanismo para extrairmos informações de um arquivo de recursos. Os arquivos de recursos
são providos pelas ferramentas (Form Builder, Report Builder, etc.) e contêm informações diversas utilizadas pelos
software. Podemos gerar nossos próprios arquivos de recursos com o utilitário ResPa21 a partir de um texto com
extensão PRN. Esse utilitário é fornecido juntamente com o Oracle*Terminal.
ROTINAS DO PACOTE
♦ Procedure Tool_Res.Rfclose(Filehandle) – Fecha o arquivo de recursos especificado.
♦ Função Tool_Res.Rfopen(Spec) – Abre o arquivo especificado como um arquivo de recursos.
♦ Função Tool_Res.Rfread([File,] Resid, Restype) – Lê o recurso especificado. Se o arquivo for fornecido, a pesquisa é
realizada apenas neste arquivo. Se o arquivo for omitido, a pesquisa é feita em todos os arquivos de recursos especificados.
TOOL_ENV
DESCRIÇÃO DO PACOTE
Permite que obtenhamos informações das variáveis de ambiente do Oracle.
ROTINAS DO PACOTE
♦ Procedure Tool_Env.Getvar(Varname, Varvalue) – Obtém o valor de uma variável de ambiente.
TOOL_ERR
DESCRIÇÃO DO PACOTE
O pacote Tool_err fornece um conjunto de informações a respeito do erro acontecido em uma área chamada “Error
Stack”. Essa área contém códigos e mensagens de erro organizadas em uma área indexada de 0 a n-1 (onde n é o
número de erros). Esse pacote permitirá a manipulação dessa área de stack.
ROTINAS DO PACOTE
♦ Procedure Tool_Err.Clear – Descarta todos os erros presentes no error stack.
♦ Função Tool_Err.Code(n) – Retorna o código do erro para o n-ésimo erro no error stack.
♦ Função Tool_Err.Encode(Prefix, Offset) – Constrói um código de erro a partir de um prefixo e um offset.
♦ Função Tool_Err.Message(n) – Retorna a mensagem formatada associada com o n-ésimo erro do error stack.
♦ Function Tool_Err.Nerrors – Retorna o número de erros presentes no error stack.
♦ Procedure Tool_Err.Pop – Descarta o erro do topo da lista de erros no error stack.
DDE
DESCRIÇÃO DO PACOTE
Este pacote permite o suporte a Dynamic Data Exchange (DDE) dentro dos componentes do Developer.
DDE é um mecanismo pelo qual aplicações podem se comunicar e trocar dados em um ambiente Windows.
As funções DDE habilitadas para as aplicações Oracle (Client) se comunicarem com outras aplicações do ambiente
Windows compatíveis com DDE (Server) compreendem três ações:
♦ Importação de dados.
♦ Exportação de dados.
♦ Execução de comandos para o servidor DDE (a outra aplicação).
ROTINAS DO PACOTE
♦ Função Dde.App_Begin(Appname, Appmode) – Inicia um programa e retorna um identificador.
♦ Procedure Dde.App_End(Appid) – Encerra um programa previamente iniciado.
♦ Procedure Dde.App_Focus(Appid) – Ativa um programa previamente iniciado.
♦ Procedure Dde.Execute(Convid, Cmdstr, Timeout) – Executa uma string de comando que é aceitável para o
programa iniciado anteriormente.
♦ Função Dde.Getformatnum(Dataformatname) – Converte ou registra um nome de formato de dado e retorna a
representação numérica da string do formato do dado.
♦ Função Dde.Getformatstr(Dataformatnum) – Converte um formato de dado numérico no nome do formato
correspondente.
♦ Função Dde.Initiate(Service, Topic) – Abre uma conversação DDE com uma aplicação servidora.
♦ Função Dde.Issupported – Retorna um booleano indicando se o pacote DDE é suportado na plataforma corrente.
♦ Procedure Dde.Poke(Convid, Item, Data, Dataformat, Timeout) – Envia o dado para a aplicação servidora.
♦ Procedure Dde.Request(Convid, Item, Buffer, Dataformat, Timeout) – Requisita dados de uma aplicação servidora.
♦ Dde.Terminate(Convid) – Encerra a conversação com a aplicação servidora especificada.
ORA_JAVA
DESCRIÇÃO DO PACOTE
Este pacote, juntamente com o pacote JNI, foi incluído na versão 6i, porém a documentação das rotinas não foi
disponibilizada. Por este motivo, apenas listaremos as rotinas pertencentes ao pacote, sem definição das mesmas.
ROTINAS DO PACOTE
♦ Procedure Ora_Java.clear_exception;
♦ Procedure Ora_Java.clear_error;
JNI
DESCRIÇÃO DO PACOTE
Este pacote juntamente com o pacote ORA_JAVA, foi incluído na versão 6i, porém a documentação das rotinas não
foi disponibilizada. Por este motivo, apenas listaremos as rotinas pertencentes ao pacote, sem definição das mesmas.
ROTINAS DO PACOTE
♦ Procedure Jni.add_boolean_arg (args in jni.arglist, value in boolean);
♦ Procedure Jni.add_byte_arg (args in jni.arglist, value in pls_integer);
♦ Procedure Jni.add_char_arg (args in jni.arglist, value in pls_integer);
♦ Procedure Jni.add_double_arg (args in jni.arglist, value in number);
♦ Procedure Jni.add_float_arg (args in jni.arglist, value in number);
♦ Procedure Jni.add_int_arg (args in jni.arglist, value in number);
♦ Procedure Jni.add_long_arg (args in jni.arglist, value in number);
♦ Procedure Jni.add_object_arg (args in jni.arglist, value in ora_java.jobject, cls in ora_java.jclass);
♦ Procedure Jni.add_short_arg (args in jni.arglist, value in pls_integer);
♦ Procedure Jni.add_short_arg (args in jni.arglist, value in pls_integer);
♦ Procedure Jni.add_string_arg (args in jni.arglist, value in varchar2);
♦ Function Jni.call_boolean_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return boolean;
♦ Function Jni.call_boolean_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return boolean;
♦ Function Jni.call_byte_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return
pls_integer;
♦ Function Jni.call_char_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return
pls_integer;
♦ Function Jni.call_double_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return
number;
♦ Function Jni.call_float_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return number;
♦ Function Jni.call_int_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return number;
♦ Function Jni.call_long_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return number;
♦ Function Jni.call_object_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return
ora_java.jobject;
♦ Function Jni.call_short_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist) return
pls_integer;
♦ Procedure Jni.call_void_method (obj in ora_java.jobject, mid in ora_java.jmethod, args in jni.arglist);
♦ Function Jni.create_arg_list (num in pls_integer) return jni.arglist;
♦ Procedure Jni.destroy_arg_list (args in jni.arglist);
♦ Function Jni.get_boolean_field (obj in ora_java.jobject, fid in ora_java.jfield) return boolean;
♦ Function Jni.get_byte_field (obj in ora_java.jobject, fid in ora_java.jfield) return pls_integer;
FTREE
DESCRIÇÃO DO PACOTE
Possui um conjunto de rotinas capazes de permitir a manipulação de itens do tipo árvore hierárquica.
ROTINAS DO PACOTE
♦ Procedure Ftree.Add_Tree_Data (item_id ou item_name, node , offset_type, offset, data_source, data) – Adiciona
um conjunto de dados associados a um determinado nó de uma árvore hierárquica existente. Os dados podem ser
obtidos através de uma string(Select) ou de um Record Group (o texto da string ou o nome do Record Group
devem ser preenchidos no parâmetro Data), de acordo com o que tiver sido preenchido no parâmetro data_source
(Ftree.Record_Group ou Ftree.Query_Text). De acordo com o parâmetro offset_type, os dados serão inseridos sob
o nó atual (offset_type = Ftree.Parent_Offset) ou no mesmo nível do nó atual (offset_type = Ftree.Sibling_Offset).
O parâmetro offset determina o posicionamento dos dados no nó e pode receber os valores Ftree.Next_Node e
Ftree.Previous_Node (quando offset_type é igual a Sibling) ou um valor numérico (de 1 a N) e, ainda, Ftree.Last_Child
(quando offset_type é igual a Parent).
♦ Function Ftree.Add_Tree_Node (Item_Name ou Item_Id, Node , Offset_Type, Offset, State, Label, Icon, Value) –
Adiciona um novo nó à arvore hierárquica. O posicionamento do nó é dado em função de um outro nó existente
na árvore. De acordo com o parâmetro offset_type, o novo nó será inserido sob o nó atual (offset_type =
Ftree.Parent_Offset) ou no mesmo nível do nó atual (offset_type = Ftree.Sibling_Offset). O parâmetro offset determina
o posicionamento do novo nó em relação ao nó atual e pode receber os valores Ftree.Next_Node e
Ftree.Previous_Node (quando offset_type é igual a Sibling) ou um valor numérico (de 1 a N) e, ainda, Ftree.Last_Child
(quando offset_type é igual a Parent). Os parâmetros State (indica o estado do nó que poderá ser: 1 – expandido,
-1 – contraído, 0 – não tem filhos), Label (texto visualizado pelo usuário), Icon (nome de um arquivo do tipo Ico
a ser mostrado no nó) e Value (valor do nó) correspondem às informações associadas ao novo nó.
♦ Procedure Ftree.Delete_Tree_Node (Item_Name ou Item_Id, Node) – Remove um nó da árvore hierárquica.
♦ Função Ftree.Find_Tree_Node (Item_Name ou Item_Id, Search_String, Search_Type, Search_By, Search_Root,
Start_Point) – Faz uma pesquisa em uma árvore hierárquica e retorna o nó correspondente ao elemento encontrado.
♦ Função Ftree.Get_Tree_Node_Parent (Item_Name ou Item_Id, Node) – Retorna o nó-pai do nó passado como parâmetro.
♦ Função Ftree.Get_Tree_Node_Property (Item_Name ou Item_Id, Node, Property) – Retorna o valor da propriedade
solicitada como parâmetro relativamente ao nó informado.
♦ Função Ftree.Get_Tree_Property (Item_Name ou Item_Id, Property) – Retorna o valor da propriedade solicitada
em relação à árvore hierárquica.
♦ Função Ftree.Get_Tree_Selection (Item_name ou Item_Id, Selection) – Esta rotina retorna a identificação do nó
selecionado pelo usuário. O parâmetro Selection indica de qual dos elementos selecionados (pode ser mais de
um) desejamos obter o nó.
♦ Função Ftree.Id_Null (Node) – Retorna True ou False indicando se o nó informado é Null.
♦ Procedure Ftree.Populate_Group_From_Tree (Group_Name, Item_Name ou Item_Id, Node) – Copia todos os
dados presentes na árvore hierárquica a partir do nó especificado como parâmetro (será o nó-pai) para o Record
Group informado.
♦ Procedure Ftree.Populate_Tree (Item_Name Ou Item_Id) – Preenche uma árvore hierárquica baseado nos
parâmetros Grupo de Registros (Record Group) ou Texto da Consulta (Query Text), de acordo com o que estiver
preenchido. Toda a árvore é inicializada primeiramente.
♦ Procedure Ftree.Set_Tree_Node_Property (Item_Name ou Item_Id, Node, Property, Value) – Atribui um valor
para a propriedade especificada relativamente ao nó passado como parâmetro.
♦ Procedure Ftree.Set_Tree_Property (Item_Name ou Item_Id, Property, Value) – Atribui um valor para a propriedade
especificada relativamente à árvore hierárquica como um todo.
♦ Procedure Ftree.Set_Tree_Selection (Item_Name ou Item_Id, Node, Selection_Type) – Navega na árvore hierárquica
selecionando o nó que informarmos como parâmetro.
EXEC_SQL
DESCRIÇÃO DO PACOTE
Este pacote, além de permitir o acesso a vários servidores Oracle em diferentes conexões, simultaneamente, contém
rotinas que nos permitirão a construção de SQL dinâmico em PL/SQL (similar ao pacote DBMS_SQL do banco de
dados, porém com algumas restrições).
Para maiores detalhes na utilização deste pacote, utilize-se da Ajuda do Form Builder.
ROTINAS DO PACOTE
♦ Procedure Exec_sql.bind_variable ([connid, ] curs_id, name, value [, out_value_size]) – Associa um valor a uma
variável Bind (referenciada com :) nomeada no comando SQL. O último parâmetro (out_value_size) deve ser
informado se o tipo da variável for Varchar2 (determina o tamanho máximo esperado).
♦ Procedure Exec_sql.close_connection [(connid )] – Libera qualquer recurso usado pela conexão e o invalida.
♦ Procedure Exec_sql.close_cursor ([connid, ] curs_id in out curstype) – Fecha o cursor especificado e libera a
memória associada a ele.
♦ Procedure Exec_sql.column_value ( [connid, ] curs_id, position, value, [column_error,] actual_length) – Esta
procedure retorna o valor do cursor relativamente à posição informada. É usada para a obtenção dos dados após
o uso da rotina Fetch_Rows.
♦ Função Exec_sql.curr_connection – Retorna um handle (Exec_Sql.ConnType) que use a mesma conexão ao
banco de dados originalmente estabelecida pelo Oracle Developer (use Default Connection, pois esta função é
semelhante à outra e será desimplementada no futuro).
♦ Função Exec_sql.default_connection – Retorna um handle (Exec_Sql.ConnType) que use a mesma conexão ao banco
de dados originalmente estabelecida pelo Oracle Developer. Na primeira vez que essa função é acionada, a conexão
default é encontrada e colocada na memória dentro do pacote Exec_Sql. Subseqüentes chamadas a esse pacote
simplesmente recuperam o handle da área de memória.
♦ Procedure Exec_sql.define_column ([connid, ] curs_id , position , column [, Column_Size]) – Usada somente com
comandos Select ou chamadas a non-Oracle Stored Procedures que retornem um conjunto de dados. Ela define uma
coluna a ser obtida (fetched) do cursor especificado. A coluna é identificada por sua posição relativa (a primeira coluna
é identificada pelo inteiro 1). O tipo do parâmetro Column determina o tipo da coluna que está sendo definida.
♦ Procedure Exec_sql.describe_column ([connid, ] curs_id , position, name, collen, type) – Obtém informações sobre
as colunas no conjunto de dados resultado de comando SQL Parsed. Os três últimos parâmetros são do tipo Out.
♦ Função Exec_sql.execute ([connid, ] curs_id) – Executa o comando SQL especificado pelo cursor. Retorna o
número de linhas processadas.
♦ Função Exec_sql.execute_and_fetch ([Connid, ] curs_id, exact) – Esta função faz uma chamada à função
Exec_Sql.Execute e, em seguida, à função Exec_Sql.Fetch_Rows. Ela executa o comando SQL especificado pelo
cursor (Select) e recupera a primeira linha que satisfaça a query.
♦ Função Exec_sql.fetch_rows ([Connid, ] curs_id) – Recupera uma linha da query especificada pelo cursor. Retorna
o número da linha atualmente lida.
♦ Função Exec_sql.is_connected [ (Connid) ] – Retorna True se a conexão especificada está conectada à origem dos
dados (banco de dados Oracle ou não).
♦ Função Exec_sql.is_oca_connection [ (Connid) ] – Retorna True se a conexão especificada é uma conexão OCA.
♦ Função Exec_sql.is_open ([Connid, ] curs_id in curstype) – Retorna True se o cursor especificado estiver aberto
na conexão informada.
♦ Função Exec_sql.last_error_code [ (Connid) ] – Retorna o último código de erro Oracle adquirido em uma conexão.
♦ Função Exec_sql.last_error_mesg [ (Connid) ] – Retorna o texto da mensagem referente ao último código de erro
adquirido na conexão.
♦ Função Exec_sql.last_error_position [ (Connid) ] – Retorna a posição (offset) dentro do comando SQL onde o
erro ocorreu. O primeiro caracter do texto é considerado na posição zero.
♦ Função Exec_sql.last_row_count [ (Connid) ] – Retorna o número acumulado de linhas já lidas.
♦ Função Exec_sql.last_sql_function_code [ (Connid) ] – Retorna o último código de função SQL indicando o tipo
de comando SQL. Deve ser usado após o Parse.
♦ Função Exec_sql.more_result_sets ([Connid, ] curs_id) – Esta função só é aplicável a dados não-Oracle. Indica se
existe outro conjunto a ser recuperado para o cursor especificado.
♦ Função Exec_sql.open_connection (username, password, datasource) – Retorna um handle para a conexão
(Exec_Sql.ConnType). Essa função estabelece uma conexão com o banco de dados para execução das ações. O
parâmetro DataSource pode ser preenchido com a string do SQL*Net ou com uma string começando com
ODBC: para uma conexão OCA.
♦ Função Exec_sql.open_cursor [(Connid)] – Cria um novo cursor em uma conexão específica e retorna um handle
para este cursor (Exec_Sql.CursType). Se a conexão não for especificada, o Oracle Developer obterá a conexão
default da área de memória interna do pacote (veja Exec_Sql.Default_Connection).
♦ Procedure Exec_sql.parse ([ connid, ] curs_id, statement [, Language]) – Faz o Parse do comando que desejamos
executar. A operação de Parse faz validação sintática, definição de caminho de acesso e associa o comando com
o cursor no código aplicativo. O parâmetro Language pode ser preenchido com Exec_Sql.V6, Exec_Sql.V7 ou
Exec_Sql.Native (default). Se o comando informado for de DDL e a conexão estabelecida for um banco de dados
Oracle, a execução é imediata.
♦ Procedure Exec_sql.variable_value ([connid, ] curs_id, name, value) – Recupera o valor de output de uma variável
Bind associada ao cursor especificado. Ela também retorna os valores de variáveis bind em blocos de PL/SQL
anônimos. O parâmetro Value é de saída.
Capítulo 16
TRIGGERS DO FORMS
Neste capítulo, apresentaremos os triggers presentes na ferramenta Form 6i, classificados de acordo com a
funcionalidade e com o prefixo.
CLASSIFICAÇÃO FUNCIONAL
ACTIVEX (ACTIVEX)
Os triggers deste grupo estão associados a objetos do tipo ActiveX.
ON-DISPATCH-EVENT
Este trigger é chamado quando o evento de um controle ActiveX ocorre. Podemos acionar a rotina Dispatch_Event
de dentro deste trigger.
WHEN-CLEAR-BLOCK
Este gatilho será acionado quando o Form Runtime limpa o bloco corrente e esvazia a área de buffer.
WHEN-CREATE-RECORD
Este gatilho será acionado quando o Form Runtime cria um novo registro em um bloco.
WHEN-DATABASE-RECORD
Este gatilho será acionado quando o Forms modifica o estado de um determinado registro, passando de New para
Insert ou de Query para Update. Com esta modificação, esse registro passa a ser considerado como pendente de
atualização, ou seja, deve ser enviado para o banco de dados.
WHEN-REMOVE-RECORD
Este gatilho será acionado quando um determinado registro é limpo ou removido.
WHEN-BUTTON-PRESSED
Inicia uma ação quando um operador seleciona (pressiona) um botão, seja com o mouse ou com o teclado. Esse
evento não é causado por programação.
WHEN-CHECKBOX-CHANGED
Inicia uma ação quando o operador troca o estado de um item do tipo caixa de verificação (Check Box). Esse
evento pode ser causado por mouse, teclado ou programação.
WHEN-CUSTOM-ITEM-EVENT
Inicia uma ação quando houver sido causado qualquer evento associado a um controle VBX, ActiveX ou JavaBean.
WHEN-FORM-NAVIGATE
Disparado quando a navegação entre Forms ocorrer. Por exemplo, quando o usuário muda o foco para uma janela
de outro Form carregado.
WHEN-IMAGE-ACTIVATED
Inicia uma ação quando o operador realiza um clique duplo em um item do tipo imagem.
WHEN-IMAGE-PRESSED
Inicia uma ação quando o operador realiza um clique simples em um item do tipo imagem.
WHEN-LIST-ACTIVATED
Inicia uma ação quando um operador efetua um clique duplo em uma lista do tipo T-List.
WHEN-LIST-CHANGED
Inicia uma ação quando um operador modifica o valor do item, selecionando outro elemento da lista. Quando a lista
é do tipo Combo, esse evento também é causado quando o operador esvazia ou digita um novo valor para o item.
WHEN-MOUSE-CLICK
Este gatilho é acionado quando o operador faz um clique em qualquer item do módulo ou em qualquer canvas se
o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de bloco ou de item, somente se o clique for
dado no item específico ou em um dos itens do bloco específico. Quando um usuário faz um clique com o mouse,
os seguintes eventos são causados: Mouse Down, Mouse Up e Mouse Click, nesta ordem. Quaisquer triggers
associados com estes eventos serão disparados antes do trigger When-Mouse-Click disparar.
WHEN-MOUSE-DOUBLECLICK
Este gatilho é acionado quando o operador faz um clique duplo em qualquer item do módulo ou em qualquer
canvas se o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de bloco ou de item, somente se o
clique duplo for dado no item específico ou em um dos itens do bloco específico. Quando um usuário faz um
clique duplo com o mouse, os seguintes eventos são causados: Mouse Down, Mouse Up, Mouse Click, Mouse
Down, Mouse Up e Mouse DoubleClick nesta ordem.
WHEN-MOUSE-DOWN
Este gatilho é acionado quando o operador faz um clique em qualquer item do módulo ou em qualquer canvas se
o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de bloco ou de item, somente se o clique for
dado no item específico ou em um dos itens do bloco específico.
WHEN-MOUSE-ENTER
Este gatilho é acionado quando o operador move o mouse (sem pressioná-lo), entrando em qualquer item do
módulo ou em qualquer canvas se o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de bloco
ou de item, somente se o operador mover o mouse (entrando) em um item específico ou em um dos itens do
bloco específico.
WHEN-MOUSE-LEAVE
Este gatilho é acionado quando o operador move o mouse (sem pressioná-lo), saindo de qualquer item do módulo
ou de qualquer canvas se o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de bloco ou de item,
somente se o operador mover o mouse (saindo) de um item específico ou de um dos itens do bloco específico.
WHEN-MOUSE-MOVE
Este gatilho é acionado quando o operador move o mouse (sem pressioná-lo) em qualquer item do módulo ou em
qualquer canvas se o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de bloco ou de item,
somente se o operador mover o mouse em um item específico ou em um dos itens do bloco específico.
WHEN-MOUSE-UP
Este gatilho é acionado quando o operador solta o botão do mouse após um clique em qualquer item do módulo
ou em qualquer canvas se o gatilho estiver em nível de módulo. Se o gatilho estiver em nível de bloco ou de item,
somente se o operador soltar o botão do mouse no item específico ou em um dos itens do bloco específico.
WHEN-RADIO-CHANGED
Inicia uma ação quando o operador altera o botão selecionado em um grupo de rádios (radio group).
WHEN-TAB-PAGE-CHANGED
Inicia uma ação quando o operador modifica a página ativa de uma canvas Tab. O evento só é causado se a mudança
de página for explícita. Uma navegação entre itens em páginas diferentes não causa o evento.
WHEN-TIMER-EXPIRED
Inicia uma ação quando o tempo programado expira. Único para todos os timers criados.
WHEN-TREE-NODE-ACTIVATED
Este trigger é acionado quando o operador efetua um clique duplo sobre um nó ou pressiona Enter com um nó
selecionado.
WHEN-TREE-NODE-EXPANDED
Este trigger é disparado quando um nó é expandido ou contraído.
WHEN-TREE-NODE-SELECTED
Este trigger é disparado quando um nó é selecionado ou liberado.
WHEN-WINDOW-ACTIVATED
Inicia uma ação quando uma janela é ativada.
WHEN-WINDOW-CLOSED
Inicia uma ação quando uma janela é fechada.
WHEN-WINDOW-DEACTIVATED
Inicia uma ação quando uma janela é desativada em função de outra janela ter se tornado ativa.
WHEN-WINDOW-RESIZED
Inicia uma ação quando uma janela muda de tamanho.
KEY-CLRBLK
Acionado quando o usuário pressionar Limpar Bloco (Clear Block).
KEY-CLRFRM
Acionado quando o usuário pressionar Limpar Forms (Clear Form).
Rotina para assegurar a funcionalidade default: Clear_Form.
KEY-CLRREC
Acionado quando o usuário pressionar Limpar Registro (Clear Record).
Rotina para assegurar a funcionalidade default: Clear_Record.
KEY-COMMIT
Acionado quando o usuário pressionar Salvar (Save) ou Aceitar (Accept).
KEY-CQUERY
Acionado quando o usuário pressionar Contar Registros Coincidentes (Count Query Hits).
Rotina para assegurar a funcionalidade default: Count_Query.
KEY-CREREC
Acionado quando o usuário pressionar Incluir Registro (Insert Record).
Rotina para assegurar a funcionalidade default: Create_Record.
KEY-DELREC
Acionado quando o usuário pressionar Remover Registro (Delete Record).
KEY-DOWN
Acionado quando o usuário pressionar Navegar para Baixo (Down).
Rotina para assegurar a funcionalidade default: Down.
KEY-DUP-ITEM
Acionado quando o usuário pressionar Duplicar Item (Duplicate Item).
Rotina para assegurar a funcionalidade default: Duplicate_Item.
KEY-DUPREC
Acionado quando o usuário pressionar Duplicar Registro (Duplicate Record).
Rotina para assegurar a funcionalidade default: Duplicate_Record.
KEY-EDIT
Acionado quando o usuário pressionar Editar (Edit).
KEY-ENTQRY
Acionado quando o usuário pressionar Entrar Consulta (Enter Query).
Rotina para assegurar a funcionalidade default: Enter_Query.
KEY-EXEQRY
Acionado quando o usuário pressionar Executar Consulta (Execute Query).
Rotina para assegurar a funcionalidade default: Execute_Query.
KEY-EXIT
Acionado quando o usuário pressionar Sair (Exit).
KEY-HELP
Acionado quando o usuário pressionar Ajuda (Help).
Rotina para assegurar a funcionalidade default: Help.
KEY-LISTVAL
Acionado quando o usuário pressionar Lov (List of Values).
Rotina para assegurar a funcionalidade default: List_Values.
KEY-MENU
Acionado quando o usuário pressionar Menu de Blocos (Block Menu).
KEY-NXTBLK
Acionado quando o usuário pressionar Próximo Bloco (Next Block).
Rotina para assegurar a funcionalidade default: Next_Block.
KEY-NEXT-ITEM
Acionado quando o usuário pressionar Próximo Item (Next Item).
KEY-NXTKEY
Acionado quando o usuário pressionar Próxima PK (Next Primary Key).
Rotina para assegurar a funcionalidade default: Next_Key.
KEY-NXTREC
Acionado quando o usuário pressionar Próximo Registro (Next Record).
Rotina para assegurar a funcionalidade default: Next_Record.
KEY-NXTSET
Acionado quando o usuário pressionar Próximo Conjunto de Registros (Next Set of Records).
KEY-PRINT
Acionado quando o usuário pressionar Imprimir (Print).
Rotina para assegurar a funcionalidade default: Print.
KEY-PRVBLK
Acionado quando o usuário pressionar Bloco Anterior (Previous Block).
Rotina para assegurar a funcionalidade default: Previous_Block.
KEY-PREV-ITEM
Acionado quando o usuário pressionar Item Anterior (Previous Item).
Rotina para assegurar a funcionalidade default: Previous_Item.
KEY-PRVREC
Acionado quando o usuário pressionar Registro Anterior (Previous Record).
KEY-SCRDOWN
Acionado quando o usuário pressionar Rolar a Tela Para Baixo (Scroll Down).
KEY-SCRUP
Acionado quando o usuário pressionar Rolar a Tela Para Cima (Scroll Up).
Rotina para assegurar a funcionalidade default: Scroll_Up.
KEY-UP
Acionado quando o usuário pressionar Navegar Para Cima (Up).
Rotina para assegurar a funcionalidade default: Up.
KEY-UPDREC
Acionado quando o usuário pressionar Bloquear Registro (Lock Record).
Rotina para assegurar a funcionalidade default: Lock_Record.
KEY-F0 A F9 E KEY-ENTER
Acionado quando o usuário pressionar as teclas correspondentes, mapeadas pelo Oracle Terminal (não
necessariamente F0 a F9 ou <enter>).
KEY-OTHERS
Acionado quando for teclada qualquer ação não prevista na aplicação.
MESTRE-DETALHE (MASTER-DETAIL)
ON-CHECK-DELETE-MASTER
Este trigger é disparado quando for feita uma tentativa de remoção de um registro presente no bloco Master de
uma relação Master-Detail.
O Form Builder gera este gatilho (trigger) automaticamente na aplicação quando criamos um objeto Relação (relation).
ON-CLEAR-DETAILS
Este trigger é disparado quando, por algum motivo, ocorrer uma navegação entre registros no bloco Master de uma
relação Master-Detail, causando a necessidade de se efetuar uma limpeza nos registros detalhes.
O Form Builder gera este gatilho (trigger) automaticamente na aplicação quando criamos um objeto Relação (relation).
ON-POPULATE-DETAILS
Este trigger é disparado quando, por algum motivo, ocorre a necessidade de se preencher os dados de um bloco que
é o detalhe de uma relação Master-Detail.
O Form Builder gera este gatilho (trigger) automaticamente na aplicação quando criamos um objeto Relação (relation).
ON-ERROR
Este evento é acionado quando o Forms recebe um erro. Podemos incluí-lo na aplicação se desejarmos substituir a
mensagem de erro padrão do Forms por uma mensagem de erro customizada.
Para assegurar a funcionalidade default, devemos usar as rotinas Error_Code, Error_Text e Error_Type.
ON-MESSAGE
Este evento é acionado quando o Forms recebe um aviso. Podemos incluí-lo na aplicação se desejarmos substituir
a mensagem de aviso padrão do Forms por uma mensagem de erro customizada.
Para assegurar a funcionalidade default, devemos usar as rotinas Message_Code, Message_Text e Message_Type.
NAVEGAÇÃO (NAVIGATIONAL)
Os eventos classificados neste grupo estão associados à navegação, ou seja, o momento em que o foco muda de um
item para outro. Essa mudança pode ocorrer entre itens de um mesmo registro, de registros diferentes, de blocos
diferentes e, ainda, para fora da aplicação ou na entrada de uma aplicação. De acordo com o tipo de navegação, um
conjunto particular de eventos é causado. Quem causa esse tipo de evento pode ser o usuário ao mudar de item ou
a programação ao comandar a mudança.
POST-BLOCK
Inicia uma ação quando o foco se move para fora do bloco corrente.
POST-FORM
Inicia uma ação antes de o Forms navegar para fora do módulo.
POST-RECORD
Inicia uma ação quando o foco deixa o registro corrente.
POST-TEXT-ITEM
Inicia uma ação quando o foco deixa o item corrente.
PRE-BLOCK
Inicia uma ação quando o foco se move para um bloco.
PRE-FORM
Inicia uma ação imediatamente antes de o Forms navegar para o módulo vindo de fora do módulo. Funciona
como um Startup.
PRE-POPUP-MENU
Este trigger é acionado quando um usuário faz com que um menu pop-up seja apresentado. As ações definidas
nesse trigger são executadas antes de o menu ser mostrado.
PRE-RECORD
Inicia uma ação quando o Forms navega para outro registro.
PRE-TEXT-ITEM
Inicia uma ação quando o Forms navega para outro item.
WHEN-NEW-BLOCK-INSTANCE
Inicia uma ação após o foco ser movido de um item em um bloco para outro item em outro bloco.
WHEN-NEW-FORM-INSTANCE
Inicia uma ação na inicialização do módulo.
WHEN-NEW-ITEM-INSTANCE
Inicia uma ação imediatamente após o foco se mover para um item diferente. Se o item estiver em um novo
registro, esse gatilho é disparado após When-New-Record-Instance.
WHEN-NEW-RECORD-INSTANCE
Inicia uma ação após o foco se mover para um novo registro. Se o novo registro estiver também em um novo bloco, este
gatilho é acionado após When-New-Block-Instance, mas antes do When-New-Item-Instance.
CONSULTA (QUERY-TIME)
Os eventos classificados neste grupo estão associados ao momento da consulta ao banco de dados, ou seja, quando o
Forms monta a query que efetivamente será enviada para o banco de dados e quando ele faz a leitura de cada uma das
linhas selecionadas. Nesses dois momentos, poderemos incluir ações em adição àquelas já estabelecidas por ele.
POST-QUERY
Este gatilho é acionado a cada linha lida do banco de dados. Isto permitirá que façamos modificações no registro
lido, completemos dados, cálculos, leitura de informações, etc.
PRE-QUERY
Este gatilho é acionado imediatamente antes de o Forms preparar o comando Select a ser enviado para o banco de
dados. Isso permitirá que façamos uma intervenção neste processo e modifiquemos por programação as condições
da consulta a ser realizada.
QUERY-PROCEDURE
Este trigger é acionado quando uma operação de consulta é requisitada.
INSERT-PROCEDURE
Este trigger é acionado quando uma operação de inclusão é requisitada.
Não deve ser alterado pelo usuário.
DELETE-PROCEDURE
Este trigger é acionado quando uma operação de exclusão é requisitada.
Não deve ser alterado pelo usuário.
LOCK-PROCEDURE
Este trigger é acionado quando uma operação de bloqueio (lock) é requisitada.
Não deve ser alterado pelo usuário.
UPDATE-PROCEDURE
Este trigger é acionado quando uma operação de atualização é requisitada.
TRANSACIONAL (TRANSACTIONAL)
Este grupo de eventos encontra-se ligado ao momento em que o Forms realiza a comunicação com o banco de
dados, seja para efetivação da transação, leitura de dados (Select), início e fim de conexão ou bloqueio (lock).
ON-CHECK-UNIQUE
Este trigger é disparado durante uma operação de Commit, quando o Form Runtime faz a verificação de unicidade
da(s) coluna(s) Primary Key, antes de montar uma operação de Insert ou Update para o banco de dados. É acionado
uma vez para cada registro que venha a ser incluído ou alterado.
ON-CLOSE
Este trigger é acionado quando o operador ou a aplicação encerram (fecham) a consulta. Por default, o Form
Runtime somente encerra a consulta quando todos os registros tiverem sido lidos, ou seja, quando o cursor interno
que está controlando a leitura receber um NotFound.
ON-COLUMN-SECURITY
Este trigger é disparado quando o Form Runtime faz a verificação do nível de segurança para as colunas dos blocos
que tenham a propriedade Enforce Column Security marcadas.
Essa ação é feita a tempo de inicialização da aplicação. Quando é encontrada uma coluna para a qual o usuário
conectado não tenha privilégio de alteração, o próprio Form Runtime utiliza a rotina Set_Item_Property para
tornar a propriedade Update Allowed desmarcada para essas colunas.
Rotina para assegurar a funcionalidade-padrão: Enforce_Column_Security.
ON-COMMIT
Este trigger é acionado quando o Form Runtime deseja enviar um Commit ao banco de dados após ter realizado
um Post para todas as linhas marcadas para inclusão, exclusão ou alteração.
Rotina para assegurar a funcionalidade-padrão: Commit_Form.
ON-COUNT
Este trigger é acionado quando o Form Runtime deseja contar o número de linhas no banco de dados que atende
ao critério estabelecido para a consulta (query).
ON-DELETE
Substitui a funcionalidade-padrão de remoção de registros. É acionado uma vez para cada registro a ser removido
do banco de dados.
ON-FETCH
Este trigger é acionado quando o Form Runtime deseja obter um conjunto de linhas resultantes de uma operação
de consulta. Para recuperação das primeiras linhas, esse trigger é acionado após o trigger On-Select.
ON-INSERT
Substitui a funcionalidade-padrão de inclusão de registros. É acionado uma vez para cada registro a ser incluído no
banco de dados.
Rotina para assegurar a funcionalidade-padrão: Insert_Record.
ON-LOCK
Este trigger é acionado quando o Form Runtime deve efetuar o bloqueio da linha corrente no banco de dados. Isso
ocorre em função de o operador iniciar uma modificação no registro corrente. O trigger é acionado entre o momento
em que o operador pressiona a tecla e o aparecimento da informação modificada.
Rotina para assegurar a funcionalidade-padrão: Lock_Record.
ON-LOGON
Este trigger é acionado quando o Form Runtime tenta efetuar uma conexão com o banco de dados.
Rotina para assegurar a funcionalidade-padrão: Logon.
ON-LOGOUT
Este trigger é acionado quando o Form Runtime tenta encerrar uma conexão com o banco de dados, e
simultaneamente, a aplicação.
Rotina para assegurar a funcionalidade-padrão: Logout.
ON-ROLLBACK
Este trigger é acionado quando o Form Runtime deseja desfazer as modificações ocorridas desde que o último
Savepoint foi marcado.
Rotina para assegurar a funcionalidade-padrão: Issue_Rollback.
ON-SAVEPOINT
Este trigger é disparado quando o Form Runtime deseja estabelecer um ponto de controle. Por default, esses pontos são
estabelecidos na inicialização do Form, e no início de cada processo transacional (Post e Commit).
Rotina para assegurar a funcionalidade-padrão: Issue_Savepoint.
ON-SELECT
Este trigger é acionado quando o Form Runtime deseja executar a operação de Select de uma Consulta. Substitui as
fases de abertura do cursor, parse e execute.
Rotina para assegurar a funcionalidade-padrão: Select_Records.
ON-SEQUENCE-NUMBER
Este trigger é acionado quando o Form Runtime deseja efetuar uma leitura no banco de dados para obter um
número de seqüência definido na propriedade Default Value de um determinado item.
Rotina para assegurar a funcionalidade-padrão: Generate_Sequence_Number.
ON-UPDATE
Substitui a funcionalidade-padrão de alteração de registros. É acionado uma vez para cada registro a ser incluído
no banco de dados.
POST-CHANGE
Este trigger foi mantido para compatibilidade com versões anteriores e seu uso não é recomendado.
POST-DATABASE-COMMIT
Adiciona uma ação ao processamento-padrão após a ação de Commit para o banco de dados. É executado uma
única vez ao término do processo transacional.
POST-DELETE
É acionado após uma determinada linha ter sido removida do banco de dados. Adiciona ações ao processamento-
padrão após o evento. É executado uma vez para cada linha removida.
POST-FORMS-COMMIT
É acionado antes da ação de Commit para o banco de dados e após a ação de Post (onde todos os comandos Insert, Update
e Delete são executados). É executado uma única vez após toda a transação ter sido enviada para o banco de dados.
POST-INSERT
É acionado após uma determinada linha ter sido incluída no banco de dados. Adiciona ações ao processamento-
padrão após o evento. É executado uma vez para cada linha incluída.
POST-LOGON
Este trigger é acionado após o Form Runtime ter estabelecido a comunicação com o banco de dados ou ter executado
o trigger On-Logon com sucesso.
POST-LOGOUT
Este trigger é acionado após o Form Runtime ter encerrado a comunicação com o banco de dados ou ter executado
o trigger On-Logout com sucesso.
POST-SELECT
Este trigger é acionado após o Form Runtime ter enviado, com sucesso, o comando de Select desejado para o banco
de dados ou após a execução bem-sucedida do trigger On-Select.
POST-UPDATE
É acionado após uma determinada linha ter sido alterada no banco de dados. Adiciona ações ao processamento-
padrão após o evento. É executado uma vez para cada linha alterada.
PRE-COMMIT
É acionado antes de o Forms iniciar o processo de Post. É executado uma única vez no início de todo o processo.
PRE-DELETE
É acionado antes de uma determinada linha ser removida do banco de dados. Adiciona ações ao processamento-
padrão antes do evento. É executado uma vez para cada linha a ser removida.
PRE-INSERT
É acionado antes de uma determinada linha ser incluída no banco de dados. Adiciona ações ao processamento-
padrão antes do evento. É executado uma vez para cada linha a ser incluída.
PRE-LOGON
Este trigger é disparado imediatamente antes de o Form Runtime iniciar um procedimento de conexão com o
banco de dados.
PRE-LOGOUT
Este trigger é disparado imediatamente antes de o Form Runtime iniciar um procedimento de desconexão com o
banco de dados.
PRE-SELECT
Este trigger é acionado após o Form Runtime ter preparado o comando Select a ser enviado para o banco de dados,
porém antes de o envio ocorrer.
O comando Select poderá ser lido se for consultada a variável de sistema System.Last_Query dentro desse trigger.
PRE-UPDATE
É acionado antes de uma determinada linha ser alterada no banco de dados. Adiciona ações ao processamento-
padrão antes do evento. É executado uma vez para cada linha a ser alterada.
VALIDAÇÃO (VALIDATION)
Os eventos classificados neste grupo estão associados ao momento de validação. O Form Runtime valida
individualmente os itens e os registros. Quando ele tem necessidade de efetuar uma validação, podemos incluir
nossas próprias regras de validação em adição (e após) àquelas estabelecidas por ele.
Existem apenas dois eventos neste grupo:
WHEN-VALIDATE-ITEM
Este evento é causado todas as vezes que o Forms percebe que um item sofreu algum tipo de modificação e precisa
ser validado novamente. Após haver modificado o valor do item, o usuário poderá tentar navegar para outro item
ou salvar o registro ou quando a programação executar uma ação de navegação ou de atualização.
Um gatilho associado a este evento é ideal quando desejamos adicionar algum tipo de validação a um determinado
item; neste caso, podemos criar esse gatilho em nível de item. Ou quando desejamos adicionar algum tipo de
validação comum a qualquer um dos itens do registro; neste caso podemos criar esse gatilho em nível de bloco.
WHEN-VALIDATE-RECORD
Este evento é causado todas as vezes que o Forms percebe que houve alguma mudança no registro e este precisa ser
validado novamente. Essa validação ocorre no momento em que o usuário tenta navegar para outro registro ou
quando ocorre o processamento-padrão do Forms (um Commit, por exemplo) e, ainda, quando causamos uma
dessas duas situações por programação.
ON-<EVENTO>
Indicam um ponto em que substituímos o processamento-padrão da ferramenta.
♦ On-Check-Delete-Master
♦ On-Check-Unique
♦ On-Clear-Details
♦ On-Close
♦ On-Column-Security
♦ On-Commit
♦ On-Count
♦ On-Delete
♦ On-Dispatch-Event
♦ On-Error
♦ On-Fetch
♦ On-Insert
♦ On-Lock
♦ On-Logon
♦ On-Logout
♦ On-Message
♦ On-Populate-Details
♦ On-Rollback
♦ On-Savepoint
♦ On-Select
♦ On-Sequence-Number
♦ On-Update
POST-<EVENTO>
Indicam um ponto imediatamente após a ocorrência de um When-<evento> ou On-<evento>. Com esses tipos de
trigger, adicionamos código ao processamento-padrão da ferramenta.
♦ Post-Block
♦ Post-Change
♦ Post-Database-Commit
♦ Post-Delete
♦ Post-Form
♦ Post-Forms-Commit
♦ Post-Insert
♦ Post-Logon
♦ Post-Logout
♦ Post-Query
♦ Post-Record
♦ Post-Select
♦ Post-Text-Item
♦ Post-Update
PRE-<EVENTO>
Indicam um ponto imediatamente antes da ocorrência de um When-<evento> ou On-<evento>. Com esses tipos
de trigger, adicionamos código ao processamento-padrão da ferramenta.
♦ Pre-Block
♦ Pre-Commit
♦ Pre-Delete
♦ Pre-Form
♦ Pre-Insert
♦ Pre-Logon
♦ Pre-Logout
♦ Pre-Query
♦ Pre-Popup-Menu
♦ Pre-Record
♦ Pre-Select
♦ Pre-Text-Item
♦ Pre-Update
WHEN-<EVENTO>
Indica um ponto em que podemos adicionar operações ou tarefas ao processamento-padrão da ferramenta.
♦ When-Button-Pressed
♦ When-Checkbox-Changed
♦ When-Clear-Block
♦ When-Create-Record
♦ When-Custom-Item-Event
♦ When-Form-Navigate
♦ When-Database-Record
♦ When-Form-Navigate
♦ When-Image-Activated
♦ When-Image-Pressed
♦ When-List-Activated
♦ When-List-Changed
♦ When-Mouse-Click
♦ When-Mouse-DoubleClick
♦ When-Mouse-Down
♦ When-Mouse-Enter
♦ When-Mouse-Leave
♦ When-Mouse-Move
♦ When-Mouse-Up
♦ When-New-Block-Instance
♦ When-New-Form-Instance
♦ When-New-Item-Instance
♦ When-New-Record-Instance
♦ When-Radio-Changed
♦ When-Remove-Record
♦ When-Tab-Page-Changed
♦ When-Timer-Expired
♦ When-Tree-Node-Activated
♦ When-Tree-Node-Expanded
♦ When-Tree-Node-Selected
♦ When-Validate-Item
♦ When-Validate-Record
♦ When-Window-Activated
♦ When-Window-Closed
♦ When-Window-Deactivated
♦ When-Window-Resized
KEY-*
Possuem uma ligação direta (1 para 1) com a tecla (ou conjunto de teclas) específica. O trigger é acionado quando
o operador pressiona a seqüência de teclas correspondente. Quando adicionados a uma aplicação, determinam a
substituição do processamento-padrão da ferramenta.
♦ Key-Clrblk
♦ Key-Clrfrm
♦ Key-Clrrec
♦ Key-Commit
♦ Key-Cquery
♦ Key-Crerec
♦ Key-Delrec
♦ Key-Down
♦ Key-Dup-Item
♦ Key-Duprec
♦ Key-Edit
♦ Key-Enter
♦ Key-Entqry
♦ Key-Exeqry
♦ Key-Exit
♦ Key-Help
♦ Key-Listval
♦ Key-Menu
♦ Key-Nxtblk
♦ Key-Nxt-Item
♦ Key-Nxtkey
♦ Key-Nxtrec
♦ Key-Nxtset
♦ Key-Print
♦ Key-Prvblk
♦ Key-Prv-Item
♦ Key-Prvrec
♦ Key-Scrdown
♦ Key-Scrup
♦ Key-Up
♦ Key-Updrec
♦ Key-Others
Capítulo 17
OS MENUS DO FORMS
Neste capítulo, apresentaremos os menus presentes no Form Builder 6i, além de explicações resumidas de sua
funcionalidade, discutida mais amplamente no tópico referente ao assunto relacionado.
NOVO (NEW)
Cria um novo módulo. O tipo de módulo dependerá do nó selecionado. Possui 5 opções para criação do módulo
Form, Formulário Usando Gabarito (cria um módulo Form a partir de um arquivo, extensão FMB, preexistente),
Menu, Biblioteca de PL/SQL ou Biblioteca de Objetos.
ABRIR (OPEN)
Abre um módulo já existente. Poderá ser apresentado um diálogo para que o usuário informe o meio de
armazenamento: disco ou banco de dados. A seguir, será apresentada uma lista dos objetos do tipo correspondente
no meio escolhido. O tipo de módulo dependerá do nó selecionado.
FECHAR (CLOSE)
Fecha o módulo corrente, ou seja, aquele que detém o foco.
SALVAR (SAVE)
Salva o módulo corrente.
REVERTER (REVERT)
Desfaz as modificações efetuadas no módulo desde sua última salva, ou seja, reverte a cópia para o mesmo estado
daquela que está em disco (se existir).
IMPORTAR (IMPORT)
Permite a importação de imagens e paletas de cores existentes em arquivos do sistema operacional (só habilitado
quando o Editor de Layout tiver o foco).
EXPORTAR (EXPORT)
Permite a exportação de imagens e paletas de cores para arquivos do sistema operacional (só habilitado quando o
Editor de Layout tiver o foco).
CONECTAR (CONNECT)
Apresenta um diálogo que permite ao usuário informar código, senha e string de conexão ao banco de dados para
que seja possível estabelecer acesso.
DESCONECTAR (DISCONNECT)
Desfaz a conexão previamente estabelecida.
ADMINISTRAÇÃO (ADMINISTRATION)
É um submenu que possui diversas ações administrativas, principalmente ligadas ao armazenamento da aplicação
no banco de dados:
RENOMEAR (RENAME)
Renomeia um módulo armazenado no banco de dados.
DELETAR (DELETE)
Remove (deleta) um módulo armazenado no banco de dados.
CONVERTER (CONVERT)
Converte os módulos de formato texto (.FMT, .MMT, .PLD) para binário (.FMB, .MMB, .PLL) e vice-versa.
A operação de Check-In leva para dentro da área de arquivamento uma nova versão do fonte.
IMPRIMIR (PRINT)
Imprime a janela corrente para uma impressora.
SAIR (QUIT)
Encerra o Form Builder.
RECORTAR (CUT)
Recorta a área corrente selecionada transferindo os dados para o Clipboard.
COPIAR (COPY)
Copia a área corrente selecionada transferindo os dados para o Clipboard.
COLAR (PASTE)
Coloca os dados que estiverem no Clipboard na área selecionada.
LIMPAR (CLEAR)
Recorta a área corrente selecionada sem efetuar qualquer transferência.
DUPLICAR (DUPLICATE)
Duplica o objeto selecionado.
SMARTCLASSES
Apresenta a lista de SmartClasses compatíveis com o objeto selecionado presentes em uma Object Library aberta.
RÉGUAS (RULERS)
Apresenta ou não as réguas vertical e horizontal do layout.
GRADE (GRID)
Apresenta ou não a grade.
RECOLHER (COLLAPSE)
Diminui, fecha o detalhamento do objeto selecionado no navegador.
CRIAR (CREATE)
Cria um novo objeto subordinado ao nó corrente.
DELETAR (DELETE)
Remove o objeto selecionado.
JUSTIFICAR (JUSTIFY)
Permite o alinhamento de um texto à direita, esquerda, centralizado, início ou fim dentro do objeto selecionado.
BEVEL
Permite a escolha de sombreados que darão noção de perspectiva ao objeto.
TRAÇO (DASH)
Permite a definição de linhas pontilhadas, linha cheia, traço e ponto para objetos gráficos (boilerplates gráficos).
SETA (ARROW)
Permite a configuração de diversos tipos de setas no desenho.
BORDA (BORDER)
Permite que determinemos quais as bordas do objeto que ficarão visíveis (topo, base, esquerda e direita).
GERAL (GENERAL)
Configurações aplicáveis aos objetos gráficos em geral.
TEXTO (TEXT)
Configurações aplicáveis aos boilerplates de texto.
IMAGEM (IMAGE)
Configurações aplicáveis aos boilerplates do tipo imagem.
ARCO (ARC)
Configurações aplicáveis aos boilerplates do tipo arco.
AGRUPAR (GROUP)
Agrupa dois ou mais objetos.
DESAGRUPAR (UNGROUP)
Libera os objetos anteriormente grupados.
CLIENTE/SERVIDOR (CLIENT/SERVER)
Corresponde à antiga opção de execução.
WEB (WEB)
Executa a aplicação com saída para um Browser.
DEPURAR (DEBUG)
Executa a aplicação e, simultaneamente, aciona o depurador para possibilitar a execução passo a passo.
COMPILAR (COMPILE)
Compila os códigos de PL/SQL. Pode ser realizada uma compilação Incremental (somente aqueles códigos ainda não
compilados ou modificados) ou Todas (todos os códigos de PL/SQL existentes no fonte).
REPORT BUILDER
Aciona o Report Builder.
PREFERÊNCIAS (PREFERENCES)
Aciona o diálogo de Preferências contendo as pastas Geral, Acesso, Assistentes e Runtime para que especifiquemos
características para o ambiente.
MENU (MENU)
CRIAR ABAIXO (CREATE DOWN)
Cria um item de menu abaixo do item atual (dentro do mesmo submenu ou em um novo submenu).
DELETAR (DELETE)
Remove o item de menu (e/ou submenu) selecionado.
EXPANDIR (EXPAND)
Expande o nível de detalhamento do item selecionado, apresentando os itens subordinados (se houver).
RECOLHER (COLLAPSE)
Fecha o nível de detalhamento do item selecionado, escondendo os itens subordinados (se houver).
QUICK TOUR
Aciona o Browser para apresentação de um tour pelas diversas ferramentas do pacote Oracle Developer. Mostra a
capacidade de cada produto. Bastante visual!
CUE CARDS
Apresenta um conjunto de diálogos que fornecem exemplos (inclusive animados) a respeito de algumas das tarefas
que podemos realizar com o Form Builder.
Por exemplo: executar uma aplicação, construir uma aplicação simples, modificar uma aplicação, construir uma
aplicação Mestre-Detalhe, etc.
MANUAIS (MANUALS)
Permite o acesso a alguns dos manuais fornecidos pela Oracle no CD-ROM.
Capítulo 18
PROPRIEDADES DO REPORTS
As propriedades serão apresentadas com seu nome em português, e entre parêntese com seu nome em inglês.
Elas estão associadas aos objetos aos quais pertencem e subdivididas de acordo com o grupo correspondente na
tela de propriedades do Report Builder.
ÂNCORA (ANCHOR)
GRUPO ÂNCORA (ANCHOR)
NOME DO OBJETO-FILHO (CHILD OBJECT NAME)
Apresenta o nome do objeto de layout dependente (filho).
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
TIPO (TYPE)
Indica o tipo de Boilerplate (Retângulo, Texto, Retângulo Arredondado, etc.).
Se essa propriedade for informada para um Frame, ela será transferida para o objeto interno que estiver situado
mais próximo do canto superior esquerdo do Frame.
MARCADOR (BOOKMARK)
Esta propriedade é um link de hipertexto que aparecerá no quadro de BookMark de um documento HTML ou na
área de BookMark de um PDF Viewer. Quando clicarmos no BookMark, o objeto associado será mostrado no
topo da janela.
HIPERLIGAÇÃO (HYPERLINK)
Esta propriedade é uma ligação URL que mostra um documento ou destino dentro de um documento quando o
objeto é clicado em um browser (Web) ou em um PDF Viewer.
Os valores válidos para essa propriedade são:
♦ Destino dentro do próprio documento: #dest_local
♦ Destino dentro de um documento local: file:/arquivos/teste.pdf#dest_local
♦ Documento na máquina local: file:/arquivos/teste.pdf ou file:///c:\arquivos\teste.pdf
♦ Documento em uma máquina remota: http://www.remoto.com.br/teste.pdf ou http://www.remoto.com.br/
teste.htm ou ftp://www.remoto.com.br/arqs.zip
♦ Destino dentro de um documento remoto: http://www.remoto.com.br/teste.pdf#dest_remoto
d) Default – Indica que o Report Builder deverá determinar a freqüência de impressão mais adequada para o objeto.
e) Primeira Página (First) – Indica que o objeto atual deve ser formatado apenas na primeira página em que o
objeto do qual ele é filho for impresso.
f) Última Página (Last) – Indica que o objeto atual deve ser formatado apenas na última página em que o objeto do
qual ele é filho for impresso.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
BOTÃO (BUTTON)
INFORMAÇÕES GERAIS (GENERAL INFORMATION)
NOME (NAME)
Nome do objeto.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
TEXTO (TEXT)
Se o tipo de etiqueta do botão for texto, nesta propriedade devemos informar o texto a ser apresentado.
♦ Coluna Multimídia (Multimedia Column) – indica que deve ser apresentado o conteúdo de uma coluna do
banco de dados (essa coluna contém uma imagem). O nome da coluna é fornecido pela propriedade Coluna
Multimídia (Multimedia Column).
♦ PL/SQL – indica que deve ser executado o texto de PL/SQL associado com o botão. Esse texto é fornecido pela
propriedade Gatilho PL/SQL (PL/SQL Trigger).
MARCADOR (BOOKMARK)
Esta propriedade é um link de hipertexto que aparecerá no quadro de BookMark de um documento HTML ou na área
de BookMark de um PDF Viewer. Quando clicarmos no BookMark, o objeto associado será mostrado no topo da janela.
HIPERLIGAÇÃO (HYPERLINK)
Esta propriedade é uma ligação URL que mostra um documento ou destino dentro de um documento quando o
objeto é clicado em um browser (Web) ou em um PDF Viewer.
Os valores válidos para esta propriedade são:
f) Última Página (Last) – Indica que o objeto atual deve ser formatado apenas na última página em que o objeto do
qual ele é filho for impresso.
CAMPO (FIELD)
INFORMAÇÕES GERAIS (GENERAL INFORMATION)
NOME (NAME)
Nome do objeto.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
CAMPO (FIELD)
ORIGEM (SOURCE)
Indica o local de onde o campo obtém seu valor (normalmente uma coluna ou parâmetro).
Se a origem for um valor de paginação (por exemplo, &Logical Page Number), poderemos, adicionalmente, definir
como a numeração de página será feita.
VISÍVEL (VISIBLE)
Esta propriedade indica se o campo deve ou não ser formatado. Se receber o valor Não (No), o campo ficará
escondido (hidden), ou seja, não será formatado. Isso é útil quando desejamos apenas referenciar o campo em um
boilerplate de texto, por exemplo, em um relatório tipo carta. A referência ao campo no boilerplate de texto é feita
com o formato &<nome do campo>.
COLUNA (COLUMN)
Reflete as informações presentes no Data Model referente à coluna origem. Possui as seguintes propriedades:
LARGURA (WIDTH)
Determina o número máximo de caracteres que os valores armazenados para esta coluna podem ocupar.
SUMÁRIO (SUMMARY)
FUNÇÃO (FUNCTION)
Determina a função de sumarização a ser aplicada à coluna. Os valores válidos são:
♦ Média (Average) – Calcula a média dos valores da coluna.
♦ Contagem (Count) – Conta o número de registros.
♦ Primeiro (First) – Apresenta o primeiro valor obtido para a coluna.
♦ Último (Last) – Imprime o último valor obtido para a coluna.
♦ Máximo (Maximum) – Calcula o maior valor para a coluna.
♦ Mínimo (Minimum) – Calcula o menor valor para a coluna.
♦ % do Total (% of Total) – Calcula o percentual da coluna em relação ao grupo especificado na propriedade
Calcular em (Compute At).
♦ Desvio Padrão (Std. Deviation) – Calcula a raiz quadrada positiva da variância para a coluna.
♦ Soma (Sum) – Calcula o somatório dos valores da coluna.
♦ Variação (Variance) – Soma os quadrados das distâncias dos valores de cada coluna em relação a um valor
central e divide o total pelo número de valores menos 1.
ORIGEM (SOURCE)
Determina a coluna sobre a qual o cálculo será realizado.
O texto informado nessa propriedade está limitado a letras, números e o caracter sublinhado. Qualquer outro
caracter será convertido para sublinhado.
Se essa propriedade for informada para um Frame, ela será transferida para o objeto interno que estiver situado
mais próximo do canto superior esquerdo do Frame.
MARCADOR (BOOKMARK)
Esta propriedade é um link de hipertexto que aparecerá no quadro de BookMark de um documento HTML ou na área
de BookMark de um PDF Viewer. Quando clicarmos no BookMark, o objeto associado será mostrado no topo da janela.
HIPERLIGAÇÃO (HYPERLINK)
Esta propriedade é uma ligação URL que mostra um documento ou destino dentro de um documento quando o
objeto é clicado em um browser (Web) ou em um PDF Viewer.
Os valores válidos para essa propriedade são:
♦ Destino dentro do próprio documento: #dest_local
♦ Destino dentro de um documento local: file:/arquivos/teste.pdf#dest_local
♦ Documento na máquina local: file:/arquivos/teste.pdf ou file:///c:\arquivos\teste.pdf
♦ Documento em uma máquina remota: http://www.remoto.com.br/teste.pdf ou http://www.remoto.com.br/
teste.htm ou ftp://www.remoto.com.br/arqs.zip
♦ Destino dentro de um documento remoto: http://www.remoto.com.br/teste.pdf#dest_remoto
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
PARÂMETRO (PARAMETER)
TIPO DE DADOS (DATATYPE)
Esta é uma propriedade Read-Only que apresenta o tipo de dado da origem escolhida.
LARGURA (WIDTH)
Esta propriedade determina a quantidade máxima de caracteres do parâmetro.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
COLUNA (COLUMN)
TIPO DE COLUNA (COLUMN TYPE)
Indica a categoria da coluna. Neste caso o valor deve ser Marcador de Posição.
LARGURA (WIDTH)
Determina o número máximo de caracteres que os valores armazenados para esta coluna podem ocupar.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
COLUNA (COLUMN)
TIPO DE COLUNA (COLUMN TYPE)
Indica a categoria da coluna. Neste caso o valor deve ser Fórmula.
LARGURA (WIDTH)
Determina o número máximo de caracteres que os valores armazenados para esta coluna podem ocupar.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
COLUNA (COLUMN)
TIPO DE COLUNA (COLUMN TYPE)
Indica a categoria da coluna. Neste caso o valor deve ser Resumo.
LARGURA (WIDTH)
Determina o número máximo de caracteres que os valores armazenados para esta coluna podem ocupar.
SUMÁRIO (SUMMARY)
FUNÇÃO (FUNCTION)
Determina a função de sumarização a ser aplicada à coluna. Os valores válidos são:
♦ Média (Average) – Calcula a média dos valores da coluna.
♦ Contagem (Count) – Conta o número de registros.
♦ Primeiro (First) – Apresenta o primeiro valor obtido para a coluna.
♦ Último (Last) – Imprime o último valor obtido para a coluna.
♦ Máximo (Maximum) – Calcula o maior valor para a coluna.
♦ Mínimo (Minimum) – Calcula o menor valor para a coluna.
♦ % do Total (% of Total) – Calcula o percentual da coluna em relação ao grupo especificado na propriedade
Calcular em (Compute At).
♦ Desvio Padrão (Std. Deviation) – Calcula a raiz quadrada positiva da variância para a coluna.
♦ Soma (Sum) – Calcula o somatório dos valores da coluna.
♦ Variação (Variance) – Soma os quadrados das distâncias dos valores de cada coluna em relação a um valor
central e divide o total pelo número de valores menos 1.
ORIGEM (SOURCE)
Determina a coluna sobre a qual o cálculo será realizado.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
COLUNA (COLUMN)
TIPO DE COLUNA (COLUMN TYPE)
Indica a categoria da coluna. Alguns dos valores possíveis são: Tipo de Dados-Escalar, Tipo de Dados-Ref, Tipo de
Dados-Objeto, Banco de Dados-Desconhecido, Fórmula, Marcador de Posição ou Resumo.
LARGURA (WIDTH)
Determina o número máximo de caracteres que os valores armazenados para esta coluna podem ocupar. O valor é
calculado a partir da coluna do banco de dados ou expressão definida na query.
CONSULTA (QUERY)
INFORMAÇÕES GERAIS (GENERAL INFORMATION)
NOME (NAME)
Nome do objeto.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
CONSULTA (QUERY)
TIPO (TYPE)
É uma propriedade Read-Only que descreve o tipo da query.
GRÁFICO (CHART)
INFORMAÇÕES GERAIS (GENERAL INFORMATION)
NOME (NAME)
Nome do objeto.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
GRÁFICO (CHART)
NOME DO ARQUIVO DE GRÁFICO (CHART FILENAME)
Indica o nome do arquivo no qual o gráfico (ou display) do Graphics Builder está localizado.
MARCADOR (BOOKMARK)
Esta propriedade é um link de hipertexto que aparecerá no quadro de BookMark de um documento HTML ou na área
de BookMark de um PDF Viewer. Quando clicarmos no BookMark, o objeto associado será mostrado no topo da janela.
HIPERLIGAÇÃO (HYPERLINK)
Esta propriedade é uma ligação URL que mostra um documento ou destino dentro de um documento quando o
objeto é clicado em um browser (Web) ou em um PDF Viewer.
Os valores válidos para esta propriedade são:
♦ Destino dentro do próprio documento: #dest_local
♦ Destino dentro de um documento local: file:/arquivos/teste.pdf#dest_local
♦ Documento na máquina local: file:/arquivos/teste.pdf ou file:///c:\arquivos\teste.pdf
♦ Documento em uma máquina remota: http://www.remoto.com.br/teste.pdf ou http://www.remoto.com.br/
teste.htm ou ftp://www.remoto.com.br/arqs.zip
♦ Destino dentro de um documento remoto: http://www.remoto.com.br/teste.pdf#dest_remoto
a) Todas as Páginas (All) – Indica que o objeto atual deve ser formatado em todas as páginas em que o objeto do
qual ele é filho for impresso.
b) Tudo, Exceto a Primeira Página (All But First) – Indica que o objeto atual deve ser formatado em todas as páginas
em que o objeto do qual ele é filho for impresso, exceto na primeira página.
c) Tudo, Exceto a Última Página (All But Last) – Indica que o objeto atual deve ser formatado em todas as páginas
em que o objeto do qual ele é filho for impresso, exceto na última.
d) Default – Indica que o Report Builder deverá determinar a freqüência de impressão mais adequada para o objeto.
e) Primeira Página (First) – Indica que o objeto atual deve ser formatado apenas na primeira página em que o
objeto do qual ele é filho for impresso.
f) Última Página (Last) – Indica que o objeto atual deve ser formatado apenas na última página em que o objeto do
qual ele é filho for impresso.
GRUPO (GROUP)
INFORMAÇÕES GERAIS (GENERAL INFORMATION)
NOME (NAME)
Nome do objeto.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
GRUPO (GROUP)
TIPO DE FILTRO (FILTER TYPE)
Indica o tipo de filtro aplicável ao grupo. Os valores válidos aceitos pelo relatório são:
♦ Nenhum (None) – Não há filtro.
♦ Primeira (First) – Os primeiros n registros são aceitos pelo relatório. A quantidade n é definida pela propriedade
Número de Registros (Number of Records).
♦ Última (Last) – Os últimos n registros são aceitos pelo relatório. A quantidade n é definida pela propriedade
Número de Registros (Number of Records).
♦ PL/SQL – Os registros aceitos ou não são definidos por uma função de PL/SQL.
CONDIÇÃO (CONDITION)
Determina a condição a ser utilizada para montagem da condição de restrição na query-filha. Os valores válidos
para esta propriedade são: = (igual a), < (menor que), <= (menor ou igual a), <> (diferente de), > (maior que), >=
(maior ou igual a), Like (Como), Not Like (Não-Como).
MATRIZ (MATRIX)
INFORMAÇÕES GERAIS (GENERAL INFORMATION)
NOME (NAME)
Nome do objeto.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
MATRIZ (MATRIX)
QUADRO DE REPETIÇÃO VERTICAL (VERTICAL REPEATING FRAME)
Indica o nome do Repeating Frame Vertical que compõe o produto matricial. Esta propriedade é read-only.
MARCADOR (BOOKMARK)
Esta propriedade é um link de hipertexto que aparecerá no quadro de BookMark de um documento HTML ou na área
de BookMark de um PDF Viewer. Quando clicarmos no BookMark, o objeto associado será mostrado no topo da janela.
HIPERLIGAÇÃO (HYPERLINK)
Esta propriedade é uma ligação URL que mostra um documento ou destino dentro de um documento quando o
objeto é clicado em um browser (Web) ou em um PDF Viewer.
Os valores válidos para esta propriedade são:
♦ Destino dentro do próprio documento: #dest_local
♦ Destino dentro de um documento local: file:/arquivos/teste.pdf#dest_local
♦ Documento na máquina local: file:/arquivos/teste.pdf ou file:///c:\arquivos\teste.pdf
♦ Documento em uma máquina remota: http://www.remoto.com.br/teste.pdf ou http://www.remoto.com.br/
teste.htm ou ftp://www.remoto.com.br/arqs.zip
♦ Destino dentro de um documento remoto: http://www.remoto.com.br/teste.pdf#dest_remoto
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
RELATÓRIO (REPORT)
UNIDADE DE MEDIDA (UNIT OF MEASUREMENT)
Especificação da unidade de medida em que o Report Builder irá trabalhar. As opções são: centímetros, polegadas e pontos.
O número de páginas de corpo não representa o número de páginas necessário para a impressão de um relatório;
quem determina o número de páginas é a query.
Desta forma, poderão ser impressas dez mil páginas ou uma, e o parâmetro maximum body pages (horizontal e
vertical) continuará sendo 10 x 10. Esse número de corpo é definido apenas para que possamos desenhar o relatório
na página de Layout.
DIREÇÃO (DIRECTION)
Associado ao Panel Print Order, indica a direção (esquerda para direita ou vice-versa).
DISTRIBUIÇÃO (DISTRIBUTION)
Esta propriedade aciona um diálogo em que determinamos os diversos formatos de geração do relatório. Nesse
diálogo, as seguintes informações devem ser preenchidas:
♦ ID de Distribuição (Distribution ID) – Um identificador único para a distribuição. Pode ser numérico ou alfanumérico.
♦ NomeDes (Desname) – Indica o destino, que pode ser um diretório com nome de arquivo (o diretório deve
existir), impressora ou e-mail ID (ou lista de distribuição).
♦ FormatoDes (Desformat) – Indica formato do arquivo ou driver da impressora quando o Tipo de Destino (Destype) for
arquivo. Os valores válidos para este campo são apresentados por uma lista. Podem ser: BitMap(default, especifica o
resultado como mostrado pelo Report Builder), HTML (formato compatível com browsers que suportem HTML 3.0),
HTMLCSS (formato compatível com browsers que suportem HTML 3.0 com Cascading Style Sheets), PDF (pode ser lido
por um PDF viewer), ASCII (especifica formato caracter, que pode ser lido por uma aplicação e-mail compatível com
padrão MAPI) ou RTF (formato Rich Text Format, compatível com editores tais como Microsoft Word).
♦ TipoDes (Destype) – Indica o tipo de destino, que pode ser: FILE (indica um arquivo nomeado por NomeDes), MAIL
(especifica um e-mail identificado por NomeDes; o parâmetro de sistema Mode deve estar preenchido com Charac-
ter) ou Printer (cuja impressora é identificada por NomeDes).
♦ Cópias (Copies) – Determina a quantidade de cópias para esta distribuição.
ALTURA (HEIGHT)
Altura da tela de parâmetro apresentado a tempo de execução do relatório. É expressa na unidade de
dimensionamento definida.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
Se essa propriedade for informada para um Frame, ela será transferida para o objeto interno que estiver situado
mais próximo do canto superior esquerdo do Frame.
MARCADOR (BOOKMARK)
Esta propriedade é um link de hipertexto que aparecerá no quadro de BookMark de um documento HTML ou na área
de BookMark de um PDF Viewer. Quando clicarmos no BookMark, o objeto associado será mostrado no topo da janela.
HIPERLIGAÇÃO (HYPERLINK)
Esta propriedade é uma ligação URL que mostra um documento ou destino dentro de um documento quando o
objeto é clicado em um browser (Web) ou em um PDF Viewer.
Os valores válidos para esta propriedade são:
♦ Destino dentro do próprio documento: #dest_local
♦ Destino dentro de um documento local: file:/arquivos/teste.pdf#dest_local
♦ Documento na máquina local: file:/arquivos/teste.pdf ou file:///c:\arquivos\teste.pdf
PARÂMETRO (PARAMETER)
INFORMAÇÕES GERAIS (GENERAL INFORMATION)
NOME (NAME)
Nome do objeto.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
PARÂMETRO (PARAMETER)
TIPO DE DADOS (DATATYPE)
Esta propriedade indica o tipo de dado do parâmetro. Os valores válidos são: Character, Date ou Number.
LARGURA (WIDTH)
Esta propriedade determina a quantidade máxima de caracteres do parâmetro.
QUADRO (FRAME)
INFORMAÇÕES GERAIS (GENERAL INFORMATION)
NOME (NAME)
Nome do objeto.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
O texto informado nessa propriedade está limitado a letras, números e o caracter sublinhado. Qualquer outro
caracter será convertido para sublinhado.
Se essa propriedade for informada para um Frame, ela será transferida para o objeto interno que estiver situado
mais próximo do canto superior esquerdo do Frame.
MARCADOR(BOOKMARK)
Esta propriedade é um link de hipertexto que aparecerá no quadro de BookMark de um documento HTML ou na área
de BookMark de um PDF Viewer. Quando clicarmos no BookMark, o objeto associado será mostrado no topo da janela.
HIPERLIGAÇÃO (HYPERLINK)
Esta propriedade é uma ligação URL que mostra um documento ou destino dentro de um documento quando o
objeto é clicado em um browser (Web) ou em um PDF Viewer.
COMENTÁRIOS (COMMENTS)
Comentários sobre o objeto. Campo de texto de livre digitação.
GRUPO (GROUP)
TIPO DE FILTRO (FILTER TYPE)
Indica o tipo de filtro aplicável ao grupo. Os valores válidos aceitos pelo relatório são:
♦ Nenhum (None) – Não há filtro.
♦ Primeira (First) – Os primeiros n registros são aceitos pelo relatório. A quantidade n é definida pela propriedade
Número de Registros (Number of Records).
♦ Última (Last) – Os últimos n registros são aceitos pelo relatório. A quantidade n é definida pela propriedade
Número de Registros (Number of Records).
♦ PL/SQL – Os registros aceitos ou não são definidos por uma função de PL/SQL.
O texto informado nessa propriedade está limitado a letras, números e o caracter sublinhado. Qualquer outro
caracter será convertido para sublinhado.
Se essa propriedade for informada para um Frame, ela será transferida para o objeto interno que estiver situado
mais próximo do canto superior esquerdo do Frame.
MARCADOR (BOOKMARK)
Esta propriedade é um link de hipertexto que aparecerá no quadro de BookMark de um documento HTML ou na área
de BookMark de um PDF Viewer. Quando clicarmos no BookMark, o objeto associado será mostrado no topo da janela.
HIPERLIGAÇÃO (HYPERLINK)
Esta propriedade é uma ligação URL que mostra um documento ou destino dentro de um documento quando o
objeto é clicado em um browser (Web) ou em um PDF Viewer.
SEÇÃO (SECTION)
Este elemento foi incluído na versão 6.0 com as seguintes propriedades:
SEÇÃO (SECTION)
LARGURA (WIDTH)
Determina a largura da página física desta seção.
ALTURA (HEIGHT)
Determina a altura da página física desta seção.
ORIENTAÇÃO (ORIENTATION)
Indica se o resultado da seção é Landscape ou Portrait.
DISTRIBUIÇÃO (DISTRIBUTION)
Esta propriedade aciona um diálogo em que determinamos os diversos formatos de geração do relatório. Nesse
diálogo, as seguintes informações devem ser preenchidas:
♦ ID de Distribuição – Um identificador único para a distribuição. Pode ser numérico ou alfanumérico.
♦ NomeDes (Desname) – Indica o destino, que pode ser um diretório com nome de arquivo (o diretório deve
existir), impressora ou e-mail ID (ou lista de distribuição).
♦ FormatoDes (Desformat) – Indica formato do arquivo ou driver da impressora quando o Tipo de Destino (Destype)
for arquivo. Os valores válidos para este campo são apresentados por uma lista. Podem ser: BitMap (default,
especifica o resultado como mostrado pelo Report Builder), HTML (formato compatível com browsers que
suportem HTML 3.0), HTMLCSS (formato compatível com browsers que suportem HTML 3.0 com Cascading
Style Sheets), PDF (pode ser lido por um PDF viewer), ASCII (especifica formato caracter, que pode ser lido por
uma aplicação e-mail compatível com padrão MAPI), RTF (formato Rich Text Format, compatível com editores
tais como Microsoft Word) ou XML.
♦ TipoDes (Destype) – Indica o tipo de destino, que pode ser: FILE (indica um arquivo nomeado por NomeDes), MAIL
(especifica um e-mail identificado por NomeDes; o parâmetro de sistema Mode deve estar preenchido com Charac-
ter) ou Printer (cuja impressora é identificada por NomeDes).
♦ Cópias (Copies) – Determina a quantidade de cópias para esta distribuição.
Capítulo 19
PARÂMETROS DE EXECUÇÃO
Os parâmetros que veremos neste capítulo são utilizados na linha de comando dos aplicativos ou no arquivo de
comandos correspondente.
O Forms possui parâmetros de execução para o Form Builder, Form Compiler e Form Runtime. Neste capítulo
relacionaremos aqueles parâmetros aplicáveis ao Form Runtime e ao Form Compiler. As opções de execução do
Form Builder foram estudadas no Capítulo 7.
O Reports também possui parâmetros de execução diferenciados para o Builder, Runtime, Cli, etc., porém a grande
maioria dos parâmetros é comum aos diversos executáveis.
PARA RELATÓRIOS
Este grupo de parâmetros é aplicável ao Report Builder (RWBLD60), Report Runtime (RWRUN60) e ao Report
Client (RWCLI60). Em separado apresentaremos os parâmetros aplicáveis ao Report Convert (RWCON60).
ACCESS
Este parâmetro determina a localização do módulo a ser aberto. Aplicável ao Report Builder.
♦ Sintaxe: [ACCESS=] { file | database }
ARRAYSIZE
Determina o tamanho (em KB) para utilização pelo Oracle Array Processing. Esse valor pode variar de 1 a 9.999, indicando
que esta quantidade de KB de memória pode ser utilizada para cada query do relatório. O valor default é 10 KB.
♦ Sintaxe: [Arraysize=]<n>
AUTHID
Indica o username e password utilizados para autenticação dos usuários junto ao report Server. Aplicável apenas ao
RWCLI60.
♦ Sintaxe: [Authid=] {<username> / <password>}
AUTOCOMMIT
Determina que as alterações enviadas ao banco de dados devem ser automaticamente Committed. Para alguns
bancos de dados (ex.: SQL Server), essa opção é indispensável.
♦ Sintaxe: [Autocommit=] { Yes | No }
BACKGROUND
Este parâmetro indica se o relatório deve ser executado em background. Os valores válidos são: Yes ou No (default).
♦ Sintaxe: [Background=] {Yes | No}
BATCH
Quando ativado, suprime toda a interface de entrada ou saída do terminal para que o relatório seja executado sem
intervenção do usuário. Este parâmetro não se aplica ao Report Builder.
♦ Sintaxe: [Batch=] {Yes | No}
BLANKPAGES
Este parâmetro indica que devem ser suprimidas as páginas em branco quando o relatório for enviado para a impressora.
♦ Sintaxe: [BLANKPAGES=] { Yes | No }
BUFFERS
Corresponde ao tamanho da área de memória virtual cache em KB. Os valores válidos variam de 1 a 9.999. O valor
default é 640 KB.
♦ Sintaxe: [Buffers=]<n>
CACHELOB
Este parâmetro indica se os Lobs recuperados do banco de dados devem ser arquivados em disco (cache), em um
diretório temporário (definido por Reports60_Tmp).
♦ Sintaxe: [CACHELOB=] { Yes | No }
CELLWRAPPER
Este parâmetro especifica um caracter a ser colocado antes e depois de cada célula de valor de um relatório cujo
formato seja Delimited (no parâmetro Desformat). O valor default é None.
♦ Sintaxe: [CELLWRAPPER=] { <valor> }
O valor poderá ser qualquer caracter alfanumérico ou uma string de caracteres alfanuméricos. Pode-se também
usar uma das seguintes palavras reservadas com significado especial: Tab (tabulação), Space (um espaço), Return
(nova linha), None (não haverá caracter em torno da célula).
Podem-se usar, também, as seqüências de escape para ASCII, tais como: \t (tabulação), \n (nova linha).
CMDFILE
O arquivo de comandos contém os argumentos necessários à execução do relatório. Podemos criá-lo para que a
cada execução do relatório especifiquemos um número menor de parâmetros.
Este parâmetro determina o nome do arquivo de comandos. Os comandos devem ser armazenados no arquivo
segundo a sintaxe: <nome do parâmetro> = <valor>.
♦ Sintaxe: [Cmdfile=]<nome do arquivo>
COPIES
Este parâmetro determina o número de cópias do relatório. Será ignorado se o destino não for impressora.
CURRENCY
Este parâmetro determina o caracter a ser usado como símbolo financeiro para formatos numéricos.
O valor default para esse parâmetro é dado pela NLS em uso.
♦ Sintaxe: [Currency=]<símbolo financeiro>
CUSTOMIZE
Este parâmetro especifica um arquivo XML ou uma lista de arquivos XML que desejamos aplicar ao relatório
identificado no parâmetro módulo. Este arquivo (ou arquivos) contém especificações como fontes, cores, etc., que
visam modificar a definição do relatório.
♦ Sintaxe: [Customize=]<nome arq>.xml | (<nome arq1>.xml, <nome arq2>.xml, …)
DATEFORMATMASK
Este parâmetro especifica um formato de data para os relatórios cujo formato seja Delimited (Desformat).
♦ Sintaxe: [DATEFORMATMASK=] { <máscara> }
DECIMAL
Este parâmetro determina o símbolo a ser usado como caracter decimal para formatos numéricos.
O valor default para esse parâmetro é dado pela NLS em uso.
♦ Sintaxe: [Decimal=]<caracter decimal>
DELIMITER
Este parâmetro especifica um caracter para separar uma célula da outra (separador entre células), em um relatório
cujo formato seja Delimited (no parâmetro Desformat). O valor default é Tab.
♦ Sintaxe: [DELIMITER=] { <valor> }
O valor poderá ser qualquer caracter alfanumérico ou uma string de caracteres alfanuméricos. Pode-se também
usar uma das seguintes palavras reservadas com significado especial: Tab (tabulação), Space (um espaço), Return
(nova linha), None (não haverá caracter em torno da célula).
Podem-se usar, também, as seqüências de escape para ASCII, tais como: \t (tabulação), \n (nova linha).
DESFORMAT
Em ambientes Bit-mapped, este parâmetro especifica o driver de impressora a ser utilizado quando Destype é File.
Em ambientes character-mode, determina as características da impressora nomeada por Desname.
♦ Sintaxe: [Desformat=]<formato destino>
Esse parâmetro é ignorado se o destino for vídeo.
Alguns dos valores válidos são: hpl, hplwide, dec, decwide, decland, dec180, deflt, wide, pdf, html, htmlcss.
♦ PDF – O arquivo gerado poderá ser lido por um software similar ao Adobe Acrobat Reader. As características do
arquivo serão determinadas pelo driver de impressora atualmente selecionado.
♦ HTML – O arquivo gerado poderá ser lido por um browser que seja compatível com o formato HTML 3.0 (por
exemplo, Netscape 2.2).
♦ HTMLCSS – O arquivo gerado poderá ser lido por um browser que seja compatível com o formato HTML 3.0 que
suporte Cascading Style Sheets (por exemplo, Microsoft Internet Explorer 3.01).
♦ HTMLCSSIE – Indica que o relatório gerado em arquivo contém padrões (Style Sheet Extensions) que podem ser
lidos pelo Microsoft Internet Explorer 3.x.
♦ RTF – Indica que o resultado do relatório será enviado para um arquivo, o qual poderá ser lido por um processador
de documento (por exemplo, Microsoft Word). Para que a visualização dos gráficos e demais objetos do relatório
fique correta, devemos escolher o layout ViewPage (no Word).
♦ DELIMITED – Indica que o resultado do relatório será enviado para um arquivo que pode ser lido por utilitários-
padrão de SpreadSheet (por exemplo, Microsoft Excel). O parâmetro de execução Delimiter também deve ser
informado para que este resultado seja o esperado.
♦ XML – Indica que a saída do relatório será enviada para um arquivo que poderá ser lido por uma aplicação que
suporte XML.
DESNAME
É o nome do arquivo ou da impressora ou do e-mail (ou lista de distribuição) para onde o relatório será enviado. O
tamanho deste parâmetro não pode exceder a 1 KB. Veja o parâmetro Destype a seguir.
♦ Sintaxe: [Desname=]<nome destino>
DESTINATION
Este parâmetro determina o nome do arquivo .DST que define a lista de distribuição para o relatório corrente.
♦ Sintaxe: [DESTINATION=] { <nome do arquivo> }
DESTYPE
Indica o tipo de periférico que receberá o resultado do relatório.
♦ Sintaxe: [Destype=] { Screen | File | Printer | Preview | Sysout | Mail | Cache | Localfile}.
Os valores válidos apresentados na sintaxe possuem o significado:
♦ Screen – Envia o resultado para o Previewer. Esse valor somente é válido quando Batch=No. Não aplicável ao RWCLI60.
♦ File – Salva o resultado em um arquivo. O nome do arquivo é definido pelo parâmetro Desname.
♦ Printer – Envia o resultado para a impressora nomeada pelo parâmetro Desname.
♦ Preview – Envia o resultado para o Previewer. Faz com que o resultado seja formatado como PostScript. O
Previewer usa o parâmetro Desname para determinar que fontes da impressora usar para apresentar a saída. Não
aplicável ao RWCLI60.
♦ Sysout – Envia o resultado para o periférico-padrão especificado para o sistema operacional. Esse valor é válido
somente quando Batch=Yes.
♦ Mail – Envia o resultado para o usuário especificado pelo parâmetro Desname. Podemos enviar o mail para
qualquer sistema de correio eletrônico que seja compatível com MAPI ou tenha o service provider driver instalado.
O relatório é enviado como um arquivo atachado.
♦ Localfile – Envia o resultado para um arquivo na máquina do cliente e força a chamada síncrona,
independentemente do valor do parâmetro Background. Aplicável ao RWCLI60.
♦ Cache – Envia o resultado diretamente para a área Cache do Report Server. Essa opção não é compatível com o
parâmetro Distribute. Se o servidor encontrar a palavra DISTRIBUTE na linha de comando, ele ignorará a opção
DESTYPE=CACHE. Aplicável ao RWCLI60.
DISABLEFILE
Este parâmetro indica se pode ou não ser feita geração do relatório para arquivo no Runtime Previewer (menu
Arquivo, opção Criar Para Arquivo).
♦ Sintaxe: [DISABLEFILE=] { Yes | No }
DISABLEMAIL
Este parâmetro indica se o menu Mail, e o botão equivalente na barra de ferramentas, está ou não habilitado
quando a execução é feita no Runtime Previewer.
♦ Sintaxe: [DISABLEMAIL=] { Yes | No }
DISABLENEW
Este parâmetro indica se pode ou não ser aberta uma nova instância do Previewer no Runtime Previewer.
♦ Sintaxe: [DISABLENEW=] { Yes | No }
DISABLEPRINT
Este parâmetro indica se a possibilidade de impressão (Configuração de Página e Escolha de Impressora), e o botão
equivalente na barra de ferramentas, está ou não habilitada quando a execução é feita no Runtime Previewer.
♦ Sintaxe: [DISABLEPRINT=] { Yes | No }
DISTRIBUTE
Este parâmetro habilita ou desabilita a distribuição do relatório para múltiplos destinos. Se habilitado, deve haver uma
lista de distribuição definida internamente no relatório ou por um arquivo do tipo .DST (parâmetro Destination).
♦ Sintaxe: [DISTRIBUTE=] { Yes | No }
ERRFILE
Indica o nome de um arquivo para armazenamento de todas as mensagens de erro ocorridas durante a execução
do relatório.
♦ Sintaxe: [Errfile=] <nome do arquivo>
EXPRESS_SERVER
Especifica o Servidor Express ao qual desejamos estabelecer conexão.
♦ Sintaxe: [EXPRESS_SERVER=]{“server=[server] / domain=[domain] / user=[userid] / password= [passwd]”}
JOBNAME
Este parâmetro especifica um nome (uma string) a ser mostrada na Reports Queue Manager para o relatório atual.
Se omitido, o Queue Manager apresentará o nome do relatório como nome do job. Aplicável somente ao RWCLI60.
♦ Sintaxe: [Jobname=]<string>
KEYIN
Determina o nome de um arquivo que contém comandos de simulação de teclado e que será usado a tempo de
execução do relatório. O arquivo é criado através do parâmetro KeyOut. Só relevante em ambientes character
mode. Não aplicável ao Report Builder.
♦ Sintaxe: [Keyin=] <nome do arquivo>
KEYOUT
Corresponde ao nome de um arquivo que será gerado pelo Report Builder para registrar todas as teclas acionadas
durante a execução do relatório. A utilização deste arquivo pode ser feita com o uso do parâmetro KeyIn. Só
relevante em ambientes character mode. Não aplicável ao Report Builder.
♦ Sintaxe: [Keyout=] <nome do arquivo>
LOGFILE
Indica o nome do arquivo para o qual o comando File -> Print Screen enviará o resultado. Se o arquivo já existir em
disco, o resultado será adicionado a esse arquivo. Esse parâmetro só é aplicável a character mode. Não aplicável ao
Report Builder.
♦ Sintaxe: [Logfile=] <nome de arquivo>
LONGCHUNK
Determina o tamanho (em KB) dos incrementos em que o Report Runtime recupera o valor de uma coluna Long. O
valor informado pode variar de 1 a 9.999, porém limitado pelo sistema operacional em uso. O valor default é 10K.
♦ Sintaxe: [Longchunk=] <n>
MAXIMIZE
Este parâmetro indica se devemos maximizar a janela do Report. Este parâmetro só se acha presente na lista de
parâmetros do Report Builder, porém a documentação indica que é aplicável apenas ao Report Runtime. O parâmetro
deve ser passado para o Builder. Quando o Previsualizador de Runtime for acionado, este será apresentado maximizado.
♦ Sintaxe: [Maximize=] {Yes | No}
MODE
Especifica a forma de execução do relatório: caracter ou bitmap. Isso é útil quando desejamos executar um relatório
caracter em um ambiente bitmap ou vice-versa.
♦ Sintaxe: [Mode=] {Bitmap | Character | Default }
MODULE | REPORT
Este parâmetro determina o nome do relatório a ser executado. A opção Report é mantida para compatibilidade
com versões anteriores.
♦ Sintaxe: [Module | Report=]<nome do módulo>
O nome do módulo corresponde a um arquivo com a extensão .Rdf ou .Rep. A partir da 6i também podemos usar a extensão .XML.
NONBLOCKSQL
Especifica se é possível a outros programas executarem enquanto o Reports Runtime está obtendo (fetch) dados do
banco de dados.
♦ Sintaxe: [Nonblocksql=] {Yes | No }
NUMBERFORMATMASK
Este parâmetro especifica um formato numérico para os relatórios cujo formato seja Delimited (Desformat).
♦ Sintaxe: [NUMBERFORMATMASK=] { <máscara> }
PAGESTREAM
Este parâmetro habilita ou desabilita a geração de arquivos diferentes para cada página do relatório quando o
formato de saída é HTML ou HTMLCSS.
♦ Sintaxe: [PAGESTREAM=] { Yes | No }
ONFAILURE
Indica a ação a ser executada se ocorrer um erro durante o processamento do relatório e este terminar sem sucesso.
♦ Sintaxe: [Onfailure=] { Commit | Rollback | Noaction }
ONSUCCESS
Indica a ação a ser executada quando o relatório é concluído com sucesso.
♦ Sintaxe: [Onsuccess=] { Commit | Rollback | Noaction }
ORIENTATION
Controla a direção na qual as páginas do relatório serão impressas. Default indica que será utilizada a orientação
determinada pela impressora.
♦ Sintaxe: [Orientation=] { Default | Landscape | Portrait }
PAGESIZE
Determina o tamanho da página física do relatório. O tamanho especificado deve ser suficiente para conter o
layout definido; caso contrário, o relatório não será executado. A unidade dessa medida depende da especificação
de Unidade de Dimensionamento (Unit of Measurement).
♦ Sintaxe: [Pagesize=] <largura> X <altura>
PARAMFORM
Especifica se deve ou não ser apresentada a tela de parâmetros (Runtime Parameter Form) a tempo de execução do
relatório.
♦ Sintaxe: [Paramform=]{Yes|No}
Paramform=Yes é incompatível com Batch=Yes porque não é possível a apresentação da tela de parâmetros em uma execução em batch.
PRINTJOB
Especifica se o diálogo PrintJob deve ou não ser apresentado ao usuário antes da execução do relatório.
♦ Sintaxe: [Printjob=] {Yes | No }
PROFILE
Corresponde ao nome do arquivo onde desejamos armazenar informações estatísticas sobre a execução do relatório.
♦ Sintaxe: [Profile=] <nome do arquivo>
As seguintes informações estatísticas são armazenadas:
♦ Total Elapsed Time – Tempo total de execução, gasto conjuntamente pelo Report Runtime e pelo Oracle (acesso
ao banco).
♦ Time – Tempo de execução somente do Report Runtime.
♦ Oracle Time – Tempo gasto com o banco de dados. Subdividido em UPI (tempo para conexão, Parse e Fetch) e
SQL (tempo gasto executando-se a rotina Srw.Do_Sql).
♦ Total CPU Time usado pelo processo – Tempo de CPU utilizado na execução do relatório.
READONLY
Determina a consistência de leitura para as diversas queries do relatório. Corresponde à execução do comando Set
Transacion Read Only ao início da execução.
♦ Sintaxe: [Readonly=] {Yes | No}
ROLE
Especifica a role do banco de dados a ser verificada pelo relatório a tempo de execução.
♦ Sintaxe: [Role=] <nome da role> [ / <password da role> ]
RUNDEBUG
Habilita ou não verificações extraordinárias de situações que não causam erros, mas que podem vir a produzir
resultados indesejáveis. São elas:
a) Frames ou Repeating Frames que cruzam mas não englobam (contêm) completamente outro objeto.
b) Objetos de Layout com dependência de página que não tem tamanho fixo. O Report Builder fará a marcação
desses objetos com o tamanho fixo independente da propriedade Elasticidade Vertical ou Horizontal.
c) Variáveis Bind referenciadas (em PL/SQL) a uma freqüência inválida.
d) O relatório é character mode ou bitmap e o ambiente é o oposto.
♦ Sintaxe: [Rundebug=]{Yes|No}
SAVE_RDF
Este parâmetro indica um arquivo que receberá o relatório indicado pelo parâmetro MODULE adicionado das
modificações sugeridas pelos arquivos indicados no parâmetro CUSTOMIZE.
♦ Sintaxe: [Save_RDF=]<nome arq>.RDF
SCHEDULE
Este parâmetro determina a freqüência futura de execução do relatório. O default é agora. Aplicável ao RWCLI60.
♦ Sintaxe: [Schedule=]<string>
A string deve ter o formato: [FREQ from] TIME [retry {n} + after LEN], onde:
a) FREQ pode ser: hourly | daily | weekly | monthly | {every LEN | DAYREPEAT} |
WEEKDAYS pode ser: mon | tue | wed | thu | fri | sat | sun
b) TIME pode ser: now | CLOCK [DATE]
CLOCK pode ser: h:m | h:mm | hh:m | hh:mm
DATE pode ser: today | tomorrow | {MONTHS {d | dd} [, year]}
MONTHS pode ser: jan | feb | mar | apr | may | jun | jul | aug | sep | oct | nov | dec
Um exemplo seria:
schedule=last_weekday_before_15_from_15:53_Oct_23,_1999_retry_after_1_hour
ou
schedule=every_first_fri_of_month_from_15:53_Oct_23,_1999_retry_3_after_1_hour
Observe que, em vez do espaço entre os elementos da string, foi usado o sublinhado para evitar a utilização de
aspas duplas.
SERVER
Este parâmetro informa o nome do endereço TNS do Reports Server. Este parâmetro é aplicável apenas ao RWCLI60.
♦ Sintaxe: [Server=]<tnsname>
TERM
Corresponde ao tipo de terminal no qual a execução será realizada. Utilizado quando o resultado for apresentado
no vídeo ou houver tela de parâmetro a ser mostrada. Esse parâmetro somente é utilizado em Character Mode. Não
aplicável ao Report Builder.
♦ Sintaxe: [Term=]<tipo do terminal>
THOUSANDS
Este parâmetro determina o símbolo a ser usado como separador de milhar para formatos numéricos.
O valor default para esse parâmetro é dado pela NLS em uso.
♦ Sintaxe: [Thousands=]<símbolo separador de milhar>
TOLERANCE
Indica o tempo (em minutos) de tolerância para detecção de jobs em duplicata. Aplicável apenas ao RWCLI60.
♦ Sintaxe: [Tolerance=]<número>
TRACEFILE
Indica o nome do arquivo no qual o Reports Runtime gravará informações de trace.
♦ Sintaxe: [Tracefile=] <nome do arquivo>
As informações de trace somente serão gravadas se executarmos um .Rdf. Não podemos especificar a geração de informações desse tipo quando
executamos um .Rep.
TRACEMODE
Indica se o Reports Runtime deve adicionar informações de trace ao arquivo ou substituir todo o conteúdo do arquivo.
♦ Sintaxe: [Tracemode=] {Trace_Append | Trace_Replace}
TRACEOPTS
Determina quais informações devem ser geradas para o arquivo. O valor default é Trace_All.
[Traceopts=] {Trace_Err | Trace_Prf | Trace_App | Trace_Pls |
A utilização de parênteses indica a simultaneidade de opções. Por exemplo, (Trace_App, Trace_Prf) indica que
desejamos que ambas as opções sejam aplicadas.
As opções possuem o significado a seguir:
♦ Trace_All – Indica que todas as possibilidades de análise devem ser aplicadas.
♦ Trace_App – Indica que informações de todos os objetos do relatório devem ser registradas.
♦ Trace_Brk – Indica o registro de todos os pontos de interrupção encontrados no relatório.
♦ Trace_Err – Indica a inclusão de todas as mensagens de erro e aviso no arquivo gerado.
♦ Trace_Pls – Indica a coleta de informações de todos os objetos PL/SQL no arquivo gerado.
♦ Trace_Prf – Determina a coleta de informações estatísticas de performance no arquivo gerado.
♦ Trace_Sql – Determina o registro de informações sobre todos os comandos de SQL no arquivo gerado.
♦ Trace_Tms – Determina a inclusão de um timestamp para cada entrada no arquivo de trace.
USERID
Indica o usuário e senha do Oracle com indicação opcional da string do SQL*Net ou especificações para o ODBC
no caso de acesso a um conjunto de dados não-Oracle. As sintaxes disponíveis são apresentadas a seguir:
♦ Sintaxe: [Userid=] username [ / password ] [ @database ].
♦ [Userid=] [ user [ /password ] ] @ODBC:datasource[:database].
♦ [Userid=] [ user [ /password ] ] @ODBC:*
CMDFILE
O arquivo de comandos contém os argumentos necessários à execução do conversor.
Este parâmetro determina o nome do arquivo de comandos. Os comandos devem ser armazenados no arquivo
segundo a sintaxe: <nome do parâmetro> = <valor>.
♦ Sintaxe: [Cmdfile=]<nome do arquivo>
CUSTOMIZE
Este parâmetro especifica um arquivo XML ou uma lista de arquivos XML que desejamos aplicar ao relatório
identificado no parâmetro origem (source). Este arquivo (ou arquivos) contém especificações como fontes, cores,
etc., que visam modificar a definição do relatório.
♦ Sintaxe: [Customize=]<nome arq>.xml | (<nome arq1>.xml, <nome arq2>.xml, …)
DEST
Indica o nome dos relatórios ou bibliotecas de saída da conversão, ou seja, o nome final dos arquivos convertidos.
Vários nomes podem ser fornecidos simultaneamente para que a conversão seja múltipla. Caso este parâmetro não
seja informado, o nome do arquivo destino será igual ao nome do arquivo origem com a extensão adequada,
exceto para REXFILE, cujo nome default é expdat.rex.
♦ Sintaxe: [Dest=] { <sname> | ( <sname1>, <sname2>, <sname3> …) }
DTYPE
Indica o formato do arquivo de saída (destination) da conversão.
♦ Sintaxe: [Dtype=] {DATABASE | PLLDB | PLDFILE | PLLFILE | RDFFILE | REPFILE | REXFILE | TDFFILE | XML}
Onde:
♦ DATABASE – Indica que o arquivo destino deve ser armazenado no banco de dados.
♦ PLLDB – Indica que a biblioteca (de PL/SQL) deve ser armazenada no banco de dados.
♦ PLDFILE – Indica que a biblioteca (de PL/SQL) deve ser armazenada no sistema operacional em arquivos de
formato ASCII (extensão PLD).
♦ PLLFILE – Indica que a biblioteca (de PL/SQL) deve ser armazenada no sistema operacional em arquivos contendo
o fonte e o executável (extensão PLL).
♦ RDFFILE – Indica que o arquivo destino deve ser um relatório e que será armazenado no sistema operacional
(extensão RDF).
♦ REPFILE – Indica que o arquivo destino deve ser um relatório e que será armazenado no sistema operacional
(extensão REP).
♦ REXFILE – Indica que o arquivo destino deve ser um relatório que será armazenado em arquivos de texto no
sistema operacional (extensão REX).
♦ TDFFILE – Indica que o arquivo destino deve ser um gabarito que será armazenado no sistema operacional
(extensão TDF).
♦ XML – Indica que o arquivo destino deve ser armazenado no sistema operacional (extensão XML).
Ao convertermos um relatório para um gabarito (template), somente os objetos presentes na área de margem são
usados no template. Os objetos presentes no corpo são ignorados.
DUNIT
Determina a unidade de dimensionamento para a qual o relatório deve ser convertido. Se este parâmetro for
omitido a unidade default é igual à unidade origem. Caso informado deve possuir valor diferente da unidade de
dimensionamento do arquivo origem.
♦ Sintaxe: [Dunit=] {CENTIMETER | CHARACTER | INCH | POINT}
FORMSIZE
Indica o tamanho da tela de parâmetros (Runtime Parameter Form) para o relatório convertido. O valor será
considerado de acordo com a unidade de dimensionamento do relatório de saída.
♦ Sintaxe: [Formsize=] <largura> X <altura>
Para unidade de dimensionamento diferente de CHARACTER podemos usar valores decimais (por exemplo 8.5 x 11).
LOGFILE
Indica o nome do arquivo para o qual as mensagens de erro e aviso serão enviadas durante o processo de conversão.
♦ Sintaxe: [Logfile=] <nome de arquivo>
OVERWRITE
Indica se o conversor deverá sobrescrever arquivos de destino já presentes no meio de armazenamento escolhido.
♦ Sintaxe: [Overwrite=] {Yes | No | Prompt }
PAGESIZE
Determina o tamanho da página física do relatório. O tamanho especificado deve ser suficiente para conter o
layout definido; caso contrário, o relatório não será executado. A unidade dessa medida depende da especificação
de Unidade de Dimensionamento (Unit of Measurement).
♦ Sintaxe: [Pagesize=] <largura> X <altura>
SOURCE
Este parâmetro determina o nome do arquivo ou arquivos a serem convertidos. Se os arquivos estiverem armazenados
no banco de dados podemos usar os caracteres especiais % e _ (sublinhado) para indicar o nome dos arquivos.
♦ Sintaxe: [Source=] { <sname> | ( <sname1>, <sname2>, <sname3> …) }
STYPE
Indica o formato do arquivo de entrada (source) a ser convertido.
♦ Sintaxe: [Stype=] {DATABASE | PLLDB | PLDFILE | PLLFILE | RDFFILE | REXFILE | XML}
Onde:
♦ DATABASE – Indica que o arquivo origem está armazenado no banco de dados.
♦ PLLDB – Indica que a biblioteca (de PL/SQL) está armazenada no banco de dados.
♦ PLDFILE – Indica que a biblioteca (de PL/SQL) está armazenada no sistema operacional em arquivos de formato
ASCII (extensão PLD).
♦ PLLFILE – Indica que a biblioteca (de PL/SQL) está armazenada no sistema operacional em arquivos contendo o
fonte e o executável (extensão PLL).
♦ RDFFILE – Indica que o arquivo origem é um relatório e que está armazenado no sistema operacional (extensão RDF)
♦ REXFILE – Indica que o arquivo origem é um relatório armazenado em arquivos de texto no sistema operacional
(extensão REX).
♦ XML – Indica que o arquivo origem está armazenado no sistema operacional (extensão XML).
USERID
Indica o usuário e senha do Oracle com indicação opcional da string do SQL*Net ou especificações para o ODBC
no caso de acesso a um conjunto de dados não-Oracle. As sintaxes disponíveis são apresentadas a seguir:
♦ Sintaxe: [Userid=] username [ / password ] [ @database ].
BLOCK_MENU
Automaticamente apresenta o diálogo Block Menu como primeira tela a tempo de execução em vez do Form.
♦ Sintaxe: [Block_Menu=] {Yes | No}
BUFFER_RECORDS
Determina que o número de registros armazenados (buffered) em memória será a quantidade de linhas apresentadas
adicionado de três (para cada bloco). Se um bloco recuperar para qualquer quantidade de registros acima desse
valor, o Form Builder armazenará os registros adicionais em um arquivo em disco.
Se esse parâmetro for igual a No, a quantidade de linhas armazenadas em memória será aquela especificada na
propriedade Buffered de cada bloco.
♦ Sintaxe: [Buffer_Records=] {Yes | No}
DEBUG
Determina a execução em modo de depuração. Se for encontrada a rotina Break durante a execução da aplicação,
haverá a interrupção do programa para acompanhamento passo a passo.
♦ Sintaxe: [Debug=] {Yes | No}
Para acionarmos o modo de depuração em ambiente não-Windows, devemos executar o depurador passando o parâmetro para ele: IFDBG60
module=<modulo> userid=<user>/<senha> debug=YES.
DEBUG_MESSAGES
Apresenta mensagens de acompanhamento sobre a execução de triggers enquanto o Form está em execução.
♦ Sintaxe: [Debug_Messages=] {Yes | No}
HELP
Mostra diálogos com a sintaxe destes parâmetros.
♦ Sintaxe: [Help=] {Yes | No}
INTERACTIVE
Boleano (True ou False). Indica se as respostas (telas de saída) deverão ou não ser mostradas no vídeo. Pode ser
utilizada juntamente com as opções Keyin e Output_File. Aplicável apenas a terminais Character Mode.
♦ Sintaxe: [Interactive=] {Yes | No}
KEYIN
Determina o nome de um arquivo de onde serão lidas todas as ações a serem executadas durante a sessão. Esse
arquivo deve conter toda a seqüência de teclas para execução, salva, navegação, etc. Aplicável apenas a terminais
Character Mode.
♦ Sintaxe: [KeyIn=] <nome do arquivo>
KEYOUT
Determina o nome de um arquivo onde serão gravadas todas as teclas utilizadas durante a execução da aplicação.
Só aplicável a terminais Character Mode.
♦ Sintaxe: [KeyOut=] <nome do arquivo>
LOG
Indica o nome do arquivo a ser gerado num processo de Form Runtime Diagnostics. Veja o parâmetro Record.
♦ Sintaxe: [LOG=] { <nome do arquivo> }
LOGON_SCREEN
Este parâmetro, quando True, força a presença da tela de Login. Neste caso, o Form Runtime ignora o userid e
password informados.
♦ Sintaxe: [Logon_Screen=] {Yes | No}
OPTIMIZESQL
Especifica que o Form irá otimizar os comados SQL processados no estilo V2 pelo compartilhamento de cursores.
Por default, o Form associa um cursor para cada comando SQL executado em V2. Isso otimiza a performance, uma
vez que o parse só é executado uma vez, ou seja, somente a primeira vez em que o comando for executado para a
sessão. Quando OptimizeSQL recebe No, o Form associa um único cursor para todos os comandos SQL executados
em V2. Isso economiza memória; por outro lado, perde-se em performance uma vez que o parse será executado
cada vez que o comando for executado. Essa opção não tem efeito para triggers escritos em PL/SQL.
♦ Sintaxe: [OptimizeSQL=] {Yes | No}
OPTIMIZETP
Por default, o Form associa um cursor separado para cada comando SQL que um Form executa implicitamente
num Post ou Query. Quando OptimizeTP recebe No, o Form irá associar um cursor separado apenas para cada
query Select. Todos os outros comandos SQL implícitos compartilharão cursores. Isso significa que todos os Insert,
Update, Delete e Select For Update devem ser parsed cada vez que forem executados.
♦ Sintaxe: [OptimizeTP=] {Yes | No}
OPTIONS_SCREEN
Mostra a janela com esta lista de opções a tempo de execução. Aplicável somente a ambientes GUI.
♦ Sintaxe: [Options_Screen=] {Yes | No}
OUTPUT_FILE
Determina o nome de um arquivo onde todas as respostas para o vídeo serão gravadas. Aplicável apenas a terminais
Character Mode.
♦ Sintaxe: [Output_File=] <nome do arquivo>
PECS
Executa o Form Runtime com Performance Event Collection Services (Pecs), habilitada para coleta de informações
para análise de performance.
♦ Sintaxe: [Pecs=] {On | Off | Full}
Pecs é uma ferramenta para análise de performance que possibilita as seguintes informações:
♦ Utilização de recursos (tempo de CPU por evento ou transações processadas por hora).
♦ Localização de problemas de performance (tempo total por evento).
♦ Análise de utilização de objetos (quando um objeto específico, tais como um trigger, alerta ou janela, é visitado
durante a execução).
♦ Análise linha a linha (para código de PL/SQL em triggers e procedures).
Para análise apenas da utilização dos objetos, escolha a opção On. Para análise linha a linha, além da utilização dos
objetos, escolha a opção Full (a compilação deve ter sido feita com Debug=On).
QUERY_ONLY
Aciona a aplicação em modo de consulta apenas.
♦ Sintaxe: [Query_Only=] {Yes | No}
QUIET
Aciona a aplicação em modo silencioso. Nessa forma de execução, a aplicação não produz beep audível.
♦ Sintaxe: [Quiet=] {Yes | No}
RECORD
Determina que seja gerado um arquivo para acompanhamento das ações efetuadas pelo usuário durante a execução
da aplicação.
A utilização desse parâmetro fará com que seja gerado um arquivo no diretório corrente de trabalho com o nome
Collect_<PID>. Para determinação de um nome específico, devemos usar simultaneamente o parâmetro Log.
♦ Sintaxe: [RECORD=] { Collect }
STATISTICS
Apresenta uma mensagem ao término da sessão que indica o número máximo de cursores simultaneamente abertos
durante a execução.
Este parâmetro envia o comando Alter session set Sql_Trace True para o banco de dados. Esse comando cria um arquivo
no ambiente servidor contendo informações estatísticas relativas aos comandos SQL executados durante a sessão.
♦ Sintaxe: [Statistics=] {Yes | No}
TERM
Este parâmetro determina o nome do arquivo de recursos para o Oracle terminal. Se não for especificado, o Form
Runtime utilizará o padrão específico para a plataforma. Por exemplo, FmrUsw para ambientes Windows.
♦ Sintaxe: [Term=] <nome do arquivo de recursos>
USESDI
Indica se o Form Runtime deve utilizar o padrão SDI. O default é NO, indicando que o padrão a ser utilizado é o
MDI, onde a janela do Form Runtime é visível. No padrão SDI será mostrada apenas a janela da aplicação.
♦ Sintaxe: [UseSdi=] {Yes | No}
WINDOW_STATE
Determina o estado da janela MDI no início da aplicação. Podemos informar: Maximize, Minimize ou Normal (default).
♦ Sintaxe: [Window_State=] {Maximize | Minimize | Normal}
BATCH
Suprime as mensagens interativas. Útil para geração em batch.
♦ Sintaxe: [Batch=] {Yes | No}
BUILD
Esta opção deve ser utilizada em conjunto com Upgrade. Quando recebe Yes (default) e Upgrade também, o Form
Compiler criará dois arquivos como parte do processo de atualização (upgrade): um fonte (.Fmb ou .Mmb) e outro
executável (.Fmx ou .Mmx). Se Build receber No, o executável não é criado.
♦ Sintaxe: [Build=] {Yes | No}
COMPILE_ALL
Compila todas as unidades de programa dentro do módulo específico.
♦ Sintaxe: [Compile_All=] {Yes | No}
CRT_FILE
Indica o nome do arquivo CRT a ser utilizado na atualização (upgrade) das versões 2.0 ou 2.3.
♦ Sintaxe: [Crt_File=] <nome do arquivo>
DEBUG
Cria um Form capacitado para depuração. Deve ser utilizado se desejamos executar a aplicação com depuração.
♦ Sintaxe: [Debug=] <nome do arquivo>
DELETE
Remove o módulo diretamente do banco de dados.
♦ Sintaxe: [Delete=] {Yes | No}
EXTRACT
Extrai o módulo do banco de dados criando um arquivo com o mesmo nome do módulo.
♦ Sintaxe: [Extract=] {Yes | No}
HELP
Aciona a tela de ajuda do Form Builder.
♦ Sintaxe: [Help=] {Yes | No}
INSERT
Inclui o módulo diretamente no banco de dados. Essa opção não age juntamente com a opção upgrade.
♦ Sintaxe: [Insert=] {Yes | No}
LOGON
Especifica se o Form Compiler deve estabelecer conexão com o banco de dados. Se o módulo contiver qualquer
código de PL/SQL com referência a tabelas, a conexão será obrigatória.
♦ Sintaxe: [Logon=] {Yes | No}
MODULE_ACCESS
Determina se desejamos abrir e salvar o módulo para o sistema operacional ou para o banco de dados.
♦ Sintaxe: [Module_Access=] {File | Database}
MODULE_TYPE
Determina o tipo do módulo corrente.
♦ Sintaxe: [Module_Type=] {Form | Menu | Library}
NOFAIL
Indica se o Form Compiler deve adicionar a palavra-chave Nofail quando atualizando (upgrade) a partir do Forms
2.0 (somente para essa versão).
♦ Sintaxe: [Nofail=] {Yes | No}
OPTIONS_SCREEN
Aciona a janela de opções. Aplicável somente a ambientes Gui.
♦ Sintaxe: [Options_Screen=] {Yes | No}
OUTPUT_FILE
Especifica o nome do arquivo a ser gerado.
Quando utilizado juntamente com Upgrade, esse parâmetro especifica o nome do módulo atualizado (.Fmb ou
.Mmb ou .Pll) e seu correspondente executável (.Fmx ou .Mmx).
♦ Sintaxe: [Output_File=] <nome do arquivo>
PARSE
Converte o arquivo-texto de um módulo (.Fmt ou .Mmt ou .Pld) para o formato binário correspondente (.Fmb ou
.Mmb ou .Pll).
♦ Sintaxe: [Parse=] {Yes | No}
SCRIPT
Converte um arquivo formato binário de um módulo (.Fmb ou .Mmb ou .Pll) para o arquivo-texto correspondente
(.Fmt ou .Mmt ou .Pld).
♦ Sintaxe: [Script=] {Yes | No}
STATISTICS
Mostra uma mensagem ao fim da sessão indicando o número dos vários objetos no Form compilado.
♦ Sintaxe: [Statistics=] {Yes | No}
Os objetos são grupados da seguinte forma:
♦ Form Statistics.
♦ Trigger Statistics.
♦ Block Statistics.
♦ Item Statistics.
STRIP_SOURCE
Remove o código-fonte do arquivo Library e gera um arquivo Library somente contendo pcode. Deve-se utilizar
também Output_File.
♦ Sintaxe: [Strip_Source=] {Yes | No}
UPGRADE
Atualiza (upgrade) módulos da versão SQL*Forms 2.0, 2.3 ou 3.0 para a versão Forms 4.5 ou do SQL*Menu 5.0 para
um Forms 4.5 ou do Forms 4.5 ou 5.0 para 6.0 ou 6i.
Para atualizarmos da versão SQL*Forms 3.0, não devemos informar a versão. Para as demais versões, o parâmetro
Version deve ser informado.
♦ Sintaxe: [Upgrade=] {Yes | No}
UPGRADE_ROLES
Atualiza (upgrade) a tabela de privilégios do SQL*Menu 5.0 para roles do banco de dados.
♦ Sintaxe: [Upgrade_Roles=] {Yes | No}
VERSION
Indica a versão original para atualização (upgrade). Deve ser utilizada juntamente com o parâmetro Upgrade.
♦ Sintaxe: [Version=] <número da versão>
Para atualização da versão 2.0 e 2.3, esse parâmetro deve ser informado. Para atualização da versão 3.0, omitido.
WIDEN_FIELDS
Quando efetuamos uma atualização (upgrade) para a versão 4.5, pode ocorrer a perda de até um caracter para cada
campo a fim de que o item seja apresentado em terceira dimensão (bevel). Esse parâmetro determina que seja
adicionado, automaticamente, um caracter à propriedade Display Width de cada campo.
Essa opção deve ser utilizada juntamente com Upgrade.
♦ Sintaxe: [Widen_Fields=] {Yes | No}
Capítulo 20
OS MENUS DO REPORT BUILDER
Neste capítulo, apresentaremos os menus presentes no Report Builder e explicações resumidas de sua funcionalidade,
discutida mais amplamente no tópico referente ao assunto relacionado no Capítulo 8.
NOVO (NEW)
Cria um novo módulo. O tipo de módulo dependerá do nó selecionado. Podemos escolher uma das seguintes opções:
♦ Relatório – Cria um novo módulo do tipo Report.
♦ Gabarito – Cria um novo módulo do tipo Template.
♦ Consulta externa – Cria um novo módulo do tipo External Query.
♦ Biblioteca PL/SQL – Cria um novo módulo do tipo Library.
ABRIR (OPEN)
Abre um módulo já existente. Poderá ser apresentado um diálogo para que o usuário informe o meio de
armazenamento: disco ou banco de dados. A seguir, será apresentada uma lista dos objetos do tipo correspondente
no meio escolhido. O tipo de módulo dependerá do nó selecionado.
FECHAR (CLOSE)
Fecha o módulo corrente, ou seja, aquele que detém o foco.
SALVAR (SAVE)
Salva o módulo corrente.
REVERTER (REVERT)
Desfaz as modificações efetuadas no módulo desde sua última salva, ou seja, reverte a cópia para o mesmo estado
daquela que está em disco (se existir).
IMPORTAR (IMPORT)
Permite a importação de desenhos (formato Oracle ou CGM), imagens (formatos diversos, dentre eles Tiff, Bmp e
Pcx), textos (formato Txt) e paletas de cores (extensão Pal) existentes em arquivos do sistema operacional (só
habilitado quando o Editor de Layout tiver o foco).
EXPORTAR (EXPORT)
Permite a exportação de desenhos, imagens, textos e paletas de cores para arquivos do sistema operacional (só
habilitado quando o Editor de Layout tiver o foco).
CONECTAR (CONNECT)
Apresenta um diálogo que permite ao usuário informar código, senha e string de conexão ao banco de dados para
que seja possível estabelecer acesso.
DESCONECTAR (DISCONNECT)
Desfaz a conexão previamente estabelecida.
EXPRESS (EXPRESS)
Trata-se de um submenu com duas opções: Conectar (Connect) e Desconectar (Disconnect). A opção Conectar
apresenta um diálogo para que possamos estabelecer o domínio, usuário, password e a conexão ao Express Server.
ADMINISTRAÇÃO (ADMINISTRATION)
É um submenu que possui diversas ações administrativas, principalmente ligadas ao armazenamento da aplicação
no banco de dados.
RENOMEAR (RENAME)
Permite a modificação do nome de um módulo armazenado no banco de dados.
DELETAR (DELETE)
Permite a remoção de módulos armazenados no banco de dados.
CONVERTER (CONVERT)
Cria uma cópia do módulo (relatório ou biblioteca de PL/SQL) em um formato diferente e/ou em um meio de
armazenamento diferente (banco de dados ou sistema operacional).
IMPRIMIR (PRINT)
Imprime a janela corrente para uma impressora.
CORREIO (MAIL)
Em plataformas Windows, podemos postar (e-mail) os relatórios através do Microsoft Messaging Application Pro-
gramming Interface (MAPI). Para que essa ação funcione, devemos ter instalado uma aplicação MAPI cliente (por
exemplo, Microsoft Exchange).
DISTRIBUIR (DISTRIBUTE)
Esta opção executa o relatório a fim de gerar para os destinos especificados nas listas de distribuição. Caso não
sejam encontradas listas, ocorre um erro e o relatório não é executado.
SAIR (EXIT)
Encerra o Report Builder.
RECORTAR (CUT)
Recorta a área corrente selecionada transferindo os dados para o Clipboard.
COPIAR (COPY)
Copia a área corrente selecionada, transferindo os dados para o Clipboard.
COLAR (PASTE)
Coloca os dados que estiverem no Clipboard na área selecionada.
LIMPAR (CLEAR)
Recorta a área corrente selecionada sem efetuar qualquer transferência.
DUPLICAR (DUPLICATE)
Duplica o objeto selecionado.
VÍNCULOS (LINKS)
Mostra uma lista de links para objetos OLE2.
OBJECT (OBJECT)
Mostra um submenu com as ações válidas para o objeto OLE2 criado (por exemplo: abrir, editar, imprimir, converter).
RÉGUAS (RULERS)
Apresenta ou não as réguas vertical e horizontal do layout.
GRADE (GRID)
Apresenta ou não a grade.
JUSTIFICAR (JUSTIFY)
Permite o alinhamento de um texto à direita, esquerda, centralizado, início ou fim dentro do objeto selecionado.
DIREÇÃO (DIRECTION)
Determina a direção de desenvolvimento do objeto. Ajustável à Nls_language em uso.
BEVEL (BEVEL)
Permite a escolha de sombreados que darão noção de perspectiva ao objeto.
TRAÇO (DASH)
Permite a definição de linhas pontilhadas, linha cheia, traço e ponto para objetos gráficos (boilerplates gráficos).
SETA (ARROW)
Permite a configuração de diversos tipos de setas no desenho.
BORDA (BORDER)
Permite que determinemos quais as bordas do objeto que ficarão visíveis (topo, base, esquerda e direita).
MOEDA (CURRENCY)
Inclui o caracter indicativo da moeda, ou seja, do símbolo financeiro local (L) na máscara de edição.
PERCENTUAL (PERCENT)
Inclui o caracter indicativo de percentual (%) na máscara de edição.
VÍRGULAS (COMMAS)
Inclui o símbolo separador de milhar (G) na máscara de edição.
GERAL (GENERAL)
Configurações aplicáveis aos objetos gráficos em geral.
IMAGEM (IMAGE)
Configurações aplicáveis aos boilerplates do tipo imagem.
ARCO (ARC)
Configurações aplicáveis aos boilerplates do tipo arco.
RÉGUAS (RULERS)
Apresenta um diálogo composto de diversas informações, a saber:
♦ Unidades (Units) – São botões (radio buttons) que especificam a unidade de dimensionamento usada para as
réguas no editor corrente. Podemos optar entre: centímetros, polegadas, pontos ou caracteres.
♦ Tamanho da Célula de Caracteres (Character Cell Size) – Especifica o tamanho de uma célula de caracter na
unidade pontos (horizontal e vertical).
♦ Espaçamento de Grade (Grid Spacing) – Especifica o intervalo entre as linhas de grade que serão apresentadas
usando a unidade da régua. Por exemplo, se a unidade é polegada e o espaçamento é 0.5 significa que haverá
um ponto de grade a cada 0.5 polegadas.
♦ Número de Pontos de Ajuste por Espaçamento de Grade (Number of Snap Points per Grid Spacing) – Determina
o número de pontos de alinhamento para cada linha de grade.
AGRUPAR (GROUP)
Agrupa dois ou mais objetos.
DESAGRUPAR (UNGROUP)
Libera os objetos anteriormente grupados.
FECHAR (COLLAPSE)
Diminui, fecha o detalhamento do objeto selecionado no navegador.
CRIAR (CREATE)
Cria um novo objeto sob o nó corrente.
DELETAR (DELETE)
Remove o objeto selecionado.
COMPILAR (COMPILE)
Compila os códigos de PL/SQL ainda não compilados (Incremental) ou todos (All).
RASTREAR (TRACE)
Cria um arquivo de Trace para acompanhamento da execução do relatório. Apresenta um diálogo em que
especificamos quais ações desejamos avaliar. Podemos escolher algumas delas ou todas:
♦ Erros e advertências (warnings) encontrados.
♦ Informações de Perfil (Profile).
♦ Pontos de Interrupção (Breakpoints) encontrados.
♦ Objetos do Report processados.
♦ PL/SQLs executados.
♦ SQLs executados.
♦ Timestamp.
♦ Distribuições realizadas.
♦ Todos.
OBJECT NAVIGATOR
Aciona o Navegador de Objetos.
PREFERÊNCIAS (PREFERENCES)
Aciona o diálogo de Preferências contendo as pastas Geral, Acessar, Assistentes, Valores de Runtime e Definições de
Runtime para que especifiquemos características para o ambiente.
QUICK TOUR
Aciona o Browser para apresentação de um tour pelas diversas ferramentas do pacote Developer. Mostra a capacidade
de cada produto. Bastante visual.
CUE CARDS
Apresenta um conjunto de diálogos que fornece exemplos (inclusive animados) a respeito de algumas das tarefas
que podemos realizar com o Report Builder. Por exemplo: executar uma aplicação, construir uma aplicação simples,
modificar uma aplicação, construir uma aplicação Mestre-Detalhe etc. Vale a pena dar uma olhada!
MANUAIS (MANUALS)
Permite o acesso a alguns dos manuais fornecidos pela Oracle no CD-Rom.
Capítulo 21
BUILT-INS DO REPORTS
Neste capítulo, listamos as rotinas presentes no nó Pacotes Embutidos (Built-in Packages) do Report Builder que já
não tenham sido listadas no Capítulo 15 (referentes ao Form Builder) e incluiremos uma descrição resumida da
ação da rotina. As rotinas sem documentação foram omitidas do capítulo.
Antes de utilizar determinada rotina, verifique informações complementares no Help da ferramenta: por exemplo,
se se tratar de uma procedure ou função, o que deve ser passado nos parâmetros, o que pode ser recebido, etc.
SRW
Este é o pacote-padrão do Report Builder, ou seja, é aquele pacote que contém as rotinas básicas para utilização
dentro de um relatório. Com ele podemos alterar as propriedades de um objeto (Set_Attr), determinar a quantidade
máxima de linhas de uma query (Set_MaxRow), acionar outro relatório (Run Report) e muitas outras funcionalidades,
algumas delas já utilizadas ao longo dos exemplos e exercícios do Capítulo 8.
♦ Procedure Srw.Add_Definition(Xml) – Esta rotina obtém uma definição XML do relatório armazenada em uma
coluna ou variável (Informada no parâmetro) e adiciona-a ao buffer. Após esta operação devemos executar a
rotina Apply_Definition para aplicar esta definição.
♦ Procedure Srw.Apply_Definition(Filename) – Esta rotina pode ser executada sem parâmetro. Neste caso aplicará
as definições encontradas no buffer. Se for informado um nome de arquivo, este deve conter definições XML,
que serão aplicadas diretamente.
♦ Procedure Srw.Break – Esta rotina interrompe a execução do relatório e apresenta os valores correntes de todas
as colunas e parâmetros. Quando a tela contendo estes valores é fechada, o relatório prossegue normalmente.
♦ Procedure Srw.Do_Sql(Sql_Statement_String) – Executa o comando SQL especificado. Esse comando pode ser de
DDL ou DML. Os comandos de DML embutidos no PL/SQL do relatório são mais rápidos do que executados
através do Srw.Do_Sql.
♦ Procedure Srw.Get_Report_Name(String) – O parâmetro passado é de saída, onde será retornado o nome do
relatório (nome do módulo).
♦ Função Srw.Get_Value(Col_Name, Fmt_Msk) – Retorna o valor da coluna (cujo nome foi passado como parâmetro)
usando a máscara de formatação especificada no segundo parâmetro. A coluna se refere a um elemento do
Modelo de Dados.
♦ Procedure Srw.Get_Page_Num(Page_Num) – Retorna o número da página corrente.
♦ Procedure Srw.Geterr_Run – Retorna uma mensagem de erro se o Report Builder receber um erro enquanto
estiver executando a procedure Srw.Run_Report.
♦ Procedure Srw.Message(Msg_Number, Msg_Text_String) – Mostra uma mensagem com o número e texto
especificados. A mensagem é apresentada com o formato MSG-<número da mensagem>: <texto da mensagem>.
♦ Procedure Srw.Reference(Bind_Variable) – Faz com que o Report Builder inclua o objeto referenciado na lista de
dependências do PL/SQL.
♦ Procedure Srw.Run_Report(Command_Line) – Aciona o RWRUN60 com a string que informarmos como
parâmetro. O parâmetro da procedure corresponde a uma linha de comando do programa RWRUN60.
♦ Procedure Srw.Set_After_Form_Html (Type, String) – Inclui qualquer texto, gráfico ou HTML que desejarmos no
fim (rodapé) da tela de parâmetros. O parâmetro Type pode ser preenchido com Srw.File_Escape, indicando que
a string contém o nome de um arquivo, ou Srw.Text_Escape, indicando que a string contém o texto.
♦ Procedure Srw.Set_After_Page_Html (Type, String) – Inclui qualquer texto, gráfico ou HTML que desejarmos no
fim (rodapé) de cada página do relatório. O parâmetro Type pode ser preenchido com Srw.File_Escape, indicando
que a string contém o nome de um arquivo, ou Srw.Text_Escape, indicando que a string contém o texto.
♦ Procedure Srw.Set_After_Printing_Code (Code) – Esta rotina inclui uma seqüência de escape após cada linha do objeto.
♦ Procedure Srw.Set_After_Report_Html (Type, String) – Esta rotina inclui qualquer texto, gráfico ou HTML que
desejarmos no fim do relatório todo. O parâmetro Type pode ser preenchido com Srw.File_Escape, indicando
que a string contém o nome de um arquivo, ou Srw.Text_Escape, indicando que a string contém o texto.
♦ Procedure Srw.Set_Attr(Object_Id, Attr) – Aplica atributos tais como fonte, cor, tamanho e objetos do layout. Os
atributos desejados devem ser associados à máscara; em seguida, os valores destes atributos devem ser especificados
para a máscara e, finalmente, a máscara deve ser atribuída ao objeto com o uso da procedure apresentada. Veja
detalhes de utilização na ajuda do Report Builder.
♦ Procedure Srw.Set_Background_Border_Color (Color) – Especifica uma cor de background para a borda do objeto
(é ignorada em Character Mode). De acordo com o tipo de textura (pattern), esta cor pode não ser vista. Por
exemplo, se Pattern é sólido, a cor de background não é apresentada, somente a cor de foreground é apresentada.
♦ Procedure Srw.Set_Background_Fill_Color (Color) – Especifica uma cor de background para o objeto (é ignorada
em Character Mode). De acordo com o tipo de textura (pattern), esta cor pode não ser vista. Por exemplo, se
Pattern é sólido, a cor de background não é apresentada, somente a cor de foreground é apresentada.
♦ Procedure Srw.Set_Before_Form_Html (Type, String) – Inclui qualquer texto, gráfico ou HTML que desejarmos
no início (topo) da tela de parâmetros. O parâmetro Type pode ser preenchido com Srw.File_Escape, indicando
que a string contém o nome de um arquivo, ou Srw.Text_Escape, indicando que a string contém um texto.
♦ Procedure Srw.Set_Before_Page_Html (Type, String) – Inclui qualquer texto, gráfico ou HTML que desejarmos no
início (topo) de cada página do relatório. O parâmetro Type pode ser preenchido com Srw.File_Escape, indicando
que a string contém o nome de um arquivo, ou Srw.Text_Escape, indicando que a string contém o texto.
♦ Procedure Srw.Set_Before_Printing_Code (Code) – Inclui uma seqüência de escape antes de cada linha do objeto.
♦ Procedure Srw.Set_Before_Report_Html (Type, String) – Inclui qualquer texto, gráfico ou HTML que desejarmos
no início do relatório todo. O parâmetro Type pode ser preenchido com Srw.File_Escape, indicando que a string
contém o nome de um arquivo, ou Srw.Text_Escape, indicando que a string contém o texto.
♦ Procedure Srw.Set_Bookmark (Bookmark) – Associa um Marcador de Livro com o objeto e especifica uma string que
aparecerá no frame (para o Marcador de Livro) do documento HTML principal (ou do PDF). Se o usuário pressionar
o mouse sobre o Marcador (no Browser), ocorre a navegação para o objeto, que aparecerá no topo da janela.
♦ Procedure Srw.Set_Border_Pattern (Pattern) – Especifica a textura (pattern) para a borda do objeto. Esse atributo
é ignorado em modo Caracter.
♦ Procedure Srw.Set_Border_Width (Width) – Especifica a largura da borda do objeto em paicas.
♦ Procedure Srw.Set_Charmode_Text (Style) – Especifica o estilo da fonte de um campo (Char, Date ou Number).
Esse atributo é ignorado em relatórios Bit-Mapped. Os valores válidos são: srw.reverse_texta, srw.bold_texta,
srw.reversebold_texta, srw.underline_texta, srw.underlinereverse_texta, srw.reverseboldunderline_texta,
srw.plain_texta.
♦ Procedure Srw.Set_Custom_Spacing (Spacing) – Determina o espacejamento interno de campos do tipo Char,
Date ou Number e para boilerplates de texto. Esse atributo é ignorado em modo Caracter. O valor informado é
numérico em unidades VGS.
♦ Procedure Srw.Set_Display_Name (Text_String) – Especifica o texto que aparecerá em um pop-up quando o
cursor se move sobre o objeto imagem em um relatório com saída HTML ou HTMLCSS.
♦ Procedure Srw.Set_Field_Char(Object_Id, Field_Char) – Atribui o valor especificado ao field (objeto do layout) informado.
♦ Procedure Srw.Set_Field_Date(Object_Id, Field_Date) – Atribui o valor especificado ao field (objeto do layout) informado.
♦ Procedure Srw.Set_Field_Num(Object_Id, Field_Num) – Atribui o valor especificado ao field (objeto do layout) informado.
♦ Procedure Srw.Set_Field (object_id, text | number | date) – Atribui um valor (caracter, numérico ou data) para
um campo (de acordo com seu tipo). O parâmetro Object_id deve ser sempre zero.
♦ Procedure Srw.Set_Fill_Pattern (Pattern) – Especifica a textura (pattern) para o objeto. Esse atributo é ignorado
em modo Caracter.
♦ Procedure Srw.Set_Font_Face (Face) – Especifica o tipo de fonte (por exemplo, Arial) para o campo. Esse atributo
é ignorado em modo Caracter.
♦ Procedures Srw.Set_Font_Size (Size) – Especifica o tamanho da fonte para o campo. Este atributo é ignorado em
modo Caracter.
♦ Procedure Srw.Set_Font_Style (Style) – Especifica o estilo da fonte para o campo. Esse atributo é ignorado em
modo Caracter. Os valores válidos para Style são: srw.italic_style, srw.oblique_style, srw.underline_style,
srw.outline_style, srw.shadow_style, srw.inverted_style, srw.blink_style, srw.plain_style.
♦ Procedure Srw.Set_Font_Weight (Weight) – Especifica a densidade da fonte para o campo. Esse atributo é ignorado
em modo Caracter. Os valores válidos para weight são: srw.ultralight_weight, srw.extralight_weight,
srw.light_weight, srw.demilight_weight, srw.demibold_weight, srw.bold_weight, srw.extrabold_weight,
srw.medium_weight.
♦ Procedure Srw.Set_Foreground_Border_Color (Color) – Especifica uma cor de foreground para a borda do objeto
(é ignorada em Character Mode).
♦ Procedure Srw.Set_Foreground_Fill_Color (Color) – Especifica uma cor de foreground para o objeto (é ignorada
em Character Mode).
♦ Procedure Srw.Set_Format_Mask (Mask) – Especifica uma máscara de formatação para campos do tipo Date ou Number.
♦ Procedure Srw.Set_Hyperlink (Hyperlink) – Especifica um URL Web Link.
♦ Procedure Srw.Set_Hyperlink_Attrs (String) – Aplica um comando HTML para o Hyperlink especificado na paleta
de propriedades ou pela procedure Srw.Set_Hyperlink.
♦ Procedure Srw.Set_Justification (Justification) – Especifica uma justificação horizontal para campos do tipo Char,
Date ou Number. Os valores válidos são: srw.left_hjust, srw.right_hjust, srw.flush_hjust, srw.center_hjust.
♦ Procedure Srw.Set_Linktag (Linktag) – Especifica um identificador para o objeto com a intenção de ser usado
como destino de Web Links.
♦ Procedure Srw.Set_Maxrow (Query_Name, Max_Row) – Determina o número máximo de registros a ser obtido
da query especificada.
♦ Procedure Srw.Set_Page_Navigation_Html (Type, String) – Inclui um script para controle de navegação em relatórios
cujo parâmetro PageStream seja Yes. O parâmetro Type pode ser preenchido com Srw.File_Escape indicando que a
string contém o nome de um arquivo ou Srw.Text_Escape indicando que a string contém o texto.
♦ Procedure Srw.Set_Pdf_Action (Action) – Especifica uma linha de comando que será executada na máquina
local quando o objeto for clicado em um PDF viewer.
♦ Procedure Srw.Set_Printer_Tray (Tray) – Especifica o nome de um printer tray válido e pode ser usada para
substituir diferentes printer trays, de acordo com o formato do relatório.
♦ Procedure Srw.Set_Spacing (Spacing) – Determina o espacejamento interno de campos do tipo Char, Date ou
Number e para boilerplates de texto. Esse atributo é ignorado em modo Caracter. Os valores válidos são:
srw.single_spacing, srw.double_spacing, srw.onehlf_spacing.
♦ Procedure Srw.Set_Text_Color (Color) – Especifica a cor do texto para campos do tipo Char, Date ou Number.
Esse atributo é ignorado em modo Caracter.
♦ Procedure Srw.Set_Xml_Prolog (Type, Prolog) – Esta procedure tem a finalidade de permitir a modificação dinâmica
do prólogo do relatório. Um prólogo XML pode incluir declarações XML, comentários, instruções e declarações
de tipo de documento (DTD). O parâmetro Type pode ser preenchido com Text ou File.
♦ Procedure Srw.Set_Xml_Tag_Attr (Type, Name, String) – Permite a modificação dos atributos XML de um elemento.
♦ Procedure Srw.Trace_Add_Option (Traceopts) – Permite que informemos uma nova opção para avaliação (trace)
após o envio de informações de trace ter sido iniciado. Veja detalhes de utilização na ajuda do Report Builder.
♦ Procedure Srw.Trace_End – Encerra o envio de informações para o arquivo de trace.
♦ Procedure Srw.Trace_Rem_Option(Traceopts) – Remove as opções informadas da máscara previamente definida.
Veja detalhes de utilização na ajuda do Report Builder.
♦ Procedure Srw.Trace_Start(Trcfile, Trcmode, Trcopts) – Inicia a gravação de informações de trace durante a execução
do relatório. Veja detalhes de utilização na ajuda do Report Builder.
♦ Procedure Srw.User_Exit(User_Exit_String) – Chama a user exit (programa 3GL) nomeada na string. Os seguintes
argumentos são passados para a user exit: a string de caracteres informada e um ponteiro para o comprimento da string.
♦ Procedure Srw.User_Exit20(User_Exit_String) – É similar à Srw.User_Exit, com a diferença de que ela aciona a
user_exit passando cinco argumentos em vez de apenas dois. Isso permite que compartilhemos as user exits
com outros produtos, tais como o Oracle Forms, que passa cinco argumentos em vez de dois. Os parâmetros
passados são os seguintes: a string especificada, um ponteiro para o comprimento da string, uma string de erro
(este argumento não é usado pelo Report Builder e será passado sempre ‘ ‘), um ponteiro para o comprimento da
string de erro (será sempre zero), um argumento relativo a query (que também não é usado pelo Report Builder
e sempre será passado zero).
LIST
Este pacote contém procedures, funções e condições de erro que podíamos usar para criar e manter listas de textos
(strings). Essa era a forma alternativa de trabalharmos com arrays no Report 2.5, uma vez que a PL/SQL disponível era
versão 1. No Report Builder, já não temos mais necessidade desta utilização. Podemos usar o recurso do Type Table.
♦ Procedure List.Appenditem(List, Item) – adiciona um item ao fim da lista.
♦ Procedure List.Deleteitem(List, Pos) – remove um elemento da posição especificada da lista.
♦ Procedure List.Destroy(List) – destrói uma lista.
♦ Função List.Getitem(List, Pos) – obtém um item da lista correspondente à posição informada.
♦ Procedure List.Insertitem(List, Pos, Item) – inclui um item na lista na posição especificada.
♦ Função List.Make – cria uma nova lista vazia. Uma lista deve ser criada antes de ser utilizada.
♦ Função List.Nitems(List) – retorna o número de itens na lista.
♦ Procedure List.Prependitem(List, Item) – adiciona um item ao início de uma lista.
ÍNDICE REMISSIVO
$$date$$, 879 Ajuda, 143
$$dbdate$$, 879 Ajustar à Janela (Fit to Window), 1475, 1562
%Bulk_Exceptions, 1281 Alerta (Alert), 1314, 1423
%Bulk_Rowcount, 485, 1280 Alertas, 913
%Found, 283, 321, 1280 Alfanuméricas, 1227
%Isopen, 284, 1280 Alfanuméricas que Retornam Valores Numéricos, 1227
%NotFound, 283, 321, 476, 1280 Alias, 121
%Rowcount, 284, 321, 1280 Alinhamento da Barra de Rolagem (Scroll Bar Alignment)
%Rowtype, 281, 459, 1280 Quadro, 1396
%Type, 266, 320, 1279 Alinhamento de Objetos Simples (Single Object Alignment)
&&, 36 Quadro, 1394
&, 36 Alinhamento do Prompt (Prompt Alignment)
/, 32, 1252 Botão de Opção, 1333
@ , 35, 1252, 1270 Item, 1371
@@, 35, 1252, 1270 Alinhamento do Prompt ao Topo (Top Prompt Alignment)
_Editor, 29 Quadro, 1395
||, 40 Alinhamento do Quadro (Frame Alignment)
Quadro, 1394
Alinhamento do Título do Quadro (Frame Title Alignment)
A Quadro, 1399
Alinhamento Inicial do Prompt (Start Prompt Alignment)
Abrindo uma Sessão, 1248 Quadro, 1394
Abrir (Open), 1472, 1556 Alinhar à Grade (Grid Snap), 1476, 1562
Abs, 70 Alinhar Objetos (Align Objects), 1479, 1566
Accept, 1252, 133, 235, 244, All, 130, 38, 53
Access, 1534 All When, 156, 157
Access_Into_Null, 294 All...Insert into, 156
Acelerador de Teclado (Keyboard Accelerator) All_Homes, 10
Item de Menu, 1376 All_Source, 519
Acesso ao Módulo (Module Access), 1473 Alter, 204, 214, 216
Acesso ao Relatório (Report Access), 1557 Alter Session, 1206, 181, 186, 244
Acionando o SQL*Plus em Batch, 1250 Alter Trigger, 450
Acos, 73 Alter Type, 539, 540
ActiveX (ActiveX), 1452, 1422, 808-09, 813 Alterando/Editando a Paleta de Cores,
Add_Months, 82 Forms Builder, 826, 937
Add_Triggers, 1550 Reports Builder, 1056
Adicionar Marcador (Add BookMark), 1567 Alternar Orientação (Switch Orientation), 1483
Adicionar Marcador (Mark), 1477 Altura (Height)
Adicionar no Grupo (Add to Group), 1480, 1567 Botão de Opção, 1331
Administração (Administration), 1473, 1557 Canvas, 1336
After, 441, 523, 525, 526 Editor, 1340
After Parameter Form, 1030 Item, 1368
After Reports, 1031 Janela, 1405
Agregate, 1296 Lov, 1381
Agrupar (Group), 1480, 1566 Módulo Relatório, 1516
Agrupar Operações (Group Operations), 1480, 1567 Quadro, 1396
Ajuda (Help) Seção, 1530
Gatilho, 1343 Altura do Relatório (Report Height)
Item, 1372 Seção, 1531
Item de Menu, 1378 Altura do Visor (ViewPort Height)
Ajuda de Controle (Control Help) Canvas, 1335
Item, 1350 Ampliar (Zoom In), 1475, 1561
Cor de Fundo do Título do Quadro (Frame Title Foreground Cursor, 279-80, 473, 486, 526-27, 529, 574
Color) Cursor_Already_Open, 294
Quadro, 1399 Customize, 1536, 1544
Cor do Prompt (Prompt Color) Cycle, 211
Botão de Opção, 1334
Item, 1372
Cor do Título do Quadro (Frame Title Color) D
Quadro, 1399
Corpo do Pacote, 1026, 1298 Dados (Data)
Corr, 55 Item, 1361
Correio (Mail), 1558 Parâmetro, 1392
Correlação, 150 Dangling, 546, 550, 585
Cos, 74, 229 Data e Hora (Date and Time), 1563
Cosh, 74 Data Streaming, 606
Cost, 619 Database, 451
Count, 56, 110-11, 127, 225, 239, 306-07, 483 Database Files, 204
Covar_Pop, 56 Datas, 1228
Covar_Samp, 56 Datatypes, 1221
Create, 203, 206, 451, 504, 516-18, 523-27, 529, 549, 566-67, Date, 208, 260
602-03, 605-06 DateFormatMask , 1536
Create Directory, 1216 Dba, 218
Create Function, 486 Dba_Directories, 396
Create Index, 335, 336 Dbms_Alert, 351
Create Java Class, 415, 416 DBMS_Flashback, 351, 408, 514, 515, 1298
Create Library, 415, 416 Dbms_Lob, 351, 387-88, 508-11, 512-13, 1299
Create Sequence, 1216 DBMS_Output, 350, 352, 498, 501, 506, 509, 520, 522, 527,
Create Table, 207, 544 1302
Create Trigger, 441, 592 Dbms_Pipe, 350, 371, 504-06, 1303
Create Type, 1217, 209, 534, 543, 557, 558 Dbms_Random, 351, 406, 514, 1304
Create Type as Object, 543-44, 547, 552, 557, 575, 579-80, 585 Dbms_Rowid, 351, 382, 507, 1306
Create Type as Table, 572, 575 Dbms_Sql, 351
Create Type as Varray, 569, 575, 579 Dbms_Standard, 349
Create Type Body, 552, 581 Dbtimezone, 230
Create User, 12 Dbtimezone, 84, 245, 472
Create View, 1220, 591 DCL, 23
Create_Pipe, 373 DDE, 1444
CreateTemporary, 394 DDL, 23, 203, 247
Crete Database Link, 210 DeadLocks, 179
Crete Index, 210 Debug, 1439, 1547, 1551
Criador de Form de Parâmetros (Parameter Form Builder), Debug_Messages, 1547
1570 Dec, 257
Criando Fila do Reports Server, 1183 Decimal, 257, 1536
Criar (Create), 1477, 1567 Declaração de Cursor, 1282
Criar à Direita (Create Right), 1482 Declarações, 1278
Criar Abaixo (Create Down), 1482 Declarações Forward, 1295
Criar para Arquivo (Generate to File), 1558 Declare, 465, 470
Criar para Navegador da Web (Generate to Web Browser), 1560 Decode, 97, 229, 233
Cross Join, 119 Decompose, 90
Crt_File, 1551 Default, 326
Cube, 66, 226-27 Deferred, 548
Cue Cards, 1483, 1571 Define, 29-30, 131, 135, 1258
Cume_Dist, 57, 111-12, 227, 514 Definição do System_Editor, 788
Currency, 1536 Definições XML (XML Definitions)
Current OF, 285-86 Coluna de Espaço Reservado, 1501
Current Row, 106 Coluna de Fórmula, 1503
Current_Date, 83 Coluna de Sumário, 1505
Current_Schema , 182, 1211 Coluna do Banco de Dados, 1507
Current_Timestamp, 84, 245, 472, 514 Grupo, 1512
Cursor Loop, 290-91, 1281 Módulo Relatório, 1518
Cursor, 1280 Del, 28, 1258
Espaçamento Horiz. Entre Quadros (Horiz. Space Between Estilo de Sobreposição (Wrap Style)
Frames) Editor, 1339
Quadro de Repetição, 1527 Item, 1356
Espaçamento Vert. Entre Quadros (Vert. Space Between Estilo de Traço (Dash Style)
Frames) Quadro, 1397
Quadro de Repetição, 1527 Estilo de União (Join Style)
Especificação de Pacote, 1026 Quadro, 1397
Especificação, 1297 Estilo dos Cantos (Corner Style)
Especificações da Coluna (Column Specifications) Botão de Opção, 1330
Grupo de Registros, 1344 Canvas, 1336
Estado do Teclado (Keyboard State) Estilos de Relatórios, 1076
Item, 1373 Estrutura, 250, 1274
Estado Inicial do Teclado (Initial Keyboard State) Etiqueta (Label)
Item, 1373 Item, 1345, 1353, 1358
Estilo Ativo (Active Style) Item de Menu, 1375
Canvas, 1337 Página Tab, 1390
Estilo da Fonte (Font Style) Etiqueta do Botão 1 (Button 1 Label)
Alerta, 1316 Alerta, 1314
Atributo Visual, 1318 Etiqueta do Botão 2 (Button 2 Label)
Botão de Opção, 1332 Alerta, 1315
Canvas, 1338 Etiqueta do Botão 3 (Button 3 Label)
Editor, 1341 Alerta, 1315
Item de Menu, 1378 Eventos de Interface (Interface Event), 1452
Item, 1371 Eventos dos Triggers, 1312
Janela, 1407 Exception, 293, 296, 476, 502, 525, 526,
Lov, 1382 527, 529, 530, 1284
Estilo da Fonte do Prompt (Prompt Font Style) Exception_Init, 297, 480, 490, 529, 1284
Botão de Opção, 1334 Exceptions, 294
Item, 1372 Exceptions para Coleçõe, 1292
Estilo da Fonte do Título do Quadro (Frame Excluindo elementos no item da Lista, 710
Title Font Style) Excluindo elementos nos Record Groups, 798
Quadro, 1399 Excluir de Saída XML (Exclude from XML Output)
Estilo da Janela (Window Style) Coluna de Espaço Reservado, 1502
Janela, 1403 Coluna de Fórmula, 1504
Estilo da Largura (Width Style) Coluna de Sumário, 1506
Canvas, 1337 Coluna do Banco de Dados, 1507
Estilo da Lista (List Style) Grupo, 1513
Item, 1349 Exec_Sql, 1448
Estilo de Alerta (Alert Style) Executar Form (Run Form), 1480
Alerta, 1314 Executar Relatório (Run Report), 1568
Estilo de Ativação de OLE (OLE Activation Style) Execute, 140, 217, 616, 1260, 1262
Item, 1351 Execute Immediate, 433, 437, 522, 1287
Estilo de Dimensionamento (Sizing Style) Execute_Query, 693
Item, 1348 Exibição Automática (Automatic Display)
Estilo de Exibição do Prompt (Prompt Display Style) Lov, 1379
Botão de Opção, 1333 Exibição na ‘Ajuda do Teclado’ (Display in
Item, 1371 ‘Keyboard Help’)
Estilo de Gatilho (Trigger Style) Gatilho, 1343
Gatilho, 1342 Exibição sem Privilégio (Display without Privilege)
Estilo de Layout (Layout Style) Item de Menu, 1377
Quadro, 1393 Exibir Dica Automaticamente (Display
Estilo de Maiúsculas (Cap Style) Hint Automatically)
Quadro, 1397 Item, 1373
Estilo de Minúsculas (Cap Style) Exists, 147, 151, 237, 306
Quadro, 1397 ExistsNode, 98
Estilo de Navegação (Navigation Style) Exit, 32, 287, 1260, 1286
Bloco de Dados, 1319 Exit_Form, 693, 897
Estilo de Redimensionamento de OLE (OLE Exp, 71
Resize Style) Exp_Full_Database, 218
Item, 1352 Expandir (Expand), 1476, 1483, 1567
Expandir Todos (Expand All), 1567
Máximo de Objetos por Linha (Maximum Mínimo Valor Permitido (Lowest Value Allowed),
Objects Per Line) Item, 1363
Quadro, 1394 Minus, 116, 233
Máximo de Registros Extraídos (Maximum Minute, 514
Records Fetched) MinValue, 211
Bloco de Dados, 1324 MMB, 668
Módulo Form, 1386 MMX, 668
Máximo de Registros por Página (Maximum Mod, 71
Records Per Page) Modal (Modal),
Quadro de Repetição, 1527 Janela, 1403
Máximo Valor Permitido (Highest Value Allowed) Mode, 1540
Item, 1364 Modelo de Dados (Data Model), 965, 1561
Maxlen, 420 Modelo de Dados, 13
MaxValue, 211 Modelo de Layout (Layout Model), 965, 1561, 1565
Mdsys.SDO_Geometry, 209 Modo Caracter (Character Mode),
Member,539, 540-41, 580 Bloco de Dados, 1328
Mensagem (Message) Item de Menu, 1378
Alerta, 1314 Módulo Relatório, 1519
Mensagem, 1430 Seção, 1531
Menu (Menu), 1482 Modo de Bloqueio (Locking Mode),
Menu Ajuda (Help), 1483, 1570 Bloco de Dados, 1323
Menu Arquivo (File), 1472, 1556 Modo de Cálculo (Calculation Mode),
Menu e Submenu (Menu), 1383 Item, 1364
Menu Editar (Edit), 1474, 1559 Modo de Coluna (Column Mode),
Menu Exibir (View) Quadro de Repetição, 1527
Layout, 1475 Modo de Compatibilidade em Runtime (Runtime
Navegador, 1475 Compatibility Mode),
Menu Exibir (View), 1560 Módulo Form, 1388
Menu Ferramentas (Tools), 1481, 1569 Modo de Comunicação (Communication Mode),
Menu Formatar (Format), 1477, 1563 Item, 1360
Menu Inicial (Initial Menu) Modo de Execução (Execution Mode),
Módulo Form, 1385 Item, 1360
Menu Inserir (Insert), 1563 Modo de Interação (Interaction Mode),
Menu Navegador (Navigator), 1476 Módulo Form, 1386
Menu Navigator (Navigator), 1567 Modo de Isolamento (Isolation Mode),
Menu Organizar (Arrange), 1479, 1566 Módulo Form, 1386
Menu Pop-up (Popup Menu) Modo de Tecla (Key Mode),
Canvas, 1335 Bloco de Dados, 1323
Item, 1345-48, 1350-52, 1354-55, 1357-59 Modularidade, 250
Menu e Submenu, 1383 Module, 1540
Menu Pop-up, 945 Module_Access, 1551
Menu Principal (Main Menu), Module_Type, 1551
Módulo Menu, 1388 Módulo de Menu (Menu Module),
Menu Programa (Program), 1480, 1568 Módulo Form, 1385
Menu Tirar (Tear-off Menu), Módulo Form (Form Module),
Menu e Submenu, 1383-84 Módulo Form, 1384
Menu, 943-45, 1429 Modulo Form, 670
Merge, 155, 240, 1237 Módulo Menu (Menu Module), 670, 1388
Mestre-Detalhe (Master-Detail), 1458 Módulo PL/SQL Lybrary,
Method, 553 Forms Builder, 670
Métodos, 305, 538 Módulo Relatório (Report), 1515
Min, 58, 64, 110-11, 127, 231, 235, 237, 239 Moeda (Currency), 1564
Minextents, 207 Months_Between, 85-6, 228
Minimização Permitida (Minimize Allowed), Mostrar Apenas PL/SQL (Only Show PL/SQL), 1475
Janela, 1404 Mostrar Barra de Rolagem (Show Scroll Bar),
Mínimo de Linhas Viúvas (Minimum Widow Lines), Bloco de Dados, 1327
Texto Padronizado, 1489 Mostrar Barra de Rolagem (Show Scroll Bar),
Mínimo de Registros Viúvos (Minimum Quadro, 1396
Widow Records) Mostrar Barra de Rolagem Horizontal (Show Horizontal
Quadro de Repetição, 1527 Scroll Bar),
Canvas, 1336