Academia.eduAcademia.edu

PLSQL PLSQL Domine a linguagem do banco de dados Oracle

Sempre gostei de livros que "conversam" com o leitor, principalmente os técnicos. Como se fosse uma troca de ideias entre o autor e a pessoa que o está lendo. Procurei escrever desta forma, pois creio que com isso a leitura se torna mais clara e amigável, um bate papo entre amigos, conversando sobre qualquer assunto. A intenção foi colocar aqui tudo o que você vai precisar saber sobre a linguagem PL/SQL. O livro aborda conceitos que são utilizados no dia a dia do desenvolvimento e análise de sistemas para banco de dados Oracle. Demonstrei diversos exemplos, que também vão ajudá-lo como fonte de referência para consulta de comandos e como utilizá-los. Tenha uma otima leitura!

Casa do Código Prefácio Sempre gostei de livros que “conversam” com o leitor, principalmente os técnicos. Como se fosse uma troca de ideias entre o autor e a pessoa que o está lendo. Procurei escrever desta forma, pois creio que com isso a leitura se torna mais clara e amigável, um bate papo entre amigos, conversando sobre qualquer assunto. A intenção foi colocar aqui tudo o que você vai precisar saber sobre a linguagem PL/SQL. O livro aborda conceitos que são utilizados no dia a dia do desenvolvimento e análise de sistemas para banco de dados Oracle. Demonstrei diversos exemplos, que também vão ajudá-lo como fonte de referência para consulta de comandos e como utilizá-los. Tenha uma otima leitura! Público alvo Este livro se destina a iniciantes e experientes na linguagem PL/SQL. Para os iniciantes, são abordados conceitos sobre a estrutura da linguagem PL/SQL e suas características. Ele ensina como criar programas, dos mais simples até os mais complexos, para atender às mais diversas necessidades. Você vai aprender como esta linguagem pode trazer um alto grau de produtividade e performance para as suas aplicações. Para os já experientes, ele ajudará como fonte de referência e para relembrar conceitos e técnicas da linguagem. Como o livro está dividido? Primeiramente, são abordados conceitos básicos da linguagem, como sua definição, como é estruturada e seus principais componentes. Logo após, entramos a fundo na sua estrutura, conhecendo cada comando e cada compoi Casa do Código nente que ela utiliza, explorando suas funcionalidades e propriedades. O livro também mostra como incorporar a linguagem SQL dentro dos programas escritos em PL/SQL, para a recuperação e manipulação de dados. Tipos de dados, estruturas condicionais e de repetição, armazenamento de programas através de procedures (procedimentos) e functions (funções), e modularização através de packages (pacotes) são alguns dos itens mostrados. Toda essa abordagem é realizada no âmbito prático, onde são detalhadas suas estruturas, seus comandos e características, sempre através de exemplos práticos e de fácil compreensão. Os scripts de base (tabelas e dados) e fontes para a execução dos exemplos do livro estão disponíveis no endereco https://github.com/ eduardogoncalvesbr/livroplsql-casadocodigo. Confira outras obras do autor SQL: Uma abordagem para bancos de dados Oracle http://www. casadocodigo.com.br/products/livro-sql-oracle Contatos Para falar com o autor, envie e-mail para eduardogoncalhttps://www.facebook.com/ ves.br@gmail.com Página no facebook: eduardogoncalvesescritor ii Casa do Código Sobre o autor Formado em Tecnologia da Informação, possui mais de 10 anos de experiência em análise e desenvolvimento de sistema voltados a tecnologias Oracle, trabalhando por grandes empresas como Lojas Renner, Mundial S.A, Tigre S.A, Pernambucanas, Tractebel Energia, Portobello Ceramica, Bematech, entre outros. Eduardo Gonçalvez é instrutor de cursos oficiais da Oracle – nas linguagens SQL e PL/SQL. Também atua no desenvolvimento de aplicações mobile para a plataforma iOS. Atualmente, atua como Coordenador de Operações na Supero Tecnologia. iii Casa do Código Agradecimentos Dedico este livro a todas os meus amigos e colegas da área de tecnologia, bem como meus professores e mentores, que tive o prazer de conhecer, e com os quais aprendi e até mesmo trabalhei. Durante esta minha trajetória aprendi muitas coisas com estas pessoas extraordinárias. Trocamos experiências e aprendemos muito, uns com os outros, programando e quebrando a cabeça para escrever a linha de código que ajudasse a solucionar um problema (regado a muito café, na maioria das vezes... risos), ou até mesmo, apenas pela paixão de programar. Saibam que cada um de vocês contribuiu imensamente para este trabalho! Sem vocês isto não seria possível! Ficam aqui meus sinceros agradecimentos! v Casa do Código Sumário Sumário 1 PL/SQL 1.1 O que é PL/SQL? . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Por que aprender PL/SQL? . . . . . . . . . . . . . . . . . . . . 1.3 SQL, SQL*Plus, PL/SQL: Qual é diferença? . . . . . . . . . . 1 1 2 3 2 Programação em bloco 7 3 Primeiros passos 3.1 Como iniciar no PL/SQL . . . . . . . . . . . . . . . . . . . . . 13 13 4 Pacote dbms_output 4.1 Exceções para o pacote dbms_output . . . . . . . . . . . . . . 19 26 5 27 27 31 35 Variáveis bind e de substituição 5.1 Variáveis bind . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Variáveis de substituição . . . . . . . . . . . . . . . . . . . . . 5.3 Utilizando variáveis em arquivos . . . . . . . . . . . . . . . . 6 Aspectos iniciais da programação PL/SQL 6.1 Caracteres e operadores . . . . . . . . . . 6.2 Identificadores . . . . . . . . . . . . . . . 6.3 Transações . . . . . . . . . . . . . . . . . 6.4 Transações em PL/SQL . . . . . . . . . . 6.5 Trabalhando com variáveis e constantes 6.6 Tipos de dados em PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 44 44 47 51 52 53 vii Casa do Código Sumário 7 Exceções 7.1 Exceções predefinidas . . . . . . . . . . . . . . . . . . . . . . . 7.2 Exceções definidas pelo usuário . . . . . . . . . . . . . . . . . 59 60 79 8 Estruturas de condição: if 8.1 Estruturas do comando if-end if . . . . . . . 8.2 Estruturas do comando if-else-end if . . . . 8.3 Estruturas do comando if-elsif(-else)-end if 8.4 Formatando as declarações if . . . . . . . . . 8.5 Evitando erros comuns no uso de if . . . . . . . . . . 85 86 87 89 93 94 . . . . 95 95 101 102 105 10 Cursores 10.1 Cursores explícitos . . . . . . . . . . . . . . . . . . . . . . . . . 107 108 9 Comandos de repetição 9.1 for loop . . . . . . . . . 9.2 while loop . . . . . . . . 9.3 loop . . . . . . . . . . . 9.4 Qual loop deve-se usar? 10.3 10.4 10.5 10.6 10.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 119 121 128 130 11 Funções de caracteres e operadores aritméticos 11.1 Funções de caracteres . . . . . . . . . . . . . . . . . . . . . . . 11.2 Funções de cálculos . . . . . . . . . . . . . . . . . . . . . . . . 11.3 Operadores aritméticos . . . . . . . . . . . . . . . . . . . . . . 143 144 149 154 12 Funções de agregação (grupo) 159 13 Funções de data 177 viii Cursor for loop com definição interna . Cursores implícitos . . . . . . . . . . . . Atributos de cursor explícito e implícito Cursores encadeados . . . . . . . . . . . Cursor com for update . . . . . . . . . . . . . . . . . . . . . . . . Casa do Código Sumário 14 Funções de conversão 183 14.1 to_date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 14.2 to_number . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 14.3 to_char . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 15 Funções condicionais 15.1 decode vs. case . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 217 16 Programas armazenados 16.1 procedures e functions . . . . . . . . . . 16.2 Uso do comando replace . . . . . . . . . 16.3 Recompilando programas armazenados 16.4 Recuperando informações . . . . . . . . 16.5 Recuperando códigos . . . . . . . . . . . 16.6 Visualizando erros de compilação . . . . 16.7 Passando parâmetros . . . . . . . . . . . 16.8 Dependência de objetos . . . . . . . . . . . . . . . . . . 225 226 236 238 238 239 240 243 249 . . . . . . 265 266 270 278 278 279 280 17 packages 17.1 Estrutura de um package . . . . . 17.2 Acesso a packages . . . . . . . . . 17.3 Recompilando packages . . . . . . 17.4 Recuperando informações . . . . 17.5 Recuperando códigos . . . . . . . 17.6 Visualizando erros de compilação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Transações autônomas 283 19 Triggers 19.1 Trigger de banco de dados 19.2 Trigger de tabela . . . . . . 19.3 Trigger de linha . . . . . . 19.4 Mutante table . . . . . . . . 19.5 Trigger de sistema . . . . . 19.6 Trigger de view . . . . . . . 293 294 294 301 316 324 330 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix Sumário Casa do Código 20 PL/SQL Tables (estruturas homogêneas) 349 21 PL/SQL Records (estruturas heterogêneas) 359 22 Pacote utl_file 365 23 SQL dinâmico 23.1 Ref cursor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 397 24 Apêndice: SQL – Primeiros passos 405 24.1 Como iniciar no SQL . . . . . . . . . . . . . . . . . . . . . . . 405 25 Referências bibliográficas 413 26 Anexos 415 x Capítulo 1 PL/SQL 1.1 O que é PL/SQL? A sigla PL/SQL significa Procedural Language / Structured Query Language, ou seja, trata-se de uma linguagem procedural tendo como base a SQL (Linguagem de Consulta Estruturada). A PL/SQL é direcionada para o banco de dados Oracle e é escrita através de blocos de código que são executados diretamente no banco de dados. Ela permite o desenvolvimento de programas complexos, nos quais grandes volumes de informação são processados. Como qualquer outra linguagem de programação, a PL/SQL é escrita através de códigos, sendo que os princípios de lógica de programa e programação estruturada podem ser implementados. Os blocos PL/SQL podem ser escritos e guardados no próprio banco de dados, através de funções ( functions), procedimentos ( procedures), 1.2. Por que aprender PL/SQL? Casa do Código gatilhos ( triggers) ou pacotes ( packages) para serem executados e reaproveitados quando necessário. Os códigos podem ser feitos utilizando-se uma interface, como o SQL*Plus, que é totalmente integrada ao banco de dados. Outras ferramentas como Oracle Forms, Oracle Reports e Workflow Builder também possuem motores PL/SQL que permitem validar e compilar os códigos escritos em PL/SQL. Através de todos esses atributos, a PL/SQL se mantém como uma linguagem robusta e muito utilizada pelos desenvolvedores e analistas do mundo todo. Muito provavelmente, isso se dá ao fato de sua crescente história, que vem desde as primeiras versões do banco de dados e sua evolução permanente desde então. No mais, a PL/SQL dá suporte aos mais variados recursos de programação de sistemas como a utilização de variáveis, constantes, cursores, estruturas de repetição e condicional, o uso de pacotes, funções, procedimentos armazenados, tratamento de erros, chamadas à API, gatilhos, vetores, registros, execução direta de comandos SQL etc. Além do mais, ela condiciona em sua estrutura os padrões ANSI para linguagem SQL e suporte à codificação Java. 1.2 Por que aprender PL/SQL? É importante conhecer a linguagem PL/SQL, independente da utilização ou não das ferramentas de desenvolvimento. Mesmo utilizando apenas o banco de dados, é fundamental conhecê-la tendo em vista que muitos processos dentro do servidor do banco são escritos ou executados por blocos nesta linguagem. No que diz respeito ao desenvolvimento, a PL/SQL proporciona rapidez, eficiência e segurança para seus programas, pois seus códigos, ou melhor, programas, podem ser armazenados no banco de dados. Assim sendo, na próxima vez que precisar executá-lo novamente, é só chamá-lo, ele já está pronto. Outro ponto interessante é que os programas não precisam estar no cliente, já que a PL/SQL utiliza o servidor do banco de dados para a execução e armazenamentos dos seus processos. Outra vantagem de se aprender PL/SQL é que no banco de dados Oracle, 2 Casa do Código Capítulo 1. PL/SQL embora seja implementado em diversas plataformas de hardware e software, a PL/SQL é igual para todas elas. Com isto, a portabilidade se mantém presente. 1.3 SQL, SQL*Plus, PL/SQL: Qual é diferença? É tanto “SQL” nos títulos dos produtos Oracle que acabamos nos confundindo. Vamos entender o que é cada uma destas siglas. • SQL: a sigla SQL significa Structured Query Language. É uma linguagem estruturada de acesso aos bancos de dados, declarativa, que usa comandos como SELECT, INSERT, UPDATE e DELETE. Ela sempre é executada no servidor através de uma interface conectada ao banco de dados. Apesar de não ser propriedade da Oracle, ela a incorpora em sua estrutura base e em suas linguagens. • PL/SQL: é uma linguagem de procedimentos, propriedade da Oracle. Caracteriza-se por uma linguagem não declarativa, ou seja, não bastam apenas comandos SQL. É necessário o uso de codificação em blocos, chamados blocos PL/SQL. Os códigos podem ser executados tanto no cliente (Oracle Forms, Reports etc.) quanto diretamente no servidor do banco de dados. • SQL*Plus: pode-se dizer que ele é a interface entre o usuário e o banco de dados. Quando executamos um comando SQL ou um bloco PL/SQL pelo SQL*Plus, ele os envia a um motor PL/SQL que executa os comandos PL/SQL e verifica a existência de comandos SQL. Caso existam, são enviados para um executor SQL, que os passa para o banco de dados. O SQL*Plus exibe o resultado na tela do seu computador. Para visualizar de forma mais clara os conceitos empregados, observe a imagem a seguir onde é mostrado o papel de cada um dentro do contexto de suas aplicações. 3 1.3. SQL, SQL*Plus, PL/SQL: Qual é diferença? Casa do Código Fig. 1.1: Esquema com as funções do SQL*Plus, PLSQL e SQL Conforme foi dito, através do SQL*Plus nós podemos entrar com comandos SQL ou blocos PL/SQL. Eles são encaminhados ao servidor do banco de dados, que pode direcionar para o motor PL/SQL, ou seja, o processador que vai validar e executar o bloco PL/SQL, e/ou para o executor de declarações de comandos SQL. Através desta visualização é possível entender a finalidade e importância de cada um desses produtos. Um ponto importante a entender é como são processadas as instruções SQL e blocos PL/SQL dentro de aplicações desenvolvidas com Oracle Forms ou Reports. Para entendimento, o Oracle Forms e Reports são ferramentas RAD para o desenvolvimento de formulários e relatórios. Essas ferramentas se conectam nativamente ao banco de dados Oracle. O termo “nativamente” faz referência a como é realizada a conexão com o banco de dados. Na maioria das vezes, uma aplicação se conecta através de drivers disponíveis pela ferramenta ou por algum gerenciador de conexão, por exemplo, via ODBC (encontrado no Windows). Pois bem, dentro das ferramentas Oracle é possível inserir tanto comandos SQL, quanto blocos PL/SQL. Esses comandos ou blocos serão executados para algum fim e quando isso acontece a solicitação de execução pode ser feita de formas diferentes 4 Casa do Código Capítulo 1. PL/SQL Quando temos dentro da aplicação comandos SQL distintos, eles são enviados um a um para o servidor do bando de dados. Dessa forma, a aplicação envia um comando para o servidor, espera a resposta e depois envia outro. Quando temos blocos PL/SQL, eles são enviados por completo ao servidor do banco de dados, não importando o seu teor. Dentro deste bloco podemos ter vários comandos SQL e demais estruturas em PL/SQL. Desse modo economizamos tempo, pois a aplicação envia de uma só vez todas as solicitações, e o número de respostas esperadas também reduz muito. Reduzindo o número de respostas e tráfego de informações entre aplicação e o servidor do banco de dados aumentamos a chance de ganho de desempenho, principalmente se esta comunicação depender de uma rede cliente x servidor. Veja a seguir a ilustração deste conceito. Fig. 1.2: Diferença entre comandos SQL e Blocos PLSQL 5 Capítulo 2 Programação em bloco A linguagem PL/SQL trabalha em blocos de comando. Dentro de bloco podemos ter outros blocos, que neste caso são chamados de sub-blocos. Quando queremos escrever um programa para um determinado fim, utilizamos blocos para estruturar os comandos e a forma de como este programa vai se comportar. Um bloco PL/SQL é iniciado pela expressão begin e é finalizada por end. Estas duas expressões determinam a área do nosso bloco. Veja um exemplo de bloco PL/SQL. ❙◗▲❃ ❜❡❣✐♥ ✷ ✸ ❡♥❞❀ ✹ ❙◗▲❃ Casa do Código Como mencionado anteriormente, podemos ter blocos dentro de outros blocos, os quais são chamados de sub-blocos. ❙◗▲❃ ❜❡❣✐♥ ✷ ❜❡❣✐♥ ✸ ✹ ❡♥❞❀ ✺ ✻ ✼ ❡♥❞❀ ✽ ❙◗▲❃ Além das expressões de delimitação do bloco, também podemos ter o declare, que é utilizado para delimitar uma área para declaração de variáveis que serão utilizadas pela aplicação e também a expressão exception, que delimita uma área para tratamento de erros. Basicamente, um bloco PL/SQL é composto por: • Área de declaração de variáveis ( declare); • Área de escopo para inserção de comandos e demais sub-blocos ( begin-end); • Área de tratamento de erros. A seguir um bloco PL/SQL contemplando estas premissas básicas. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✸ ❜❡❣✐♥ ✹ ✺ ❜❡❣✐♥ ✻ ✼ ❡♥❞❀ ✽ ✾ ❡①❝❡♣t✐♦♥ ✶✵ ✇❤❡♥ ♦t❤❡rs t❤❡♥ 8 Casa do Código Capítulo 2. Programação em bloco ✶✶ ✶✷ ❡♥❞❀ ✶✸ ✶✹ ❙◗▲❃ Este tipo de bloco é chamado de bloco anônimo, pois não possuem um cabeçalho e também não podem ser gravados diretamente no banco de dados. Caso você queira executá-los novamente, é necessário salvar em um arquivo, pois ao fechar a ferramenta ele não é guardado. A programação em bloco torna os programas mais estruturados e limpos. Principalmente, quando utilizamos vários sub-blocos para a realização de determinadas tarefas distintas, como a seleção de dados, uma atualização ou exclusão. Fazendo desta forma, é possível tratar cada bloco buscando uma programação mais lógica e que possa fornecer informações sobre os comandos contidos nele ou até mesmo identificar possíveis erros que possam surgir. Veja um exemplo de programa. ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ❞❡❝❧❛r❡ s♦♠❛ ♥✉♠❜❡r❀ ❜❡❣✐♥ s♦♠❛ ✿❂ ✹✺✰✺✺❀ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙♦♠❛ ✿✬⑤⑤s♦♠❛✮❀ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♦t❤❡rs t❤❡♥ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✶✱✬❊rr♦ ❛♦ s♦♠❛r ✈❛❧♦r❡s✦✬✮❀ ❡♥❞❀ ❙◗▲❃ Neste programa, é possível verificar a existência de uma área de declaração de variáveis onde temos a variável soma declarada como number (veremos estes conceitos mais adiante); uma área onde são inseridos os comandos propriamente ditos, soma recebendo a soma de 45+45. Também temos o pacote dbms_output, utilizado quando queremos escrever algo na tela. Neste caso, estamos solicitando a escrita do resultado da soma. Por último, temos 9 Casa do Código uma área de declaração de erros onde podemos tomar alguma ação caso um erro aconteça. Neste exemplo, caso surja qualquer tipo de erro, chamamos o procedimento raise_application_error, que faz com que a aplicação pare e imprima uma mensagem na tela. Vale lembrar que as áreas de declaração e tratamento de erros podem existir também dentro dos sub-blocos. Ok. Nosso programa já está criado. Agora vamos ver como executálo. Para isso, podemos utilizar a ferramenta SQL*Plus. Através do comando barra / podemos executar um bloco PL/SQL. ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ❙♦♠❛ ❞❡❝❧❛r❡ s♦♠❛ ♥✉♠❜❡r❀ ❜❡❣✐♥ s♦♠❛ ✿❂ ✹✺✰✺✺❀ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙♦♠❛ ✿✬⑤⑤s♦♠❛✮❀ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♦t❤❡rs t❤❡♥ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✶✱✬❊rr♦ ❛♦ s♦♠❛r ✈❛❧♦r❡s✦✬✮❀ ❡♥❞❀ ✴ ✿✶✵✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ O comando / executa o bloco PL/SQL, mostrando a saída gerada pelo dbms_output. Blocos PL/SQL não necessariamente possuem uma saída impressa na tela. Uma mensagem indicando que o bloco foi executado com sucesso também é mostrada. Caso ocorra algum erro de sintaxe na construção do comando, ou seja, algum comando escrito incorretamente ou uma função utilizada indevidamente, ele também é mostrado. A seguir vamos simular um erro de sintaxe para ver como a ferramenta se comporta. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ s♦♠❛ ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ s♦♠❛ ✹✺✰✺✺❀ 10 Casa do Código Capítulo 2. Programação em bloco ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙♦♠❛ ✿✬⑤⑤s♦♠❛✮❀ ✻ ❡①❝❡♣t✐♦♥ ✼ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✽ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✶✱✬❊rr♦ ❛♦ s♦♠❛r ✈❛❧♦r❡s✦✬✮❀ ✾ ❡♥❞❀ ✶✵ ✴ s♦♠❛ ✹✺✰✺✺❀ ✯ ❊❘❘❖ ♥❛ ❧✐♥❤❛ ✹✿ ❖❘❆✲✵✻✺✺✵✿ ❧✐♥❤❛ ✹✱ ❝♦❧✉♥❛ ✽✿ P▲❙✲✵✵✶✵✸✿ ❊♥❝♦♥tr❛❞♦ ♦ sí♠❜♦❧♦ ✧✹✺✧ q✉❛♥❞♦ ✉♠ ❞♦s s❡❣✉✐♥t❡s sí♠❜♦❧♦s ❡r❛ ❡s♣❡r❛❞♦✿ ✿❂ ✳ ✭ ❅ ✪ ❀ ❖ sí♠❜♦❧♦ ✧✿❂✧ ❢♦✐ s✉❜st✐t✉í❞♦ ♣♦r ✧✹✺✧ ♣❛r❛ ❝♦♥t✐♥✉❛r✳ ❙◗▲❃ Quando o comando é executado, a ferramenta SQL*Plus faz várias verificações, inclusive a de sintaxe de comandos. Na linha 4 está faltando o comando de atribuição := que atribui a soma de 45+55 à variável soma. Com isso, um erro é gerado e mostrado na tela. Ele geralmente vem acompanhado de algumas informações como a linha e a coluna onde o erro está ocorrendo. Além disso, a ferramenta costuma clarear o motivo pelo qual o erro está ocorrendo. Neste nosso exemplo, ele diz que foi encontrado o símbolo “45” quando na verdade era esperado algum outro, por exemplo, o símbolo de atribuição. Note que este erro foi detectado antes mesmo de o Oracle executar o bloco. Agora vamos gerar um erro, mas não de sintaxe, mas sim, um erro referente a dados incorretos. Vamos tentar somar números com caracteres alfanuméricos. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ s♦♠❛ ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ s♦♠❛ ✿❂ ✹✺✰✬❆✬❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙♦♠❛ ✿✬⑤⑤s♦♠❛✮❀ ✻ ❡①❝❡♣t✐♦♥ 11 Casa do Código ✼ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✽ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✶✱✬❊rr♦ ❛♦ s♦♠❛r ✈❛❧♦r❡s✦✬✮❀ ✾ ❡♥❞❀ ✶✵ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖ ♥❛ ❧✐♥❤❛ ✶✿ ❖❘❆✲✷✵✵✵✶✿ ❊rr♦ ❛♦ s♦♠❛r ✈❛❧♦r❡s✦ ❖❘❆✲✵✻✺✶✷✿ ❡♠ ❧✐♥❡ ✽ ❙◗▲❃ Agora temos outro erro, entretanto, ele ocorreu quando o bloco foi executado. Neste caso, o programa transferiu a ação para a área de tratamento de erros, gerando uma saída que informa a circunstância em que erro aconteceu. Já vimos que para construir um programa em PL/SQL temos que trabalhar em nível de bloco. Assim sendo, a linguagem PL/SQL permite adicionar, dentro das estruturas destes blocos, todo e qualquer recurso para que este programa possa executar ações ou procedimentos servindo. Dentro dos blocos é possível declarar variáveis e constantes, executar comandos DML ( select, delete, update e insert), executar procedimentos armazenados, funções, utilizar estruturas de repetição, estruturas de condição, além do uso de operadores relacionais e numéricos. 12 Capítulo 3 Primeiros passos 3.1 Como iniciar no PL/SQL Uma das dificuldades que encontramos quando estamos aprendendo uma linguagem de programação é saber por onde começar. No caso do aprendizado da PL/SQL, não seria diferente. É uma situação normal. Até sentirmos segurança e termos conhecimento suficiente, é interessante termos um roteiro contendo os primeiros passos para iniciar um programa PL/SQL. Demonstro aqui uma técnica que utilizo bastante, mesmo tendo um bom conhecimento na linguagem. Na verdade, já está implícito na minha forma de pensar, tanto que acabo executando-a mentalmente, enquanto escrevo nesta linguagem. Este método não foi retirado de nenhum livro, foi algo que, entendendo a lógica, fui seguindo e deu certo. Espero que ajude vocês. Vamos tomar como exemplo, o enunciado a seguir: Casa do Código 3.1. Como iniciar no PL/SQL Escreva um programa PL/SQL que imprima na tela os nomes os empregados de um determinado gerente e de uma determinada localização. Primeiro passo Identifico no enunciado as fontes de dados, ou seja, as tabelas que farão parte do programa, caso seja necessário. Caso tenha dúvida em identificar a fonte de dados, veja o documento: 24. Após identificar as tabelas, monto os selects e executo os comandos para trazer os dados que o programa solicita. Tudo isso sem escrever uma única linha em PL/SQL. Somente monto os selects e os executo para ver se os dados estão sendo retornados. Exemplo: ❙◗▲❃ ✷ ✸ ✹ s❡❧❡❝t ❢r♦♠ ✇❤❡r❡ ❛♥❞ ✺ ❛♥❞ ✻ ✴ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❆▲▲❊◆ ❲❆❘❉ ▼❆❘❚■◆ ❚❯❘◆❊❘ ❏❆▼❊❙ ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ❡♠♣✱ ❞❡♣t ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ❞❡♣t✳❧♦❝ ❂ ✬❈❍■❈❆●❖✬ ✲✲ s❡rá ♦ ♣❛râ♠❡tr♦ r❡❢❡r❡♥t❡ ❛ ❧♦❝❛❧✐③❛çã♦ ❡♠♣✳♠❣r ❂ ✬✼✻✾✽✬ ✲✲ s❡rá ♦ ♣❛râ♠❡tr♦ r❡❢❡r❡♥t❡ ❛♦ ❣❡r❡♥t❡ ❏❖❇ ✲✲✲✲✲✲✲✲✲ ❙❆▲❊❙▼❆◆ ❙❆▲❊❙▼❆◆ ❙❆▲❊❙▼❆◆ ❙❆▲❊❙▼❆◆ ❈▲❊❘❑ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❙❆▲❊❙ ❙❆▲❊❙ ❙❆▲❊❙ ❙❆▲❊❙ ❙❆▲❊❙ Tendo montado todos os selects de que o programa necessita, vamos para o próximo passo. Segundo passo Inicio a montagem da estrutura do programa PL/SQL. Neste caso, analiso que tipo de objeto o programa pede. Geralmente, o enunciado traz esta informação, por exemplo, “faça um bloco PL/SQL anônimo”, uma procedure, uma function, uma package etc. No nosso 14 Casa do Código Capítulo 3. Primeiros passos exemplo, ele não menciona. Como ele não pede para retornar informações, apenas imprimir na tela, não criarei uma function, por exemplo. Como também não menciona nada sobre programas armazenados, também não criarei uma procedure, muito menos uma package. Como também não menciona disparos de triggers, não será preciso criar um. Vou criar um bloco PL/SQL anônimo, mesmo porque, se for o caso, mais adiante eu posso criar um cabeçalho para tornar este objeto um programa armazenado. É simples. Começo desenhando o bloco PL/SQL, seguindo a seguinte estrutura: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ❞❡❝❧❛r❡ ❜❡❣✐♥ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ❡♥❞❀ ✴ Esta não é a estrutura mínima de um PL/SQL, pois sabemos que a área de declaração de variáveis ( declare) e a área de tratamento de erros ( exception) não são obrigatórias, embora esta última seja imprescindível, pois o tratamento de erros é fundamental para o bom funcionamento do sistema. Contudo, na grande maioria dos programas teremos esta estrutura: a área de declaração de variáveis, a área onde ficarão a maioria dos comandos, propriamente ditos, ( begin- end), e a área de tratamento de erros ( exception). Pronto. A estrutura inicial do seu programa PL/SQL está pronta para ser utilizada. Dentro da área de declaração de variáveis, você vai colocar todas as que você vai utilizar dentro do seu programa. Aqui também estarão declarados os tipos de dados definidos por você, os cursores, exceptions de usuário, funções e procedimentos etc. Caso seu programa não vá utilizar esta área, ela pode ser excluída. Já dentro do corpo do programa, begin-end, é onde você vai escrever a parte principal dele. É nele onde se localizam e serão executados os comandos 15 3.1. Como iniciar no PL/SQL Casa do Código da SQL, condições ifs, laços de repetição, aberturas de cursor, chamadas a funções e outros procedimentos armazenados, e assim por diante. A área de tratamento de erros é onde você vai tratar os possíveis problemas que poderão surgir durante a execução do seu programa. Quando estiver escrevendo um programa PL/SQL sempre trate os possíveis erros. Pelo menos a exception others deve ser tratada, para que ao sinal de um problema, o programa não aborte. Também é recomendada a utilização das funções sqlerrm e sqlcode, para que o motivo do erro seja mencionado na mensagem. Um programa PL/SQL sempre seguirá esta estrutura. Vale ressaltar também que podemos ver esta estrutura declare-BEGIN-exception-END, de forma encadeada, ou seja, um bloco dentro de outro, como forma de isolar determinadas informações ou realizar verificações dentro do programa. Contudo, a estrutura lógica é a mesma. Segue o programa completo: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷ ✹ ✱♣♠❣r ♥✉♠❜❡r✮ ✐s ✺ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✻ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✼ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✽ ❛♥❞ ❡♠♣✳♠❣r ❂ ♣♠❣r❀ ✾ ✲✲ ✶✵ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✶ ❜❡❣✐♥ ✶✷ ♦♣❡♥ ❝✶✭ ♣♠❣r ❂❃ ✼✻✾✽✱ ♣❞♥❛♠❡ ❂❃ ✬❈❍■❈❆●❖✬✮❀ ✶✸ ❧♦♦♣ ✶✹ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✺ ✲✲ ✶✻ ✐❢ ❝✶✪❢♦✉♥❞ t❤❡♥ ✶✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✶✽ ❡❧s❡ ✶✾ ✲✲ ✷✵ ❡①✐t❀ 16 Casa do Código Capítulo 3. Primeiros passos ✷✶ ❡♥❞ ✐❢❀ ✷✷ ❡♥❞ ❧♦♦♣❀ ✷✸ ✲✲ ✷✹ ❝❧♦s❡ ❝✶❀ ✷✺ ❡①❝❡♣t✐♦♥ ✷✻ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✷✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠✮❀ ✷✽ ❡♥❞❀ ✷✾ ✴ ◆♦♠❡✿ ❆▲▲❊◆ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ◆♦♠❡✿ ❲❆❘❉ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ◆♦♠❡✿ ▼❆❘❚■◆ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ◆♦♠❡✿ ❚❯❘◆❊❘ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ◆♦♠❡✿ ❏❆▼❊❙ ❈❛r❣♦✿ ❈▲❊❘❑ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Observação Para garantir a impressão na tela, através do pacote dbms_output, execute o seguinte comando no SQL*Plus: set serveroutput on. 17 Capítulo 4 Pacote dbms_output Este pacote possui funções e procedimentos que permitem a geração de mensagens a partir de blocos anônimos de PL/SQL, procedures, packages ou triggers. Ele utiliza-se de um buffer em memória para transferência destas mensagens na sessão onde o programa está sendo executado. Quando um programa envia mensagens através do pacote dbms_output, elas são armazenadas na área de buffer e são apresentadas apenas ao término do programa. Se estivermos utilizando a ferramenta SQL*Plus, pode-se habilitar este recurso digitando o seguinte comando: set serveroutput on. Fazendo isso, todas as mensagens passarão a ser visualizadas no prompt da ferramenta. Na tabela a seguir, serão vistos os componentes mais usados deste pacote, todos do tipo procedure. • enable: habilita a chamada das demais rotinas do pacote. Casa do Código • disable: desabilita a chamada das demais rotinas do pacote. • put: inclui uma informação na área de buffer. • put_line: inclui uma informação na área de buffer e adiciona, simultaneamente, um caractere para quebra de linha (linha nova). • get_line: recupera uma linha do buffer. • get_lines: recupera várias linhas do buffer. Agora, será abordado em detalhes, com scripts exemplos, como são utilizados estes componentes. enable Esta procedure habilita chamadas para put, put_line, new_line, get_line e get_lines. Deve ser especificado um tamanho para a área do buffer a ser usada, definido em bytes e podendo variar de 2.000 até 1.000.000. Se isso for ultrapassado, uma mensagem de erro será mostrada. ❙◗▲❃ ❜❡❣✐♥ ✷ ❞❜♠s❴♦✉t♣✉t✳❡♥❛❜❧❡✭✷✵✵✵✮❀ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬❚❊❙❚❊✬✮❀ ✹ ❡♥❞❀ ✺ ✴ ❚❊❙❚❊ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ disable Esta procedure desabilita as chamadas para put, put_line, new_line, get_line e get_lines e limpa o buffer. É muito útil na depuração de programas, quando for indesejado o surgimento de mensagens informativas. 20 Casa do Código Capítulo 4. Pacote dbms_output ❙◗▲❃ ❜❡❣✐♥ ✷ ❞❜♠s❴♦✉t♣✉t✳❞✐s❛❜❧❡❀ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬❚❊❙❚❊✬✮❀ ✹ ❡♥❞❀ ✺ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Note que a mensagem “TESTE” não apareceu na tela. put Esta procedure recebe um parâmetro cujo valor será armazenado na área do buffer imediatamente após a última informação. Não é incluído qualquer caractere indicativo de fim de linha ( enter). É bom lembrar que estes valores de saída são transformados em strings (caractere), portanto, se desejar que eles tenham uma formatação diferente será preciso fazê-lo através do comando to_char ou to_number, por exemplo. Esta procedure por si só não imprime na tela. Por isso, podemos utilizá-la juntamente com a procedure new_line. Neste exemplo, como forma de armazenamento no buffer, utilizamos vários procedimentos put, um para cada letra. Veja o exemplo a seguir. ❙◗▲❃ ❜❡❣✐♥ ✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬❚✬✮❀ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬❊✬✮❀ ✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬❙✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬❚✬✮❀ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬❊✬✮❀ ✼ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ✽ ❡♥❞❀ ✾ ✴ ❚❊❙❚❊ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ 21 Casa do Código put_line Este procedimento envia o parâmetro informado para a área de buffer, acrescentando, automaticamente, um caractere indicativo de fim de linha após o texto enviado. Com isso, o resultado é impresso na tela, sem a necessidade da execução de qualquer outro procedimento. Note que em cada execução do put_line o buffer é limpo. ❙◗▲❃ ❜❡❣✐♥ ✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❚✬✮❀ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊✬✮❀ ✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❚✬✮❀ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊✬✮❀ ✼ ❡♥❞❀ ✽ ✴ ❚ ❊ ❙ ❚ ❊ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ get_line Este procedimento permite ler do buffer uma única linha de cada vez. Ele possui dois parâmetros de saída onde o primeiro retornará o conteúdo da linha ( line) e o segundo retornará seu status ( status). O status indica se a linha foi recuperada seguindo os critérios: 1 indica que foi recuperada uma linha do buffer; ❙◗▲❃ s❡t s❡r✈❡r♦✉t♣✉t ♦❢❢ ❙◗▲❃ ❜❡❣✐♥ ✷ ❞❜♠s❴♦✉t♣✉t✳❡♥❛❜❧❡✭✷✵✵✵✮❀ ✸ ✲✲ ✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬❈♦♠♦✬✮❀ 22 Casa do Código Capítulo 4. Pacote dbms_output ✺ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬❛♣r❡♥❞❡r✬✮❀ ✼ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬P▲❙◗▲❄✬✮❀ ✾ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ✶✵ ❡♥❞❀ ✶✶ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ s❡t s❡r✈❡r♦✉t♣✉t ♦♥ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✈❛r✶ ✈❛r❝❤❛r✷✭✶✵✵✮ ❞❡❢❛✉❧t ♥✉❧❧❀ ✸ ✈❛r✷ ✈❛r❝❤❛r✷✭✶✵✵✮ ❞❡❢❛✉❧t ♥✉❧❧❀ ✹ ✈❛r✸ ✈❛r❝❤❛r✷✭✶✵✵✮ ❞❡❢❛✉❧t ♥✉❧❧❀ ✺ st❛t✉s ♥✉♠❜❡r ❞❡❢❛✉❧t ♥✉❧❧❀ ✻ ❜❡❣✐♥ ✼ ✲✲ ✽ ❞❜♠s❴♦✉t♣✉t✳❣❡t❴❧✐♥❡✭✈❛r✶✱st❛t✉s✮❀ ✾ ❞❜♠s❴♦✉t♣✉t✳❣❡t❴❧✐♥❡✭✈❛r✷✱st❛t✉s✮❀ ✶✵ ❞❜♠s❴♦✉t♣✉t✳❣❡t❴❧✐♥❡✭✈❛r✸✱st❛t✉s✮❀ ✶✶ ✲✲ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬P❡r❣✉♥t❛✿ ✬⑤⑤✈❛r✶⑤⑤✬ ✬⑤⑤✈❛r✷⑤⑤✬ ✬⑤⑤✈❛r✸✮❀ ✶✸ ❡♥❞❀ ✶✹ ✴ P❡r❣✉♥t❛✿ ❈♦♠♦ ❛♣r❡♥❞❡r P▲❙◗▲❄ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Primeiramente, configuramos a sessão para não mostrar as saídas dos comandos put e put_line, através do comando set serveroutput off. Logo após, no primeiro bloco, habilitamos um buffer de 2000 bytes (linha 2). Nas linhas 4 a 9, temos comandos put inserindo caracteres no buffer que acabamos de habilitar. Estamos utilizando também o comando new_line para que os caracteres sejam guardados em linhas diferentes. 23 Casa do Código No segundo bloco, temos declaradas as variáveis var1, var2 e var3 (linha 2 a 4), que utilizaremos para atribuir os valores do buffer. Também declaramos a variável status (linha 5), que será utilizada para completar a chamada da procedure get_line. Nas linhas 8 a 10, temos as chamadas à procedure get_line, que recuperam as linhas do buffer e atribuem os valores às variáveis declaradas, anteriormente. Na linha 12, utilizamos o comando put_line para imprimir na tela o conteúdo das variáveis, ou seja, os mesmos recuperados do buffer. Note que, para que a impressão em tela funcione, executamos o comando set serveroutput on, antes da execução do segundo bloco. get_lines Este procedimento permite ler várias linhas do buffer utilizando um array de caracteres. Ele possui dois parâmetros, um de saída ( lines) e outro de entrada e saída ( numlines). O primeiro parâmetro, lines, se trata de uma tabela do tipo varchar2(255), podendo ser declarada com tipo dbms_output.chararr. Já o parâmetro numlines serve tanto para informar a quantidade de linhas que se deseja recuperar, quanto para retornar a quantidade de linhas que realmente foram retornadas após a execução da procedure. Veja o exemplo a seguir. ❙◗▲❃ ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ s❡t s❡r✈❡r♦✉t♣✉t ♦❢❢ ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳❡♥❛❜❧❡✭✷✵✵✵✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬❈♦♠♦✬✮❀ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬❛♣r❡♥❞❡r✬✮❀ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ❞❜♠s❴♦✉t♣✉t✳♣✉t✭✬P▲❙◗▲❄✬✮❀ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ 24 Casa do Código Capítulo 4. Pacote dbms_output ❙◗▲❃ s❡t s❡r✈❡r♦✉t♣✉t ♦♥ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ t❛❜ ❞❜♠s❴♦✉t♣✉t✳❝❤❛r❛rr❀ ✸ qt❧✐♥❡s ♥✉♠❜❡r ❞❡❢❛✉❧t ✸❀ ✹ r❡s ✈❛r❝❤❛r✷✭✶✵✵✮ ❞❡❢❛✉❧t ♥✉❧❧❀ ✺ ❜❡❣✐♥ ✻ ✲✲ ✼ ❞❜♠s❴♦✉t♣✉t✳❣❡t❴❧✐♥❡s✭t❛❜✱qt❧✐♥❡s✮❀ ✽ ✲✲ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❘❡t♦r♥♦✉✿ ✬⑤⑤qt❧✐♥❡s⑤⑤✬ r❡❣✐str♦s✳✬✮❀ ✶✵ ✲✲ ✶✶ ❢♦r ✐ ✐♥ ✶✳✳qt❧✐♥❡s ❧♦♦♣ ✶✷ r❡s ✿❂ r❡s⑤⑤✬ ✬⑤⑤t❛❜✭✐✮❀ ✶✸ ❡♥❞ ❧♦♦♣❀ ✶✹ ✲✲ ✶✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬P❡r❣✉♥t❛✿ ✬⑤⑤r❡s✮❀ ✶✻ ✲✲ ✶✼ ❡♥❞❀ ✶✽ ✴ ❘❡t♦r♥♦✉✿ ✸ r❡❣✐str♦s✳ P❡r❣✉♥t❛✿ ❈♦♠♦ ❛♣r❡♥❞❡r P▲❙◗▲❄ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Muito parecido com o exemplo anterior, neste exemplo, a alteração foi substituir as três variáveis var1, var2 e var3, pela variável tab, do tipo array (linha 2). Também declaramos as variáveis qtlines e res (linhas 3 e 4), sendo que a primeira é usada para passar a quantidade de registros a serem retornados (e consequentemente fazer o retorno) e a segunda apenas para montar a string a ser impressa na tela. Na linha 7, temos a chamada à procedure get_lines, que retorna os dados do buffer para dentro de nossa variável tab. Já nas linhas 11 a 13, utilizamos uma estrutura loop, para ler os dados da variável array e concatená-los na variável res. Observe que utilizamos a variável qtlines (contendo a quantidade de linhas retornadas) para determinar o valor final da faixa para loop. Na linha 15, temos a 25 4.1. Exceções para o pacote dbms_output Casa do Código impressão do conteúdo de res. 4.1 Exceções para o pacote dbms_output Existem duas exceções que podem ocorrer quando utilizamos o pacote dbms_output. Seguem informações sobre elas e como tratá-las. • ORU-10027 (Overflow de buffer). Solução: aumentar o tamanho do buffer se possível. Caso contrário, encontrar um modo de gravar menos dados. • ORU-10028 (Overflow de comprimento de linha, limite de 255 caracteres por linha). Solução: verificar se todas as chamadas feitas a caracteres por linha put e put_line têm menos de 255 caracteres por linha. Neste capítulo falamos sobre o dbms_output e seus recursos. Durante o todo o livro de PL/SQL vamos utilizar este pacote para gerar as saídas das informações para nossos exemplos. Desta forma, é muito importante conhecêlo e saber utilizá-lo. 26 Capítulo 5 Variáveis bind e de substituição A ferramenta SQL*Plus permite o uso de variáveis com referências do tipo bind e de substituição. 5.1 Variáveis bind As variáveis bind são declaradas dentro do SQL*Plus e podem ser utilizadas em todo seu ambiente, sendo em comandos SQL ou dentro de programas PL/SQL. A declaração deste tipo de variável é muito semelhante à declaração utilizada no PL/SQL, onde a nomeamos e definimos um tipo para ela. Contudo, não é necessária uma área específica para declaração, bastando apenas declará-la no prompt do SQL*Plus. Veja o exemplo: ❙◗▲❃ ✈❛r✐❛❜❧❡ ♠❡♥s❛❣❡♠ ✈❛r❝❤❛r✷✭✷✵✵✮ ❙◗▲❃ 5.1. Variáveis bind Casa do Código Estamos declarando uma variável chamada mensagem do tipo varchar2 com 200 posições. Depois de declarada, é só utilizá-la nos programas. ❙◗▲❃ ❜❡❣✐♥ ✷ ✿♠❡♥s❛❣❡♠ ✿❂ ✬❈✉rs♦ P▲❙◗▲✬❀ ✸ ❡♥❞❀ ✹ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Note que estamos utilizando-a dentro de um bloco PL/SQL, onde atribuímos um valor para ela. Para recuperar ou atribuir um valor para uma variável bind, em um programa PL/SQL ou comando SQL, é necessário referenciá-la através da utilização do caractere dois pontos ( :), colocando-o antes do seu nome. No entanto, quando a definimos ou quando forçamos a impressão do seu valor em tela, não há a necessidade deste caractere especial. Para visualizar o conteúdo de uma variável bind na tela do SQL*Plus, você deve habilitar a impressão através do comando a seguir. ❙◗▲❃ s❡t ❛✉t♦♣r✐♥t ♦♥ ❙◗▲❃ Após habilitar a impressão, o conteúdo da variável é impresso logo após a execução do comando ou programa onde ela está sendo utilizada. Veja a execução do exemplo anterior, agora com o autoprint ligado. ❙◗▲❃ ❜❡❣✐♥ ✷ ✿♠❡♥s❛❣❡♠ ✿❂ ✬❈✉rs♦ P▲❙◗▲✬❀ ✸ ❡♥❞❀ ✹ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ▼❊◆❙❆●❊▼ 28 Casa do Código Capítulo 5. Variáveis bind e de substituição ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❈✉rs♦ P▲❙◗▲ ❙◗▲❃ Veja mais um exemplo, agora utilizando a variável no comando select. ❙◗▲❃ s❡❧❡❝t ✿♠❡♥s❛❣❡♠ ❢r♦♠ ❞✉❛❧❀ ✿▼❊◆❙❆●❊▼ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❈✉rs♦ P▲❙◗▲ ❙◗▲❃ Note que, como a variável já havia recebido um valor, quando executamos o bloco PL/SQL, este valor ainda persiste em execuções posteriores. Para alterar um valor de uma variável bind diretamente pelo SQL*Plus, podemos utilizar o comando exec. Veja o exemplo a seguir, onde definimos uma variável chamada gdepno, e logo após atribuímos o valor 10 a ela. ❙◗▲❃ ✈❛r✐❛❜❧❡ ❣❞❡♣♥♦ ♥✉♠❜❡r ❙◗▲❃ ❙◗▲❃ ❡①❡❝ ✿❣❞❡♣♥♦ ✿❂ ✶✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❣❞❡♣♥♦ ✲✲✲✲✲✲✲✲✲✲ ✶✵ ❙◗▲❃ Agora, selecionamos os empregados com base no código do departamento, vindo da variável bind gdepno. ❙◗▲❃ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✿❣❞❡♣♥♦❀ 29 5.1. Variáveis bind Casa do Código ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❈▲❆❘❑ ❑■◆● ▼■▲▲❊❘ ❙◗▲❃ Se quisermos visualizar o conteúdo de uma variável bind, utilizamos o comando print. Veja o exemplo a seguir: ❙◗▲❃ ♣r✐♥t ❣❞❡♣♥♦❀ ❣❞❡♣♥♦ ✲✲✲✲✲✲✲✲✲✲ ✶✵ ❙◗▲❃ Uma variável bind tem sua vida útil com base na sessão do SQL*Plus. Portanto, outras sessões não as enxergam, somente a que as criou. Quando o SQL*Plus é fechado, automaticamente, elas são excluídas da memória. A utilização de variáveis bind tem algumas restrições, por exemplo seu uso na cláusula from, que não é permitido, e na substituição de palavras reservadas. Para ver todas as variáveis binds declaradas em uma sessão do SQL*Plus utilize o comando var. ❙◗▲❃ ✈❛r ✈❛r✐á✈❡❧ ✇❞♥❛♠❡ ❚✐♣♦ ❞❡ ❞❛❞♦s ◆❯▼❇❊❘ ✈❛r✐á✈❡❧ ❣♥♦♠❡ ❚✐♣♦ ❞❡ ❞❛❞♦s ✈❛r❈❍❆❘✷✭✶✵✵✮ ❙◗▲❃ 30 Casa do Código 5.2 Capítulo 5. Variáveis bind e de substituição Variáveis de substituição Outro tipo de variável de usuário é a variável de substituição. Este tipo também pode ser utilizado em comandos DML ou PL/SQL. Seu objetivo é substituir tal variável, dentro de comandos SQL ou PL/SQL, por um conjunto de caracteres predefinidos ou definidos em tempo de execução. Ao contrário das variáveis binds, as de substituição podem ser utilizadas também como forma de completar comandos SQL, pois ela permite a utilização de palavras reservadas em seu teor. Veja a seguir como definir uma variável de substituição. ❙◗▲❃ ❞❡❢✐♥❡ ✇❡♠♣♥♦ ❂ ✼✸✻✾ ❙◗▲❃ Para definir uma variável de substituição utilizamos o comando define seguido de um nome para a variável. Neste exemplo, além de definir um nome, atribuímos um valor para a variável através do operador de igualdade ( =). Note que para as variáveis de substituição não definimos um tipo, pois são sempre do tipo alfanumérico. Veja um exemplo, utilizando a variável wempno que acabamos de definir. ❙◗▲❃ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫✇❡♠♣♥♦❀ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫✇❡♠♣♥♦ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✼✸✻✾ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❙◗▲❃ Note que, para utilizarmos a variável de substituição, colocamos na frente de seu nome o &. Esta é a indicação de que estamos utilizando uma variável de substituição. Veja um exemplo utilizando-a em PL/SQL. ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r ✐ ✐♥ ✭s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫✇❡♠♣♥♦✮ ❧♦♦♣ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✐✳❡♥❛♠❡✮❀ ✹ ❡♥❞ ❧♦♦♣❀ ✺ ❡♥❞❀ 31 Casa do Código 5.2. Variáveis de substituição ✻ ✴ ❛♥t✐❣♦ ♥♦✈♦ ❙▼■❚❍ ✷✿ ✷✿ ❢♦r ✐ ✐♥ ✭ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫✇❡♠♣♥♦✮ ❧♦♦♣ ❢♦r ✐ ✐♥ ✭ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✼✸✻✾✮ ❧♦♦♣ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Para alterar um valor de uma variável de substituição também utilizamos o comando define. Veja a seguir: ❙◗▲❃ ❞❡❢✐♥❡ ✇❡♠♣♥♦ ❂ ✶✵ ❙◗▲❃ ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r ✐ ✐♥ ✭ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫✇❡♠♣♥♦✮ ❧♦♦♣ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✐✳❡♥❛♠❡✮❀ ✹ ❡♥❞ ❧♦♦♣❀ ✺ ❡♥❞❀ ✻ ✴ ❛♥t✐❣♦ ✷✿ ❢♦r ✐ ✐♥ ✭ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫✇❡♠♣♥♦✮ ❧♦♦♣ ❢♦r ✐ ✐♥ ✭ ♥♦✈♦ ✷✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✶✵✮ ❧♦♦♣ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Já para sabermos qual o valor corrente de uma variável de substituição, utilizamos o comando define seguido do nome da variável. ❙◗▲❃ ❞❡❢✐♥❡ ✇❡♠♣♥♦ ❞❡❢✐♥❡ ✇❡♠♣♥♦ ❙◗▲❃ 32 ❂ ✧✶✵✧ ✭❈❍❆❘✮ Casa do Código Capítulo 5. Variáveis bind e de substituição Como mencionado anteriormente, as variáveis de substituição podem também ser utilizadas para substituição de palavras reservadas, ou seja, podemos não só substituir tal variável por um valor alfanumérico, como também por uma sentença SQL, como uma clausula where ou order by. Veja o exemplo: ❙◗▲❃ ❞❡❢✐♥❡ ❣❢r♦♠ ❂ ✬❢r♦♠ ❡♠♣✬ ❙◗▲❃ ❞❡❢✐♥❡ ❣✇❤❡r❡ ❂ ✬✇❤❡r❡ ❡♠♣♥♦ ❂ ✼✸✻✾✬ ❙◗▲❃ ❞❡❢✐♥❡ ❣♦r❞❡r❜② ❂ ✬♦r❞❡r ❜② ✶✬ ❙◗▲❃ ❙◗▲❃ s❡❧❡❝t ❡♥❛♠❡ ✫❣❢r♦♠ ✫❣✇❤❡r❡ ✫❣♦r❞❡r❜②❀ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ✫❣❢r♦♠ ✫❣✇❤❡r❡ ✫❣♦r❞❡r❜② ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✼✸✻✾ ♦r❞❡r ❜② ✶ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❙◗▲❃ Isso também funciona para PL/SQL. ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r ✐ ✐♥ ✭s❡❧❡❝t ❡♥❛♠❡ ✫❣❢r♦♠ ✫❣✇❤❡r❡ ✫❣♦r❞❡r❜②✮ ❧♦♦♣ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✐✳❡♥❛♠❡✮❀ ✹ ❡♥❞ ❧♦♦♣❀ ✺ ❡♥❞❀ ✻ ✴ ❛♥t✐❣♦ ✷✿ ❢♦r ✐ ✐♥ ✭ s❡❧❡❝t ❡♥❛♠❡ ✫❣❢r♦♠ ✫❣✇❤❡r❡ ✫❣♦r❞❡r❜②✮ ❧♦♦♣ ❢♦r ✐ ✐♥ ✭ ♥♦✈♦ ✷✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✼✸✻✾ ♦r❞❡r ❜② ✶✮ ❧♦♦♣ ❙▼■❚❍ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ 33 5.2. Variáveis de substituição Casa do Código A vida útil de uma variável de substituição também será limitada pela sessão do SQL*Plus. Enquanto a sessão estiver ativa, ela existirá. Outras sessões não podem vê-la, como também acontece com as variáveis do tipo bind. Uma variável de substituição pode ter sua definição excluída. Para tal ação, podemos utilizar o comando undefine. Veja o exemplo. ❙◗▲❃ ✉♥❞❡❢✐♥❡ ❣❢r♦♠ ❙◗▲❃ Ao contrário de uma variável bind, uma variável de substituição não necessita ser obrigatoriamente definida ou declarada. Podemos simplesmente informá-la em nosso comando SQL ou PL/SQL, e deixar que o motor do SQL*Plus solicite o valor para ela, sem que seja necessária uma definição prévia. Observe o exemplo a seguir: ❙◗▲❃ s❡❧❡❝t ❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫❝♦❞✐❣♦❀ ■♥❢♦r♠❡ ♦ ✈❛❧♦r ♣❛r❛ ❝♦❞✐❣♦✿ ✼✾✵✷ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫❝♦❞✐❣♦ ♥♦✈♦ ✶✿ s❡❧❡❝t ❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✼✾✵✷ ❏❖❇ ✲✲✲✲✲✲✲✲✲ ❆◆❆▲❨❙❚ ❙◗▲❃ ❞❡❢✐♥❡ ❞❡❢✐♥❡ ❴❈❖◆◆❊❈❚❴■❉❊◆❚■❋■❊❘ ❂ ✧①❡✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ❴❙◗▲P▲❯❙❴❘❊▲❊❆❙❊ ❂ ✧✾✵✷✵✵✵✶✵✵✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ❴❊❉■❚❖❘ ❂ ✧◆♦t❡♣❛❞✧ ✭❈❍❆❘✮ ❂ ✧❖r❛❝❧❡ ❉❛t❛❜❛s❡ ✶✵❣ ❊①♣r❡ss ❊❞✐t✐♦♥ ❞❡❢✐♥❡ ❴❖❴❱❊❘❙■❖◆ ❘❡❧❡❛s❡ ✶✵✳✷✳✵✳✶✳✵ ✲ Pr♦❞✉❝t✐♦♥✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ❴❖❴❘❊▲❊❆❙❊ ❂ ✧✶✵✵✷✵✵✵✶✵✵✧ ✭❈❍❆❘✮ ❂ ✧✶✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ✶ ❞❡❢✐♥❡ ❴❘❈ ❂ ✧✶✧ ✭❈❍❆❘✮ ❂ ✧✶✶✶✶✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ✇❡♠♣♥♦ ❞❡❢✐♥❡ ●✇❤❡r❡ ❂ ✧✇❤❡r❡ ❡♠♣♥♦ ❂ ✼✸✻✾✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ●❖❘❉❊❘❇❨ ❂ ✧♦r❞❡r ❜② ✶✧ ✭❈❍❆❘✮ ❙◗▲❃ 34 Casa do Código Capítulo 5. Variáveis bind e de substituição Veja que utilizamos uma variável como substituição, chamada codigo. Vale ressaltar que não a definimos em nenhum momento. Mesmo assim, o SQL*Plus a reconheceu como uma variável, pois utilizamos o & na frente do seu nome, e solicitou um valor para ela. Desta forma, se não tivermos a variável de substituição já definida, o SQL*Plus vai solicitar um valor. Note também que após a sua utilização o SQL*Plus não a deixa definida, ou seja, isso ocorre apenas em tempo de execução. Em PL/SQL também podemos utilizá-la desta forma. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❥♦❜ ❡♠♣✳❥♦❜✪t②♣❡❀ ✸ ❜❡❣✐♥ ✹ s❡❧❡❝t ❥♦❜ ✐♥t♦ ✇❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫❝♦❞❴❡♠♣❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇❥♦❜✮❀ ✼ ❡♥❞❀ ✽ ✴ ■♥❢♦r♠❡ ♦ ✈❛❧♦r ♣❛r❛ ❝♦❞❴❡♠♣✿ ✼✾✵✷ ❛♥t✐❣♦ ✹✿ s❡❧❡❝t ❥♦❜ ✐♥t♦ ✇❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✫❝♦❞❴❡♠♣❀ ♥♦✈♦ ✹✿ s❡❧❡❝t ❥♦❜ ✐♥t♦ ✇❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✼✾✵✷❀ ❆◆❆▲❨❙❚ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ 5.3 Utilizando variáveis em arquivos Também podemos utilizar variáveis binds ou de substituição dentro de arquivos e depois executá-los via SQL*Plus. Nesses casos, se forem encontradas variáveis do tipo bind ou de substituição, o SQL*Plus vai fazer o preenchimento dos valores correspondentes. Nos casos de variáveis bind, o SQL*Plus não solicitará os valores, pois eles já devem estar definidos. No caso de variáveis de substituição, vai depender se já se encontram ou não definidas na sessão. Veja os exemplos: A seguir estamos criando um arquivo de script chamado S_EMP.sql contendo o comando para retornar os empregados com base em um depar35 5.3. Utilizando variáveis em arquivos Casa do Código tamento informado via uma variável bind. ❙◗▲❃ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✿❜❞❡♣t♥♦ ✷ ❙◗▲❃ s❛✈❡ ❇❴❊▼P✳sq❧ ❈r✐❛❞♦ ❛rq✉✐✈♦ ❇❴❊▼P✳sq❧ ❙◗▲❃ ❙◗▲❃ ❣❡t ❇❴❊▼P✳sq❧ ✶✯ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✿❜❞❡♣t♥♦ ❙◗▲❃ Definindo a variável bind dentro da sessão do SQL*Plus: ❙◗▲❃ ✈❛r ❜❞❡♣t♥♦ ♥✉♠❜❡r ❙◗▲❃ Definindo um valor para a variável bind bdeptno: ❙◗▲❃ ❡①❡❝ ✿❜❞❡♣t♥♦ ✿❂ ✶✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ♣r✐♥t ❜❞❡♣t♥♦ ❇❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✶✵ ❙◗▲❃ Executando o arquivo S_EMP.sql: ❙◗▲❃ ❅❇❴❊▼P✳sq❧ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❈▲❆❘❑ ❑■◆● ▼■▲▲❊❘ ❙◗▲❃ 36 ❏❖❇ ✲✲✲✲✲✲✲✲✲ ▼❆◆❆●❊❘ P❘❊❙■❉❊◆❚ ❈▲❊❘❑ Casa do Código Capítulo 5. Variáveis bind e de substituição Agora vamos ver outro exemplo utilizando variáveis de substituição: ❙◗▲❃ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫s❞❡♣t♥♦ ✷ ❙◗▲❃ s❛✈❡ ❙❴❊▼P✳sq❧ ❈r✐❛❞♦ ❛rq✉✐✈♦ ❙❴❊▼P✳sq❧ ❙◗▲❃ ❙◗▲❃ No caso das variáveis de substituição, conforme já mencionado, mesmo não as definindo, o SQL*Plus faz a solicitação de valores. Vamos testar. ❙◗▲❃ ❅❙❴❊▼P✳sq❧ ■♥❢♦r♠❡ ♦ ✈❛❧♦r ♣❛r❛ s❞❡♣t♥♦✿ ✷✵ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫s❞❡♣t♥♦ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❏❖◆❊❙ ❙❈❖❚❚ ❆❉❆▼❙ ❋❖❘❉ ❙◗▲❃ Note que o SQL*Plus solicitou o valor através da linha “Informe o valor para sdeptno:”. Neste caso, foi informado o valor 20. Contudo, como a variável não está definida, sempre que executamos este script o programa vai solicitar um valor. Para que ele não fique solicitando um valor sempre o que script for executado, definimos a variável através do comando define. Com isso, o SQL*Plus não pedirá mais o valor. Veja o exemplo: ❙◗▲❃ ❞❡❢✐♥❡ s❞❡♣t♥♦ ❂ ✶✵ ❙◗▲❃ ❅❙❴❊▼P✳sq❧ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫s❞❡♣t♥♦ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✶✵ 37 5.3. Utilizando variáveis em arquivos Casa do Código ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❈▲❆❘❑ ❑■◆● ▼■▲▲❊❘ ❙◗▲❃ Repare que agora ele não pede mais o valor, apenas faz a substituição da variável com base no valor guardado na sessão do SQL*Plus. Se excluirmos a definição da variável, ele volta a solicitar o valor. ❙◗▲❃ ✉♥❞❡❢✐♥❡ s❞❡♣t♥♦ ❙◗▲❃ ❅❙❴❊▼P✳sq❧ ■♥❢♦r♠❡ ♦ ✈❛❧♦r ♣❛r❛ s❞❡♣t♥♦✿ ✷✵ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫s❞❡♣t♥♦ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❏❖◆❊❙ ❙❈❖❚❚ ❆❉❆▼❙ ❋❖❘❉ ❙◗▲❃ Outra forma de definir uma variável de substituição é utilizando && (duplo) em vez de um só &. Isso faz com que o SQL*Plus crie a definição da variável: ❙◗▲❃ ❡❞✐t ❙❴❊▼P✳sq❧ ❙◗▲❃ ❣❡t ❙❴❊▼P✳sq❧ ✶✯ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫✫s❞❡♣t♥♦ ❙◗▲❃ ❙◗▲❃ ❅❙❴❊▼P✳sq❧ 38 Casa do Código Capítulo 5. Variáveis bind e de substituição ■♥❢♦r♠❡ ♦ ✈❛❧♦r ♣❛r❛ s❞❡♣t♥♦✿ ✶✵ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫✫s❞❡♣t♥♦ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✶✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❈▲❆❘❑ ❑■◆● ▼■▲▲❊❘ ❙◗▲❃ ❅❙❴❊▼P✳sq❧ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫✫s❞❡♣t♥♦ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✶✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❈▲❆❘❑ ❑■◆● ▼■▲▲❊❘ ❙◗▲❃ Veja que editamos o arquivo S_EMP e acrescentamos mais um & ao já existente. Depois, salvamos o arquivo. Ao executá-lo, o SQL*Plus detectou os &&, contudo, como a variável não continha nenhum valor inicial definido, ele solicitou um valor. Já na segunda vez que executamos o arquivo, o SQL*Plus já não o solicitou. Se executarmos o comando define para ver as variáveis de substituição definidas na sessão, veremos que o SQL*Plus definiu automaticamente a nossa variável SDEPTNO. ❙◗▲❃ ❞❡❢✐♥❡ ❞❡❢✐♥❡ ❴❈❖◆◆❊❈❚❴■❉❊◆❚■❋■❊❘ ❂ ✧①❡✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ❴❙◗▲P▲❯❙❴❘❊▲❊❆❙❊ ❂ ✧✾✵✷✵✵✵✶✵✵✧ ✭❈❍❆❘✮ ❂ ✧◆♦t❡♣❛❞✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ❴❊❉■❚❖❘ ❞❡❢✐♥❡ ❴❖❴❱❊❘❙■❖◆ ❂ ✧❖r❛❝❧❡ ❉❛t❛❜❛s❡ ✶✵❣ ❊①♣r❡ss ❊❞✐t✐♦♥ ❘❡❧❡❛s❡ ✶✵✳✷✳✵✳✶✳✵ ✲ Pr♦❞✉❝t✐♦♥✧ ✭❈❍❆❘✮ ❂ ✧✶✵✵✷✵✵✵✶✵✵✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ❴❖❴❘❊▲❊❆❙❊ ❞❡❢✐♥❡ ❴❘❈ ❂ ✧✶✧ ✭❈❍❆❘✮ ❞❡❢✐♥❡ ✶ ❂ ✧✸✵✧ ✭❈❍❆❘✮ 39 Casa do Código 5.3. Utilizando variáveis em arquivos ❞❡❢✐♥❡ ❙❉❊P❚◆❖ ❙◗▲❃ ❂ ✧✶✵✧ ✭❈❍❆❘✮ Outro recurso que pode ser utilizado é a passagem de valores para as variáveis de substituição quando executamos um arquivo. Este recurso está habilitado somente para as variáveis deste tipo. Neste caso, devemos utilizar indexadores numéricos juntamente com o &, como por exemplo, &1, &2 etc. nos comandos dentro do arquivo. Caso contrário, o SQL*Plus vai ignorar este valores, solicitando a entrada deles assim que for executado o arquivo. Veja o exemplo a seguir: ❙◗▲❃ ❡❞✐t ❙❴❊▼P✳sq❧ ❙◗▲❃ ❣❡t ❙❴❊▼P✳sq❧ ✶✯ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫✶ ❙◗▲❃ Editamos o arquivo S_EMP.sql modificando o nome da variável de substituição de sdeptno para 1. Agora vamos executar o arquivo passando um valor como parâmetro na chamada da execução. ❙◗▲❃ ❅❙❴❊▼P✳sq❧ ✶✵ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫✶ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✶✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❈▲❆❘❑ ❑■◆● ▼■▲▲❊❘ ❙◗▲❃ Veja que o valor 10 informado na chamada da execução do arquivo foi passado para dentro dele, substituindo a variável &1. Com o uso de indexadores, o SQL*Plus define automaticamente a variável na sessão, e com isso, nas próximas execuções, não necessitamos informar o valor caso ele não seja diferente da execução anterior. Para trocar o valor da variável, basta informar um novo valor na chamada. 40 Casa do Código Capítulo 5. Variáveis bind e de substituição ❙◗▲❃ ❅❙❴❊▼P✳sq❧ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫✶ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✶✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❈▲❆❘❑ ❑■◆● ▼■▲▲❊❘ ❙◗▲❃ ❅❙❴❊▼P✳sq❧ ✷✵ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫✶ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❏❖◆❊❙ ❙❈❖❚❚ ❆❉❆▼❙ ❋❖❘❉ ❙◗▲❃ Note que, na primeira execução, apenas chamamos o arquivo sem a passagem de um valor. Como anteriormente já havíamos executado o arquivo passando o valor 10, ele assumiu este valor para as demais execuções. Na segunda execução, informamos um valor diferente, 20, fazendo com que ele seja passado como parâmetro a partir de então. Outro comando que é utilizado para definir uma variável de substituição é o accept. A diferença dele para define é que podemos formatar uma mensagem para ser mostrada ao usuário no momento de solicitar a entrada de um valor. Sua utilização é muito interessante quando estamos executando scripts via arquivo. Veja o exemplo. ❙◗▲❃ ❡❞✐t ❙❴❊▼P✳sq❧ ❙◗▲❃ ❣❡t ❙❴❊▼P✳sq❧ 41 5.3. Utilizando variáveis em arquivos Casa do Código ✶ ❛❝❝❡♣t ❙❉❊P❚◆❖ ♥✉♠❜❡r ❢♦r ✾✾✾ ❞❡❢❛✉❧t ✷✵ ♣r♦♠♣t ✧■♥❢♦r♠❡ ♦ ❞❡♣t♥♦✿ ✧ ✷✯ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫❙❉❊P❚◆❖ ❙◗▲❃ ❙◗▲❃ ❅❙❴❊▼P✳sq❧ ■♥❢♦r♠❡ ♦ ❞❡♣t♥♦✿ ✷✵ ❛♥t✐❣♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✫❙❉❊P❚◆❖ ✷✵ ♥♦✈♦ ✶✿ s❡❧❡❝t ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❏❖◆❊❙ ❙❈❖❚❚ ❆❉❆▼❙ ❋❖❘❉ ❙◗▲❃ Em primeiro lugar, alteramos o arquivo S_EMP acrescentando a linha referente ao accept, que deve vir antes do comando SQL ao qual se quer associar a mensagem e a variável. Neste nosso exemplo, o comando está antes do select. Logo após o comando accept, informamos o nome para variável, seguido pelo tipo do dado. Escolhemos uma variável do tipo number que vai se chamar SDEPTNO. Logo após o tipo da variável, podemos informar também a máscara utilizando o comando for seguido do formato. No exemplo, colocamos o formato como 999 (máximo de 3 casas). Também definimos o valor 20 como padrão, através da expressão default, ou seja, a variável já será inicializada com este valor. E agora vem o suprassumo do recurso. Através do comando prompt, definimos uma mensagem para ser mostrada para o usuário no momento da solicitação dos valores. Esta mensagem deve ser informada sempre logo após o comando. Por fim, executamos o arquivo. 42 Capítulo 6 Aspectos iniciais da programação PL/SQL Como em qualquer linguagem de programação, em PL/SQL também há regras que devem ser seguidas na hora de codificar programas. Cada linguagem de programação trabalha de uma forma, contudo certos conceitos prevalecem entre todas. Aspectos relacionados ao desenvolvimento, como áreas predefinidas para declarações de variáveis, tratamentos de erros ou comentários em programas, por exemplo, são comuns em todas as linguagens. O que difere entre elas é a forma como cada uma trata estes aspectos. Para programar em PL/SQL, você deve conhecer sua sintaxe e os elementos que podem ser utilizados na codificação dos programas. Veja agora alguns pontos importantes para você iniciar na escrita de códigos nesta linguagem. 6.1. Caracteres e operadores 6.1 Casa do Código Caracteres e operadores Dentro da linguagem você pode utilizar caracteres e operadores para auxiliar na codificação. São eles: • Caracteres: A a Z (maiúsculos e minúsculos), números de 0 a 9 e os caracteres especiais: ( ) + - * / < > = ! ; : . ’ @ % , "$ & _ \{ } [ ] | # • Operadores Relacionais: <, >, =, !=, >=, <=, IS NULL, IS NOT NULL • Operadores Lógicos: AND, OR e NOT 6.2 Identificadores Para nomear identificadores em PL/SQL, por exemplo, variáveis, constantes ou qualquer objeto, nós devemos seguir algumas regras. São elas: • A quantidade de caracteres para nomear um identificador é de no máximo 30. • Não podemos utilizar palavras reservadas como begin, if, loop, end etc. • Para nomear os identificadores, podemos utilizar letras, números e alguns caracteres especiais, mas nem todos. • Obrigatoriamente, o primeiro caractere em um nome de identificador deve ser uma letra. Escopo de identificadores O escopo de um identificador está limitado ao bloco onde foi declarado. Podemos ter vários blocos encadeados. Logo, cada bloco pode ter sua própria área de declaração de identificadores. Neste caso, um identificador, por exemplo, uma variável, declarada em um bloco mais interno, não poderá ser acessada em um bloco mais externo. Veja o exemplo a seguir. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ❢♦❧❤❛❴♣❛❣❛♠❡♥t♦✭♣qt❴❞✐❛s ♥✉♠❜❡r✮ ✐s 44 Casa do Código Capítulo 6. Aspectos iniciais da programação PL/SQL ✷ ✲✲ ✸ ✇qt❴❞✐❛s ♥✉♠❜❡r❀ ✹ ✇✈❧❴❜r✉t♦ ♥✉♠❜❡r❀ ✺ ✇✈❧❴✐r ♥✉♠❜❡r❀ ✻ ✇✈❧❴❧✐q✉✐❞♦ ♥✉♠❜❡r❀ ✼ ✲✲ ✽ ❜❡❣✐♥ ✾ ✇✈❧❴❜r✉t♦ ✿❂ ✭♣qt❴❞✐❛s ✯ ✷✺✮❀ ✶✵ ✲✲ ✶✶ ❞❡❝❧❛r❡ ✶✷ ✇t①❴✐r ♥✉♠❜❡r❀ ✶✸ ❜❡❣✐♥ ✶✹ ✐❢ ✇✈❧❴❜r✉t♦ ❃ ✺✹✵✵ t❤❡♥ ✶✺ ✲✲ ✶✻ ✇t①❴✐r ✿❂ ✷✼❀ ✶✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❚❛①❛ ■❘✿ ✬⑤⑤✇t①❴✐r✮❀ ✶✽ ✲✲ ✶✾ ❡❧s❡ ✷✵ ✲✲ ✷✶ ✇t①❴✐r ✿❂ ✽❀ ✷✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❚❛①❛ ■❘✿ ✬⑤⑤✇t①❴✐r✮❀ ✷✸ ✲✲ ✷✹ ❡♥❞ ✐❢❀ ✷✺ ✲✲ ✷✻ ✇✈❧❴✐r ✿❂ ✭✇✈❧❴❜r✉t♦ ✯ ✇t①❴✐r✮ ✴ ✶✵✵❀ ✷✼ ✲✲ ✷✽ ✇✈❧❴❧✐q✉✐❞♦ ✿❂ ✭✇✈❧❴❜r✉t♦ ✲ ✇✈❧❴✐r✮❀ ✷✾ ✲✲ ✸✵ ❡♥❞❀ ✸✶ ✲✲ ✸✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❱❛❧♦r ❞♦ s❛❧❛r✐♦ ❜r✉t♦✿ ✬⑤⑤✇✈❧❴❜r✉t♦✮❀ ✸✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡s❝♦♥t♦ ❞♦ ✈❛❧♦r ❞♦ ■❘✿ ✬⑤⑤✇✈❧❴✐r✮❀ ✸✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❱❛❧♦r ❞♦ s❛❧❛r✐♦ ❧✐q✉✐❞♦✿ ✬⑤⑤✇✈❧❴❧✐q✉✐❞♦✮❀ ✸✺ ✲✲ ✸✻ ❡①❝❡♣t✐♦♥ ✸✼ ✇❤❡♥ ♦t❤❡rs t❤❡♥ 45 6.2. Identificadores Casa do Código ✸✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦ ❛♦ ❝❛❧❝✉❧❛r ♣❛❣❛♠❡♥t♦✳ ❊rr♦✿ ✬⑤⑤sq❧❡rr♠✮❀ ✸✾ ❡♥❞ ❢♦❧❤❛❴♣❛❣❛♠❡♥t♦❀ ✹✵ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ Nesse exemplo, temos um programa que calcula o valor a ser pago a um empregado, mediante a quantidade de horas passada por parâmetro a um procedimento. Uma das premissas para calcular o valor líquido a ser pago é o cálculo do imposto de renda (IR). Se analisarmos o programa, é possível identificar dois blocos. Um principal e outro mais interno. O bloco interno é utilizado para o cálculo do IR. Note que nele criamos uma segunda área de declaração de variáveis que é específica deste bloco. Ali declaramos a variável wtx_ir que receberá a taxa para o cálculo do imposto mediante uma condição. A partir da obtenção da taxa, é calculado o valor do imposto e também o valor líquido a ser pago. Observações importantes: o escopo da variável wtx_ir está limitado ao bloco em que ela foi declarada. Caso a usássemos fora deste escopo, o Oracle geraria um erro indicando que ela não foi declarada. Em contrapartida, podemos observar que as variáveis wvl_ir e wvl_liquido estão sendo utilizadas dentro do bloco mais interno, sem que nenhum erro aconteça. Isso é possível devido ao fato de elas terem sido declaradas em um bloco mais externo. Logo, seus escopos abrangem todo o bloco onde foram declaradas, inclusive, blocos internos contidos neste. Segue o resultado. ❙◗▲❃ ❜❡❣✐♥ ❢♦❧❤❛❴♣❛❣❛♠❡♥t♦✭♣qt❴❞✐❛s ❂❃ ✸✵✵✮❀ ❡♥❞❀ ✷ ✴ ❚❛①❛ ■❘✿ ✷✼ ❱❛❧♦r ❞♦ s❛❧❛r✐♦ ❜r✉t♦✿ ✼✺✵✵ ❉❡s❝♦♥t♦ ❞♦ ✈❛❧♦r ❞♦ ■❘✿ ✷✵✷✺ ❱❛❧♦r ❞♦ s❛❧❛r✐♦ ❧✐q✉✐❞♦✿ ✺✹✼✺ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ 46 Casa do Código Capítulo 6. Aspectos iniciais da programação PL/SQL ❙◗▲❃ 6.3 Transações Primeiramente, antes de começarmos a trabalhar com PL/SQL, é preciso conhecer o conceito de transação. Uma das características mais bem-vindas dos bancos de dados Cliente/Servidor, em relação aos bancos de dados desktop, é o conceito de transações. Uma transação é uma unidade lógica de trabalho composta por uma ou mais declarações da Data Manipulation Language (DML) ou Data Definition Language (DDL). Os comandos para o controle da transação são aqueles necessários para que se possa controlar a efetivação ou não das modificações feitas no banco de dados. Para explicar o que é uma transação, pode-se tomar como exemplo uma transferência bancária onde um determinado valor é transferido de uma conta para outra. O processo de transferência deste valor consiste em vários passos, que são agrupados de modo que, se não forem concluídos em sua totalidade, ou seja, se a transação não chegar até o final, todas as outras alterações já realizadas serão descartadas e a conta voltará ao seu estado anterior, como se nenhuma transferência tivesse sido realizada. Através deste controle, podese garantir que os dados permanecerão consistentes. Os comandos commit e rollback da DCL auxiliam neste trabalho. Commit Tornam permanentes todas as alterações feitas no banco de dados durante a sessão. Todas as alterações realizadas em uma determinada transação serão confirmadas caso este comando seja aplicado. 47 6.3. Transações Casa do Código Fig. 6.1: Confirmando as alterações no banco de dados Rollback Usado para desfazer todas as alterações feitas desde o último commit durante a sessão. Esse comando vai restaurar os dados ao lugar onde eles estavam no último commit. Alterações serão desfeitas caso a transação seja encerrada pelo comando rollback. 48 Casa do Código Capítulo 6. Aspectos iniciais da programação PL/SQL Fig. 6.2: Desfazendo as alterações no banco de dados No Oracle, uma transação se inicia com a execução da primeira instrução SQL e termina quando as alterações são salvas ou descartadas. O comando set transaction também inicia uma transação – transação explícita. O uso do comando set transaction determina algumas regras, as quais são listadas a seguir. 49 6.3. Transações Casa do Código • 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. Fig. 6.3: Abrindo uma nova transação dentro do SQL*Plus Nota: A figura mostra um comando DML sendo executado e, logo após, uma transação sendo aberta. Como uma das regras para se abrir uma transação é que ela seja um dos primeiros comandos da transação, o erro acontece quando executamos o comando. Note que após encerrarmos a transação (através do rollback) aberta pelo comando DML, nós conseguimos executar o comando e abrir uma nova transação. 50 Casa do Código Capítulo 6. Aspectos iniciais da programação PL/SQL 6.4 Transações em PL/SQL As transações em PL/SQL seguem os mesmo preceitos expostos anteriormente. Um ponto a acrescentar é o uso dos savepoints. Quando trabalhamos com PL/SQL temos este recurso que nos permite definir pontos de salvamento dentro do programa. Todavia, não é uma prática muito utilizada, principalmente pelo fato de geralmente trabalharmos com grandes volumes de código, pois pode dificultar o entendimento do programa e inclusive desestruturá-lo logicamente. É sempre bom ter muito cuidado quanto à efetivação de dados no momento de construirmos nossos programas. Devemos visar sempre à consistência e integridade das informações manipuladas a fim de atingirmos o objetivo esperado. Além de permitir que sejam salvas partes de ações em determinados pontos do programa, também é possível desfazer tais ações usando estes mesmos pontos de salvamento. Veja um exemplo simples do uso deste recurso. ❙◗▲❃ ❜❡❣✐♥ ✷ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✈❛❧✉❡s ✭✹✶✱ ✬●❊◆❊❘❆▲ ▲❊❉●❊❘✬✱ ✬✬✮❀ ✸ s❛✈❡♣♦✐♥t ♣♦♥t♦❴✉♠❀ ✹ ✲✲ ✺ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✈❛❧✉❡s ✭✹✷✱ ✬P❯❘❈❍❆❙■◆●✬✱ ✬✬✮❀ ✻ s❛✈❡♣♦✐♥t ♣♦♥t♦❴❞♦✐s❀ ✼ ✲✲ ✽ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✈❛❧✉❡s ✭✹✸✱ ✬❘❊❈❊■❱❆❇▲❊❙✬✱ ✬✬✮❀ ✾ s❛✈❡♣♦✐♥t ♣♦♥t♦❴tr❡s❀ ✶✵ ✲✲ ✶✶ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✈❛❧✉❡s ✭✹✹✱ ✬P❆❨❆❇▲❊❙✬✱ ✬✬✮❀ ✶✷ r♦❧❧❜❛❝❦ t♦ s❛✈❡♣♦✐♥t ♣♦♥t♦❴❞♦✐s❀ ✶✸ ✲✲ ✶✹ ❝♦♠♠✐t❀ ✶✺ ❡♥❞❀ ✶✻ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Neste exemplo temos vários pontos de salvamento identificados por 51 6.5. Trabalhando com variáveis e constantes Casa do Código ponto_um, ponto_dois e ponto_tres. Cada ponto está referenciando um comando insert. Logo após, temos um rollback to savepoint desfazendo todas as operações a partir do ponto_dois. Isso indica que os comandos referentes às linhas 2 e 5 permanecem intactos. Já os comandos referentes às linhas 8 e 11 serão descartados. 6.5 Trabalhando com variáveis e constantes Identificadores de variáveis e constantes são muito comuns em programas PL/SQL, pois toda a informação geralmente é manipulada dentro deles e na maioria das vezes precisamos armazená-la em memória antes de, por exemplo, inseri-la em uma tabela, enviar para uma impressora ou para exportá-la para algum outro sistema. Dessa forma, variáveis e constantes nada mais são que áreas em memória definidas e usadas dentro de programa que servem para guardar informações em tempo de execução. Como o nome sugere, uma variável pode ter seus valores atualizados várias vezes ao longo da execução de um programa. Contudo, uma constante nasce com um valor definido e o mantém até o término da sua utilização. Uma variável ou constante deve ter um tipo definido, que não se altera ao longo da execução de um programa. Ao declará-las, recebem um nome que será sua identificação. Por regra, dentro do Oracle, este nome não pode ultrapassar 30 caracteres. No mais, ela deve obedecer às regras de definição mencionadas anteriormente quando falamos de identificadores. Esta definição deve ser feita dentro de uma área específica de declarações de variáveis que cada bloco PL/SQL pode ter, identificada como declare. O escopo de uma variável ou constante se limita ao bloco em que foram declaradas, podendo sempre ser acessadas no seu bloco e em blocos mais internos, nunca em blocos externos à sua declaração. Entretanto, caso uma variável tenha sido declarada duas vezes (mesmo nome), uma em um bloco externo e outra em um bloco mais interno, a variável do bloco externo não poderá ser acessada dentro do interno, pois haveria um conflito. Todavia, pelas boas práticas de programação não devemos ter identificadores com o mesmo nome. Logo, casos como este não são comuns. 52 Casa do Código Capítulo 6. Aspectos iniciais da programação PL/SQL Além dos tipos predefinidos, como numérico, data, string, entre outros, as variáveis e constantes podem referenciar tipos de dados de determinadas colunas de uma tabela criada em um banco de dados ( %TYPE), ou seu tipo pode referenciar uma tabela inteira ( %ROWTYPE). Quando declaramos uma variável podemos definir um valor padrão, chamado de DEFAULT, para que ela já inicialize assim. Para as constantes, isso é obrigatório. No mais, os valores de variáveis e constantes podem ser manipulados e convertidos para outros tipos a fim de serem utilizados dentro dos programas para satisfazer objetivos específicos. Seguem exemplos de declarações de variáveis. ❉❊❈▲❆❘❊ ❉❚❴❊◆❚❘❆❉❆ ❉❚❴❙❆■❉❆ ❋❖❘◆❊❈❊❉❖❘ ❉❆❚❊ ❉❊❋❆❯▲❚ ❙❨❙❉❆❚❊❀ ❉❆❚❊❀ ❚■P❖❴P❊❙❙❖❆❀ ✲✲ ❚✐♣♦ ❞❡ ❞❛❞♦ ❞❡❢✐♥✐❞♦ ♣❡❧♦ ❞❡s❡♥✈♦❧✈❡❞♦r ◆❯▼❇❊❘✭✺✮ ❉❊❋❆❯▲❚ ✶✵✵✵❀ ◗❚❴▼❆❳ ◗❚❴▼■◆ ❈❖◆❙❚❆◆❚ ◆❯▼❇❊❘✭✺✵✮ ❉❊❋❆❯▲❚ ✶✵✵❀ ◆▼❴P❊❙❙❖❆ ❈❍❆❘✭✻✵✮❀ ◆❯▼❇❊❘✭✶✶✱✷✮❀ ❱▲❴❙❆▲❆❘■❖ ❈❉❴❉❊P❚❖ ◆❯▼❇❊❘✭✺✮❀ ■◆❴◆❆❖ ❈❖◆❙❚❆◆❚ ❇❖❖▲❊❆◆ ❉❊❋❆❯▲❚ ❋❆▲❙❊❀ ◆❯▼❇❊❘✭✶✵✮ ✿❂ ✵❀ ◗❚❉ ❱▲❴P❊❘❈ ❈❖◆❙❚❆◆❚ ◆❯▼❇❊❘✭✹✱✷✮ ✿❂ ✺✺✳✵✵❀ ❈❉❴❈❆❘●❖ ❊▼P▲❖❨❊❊✳❏❖❇✪❚❨P❊❀ ❘❊●❴❉❊P❚ ❉❊P❆❘❚▼❊◆❚✪❘❖❲❚❨P❊❀ 6.6 Tipos de dados em PL/SQL VARCHAR2 Tamanho máximo para campos de tabela: 4.000 bytes. Tamanho máximo para PL/SQL: 32.767 bytes. O VARCHAR2 é variável e somente usa o espaço que está ocupado. Diferentemente do CHAR. VARCHAR é um subtipo (assim como STRING) que existe por questões de compatibilidade com outras marcas de banco de dados e também com o padrão SQL. Entretanto, a Oracle no momento não recomenda o uso do 53 6.6. Tipos de dados em PL/SQL Casa do Código tipo VARCHAR porque sua definição deve mudar à medida que o padrão SQL evoluir. Deve-se usar VARCHAR2. CHAR Tamanho máximo: 2.000 bytes O tipo CHAR é usado para conter dados de string de comprimento fixo. Ao contrário das strings de VARCHAR2, uma string CHAR sempre contém o número máximo de caracteres. Outros tipos: • NCHAR Tamanho máximo: 2.000 bytes; • NCHAR VARYING Tamanho máximo: 4.000 bytes; • CHAR VARYING Tamanho máximo: 4.000 bytes. NUMBER(p,s) Numérico com sinal e ponto decimal, sendo que p é a precisão de 1 a 38 dígitos e s é a escala, de -84 a 127. Este tipo também possui subtipos como: • DECIMAL: igual a NUMBER • DEC: igual a DECIMAL • DOUBLE PRECISION: igual a NUMBER • NUMERIC: igual a NUMBER • REAL: igual a NUMBER • INTEGER: equivalente a NUMBER(38) • INT: igual a INTEGER • SMALLINT: igual a NUMBER(38) • FLOAT: igual a NUMBER 54 Casa do Código Capítulo 6. Aspectos iniciais da programação PL/SQL • FLOAT(prec): igual a NUMBER(prec), mas a precisão é expressa em termos de bits binários, não de dígitos decimais. A precisão binária pode variar de 1 até 126. • BINARY_INTEGER: semelhante a INTEGER. É usada para indexar tabela PL/SQL. DATE 1 JAN 4712 BC até 31 DEC 4712 AD (DATA com hora, minuto e segundo) O tipo DATE é usado para armazenar os valores de data e hora. Um nome melhor seria DATETIME porque o componente de hora está sempre lá, independente de você usá-lo ou não. Se não for especificada a hora ao atribuir um valor para uma variável deste tipo, o padrão de meia-noite (12:00:00 a.m.) será usado. BOOLEAN True e False. LONG Tamanho máximo para tabela: 2 GB. Tamanho máximo para PLSQL: 32.760. Somente pode existir uma coluna por tabela. RAW Tamanho máximo para campos de tabela: 2.000 bytes. Tamanho máximo para PL/SQL: 32.767. LONG RAW é outro tipo parecido com RAW, a diferença é que ele possui 7 bytes a menos quando utilizado em PL/SQL. CLOB Tamanho máximo: (4 GB - 1) * DB_BLOCK_SIZE. Parâmetro de inicialização: 8 TB a 128 TB. O número de colunas CLOB por tabela é limitado somente pelo número máximo de colunas por tabela. Armazena textos, que são validados conforme o set de caracteres, ou seja, armazena acentuação etc. 55 6.6. Tipos de dados em PL/SQL Casa do Código Tipos LOB, surgiram em substituição aos tipos LONG e LONG RAW, pois eles só permitiam uma coluna por tabela. Já os tipos LOB permitem mais de uma coluna. NCLOB Tamanho máximo: (4 GB - 1) * DB_BLOCK_SIZE. Parâmetro de inicialização: 8 TB a 128 TB. O número de colunas NCLOB por tabela é limitado somente pelo número máximo de colunas por tabela. Objeto de grande capacidade de caracteres nacionais – contém até 4 GB de caracteres de bytes simples ou caracteres multibyte que atendem o conjunto de caracteres nacional definido pelo banco de dados Oracle. BLOB Tamanho máximo: (4 GB - 1) * DB_BLOCK_SIZE. Parâmetro de inicialização: 8 TB a 128 TB. O número de colunas BLOB por tabela é limitado somente pelo número máximo de colunas por tabela. Armazenam dados não estruturados como: som, imagem, dados binários. BFILE Tamanho máximo: 4 GB. Tamanho máximo para o nome do arquivo: 255 caracteres. Tamanho máximo para o nome do diretório: 30 caracteres. O valor máximo de BFILEs é limitado pelo valor do parâmetro de inicialização SESSION_MAX_OPEN_FILES, o qual é limitado pelo número máximo de arquivos abertos que o sistema operacional suporta. ROWID É um tipo especial usado para armazenar os ROWIDs (endereços físicos) das linhas armazenadas em uma tabela. Campos LONG Em resumo, os tipos comumente utilizados são: NUMBER, DATE, BOOLEAN e os da família LOB. 56 CHAR, VARCHAR2, Casa do Código Capítulo 6. Aspectos iniciais da programação PL/SQL No entanto, existem algumas restrições para campos LONG e LONG RAW. • Não se pode criar um OBJECT TYPE com o atributo de LONG. • Uma coluna LONG não pode estar dentro da cláusula WHERE ou com referência integral dos dados, exceto NULL ou NOT NULL. • Uma função não pode retornar um campo LONG. • Uma tabela poderá ter somente um campo LONG. • LONG não pode ser indexada. • LONG não pode usar cláusulas WHERE, conforme já mencionado, GROUP BY, ORDER BY e CONNECT BY. Uma dica para você usar um campo LONG na cláusula WHERE é criar uma tabela temporária com os campos da tabela original, mas alterando um tipo LONG para CLOB. Também é possível alterar diretamente na tabela o campo LONG para CLOB, caso não tenha problema de alterar a estrutura da tabela original. 57 Capítulo 7 Exceções Exceções são utilizadas dentro do Oracle quando algum erro acontece. Quando construímos programas em PL/SQL é fundamental tratarmos as exceções que podem ocorrer mediante a execução do sistema e seus diversos processos. Basicamente, existem dois tipos de exceções dentro do Oracle: as predefinidas e as definidas pelo usuário. • Exceções predefinidas: são exceções existentes implicitamente dentro do Oracle e que são disparadas automaticamente por ele quando ocorre um erro no programa. • Exceções definidas pelo usuário: são exceções que precisam ser declaradas e disparadas pelo usuário. O Oracle desconhece sua existência. 7.1. Exceções predefinidas Casa do Código 7.1 Exceções predefinidas Como foi dito, uma exceção é acionada quando um erro acontece dentro do programa. Mesmo que não as tratemos, o Oracle intercepta o problema e mostra o erro. Todavia, se deixarmos que o Oracle faça isto nós podemos ter sérios problemas, pois erros que não são tratados causam a parada do sistema, ou seja, o programa é abortado. Dentro da PL/SQL tratamos estes erros através das exceptions. Os mais variados tipos de erros podem ser tratados através deste recurso. Por exemplo, se temos dentro do nosso programa PL/SQL um cálculo onde possa acontecer uma divisão por zero, caso ocorra, um erro é disparado, pois sabemos que matematicamente não é possível resolvê-lo. A PL/SQL sabe disso e vai gerar uma exceção caso isto ocorra. Mediante isto, podemos nos antecipar e tratar este possível erro. Um ponto bom de tratarmos os erros é a possibilidade de mostrarmos mensagens mais amigáveis aos usuários e lhes propor ações que possam ajudá-los a resolver sem a intervenção da área de suporte, por exemplo. Além do mais, evitamos que o programa ou todo o sistema seja abortado, o que geraria um grande incômodo. Através do tratamento de exceções também é possível determinar se o programa pode continuar ou não com a ação após o erro ter ocorrido. Como este acionamento é feito? Quando acontece um desses erros predefinidos pelo Oracle, automaticamente a PL/SQL percebe sua ocorrência e o transfere para uma área de tratamento de erro. No entanto, às vezes esses erros demonstram certa falta de clareza em suas descrições, envolvendo termos muito técnicos, geralmente em inglês, o que pode confundir o usuário. Com isso em mente, eles podem ser tratados pelo desenvolvedor de sistemas a fim de torná-los mais compreensíveis. Contudo, o mesmo não acontece com os erros causados pelos usuários. Este tipo de erro a PL/SQL não consegue detectar pelo fato de não estarem incluídos implicitamente no Oracle. O uso das exceções é bem flexível, podendo ser usadas dentro de blocos anônimos, procedures, functions, packages e triggers. 60 Casa do Código Capítulo 7. Exceções Primeiramente, vamos falar sobre as exceptions predefinidas. Segue uma lista de exceptions que podem ser utilizadas em PL/SQL. • no_data_found: dispara quando um select into é executado e não retorna nenhum registro. Não ocorre se usarmos funções de grupo, pois estas retornam valores nulos quando não há registros. Também não ocorre em fetch (usado em cursores). Neste caso usamos atributos de cursor. Exemplo: C1%NO* TFOUND retorna verdadeiro se não encontrar mais linhas. • invalid_cursor: tentamos usar um cursor que não está aberto. • invalid_number: quando a conversão de um tipo para outro não é possível, ou quando um valor ultrapassa o número de casas definidas para o tipo de dado. Exemplo: uma variável number(2) recebe o valor 100. • login_denied: tentativa de conectar ao banco de dados com usuário inválido. • cursor_already_open: tentamos abrir um cursor que já se encontra aberto. • dup_val_on_index: tentativa de inserir valor duplicado em um índice único. Usado na verificação de chave primária ou única. • not_logged_on: tentamos usar algum recurso do banco sem estarmos conectados. • program_error: erro interno ao sistema Oracle, chamado de internal. • rowtype_mismatch: quando um fetch retorna uma determinada linha do banco de dados para uma variável do tipo registro onde os dados desta linha não são compatíveis com os tipos definidos na variável. • timeout_on_resource: tempo expirou quando o banco esperava pelo recurso. 61 7.1. Exceções predefinidas Casa do Código • too_many_rows: um select into retornou mais de uma linha. • value_error: em algumas circunstâncias invalid_number ou value_error. é disparado • zero_divide: tentamos dividir por zero. • others: quando não sabemos qual erro pode ocorrer. Esta é uma lista das exceptions mais comuns. Para maiores detalhes e demais exceções, consulte a documentação do banco de dados da versão que estiver utilizando. Vamos abrir um parêntese para falar um pouco sobre a exceção others e sobre as exceções invalid_number e value_error. A exception others é muito utilizada, pois mesmo que tratemos erros específicos sempre a utilizamos para garantir que demais erros não causem a parada do sistema. Qualquer exception quando não tratada em específico acaba sendo amparada pela exceção others. Portanto, quando tratamos diversas exceções devemos sempre colocá-la por último na seção de tratamento. Outro ponto altamente recomendado é que pelo menos a exceção others seja sempre tratada, independente se já estamos tratado de outras em específico. Já com relação às exceções invalid_number e value_error, embora, possam parecer redundantes, existem lugares específicos onde elas podem ser usadas. invalid_number é acionada por erros em comandos SQL dentro dos blocos PL/SQL. Já a exceção value_error é disparada por erros em comandos PL/SQL. Veja onde e como tratar as exceções. Analise o caso a seguir. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❡♠♣♥♦ ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ s❡❧❡❝t ❡♠♣♥♦ ✻ ✐♥t♦ ✇❡♠♣♥♦ ✼ ❢r♦♠ ❡♠♣ ✽ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✾✾✾✾❀ 62 Casa do Código Capítulo 7. Exceções ✾ ✲✲ ✶✵ ❡♥❞❀ ✶✶ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖ ♥❛ ❧✐♥❤❛ ✶✿ ❖❘❆✲✵✶✹✵✸✿ ❞❛❞♦s ♥ã♦ ❡♥❝♦♥tr❛❞♦s ❖❘❆✲✵✻✺✶✷✿ ❡♠ ❧✐♥❡ ✺ ❙◗▲❃ Neste exemplo estamos tentando selecionar o empregado com o código 9999. Entretanto, este empregado não existe. Como estamos utilizando um select into, sabemos que quando um select deste tipo não retorna linhas o Oracle dispara uma exceção. Neste caso, foi o que aconteceu. Ao tentarmos selecionar a linha, o comando não a localizou fazendo com que o Oracle gerasse uma exceção. O resultado foi uma mensagem de erro informando que os dados não foram encontrados. Contudo, estamos falando de um exemplo simples. Se tivéssemos um programa com muitos comandos select, ficaria difícil saber onde estaria o erro. Sem falar que a mensagem não ajudaria muito o usuário a resolver o problema por si só. Agora vamos tratar esta exceção e ver o que acontece. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❡♠♣♥♦ ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ s❡❧❡❝t ❡♠♣♥♦ ✻ ✐♥t♦ ✇❡♠♣♥♦ ✼ ❢r♦♠ ❡♠♣ ✽ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✾✾✾✾❀ ✾ ✲✲ ✶✵ ❡①❝❡♣t✐♦♥ ✶✶ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✶✸ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ❡♠♣r❡❣❛❞♦✳✬✮❀ 63 7.1. Exceções predefinidas Casa do Código ✶✺ ❡♥❞❀ ✶✻ ✴ ❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Primeiramente, vamos analisar o programa. Como pode ser visto, entre o begin e o end, temos a expressão exception. É nesta área que definimos quais exceções vamos tratar. Perceba que logo após a expressão exception temos várias cláusulas when indicando quais exceções estamos tratando. Neste exemplo, estamos tratando as exceções no_data_found e others. O tratamento de exceções deve sempre acompanhar um bloco PL/SQL e seu escopo é válido somente dentro dele. Veja a sintaxe. ❞❡❝❧❛r❡ ✲✲ ✈❛r✐á✈❡✐s ❜❡❣✐♥ ✲✲ ✲✲ ❝♦♠❛♥❞♦s ❜❡❣✐♥ ✲✲ ❝♦♠❛♥❞♦s ❡①❝❡♣t✐♦♥ ✇❤❡♥ ❁❡①❝❡♣t✐♦♥ ✶❃ t❤❡♥ ✲✲ ❝♦♠❛♥❞♦s ♦✉ ♠❡♥s❛❣❡♥s✳ ✇❤❡♥ ❁❡①❝❡♣t✐♦♥ ♥❃ t❤❡♥ ✲✲ ❝♦♠❛♥❞♦s ♦✉ ♠❡♥s❛❣❡♥s✳ ❡♥❞❀ ✲✲ ♠❛✐s ❝♦♠❛♥❞♦s ✲✲ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ❁❡①❝❡♣t✐♦♥ ✶❃ t❤❡♥ ✲✲ ❝♦♠❛♥❞♦s ♦✉ ♠❡♥s❛❣❡♥s✳ ✇❤❡♥ ❁❡①❝❡♣t✐♦♥ ♥❃ t❤❡♥ ✲✲ ❝♦♠❛♥❞♦s ♦✉ ♠❡♥s❛❣❡♥s✳ ❡♥❞❀ Veja neste exemplo que temos um bloco dentro de outro, e cada um possui 64 Casa do Código Capítulo 7. Exceções sua área de tratamento de exceções. Note também que esta é definida sempre no fim do bloco. Muito bem, continuando nosso exemplo, podemos perceber que nele temos dois tratamentos. Um para verificar se o empregado existe e outro para o caso de acontecer qualquer outro erro de que não se tenha conhecimento. De propósito, tentamos selecionar os empregados que são de um departamento que não existe na tabela EMP para que a exceção fosse acionada. Com o acionamento da exceção, a mensagem “Empregado não encontrado” foi impressa na tela, atingindo nosso objetivo. Com isso, foi possível mostrar uma mensagem muito mais inteligível e de quebra não permitimos que o Oracle abortasse o programa. Utilizamos o pacote dbms_output para imprimir na tela a nossa mensagem de erro. Neste exemplo, vamos colocar um código de departamento que existe na tabela EMP. ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ❊rr♦ ❞❡❝❧❛r❡ ✇❡♠♣♥♦ ♥✉♠❜❡r❀ ❜❡❣✐♥ ✲✲ s❡❧❡❝t ❡♠♣♥♦ ✐♥t♦ ✇❡♠♣♥♦ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✸✵❀ ✲✲ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ❡♠♣r❡❣❛❞♦✳✬✮❀ ❡♥❞❀ ✴ ❛♦ s❡❧❡❝✐♦♥❛r ❡♠♣r❡❣❛❞♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Analisando este segundo exemplo podemos observar que a exceção 65 7.1. Exceções predefinidas Casa do Código no_data_found não foi acionada. Entretanto a exceção others foi. Tam- bém pudera, quando colocamos um código de departamento existente na tabela EMP, o select retornou várias linhas. Várias linhas em um select into geram uma exceção chamada too_many_rows. Desta forma vamos incluí-la em nosso programa. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❡♠♣♥♦ ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ s❡❧❡❝t ❡♠♣♥♦ ✻ ✐♥t♦ ✇❡♠♣♥♦ ✼ ❢r♦♠ ❡♠♣ ✽ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✸✵❀ ✾ ✲✲ ✶✵ ❡①❝❡♣t✐♦♥ ✶✶ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✶✸ ✇❤❡♥ t♦♦❴♠❛♥②❴r♦✇s t❤❡♥ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦✿ ❖ ❝ó❞✐❣♦ ❞❡ ❞❡♣❛rt❛♠❡♥t♦ ✐♥❢♦r♠❛❞♦✬⑤⑤ ✶✺ ✬ r❡t♦r♥♦✉ ♠❛✐s ❞❡ ✉♠ r❡❣✐str♦✳✬✮❀ ✶✻ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✶✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ❡♠♣r❡❣❛❞♦✳✬✮❀ ✶✽ ❡♥❞❀ ✶✾ ✴ ❊rr♦✿ ❖ ❝ó❞✐❣♦ ❞❡ ❞❡♣❛rt❛♠❡♥t♦ ✐♥❢♦r♠❛❞♦ r❡t♦r♥♦✉ ♠❛✐s ❞❡ ✉♠ r❡❣✐str♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Incluindo a exceção too_many_rows, foi possível tratar o erro em específico e melhorar a mensagem de erro. Vale salientar que a exception foi incluída antes da exceção others. Isso sempre deve ser feito desta forma. Voltando um pouco no exemplo anterior a este, foi possível observar que sem o tratamento da exceção too_many_rows, ficou difícil identificar qual 66 Casa do Código Capítulo 7. Exceções o problema ocorreu, pois como a exceção others é para todas as exceções que podem ocorrer dentro do programa, não conseguimos especificar uma mensagem de erro clara o suficiente. É óbvio que nesse exemplo, sabíamos qual era o problema e alteramos o programa para tratá-lo. Contudo, mesmo assim, outros tipos de problemas podem ocorrer fora os tratados especificamente. Caso isso aconteça, é necessário pelo menos uma mensagem mais detalhada sobre o erro, para que o problema possa ser identificado e resolvido. Para identificar erros não conhecidos, aqueles que acabam caindo na exceção others, podemos contar com duas variáveis que são alimentadas cada vez que uma exception é disparada. As variáveis são sqlcode e sqlerrm. A primeira mostra somente o código e a segunda mostra o código e a descrição do erro, vindos do Oracle. Cada erro dentro Oracle possui um código associado a ele. Desta forma, quando uma exception é gerada, o código do erro corrente é gravado na variável sqlcode. A mesma coisa acontece com a variável sqlerrm. Cada erro possui uma descrição explicando seu motivo. Ao ser gerada uma exceção, esta variável recebe a descrição do erro corrente. Com isto, é possível obter o código e descrição do erro, o que possibilita identificar sua causa. Estas variáveis podem e devem ser usadas quando tratamos a exceção others. Vale salientar, entretanto, que na maioria das vezes a descrição dos erros vindos do Oracle não são descrições muito amigáveis. Os usuários podem ter dificuldades em identificar o que exatamente ocorreu. Por isso a importância de tratarmos pelo menos as exceções conhecidas dentro de um programa, a fim de clarear ao máximo os erros que podem ocorrer. Vamos voltar ao exemplo anterior e usar as variáveis para identificar o problema ocorrido. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❡♠♣♥♦ ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ s❡❧❡❝t ❡♠♣♥♦ ✻ ✐♥t♦ ✇❡♠♣♥♦ ✼ ❢r♦♠ ❡♠♣ ✽ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✸✵❀ ✾ ✲✲ ✶✵ ❡①❝❡♣t✐♦♥ 67 7.1. Exceções predefinidas Casa do Código ✶✶ ✶✷ ✶✸ ✶✹ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ✬⑤⑤sq❧❡rr♠ ✶✺ ⑤⑤✬ ✲ ❈ó❞✐❣♦✿ ✭✬⑤⑤sq❧❝♦❞❡⑤⑤✬✮✳✬✮❀ ✶✻ ❡♥❞❀ ✶✼ ✴ ❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ❖❘❆✲✵✶✹✷✷✿ ❛ ❡①tr❛çã♦ ❡①❛t❛ r❡t♦r♥❛ ♠❛✐s ❞♦ q✉❡ ♦ ♥ú♠❡r♦ s♦❧✐❝✐t❛❞♦ ❞❡ ❧✐♥❤❛s ✲ ❈ó❞✐❣♦✿ ✭✲✶✹✷✷✮✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ No exemplo a seguir concatenamos as variáveis sqlcode e sqlerrm com nossa mensagem de erro. Uma observação, a variável sqlerrm já traz o código do erro, não tendo necessidade de utilizar o sqlcode, a menos, é claro, que você queira usar este código para algo diferente de apenas mostrar a informação. Para mostrar apenas a descrição do erro use sqlerrm(sqlcode). Note também que a informação vinda do banco de dados não é muito clara. Dependendo da linguagem instalada para banco de dados, o Oracle procura traduzir a mensagem de erro e às vezes torna mais difícil sua compreensão. Uma dica importante: caso você não compreenda a mensagem de erro ou ela não exista, é possível, através do código do erro, pesquisar maiores detalhes na documentação do banco Oracle ou na internet. Estes códigos são padronizados e em qualquer versão ou linguagem eles se mantêm os mesmos. Uma vez gerada a exceção, isso não garante que o programa vá parar o processo. Como foi visto, podemos ter vários blocos dentro do mesmo programa PL/SQL e cada um destes blocos podem ter tratamentos de erros. Estes blocos, por sua vez, podem conter dependências uns com os outros e para isto pode ser necessário parar o processo quando um erro acontece, não permitindo que o programa continue. 68 Casa do Código Capítulo 7. Exceções Nota: o fato de nós tratarmos as exceptions nos remete a outro ponto a que devemos estar atentos. Quando não a tratamos, o Oracle realiza este tratamento e aborta o programa. Já quando o tratamento fica por nossa conta, ou melhor, por conta do nosso programa, somos nós quem define se haverá ou não uma parada no sistema ou no processo que está sendo executado, ou seja, quando tratamos um erro, o Oracle passa a não tratá-lo mais e as ações ficam por nossa conta. Veja o exemplo a seguir. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧ ♥✉♠❜❡r❀ ✸ ✇❞❡♣t♥♦ ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ ❜❡❣✐♥ ✼ s❡❧❡❝t ❛✈❣✭s❛❧✮✱ ❞❡♣t♥♦ ✽ ✐♥t♦ ✇s❛❧✱ ✇❞❡♣t♥♦ ✾ ❢r♦♠ ❡♠♣ ✶✵ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✾✾ ✶✶ ❣r♦✉♣ ❜② ❞❡♣t♥♦❀ ✶✷ ❡①❝❡♣t✐♦♥ ✶✸ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❱❛❧♦r❡s ♥ã♦ ❡♥❝♦♥tr❛❞♦s ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ✾✾✳✬✮❀ ✶✺ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✶✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ✈❛❧♦r❡s r❡❢❡r❡♥t❡s ❛♦ ❞❡♣t♦✳ ✾✾✳ ✬⑤⑤ ✶✼ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✶✽ ❡♥❞❀ ✶✾ ✲✲ ✷✵ ❜❡❣✐♥ ✷✶ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✮ ✷✷ ✈❛❧✉❡s ✭✽✵✵✷✱ ✬❆◆●❊▲■◆❆✬✱ ✬▼❆◆❆●❊❘✬✱ ✼✽✸✾✱ ❚❖❴❉❆❚❊✭✬✷✵✴✶✵✴✷✵✶✶✬✱✬❉❉✴▼▼✴❘❘❘❘✬✮✱ ✇s❛❧✱ ♥✉❧❧✱ ✷✵✮❀ 69 7.1. Exceções predefinidas Casa do Código ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✲✲ ❝♦♠♠✐t❀ ✲✲ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦ ❛♦ ✐♥s❡r✐r ♥♦✈♦ ❡♠♣r❡❣❛❞♦✳ ✬⑤⑤ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✷✾ ✸✵ ❡♥❞❀ ✸✶ ✲✲ ✸✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊♠♣r❡❣❛❞♦ ❆◆●❊▲■◆❆ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ✸✸ ✲✲ ✸✹ ❡①❝❡♣t✐♦♥ ✸✺ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✸✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✸✼ ✇❤❡♥ t♦♦❴♠❛♥②❴r♦✇s t❤❡♥ ✸✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦✿ ❖ ❝ó❞✐❣♦ ❞❡ ❞❡♣❛rt❛♠❡♥t♦ ✐♥❢♦r♠❛❞♦✬⑤⑤ ✸✾ ✬ r❡t♦r♥♦✉ ♠❛✐s ❞❡ ✉♠ r❡❣✐str♦✳✬✮❀ ✹✵ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✹✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦ ❛♦ ✐♥s❡r✐r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ✬⑤⑤sq❧❡rr♠ ✹✷ ⑤⑤✬ ✲ ❈ó❞✐❣♦✿ ✭✬⑤⑤sq❧❝♦❞❡⑤⑤✬✮✳✬✮❀ ✹✸ ❡♥❞❀ ✹✹ ✴ ❱❛❧♦r❡s ♥ã♦ ❡♥❝♦♥tr❛❞♦s ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ✾✾✳ ❊♠♣r❡❣❛❞♦ ❆◆●❊▲■◆❆ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Neste exemplo criamos um bloco PL/SQL que insere um novo empregado. Dentro do nosso programa temos um select que busca a média dos salários dos empregados de um determinado departamento. Neste select estamos tratando as exceções no_data_found e others. Logo após, realizamos a inclusão do empregado através do comando insert informando como salário deste empregado o valor vindo do select anterior. Depois 70 Casa do Código Capítulo 7. Exceções informamos ao usuário que o empregado foi inserido com sucesso. Veja que para o comando insert também estamos tratando a exceção others para o caso de algum erro. Entretanto, executando o programa podemos observar que algumas mensagens foram geradas, inclusive a de que os valores dos salários não foram encontrados para o departamento em questão. O resultado disso foi a inclusão do empregado com o salário igual a zero. ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣ ♦r❞❡r ❜② ❡♠♣♥♦❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✹✾✾ ✼✺✷✶ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✽✸✾ ✼✽✹✹ ✼✾✵✵ ✼✾✸✹ ✼✾✸✺ ✽✵✵✶ ✽✵✵✷ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❆▲▲❊◆ ❲❆❘❉ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❑■◆● ❚❯❘◆❊❘ ❏❆▼❊❙ ▼■▲▲❊❘ P❆❯▲ ❙■▲❱❊❙❚❊❘ ❆◆●❊▲■◆❆ ❏❖❇ ▼●❘ ❍■❘❊❉❆❚❊ ❙❆▲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✵✴✵✷✴✽✶ ✶✻✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✷✴✵✷✴✽✶ ✶✷✺✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✽✴✵✾✴✽✶ ✶✷✺✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✶✴✵✺✴✽✶ ✷✽✺✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✾✴✵✻✴✽✶ ✷✹✺✵ P❘❊❙■❉❊◆❚ ✶✼✴✶✶✴✽✶ ✺✵✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✵✽✴✵✾✴✽✶ ✶✺✵✵ ❈▲❊❘❑ ✼✻✾✽ ✵✸✴✶✷✴✽✶ ✾✺✵ ❈▲❊❘❑ ✼✼✽✷ ✷✸✴✵✶✴✽✷ ✶✸✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✶✺✴✵✸✴✽✵ ✶✵✵✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✶✵✵✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✷✵✴✶✵✴✶✶ ❈❖▼▼ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✸✵✻ ✸✵ ✺✶✵ ✸✵ ✶✹✷✽ ✸✵ ✷✽✺ ✸✵ ✷✹✺ ✶✵ ✺✵✵ ✶✵ ✶✺✵ ✸✵ ✾✺ ✸✵ ✶✸✵ ✶✵ ✶✵✵ ✸✵ ✽✵ ✷✵ 71 Casa do Código 7.1. Exceções predefinidas ✶✷ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ Podemos agravar a situação colocando a coluna SAL como not null, para que surja um erro no momento da inserção do registro. ❙◗▲❃ ❛❧t❡r t❛❜❧❡ ❡♠♣ ♠♦❞✐❢② s❛❧ ♥✉♠❜❡r✭✼✱✷✮ ♥♦t ♥✉❧❧❀ ❚❛❜❡❧❛ ❛❧t❡r❛❞❛✳ ❙◗▲❃ ❞❡s❝ ❡♠♣ ◆♦♠❡ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❊▼P◆❖ ❊◆❆▼❊ ❏❖❇ ▼●❘ ❍■❘❊❉❆❚❊ ❙❆▲ ❈❖▼▼ ❉❊P❚◆❖ P❈❴❈❖▼❴❙❆▲ ❚✐♣♦ ◆✉❧♦❄ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ◆❖❚ ◆❯▲▲ ◆❯▼❇❊❘✭✹✮ ❱❆❘❈❍❆❘✷✭✶✵✮ ❱❆❘❈❍❆❘✷✭✾✮ ◆❯▼❇❊❘✭✹✮ ❉❆❚❊ ◆❖❚ ◆❯▲▲ ◆❯▼❇❊❘✭✼✱✷✮ ◆❯▼❇❊❘✭✼✱✷✮ ◆❯▼❇❊❘✭✷✮ ◆❯▼❇❊❘ ❙◗▲❃ Vamos excluir o registro existente e executar o programa novamente. ❙◗▲❃ ❞❡❧❡t❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✽✵✵✷❀ ✶ ❧✐♥❤❛ ❞❡❧❡t❛❞❛✳ ❙◗▲❃ ❝♦♠♠✐t❀ ❱❛❧✐❞❛çã♦ ❝♦♠♣❧❡t❛✳ ❙◗▲❃ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧ 72 ♥✉♠❜❡r❀ Casa do Código Capítulo 7. Exceções ✸ ✇❞❡♣t♥♦ ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ ❜❡❣✐♥ ✼ s❡❧❡❝t ❛✈❣✭s❛❧✮✱ ❞❡♣t♥♦ ✽ ✐♥t♦ ✇s❛❧✱ ✇❞❡♣t♥♦ ✾ ❢r♦♠ ❡♠♣ ✶✵ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✾✾ ❣r♦✉♣ ❜② ❞❡♣t♥♦❀ ✶✶ ✶✷ ❡①❝❡♣t✐♦♥ ✶✸ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❱❛❧♦r❡s ♥ã♦ ❡♥❝♦♥tr❛❞♦s ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ✾✾✳✬✮❀ ✶✺ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✶✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ✈❛❧♦r❡s r❡❢❡r❡♥t❡s ❛♦ ❞❡♣t♦✳ ✾✾✳ ✬⑤⑤ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✶✼ ✶✽ ❡♥❞❀ ✶✾ ✲✲ ✷✵ ❜❡❣✐♥ ✷✶ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✮ ✷✷ ✈❛❧✉❡s ✭✽✵✵✷✱ ✬❆◆●❊▲■◆❆✬✱ ✬▼❆◆❆●❊❘✬✱ ✼✽✸✾✱ ❚❖❴❉❆❚❊✭✬✷✵✴✶✵✴✷✵✶✶✬✱✬❉❉✴▼▼✴❘❘❘❘✬✮✱ ✇s❛❧✱ ♥✉❧❧✱ ✷✵✮❀ ✷✸ ✲✲ ✷✹ ❝♦♠♠✐t❀ ✷✺ ✲✲ ✷✻ ❡①❝❡♣t✐♦♥ ✷✼ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✷✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦ ❛♦ ✐♥s❡r✐r ✉♠ ♥♦✈♦ ❡♠♣r❡❣❛❞♦✳ ✬⑤⑤ ✷✾ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✸✵ ❡♥❞❀ ✸✶ ✲✲ ✸✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊♠♣r❡❣❛❞♦ ❆◆●❊▲■◆❆ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ✸✸ ✲✲ ✸✹ ❡①❝❡♣t✐♦♥ 73 7.1. Exceções predefinidas ✸✺ ✸✻ ✸✼ ✸✽ ✸✾ ✹✵ ✹✶ ✹✷ ✹✸ ✹✹ Casa do Código ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✇❤❡♥ t♦♦❴♠❛♥②❴r♦✇s t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦✿ ❖ ❝ó❞✐❣♦ ❞❡ ❞❡♣❛rt❛♠❡♥t♦ ✐♥❢♦r♠❛❞♦✬⑤⑤ ✬ r❡t♦r♥♦✉ ♠❛✐s ❞❡ ✉♠ r❡❣✐str♦✳✬✮❀ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦ ❛♦ ✐♥s❡r✐r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ✬⑤⑤sq❧❡rr♠ ⑤⑤✬ ✲ ❈ó❞✐❣♦✿ ✭✬⑤⑤sq❧❝♦❞❡⑤⑤✬✮✳✬✮❀ ❡♥❞❀ ✴ ❱❛❧♦r❡s ♥ã♦ ❡♥❝♦♥tr❛❞♦s ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ✾✾✳ ❊rr♦ ❛♦ ✐♥s❡r✐r ✉♠ ♥♦✈♦ ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ❖❘❆✲✵✶✹✵✵✿ ♥ã♦ é ♣♦ssí✈❡❧ ✐♥s❡r✐r ◆❯▲▲ ❡♠ ✭✧❚❙◗▲✧✳✧❊▼P✧✳✧❙❆▲✧✮✳ ❊♠♣r❡❣❛❞♦ ❆◆●❊▲■◆❆ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Veja que o programa nos deu várias mensagens. A primeira informa que não conseguiu recuperar o salário referente ao departamento encontrado. A segunda nos alerta que o empregado não pode ser inserido pelo fato de um erro ter ocorrido. Note que usamos a exceção others com as variáveis de erro, que nos apontou que não é possível inserir valores nulos para o campo SAL da tabela EMP. Isso aconteceu devido à alteração que realizamos. Entretanto, veja que a mensagem nos informando que o empregado foi inserido com sucesso também é mostrada. Isso é um erro, pois na verdade ele não foi inserido. Neste caso, temos que tratar estas situações no programa para que as ações e mensagens estejam condizentes com que realmente está acontecendo. Se nós partimos do pressuposto de que nenhum dos empregados pudesse ser incluído sem um valor de salário definido, teríamos que alterar o programa para que ele não incluísse o empregado caso não conseguisse recuperar o salário. Pois bem, sem alterar a estrutura do nosso programa vamos utilizar um recurso da PL/SQL que permite parar a execução do programa quando for necessário. 74 Casa do Código Capítulo 7. Exceções Quando desejarmos que um programa ou processo seja interrompido após uma exceção, utilizamos a chamada raise_applications_error. Esta chamada faz com que o programa pare sua execução a partir de um determinado ponto. Em contrapartida, ela desvia o programa para o primeiro tratamento de erro existente, que se encaixe com o erro ocorrido, seguindo a hierarquia dos blocos. No geral, este desvio sempre é interceptado pela exceção others. Esta chamada requer dois parâmetros, um código de erro e uma descrição. Como já foi dito, a Oracle mantém uma padronização de códigos de erros para que o mesmo erro seja identificado em qualquer banco de dados, em qualquer versão ou idioma, seja aqui ou do outro lado do mundo. Logo, estes códigos não podem ser usados pelos desenvolvedores para customizar erros. Em contrapartida ela disponibiliza uma faixa de código que vai a partir do número -20000 até -20999, para que utilizemos nestes casos. Seria uma faixa de códigos de erros customizável. A descrição do erro fica por nossa conta. Vamos testar a alteração do programa. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧ ♥✉♠❜❡r❀ ✸ ✇❞❡♣t♥♦ ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ ❜❡❣✐♥ ✼ s❡❧❡❝t ❛✈❣✭s❛❧✮✱ ❞❡♣t♥♦ ✽ ✐♥t♦ ✇s❛❧✱ ✇❞❡♣t♥♦ ✾ ❢r♦♠ ❡♠♣ ✶✵ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✾✾ ✶✶ ❣r♦✉♣ ❜② ❞❡♣t♥♦❀ ✶✷ ❡①❝❡♣t✐♦♥ ✶✸ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✶✹ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✵✱ ✬❱❛❧♦r❡s ♥ã♦ ❡♥❝♦♥tr❛❞♦s ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ✾✾✳✬✮❀ ✶✺ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✶✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ✈❛❧♦r❡s r❡❢❡r❡♥t❡s ❛♦ ❞❡♣t♦✳ ✾✾✳ ✬⑤⑤ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✶✼ ✶✽ ❡♥❞❀ 75 7.1. Exceções predefinidas ✶✾ ✷✵ ✷✶ Casa do Código ✲✲ ❜❡❣✐♥ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✮ ✷✷ ✈❛❧✉❡s ✭✽✵✵✷✱ ✬❆◆●❊▲■◆❆✬✱ ✬▼❆◆❆●❊❘✬✱ ✼✽✸✾✱ ❚❖❴❉❆❚❊✭✬✷✵✴✶✵✴✷✵✶✶✬✱✬❉❉✴▼▼✴❘❘❘❘✬✮✱ ✇s❛❧✱ ♥✉❧❧✱ ✷✵✮❀ ✷✸ ✲✲ ✷✹ ❝♦♠♠✐t❀ ✷✺ ✲✲ ✷✻ ❡①❝❡♣t✐♦♥ ✷✼ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✷✽ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✵✱✬❊rr♦ ❛♦ ✐♥s❡r✐r ✉♠ ♥♦✈♦ ❡♠♣r❡❣❛❞♦✳ ✬⑤⑤ ✷✾ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✸✵ ❡♥❞❀ ✸✶ ✲✲ ✸✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊♠♣r❡❣❛❞♦ ❆◆●❊▲■◆❆ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ✸✸ ✲✲ ✸✹ ❡①❝❡♣t✐♦♥ ✸✺ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✸✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✸✼ ✇❤❡♥ t♦♦❴♠❛♥②❴r♦✇s t❤❡♥ ✸✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦✿ ❖ ❝ó❞✐❣♦ ❞❡ ❞❡♣❛rt❛♠❡♥t♦ ✐♥❢♦r♠❛❞♦✬⑤⑤ ✸✾ ✬ r❡t♦r♥♦✉ ♠❛✐s ❞❡ ✉♠ r❡❣✐str♦✳✬✮❀ ✹✵ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✹✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦ ❛♦ ✐♥s❡r✐r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ✬⑤⑤sq❧❡rr♠ ✹✷ ⑤⑤✬ ✲ ❈ó❞✐❣♦✿ ✭✬⑤⑤sq❧❝♦❞❡⑤⑤✬✮✳✬✮❀ ✹✸ ❡♥❞❀ ✹✹ ✴ ❊rr♦ ❛♦ ✐♥s❡r✐r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ❖❘❆✲✷✵✵✵✵✿ ❱❛❧♦r❡s ♥ã♦ ❡♥❝♦♥tr❛❞♦s ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ✾✾✳ ✲ ❈ó❞✐❣♦✿ ✭✲✷✵✵✵✵✮✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ 76 Casa do Código Capítulo 7. Exceções ❙◗▲❃ Analisando o resultado da execução, podemos perceber que ocorreu um erro na busca pelo valor do salário, onde não foi encontrado. Isso gerou a exceção no_data_found. Através do tratamento desta exceção foi chamado o raise_application_error, que gerou uma exceção fazendo com o programa fosse desviado para o tratamento de exceção mais externo ao seu bloco, no caso, o tratamento others, localizado na linha 40 no nosso programa. Isso, porque, embora, exista outro tratamento others logo a seguir, no bloco referente ao insert, eles estão em um mesmo nível. Por isso, a ação do programa foi desviada para o tratamento mais externo. Com o desvio, o programa não continua com as ações subsequentes atingindo assim nosso objetivo de tratamento. Nota: se estivermos utilizando uma estrutura loop e uma exceção for gerada dentro dela, e não havendo uma área de tratamento de exceções nesta estrutura, o loop é interrompido e o programa é desviado para o primeiro tratamento encontrado em um nível mais externo. Caso haja uma área de tratamento de exceções dentro loop, e ela não requerer a parada do sistema, o loop continuará normalmente até alcançar o término programado. Agora vamos alterar o código do departamento para um existente, para realizar um novo teste. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧ ♥✉♠❜❡r❀ ✸ ✇❞❡♣t♥♦ ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ ❜❡❣✐♥ ✼ s❡❧❡❝t ❛✈❣✭s❛❧✮✱ ❞❡♣t♥♦ ✽ ✐♥t♦ ✇s❛❧✱ ✇❞❡♣t♥♦ ✾ ❢r♦♠ ❡♠♣ ✶✵ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✶✵ 77 7.1. Exceções predefinidas ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ ✸✵ ✸✶ ✸✷ ✸✸ ✸✹ ✸✺ ✸✻ ✸✼ ✸✽ ✸✾ ✹✵ ✹✶ 78 Casa do Código ❣r♦✉♣ ❜② ❞❡♣t♥♦❀ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✵✱ ✬❱❛❧♦r❡s ♥ã♦ ❡♥❝♦♥tr❛❞♦s ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ✾✾✳✬✮❀ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ✈❛❧♦r❡s r❡❢❡r❡♥t❡s ❛♦ ❞❡♣t♦✳ ✶✵✳ ✬⑤⑤ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ❡♥❞❀ ✲✲ ❜❡❣✐♥ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✮ ✈❛❧✉❡s ✭✽✵✵✷✱ ✬❆◆●❊▲■◆❆✬✱ ✬▼❆◆❆●❊❘✬✱ ✼✽✸✾✱ ❚❖❴❉❆❚❊✭✬✷✵✴✶✵✴✷✵✶✶✬✱✬❉❉✴▼▼✴❘❘❘❘✬✮✱ ✇s❛❧✱ ♥✉❧❧✱ ✷✵✮❀ ✲✲ ❝♦♠♠✐t❀ ✲✲ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♦t❤❡rs t❤❡♥ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✵✱ ✬❊rr♦ ❛♦ ✐♥s❡r✐r ✉♠ ♥♦✈♦ ❡♠♣r❡❣❛❞♦✳ ✬⑤⑤ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ❡♥❞❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊♠♣r❡❣❛❞♦ ❆◆●❊▲■◆❆ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ✲✲ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✇❤❡♥ t♦♦❴♠❛♥②❴r♦✇s t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦✿ ❖ ❝ó❞✐❣♦ ❞❡ ❞❡♣❛rt❛♠❡♥t♦ ✐♥❢♦r♠❛❞♦✬⑤⑤ ✬ r❡t♦r♥♦✉ ♠❛✐s ❞❡ ✉♠ r❡❣✐str♦✳✬✮❀ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ Casa do Código Capítulo 7. Exceções ✬❊rr♦ ❛♦ ✐♥s❡r✐r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ✬⑤⑤sq❧❡rr♠ ⑤⑤✬ ✲ ❈ó❞✐❣♦✿ ✭✬⑤⑤sq❧❝♦❞❡⑤⑤✬✮✳✬✮❀ ✹✷ ✹✸ ❡♥❞❀ ✹✹ ✴ ❊♠♣r❡❣❛❞♦ ❆◆●❊▲■◆❆ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Como era o esperado, o programa funcionou normalmente. Pode-se ainda simular o erro referente ao comando insert, atribuindo null à variável wsal antes da inclusão. 7.2 Exceções definidas pelo usuário Como foi dito anteriormente, além das exceções predefinidas existentes no Oracle, podemos criar novas exceções para atender a necessidades mais específicas do nosso programa. A diferença entre estes tipos está na definição e controle destas exceções. Este tipo, quando utilizado pelo usuário, deve ser declarado e manipulado pelo próprio programa. Para o Oracle, estas exceções não existem, por isso, todo o controle deve ser feito pela aplicação. Vamos ver o exemplo a seguir. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧ ♥✉♠❜❡r❀ ✸ ✇❡rr♦❴s❛❧❛r✐♦ ❡①❝❡♣t✐♦♥❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ ❜❡❣✐♥ ✼ s❡❧❡❝t ♥✈❧✭❛✈❣✭s❛❧✮✱✵✮ ✽ ✐♥t♦ ✇s❛❧ ✾ ❢r♦♠ ❡♠♣ ✶✵ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✾✾❀ ✶✶ ✲✲ ✶✷ ✐❢ ✇s❛❧ ❂ ✵ t❤❡♥ ✶✸ ✲✲ ✶✹ r❛✐s❡ ✇❡rr♦❴s❛❧❛r✐♦❀ 79 7.2. Exceções definidas pelo usuário ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ Casa do Código ✲✲ ❡♥❞ ✐❢❀ ✲✲ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♦t❤❡rs t❤❡♥ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✵✱ ✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ✈❛❧♦r❡s r❡❢❡r❡♥t❡s ❛♦ ❞❡♣t♦✳ ✾✾✳ ✬⑤⑤ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✷✶ ✷✷ ❡♥❞❀ ✷✸ ✲✲ ✷✹ ❜❡❣✐♥ ✷✺ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✮ ✷✻ ✈❛❧✉❡s ✭✽✵✵✷✱ ✬❆◆●❊▲■◆❆✬✱ ✬▼❆◆❆●❊❘✬✱ ✼✽✸✾✱ ❚❖❴❉❆❚❊✭✬✷✵✴✶✵✴✷✵✶✶✬✱✬❉❉✴▼▼✴❘❘❘❘✬✮✱ ✇s❛❧✱ ♥✉❧❧✱ ✷✵✮❀ ✷✼ ✲✲ ✷✽ ❝♦♠♠✐t❀ ✷✾ ✲✲ ✸✵ ❡①❝❡♣t✐♦♥ ✸✶ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✸✷ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✵✱ ✬❊rr♦ ❛♦ ✐♥s❡r✐r ✉♠ ♥♦✈♦ ❡♠♣r❡❣❛❞♦✳ ✬⑤⑤ ✸✸ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✸✹ ❡♥❞❀ ✸✺ ✲✲ ✸✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊♠♣r❡❣❛❞♦ ❆◆●❊▲■◆❆ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ✸✼ ✲✲ ✸✽ ❡①❝❡♣t✐♦♥ ✸✾ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✹✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✹✶ ✇❤❡♥ t♦♦❴♠❛♥②❴r♦✇s t❤❡♥ ✹✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦✿ ❖ ❝ó❞✐❣♦ ❞❡ ❞❡♣❛rt❛♠❡♥t♦ ✐♥❢♦r♠❛❞♦✬⑤⑤ ✬ r❡t♦r♥♦✉ ♠❛✐s ❞❡ ✉♠ r❡❣✐str♦✳✬✮❀ ✹✸ ✹✹ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✹✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ 80 Casa do Código Capítulo 7. Exceções ✬❊rr♦ ❛♦ ✐♥s❡r✐r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ✬⑤⑤sq❧❡rr♠ ⑤⑤✬ ✲ ❈ó❞✐❣♦✿ ✭✬⑤⑤sq❧❝♦❞❡⑤⑤✬✮✳✬✮❀ ✹✻ ✹✼ ❡♥❞❀ ✹✽ ✴ ❊rr♦ ❛♦ ✐♥s❡r✐r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ❖❘❆✲✷✵✵✵✵✿ ❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ✈❛❧♦r❡s r❡❢❡r❡♥t❡s ❛♦ ❞❡♣t♦✳ ✾✾✳ ❊rr♦✿ ❯s❡r✲❉❡❢✐♥❡❞ ❡①❝❡♣t✐♦♥✳ ✲ ❈ó❞✐❣♦✿ ✭✲✷✵✵✵✵✮✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Vamos entender o exemplo. Primeiramente, precisamos definir um nome para a exceção e declará-la na área de declaração de variáveis. No exemplo, chamamos nossa exceção de werro_salario. Quando declaramos uma variável do tipo exceção utilizamos o tipo exception. Feito isto, já podemos utilizá-la em nosso programa. Modificamos o programa utilizado nos exemplos anteriores, justamente para mostrar formas diferentes de tratar os mesmos problemas. Modificamos o select que busca o salário para que ele não gere a exceção nativa do Oracle. Sabemos que o uso de funções de agrupamento, como sum, min, max, avg etc., não geram exceções mesmo não atendendo à cláusula where. Com isso, a exceção no_data_found não é gerada. Contudo, para realizar o controle e não permitir que valores nulos ou zerados sejam cadastrados no campo salário, nós utilizamos uma estrutura if para testar o resultado vindo do select, e dependendo como for, acionar ou não a exceção que definimos. Nosso teste é bem simples, verificamos se o valor é igual ou diferente de zero. Caso seja igual a zero chamamos nossa exceção através do comando raise. Este comando aciona nossa exceção e faz com que a ação do programa seja desviada para a área de tratamento de erros dentro da hierarquia de níveis, ou seja, a partir daí as regras e sequências são as mesmas utilizadas nas exceções predefinidas. Uma observação importante. Se houver comandos após a chamada raise, eles nunca serão executados. Portanto, fique atento quanto a isto. Note também que duas mensagens de erro foram geradas, inclusive, uma que 81 7.2. Exceções definidas pelo usuário Casa do Código diz que a exceção gerada foi uma exceção definida pelo usuário: User-Defined exception. Ainda podemos melhorar esta mensagem inibindo os códigos de erro e fazendo com que apareça apenas uma mensagem. Veja a seguir. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧ ♥✉♠❜❡r❀ ✸ ✇❡rr♦❴s❛❧❛r✐♦ ❡①❝❡♣t✐♦♥❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ ❜❡❣✐♥ ✼ s❡❧❡❝t ♥✈❧✭❛✈❣✭s❛❧✮✱✵✮ ✽ ✐♥t♦ ✇s❛❧ ✾ ❢r♦♠ ❡♠♣ ✶✵ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✾✾❀ ✶✶ ✲✲ ✶✷ ✐❢ ✇s❛❧ ❂ ✵ t❤❡♥ ✶✸ ✲✲ ✶✹ r❛✐s❡ ✇❡rr♦❴s❛❧❛r✐♦❀ ✶✺ ✲✲ ✶✻ ❡♥❞ ✐❢❀ ✶✼ ✲✲ ✶✽ ❡①❝❡♣t✐♦♥ ✶✾ ✇❤❡♥ ✇❡rr♦❴s❛❧❛r✐♦ t❤❡♥ ✷✵ r❛✐s❡ ✇❡rr♦❴s❛❧❛r✐♦❀ ✷✶ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✷✷ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✵✱✬❊rr♦ ❛♦ s❡❧❡❝✐♦♥❛r ✈❛❧♦r❡s r❡❢❡r❡♥t❡s ❛♦ ❞❡♣t♦✳ ✾✾✳ ✬⑤⑤ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✷✸ ✷✹ ❡♥❞❀ ✷✺ ✲✲ ✷✻ ❜❡❣✐♥ ✷✼ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✮ ✷✽ ✈❛❧✉❡s ✭✽✵✵✷✱ ✬❆◆●❊▲■◆❆✬✱ ✬▼❆◆❆●❊❘✬✱ ✼✽✸✾✱ ❚❖❴❉❆❚❊✭✬✷✵✴✶✵✴✷✵✶✶✬✱✬❉❉✴▼▼✴❘❘❘❘✬✮✱ ✇s❛❧✱ ♥✉❧❧✱ ✷✵✮❀ ✷✾ ✲✲ ✸✵ ❝♦♠♠✐t❀ ✸✶ ✲✲ 82 Casa do Código Capítulo 7. Exceções ✸✷ ✸✸ ✸✹ ❡①❝❡♣t✐♦♥ ✇❤❡♥ ♦t❤❡rs t❤❡♥ r❛✐s❡❴❛♣♣❧✐❝❛t✐♦♥❴❡rr♦r✭✲✷✵✵✵✵✱ ✬❊rr♦ ❛♦ ✐♥s❡r✐r ✉♠ ♥♦✈♦ ❡♠♣r❡❣❛❞♦✳ ✬⑤⑤ ✬❊rr♦✿ ✬⑤⑤sq❧❡rr♠⑤⑤✬✳✬✮❀ ✸✺ ✸✻ ❡♥❞❀ ✸✼ ✲✲ ✸✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊♠♣r❡❣❛❞♦ ❆◆●❊▲■◆❆ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ✸✾ ✲✲ ✹✵ ❡①❝❡♣t✐♦♥ ✹✶ ✇❤❡♥ ✇❡rr♦❴s❛❧❛r✐♦ t❤❡♥ ✹✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❖ s❛❧ár✐♦ ♥❡❝❡ss✐t❛ s❡r ♠❛✐♦r q✉❡ ③❡r♦✳✬✮❀ ✹✸ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✹✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦ ♥ã♦ ❡♥❝♦♥tr❛❞♦✳✬✮❀ ✹✺ ✇❤❡♥ t♦♦❴♠❛♥②❴r♦✇s t❤❡♥ ✹✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦✿ ❖ ❝ó❞✐❣♦ ❞❡ ❞❡♣❛rt❛♠❡♥t♦ ✐♥❢♦r♠❛❞♦✬⑤⑤ ✹✼ ✬ r❡t♦r♥♦✉ ♠❛✐s ❞❡ ✉♠ r❡❣✐str♦✳✬✮❀ ✹✽ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✹✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊rr♦ ❛♦ ✐♥s❡r✐r ❡♠♣r❡❣❛❞♦✳ ❊rr♦✿ ✬⑤⑤sq❧❡rr♠ ✺✵ ⑤⑤✬ ✲ ❈ó❞✐❣♦✿ ✭✬⑤⑤sq❧❝♦❞❡⑤⑤✬✮✳✬✮❀ ✺✶ ❡♥❞❀ ✺✷ ✴ ❖ s❛❧ár✐♦ ♥❡❝❡ss✐t❛ s❡r ♠❛✐♦r q✉❡ ③❡r♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Com isso, finalizamos a parte sobre exceções. Vimos que através delas é possível realizar todos os tratamentos de erros de uma forma organizada e sem prejudicar o funcionamento do sistema. Outro fator que deve ser comentado é que as exceções não servem apenas para geração de mensagens de erro. Dentro das áreas de tratamento podemos usar chamadas a functions, procedures ou packages para solucionar problemas sem a intervenção ou 83 7.2. Exceções definidas pelo usuário até mesmo sem conhecimento do usuário. 84 Casa do Código Capítulo 8 Estruturas de condição: if As estruturas de condição são utilizadas quando precisamos alterar o fluxo de caminho de um programa. Através deste tipo de estrutura conseguimos criar condições que podem levar o programa a executar tarefas diferentes dependendo de cada situação. Portanto, utilizamos a declaração if para avaliar uma ou mais condições, executando ou não determinadas linhas de instruções. No PL/SQL utilizamos o comando if (se) para montar estas condições. Podemos ter condições simples, com uma condição apenas, até o uso de condições aninhadas onde podemos ter comandos if dentro de outros comandos if, em uma mesma estrutura. Juntamente com o comando if temos o comando else (se não), que é utilizado para direcionar o programa para outros caminhos caso o if não satisfaça a condição desejada. Dentro da estrutura de um comando if podemos ter desde um else até vários elses ( elsif), seguindo sua sintaxe. 8.1. Estruturas do comando if-end if Casa do Código O que deve ficar claro é que esta estrutura gera um resultado mediante uma condição que satisfaça o critério imposto. No mais, podemos dizer que será comum achar este tipo de estrutura dentro dos programas. Portanto, você vai utilizá-la com frequência, pois como na grande maioria das vezes escrevemos códigos que refletem e abstraem situações do dia a dia, precisamos testar n variáveis para fazer com que o programa chegue ao objetivo proposto em cada situação. 8.1 Estruturas do comando if-end if ❙◗▲❃ ❜❡❣✐♥ ✷ ✲✲ ✸ ✐❢ ❁❝♦♥❞✐❝❛♦❃ t❤❡♥ ✹ ❁✐♥str✉çõ❡s❃ ❡♥❞ ✐❢❀ ✺ ✻ ❡♥❞❀ ✼ ❙◗▲❃ Nesta estrutura, temos apenas uma condição. Caso o resultado de <condicao> (linha 3) seja verdadeiro, ele estará satisfazendo a condição e executará os comandos que estiverem dentro do escopo do if. Caso contrário, não. O end if indica o fim do comando if. Veja as execuções a seguir, onde o programa é executado duas vezes, mas com diferentes valores: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ 86 ❞❡❝❧❛r❡ ① ♥✉♠❜❡r ✿❂ ✶✵❀ r❡s ♥✉♠❜❡r❀ ❜❡❣✐♥ r❡s ✿❂ ♠♦❞✭①✱✷✮❀ ✐❢ r❡s ❂ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦✬✮❀ ❡♥❞ ✐❢❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ❡♥❞❀ ✴ Casa do Código Capítulo 8. Estruturas de condição: if ❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ① ♥✉♠❜❡r ✿❂ ✼❀ ✸ r❡s ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ r❡s ✿❂ ♠♦❞✭①✱✷✮❀ ✻ ✐❢ r❡s ❂ ✵ t❤❡♥ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦✬✮❀ ✽ ❡♥❞ ✐❢❀ ✾ ✲✲ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✶✶ ❡♥❞❀ ✶✷ ✴ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✶ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ 8.2 Estruturas do comando if-else-end if ❙◗▲❃ ❜❡❣✐♥ ✷ ✲✲ ✸ ✐❢ ❁❝♦♥❞✐❝❛♦❃ t❤❡♥ ✹ ❁✐♥str✉çõ❡s❃ ✺ ❡❧s❡ ✻ ❁✐♥str✉çõ❡s❃ ✼ ❡♥❞ ✐❢❀ ✽ ❡♥❞❀ ✾ ❙◗▲❃ Esta estrutura é formada por um if e um else. Caso a condição do if 87 8.2. Estruturas do comando if-else-end if Casa do Código não seja atendida o fluxo será desviado para o else. Note que o else não faz restrição ou checagem de condição. Em vias gerais o comando quer dizer: se a condição for verdadeira faça isso, se não faça aquilo. Vamos ver o mesmo exemplo, agora com duas condições, if e else, onde dependendo do resultado pode-se determinar qual fluxo o programa deve percorrer. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ① ♥✉♠❜❡r ✿❂ ✶✵❀ ✸ r❡s ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ r❡s ✿❂ ♠♦❞✭①✱✷✮❀ ✻ ✐❢ r❡s ❂ ✵ t❤❡♥ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦✬✮❀ ✽ ❡❧s❡ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ ♥ã♦ é ③❡r♦✦✬✮❀ ✶✵ ❡♥❞ ✐❢❀ ✶✶ ✲✲ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✶✸ ❡♥❞❀ ✶✹ ✴ ❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ① ♥✉♠❜❡r ✿❂ ✼❀ ✸ r❡s ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ r❡s ✿❂ ♠♦❞✭①✱✷✮❀ ✻ ✐❢ r❡s ❂ ✵ t❤❡♥ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦✬✮❀ ✽ ❡❧s❡ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ ♥ã♦ é ③❡r♦✦✬✮❀ ✶✵ ❡♥❞ ✐❢❀ ✶✶ ✲✲ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✶✸ ❡♥❞❀ 88 Casa do Código Capítulo 8. Estruturas de condição: if ✶✹ ✴ ❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ ♥ã♦ é ③❡r♦✦ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✶ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ 8.3 Estruturas do comando if-elsif(-else)-end if ❙◗▲❃ ❜❡❣✐♥ ✷ ✲✲ ✸ ✐❢ ❁❝♦♥❞✐❝❛♦❃ t❤❡♥ ✹ ❁✐♥str✉çõ❡s❃ ❡❧s✐❢ ❁❝♦♥❞✐❝❛♦❃ t❤❡♥ ✺ ✻ ❁✐♥str✉çõ❡s❃ ✼ ❡♥❞ ✐❢❀ ✽ ❡♥❞❀ ✾ ❙◗▲❃ ❙◗▲❃ ❜❡❣✐♥ ✷ ✲✲ ✸ ✐❢ ❁❝♦♥❞✐❝❛♦❃ t❤❡♥ ✹ ❁✐♥str✉çõ❡s❃ ❡❧s✐❢ ❁❝♦♥❞✐❝❛♦❃ t❤❡♥ ✺ ✻ ❁✐♥str✉çõ❡s❃ ❡❧s❡ ✼ ✽ ❁✐♥str✉çõ❡s❃ ✾ ❡♥❞ ✐❢❀ ✶✵ ❡♥❞❀ ✶✶ ❙◗▲❃ Esta estrutura permite testar mais de uma condição dentro de uma estrutura if. Além do if e else podemos ter o elsif. Podemos ter uma 89 8.3. Estruturas do comando if-elsif(-else)-end if Casa do Código estrutura if com vários elsif, dependendo da necessidade e quantidade de condições que precisarmos testar. A seguir, um exemplo: Entrando na primeira condição: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ① ♥✉♠❜❡r ✿❂ ✶✵❀ ✸ r❡s ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ r❡s ✿❂ ♠♦❞✭①✱✺✮❀ ✻ ✐❢ r❡s ❂ ✵ t❤❡♥ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦✬✮❀ ✽ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ ♥ã♦ é ③❡r♦✦✬✮❀ ✶✵ ❡❧s❡ ✶✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ♠❡♥♦r ③❡r♦✦✬✮❀ ✶✷ ❡♥❞ ✐❢❀ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✶✺ ❡♥❞❀ ✶✻ ✴ ❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Entrando na segunda condição: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ① ♥✉♠❜❡r ✿❂ ✶✶❀ ✸ r❡s ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ r❡s ✿❂ ♠♦❞✭①✱✺✮❀ ✻ ✐❢ r❡s ❂ ✵ t❤❡♥ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦✬✮❀ ✽ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ ♥ã♦ é ③❡r♦✦✬✮❀ ✶✵ ❡❧s❡ 90 Casa do Código Capítulo 8. Estruturas de condição: if ✶✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ♠❡♥♦r ③❡r♦✦✬✮❀ ✶✷ ❡♥❞ ✐❢❀ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✶✺ ❡♥❞❀ ✶✻ ✴ ❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ ♥ã♦ é ③❡r♦✦ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✶ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Entrando na terceira condição: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ① ♥✉♠❜❡r ✿❂ ✲✻❀ ✸ r❡s ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ r❡s ✿❂ ♠♦❞✭①✱✺✮❀ ✻ ✐❢ r❡s ❂ ✵ t❤❡♥ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ③❡r♦✦✬✮❀ ✽ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ ♥ã♦ é ③❡r♦✦✬✮❀ ✶✵ ❡❧s❡ ✶✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ♠❡♥♦r ③❡r♦✦✬✮❀ ✶✷ ❡♥❞ ✐❢❀ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✶✺ ❡♥❞❀ ✶✻ ✴ ❖ r❡st♦ ❞❛ ❞✐✈✐sã♦ é ♠❡♥♦r ③❡r♦✦ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✲✶ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Vimos que a estrutura de condição nos dá várias possibilidades para fazer com que os programas tomem rumos diferentes para cada situação. Também 91 8.3. Estruturas do comando if-elsif(-else)-end if Casa do Código foi mencionado anteriormente que é possível montar estruturas if aninhadas, ou seja, uma estrutura if dentro de outra estrutura if, por exemplo. Portanto, pode-se usar um aninhamento de declarações if, quando se tem a necessidade de filtrar uma série de dados. Mas tome cuidado, pois muitos níveis de declarações if podem causar problemas no momento da depuração do programa. O número máximo de níveis de declarações if recomendado são quatro. Veja a seguir o exemplo da sintaxe de declarações aninhadas if: ❙◗▲❃ ❜❡❣✐♥ ✷ ✐❢ ❁❝♦♥❞✐çã♦❃ t❤❡♥ ✸ ✐❢ ❁❝♦♥❞✐çã♦❃ t❤❡♥ ✹ ❁✐♥str✉çõ❡s❃ ✺ ❡❧s❡ ✻ ❁✐♥str✉çõ❡s❃ ✼ ✐❢ ❁❝♦♥❞✐çã♦❃ t❤❡♥ ✽ ❁✐♥str✉çõ❡s❃ ✾ ❡❧s❡ ✶✵ ❁✐♥str✉çõ❡s❃ ✶✶ ❡♥❞ ✐❢❀ ✶✷ ❡♥❞ ✐❢❀ ✶✸ ❡♥❞ ✐❢❀ ✶✹ ❡♥❞❀ ✶✺ ❙◗▲❃ Vamos ver o exemplo: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ①✶ ♥✉♠❜❡r ✿❂ ✶✵❀ ✸ ①✷ ♥✉♠❜❡r ✿❂ ✺❀ ✹ ♦♣ ✈❛r❝❤❛r✷✭✶✮ ✿❂ ✬✰✬❀ ✺ r❡s ♥✉♠❜❡r❀ ✻ ❜❡❣✐♥ ✼ ✐❢ ✭①✶ ✰ ①✷✮ ❂ ✵ t❤❡♥ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✵✬✮❀ ✾ ❡❧s✐❢ ♦♣ ❂ ✬✯✬ t❤❡♥ ✶✵ r❡s ✿❂ ①✶ ✯ ①✷❀ ✶✶ ❡❧s✐❢ ♦♣ ❂ ✬✴✬ t❤❡♥ 92 Casa do Código Capítulo 8. Estruturas de condição: if ✶✷ ✐❢ ①✷ ❂ ✵ t❤❡♥ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❞❡ ❞✐✈✐sã♦ ♣♦r ③❡r♦✦✬✮❀ ✶✹ ❡❧s❡ ✶✺ r❡s ✿❂ ①✶ ✴ ①✷❀ ✶✻ ❡♥❞ ✐❢❀ ✶✼ ❡❧s✐❢ ♦♣ ❂ ✬✲✬ t❤❡♥ ✶✽ r❡s ✿❂ ①✶ ✲ ①✷❀ ✶✾ ✐❢ r❡s ❂ ✵ t❤❡♥ ✷✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ✐❣✉❛❧ ❛ ③❡r♦✦✬✮❀ ✷✶ ❡❧s✐❢ r❡s ❁ ✵ t❤❡♥ ✷✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❡♥♦r q✉❡ ③❡r♦✦✬✮❀ ✷✸ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ✷✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❛✐♦r❧ ❛ ③❡r♦✦✬✮❀ ✷✺ ❡♥❞ ✐❢❀ ✷✻ ❡❧s✐❢ ♦♣ ❂ ✬✰✬ t❤❡♥ ✷✼ r❡s ✿❂ ①✶ ✰ ①✷❀ ✷✽ ❡❧s❡ ✷✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖♣❡r❛❞♦r ✐♥✈á❧✐❞♦✦✬✮❀ ✸✵ ❡♥❞ ✐❢❀ ✸✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✸✷ ❡♥❞❀ ✸✸ ✴ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✶✺ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ 8.4 Formatando as declarações if Para que o código que contenha a declaração if fique mais legível e mais fácil de entender, é necessário o emprego de algumas regras de alinhamento tais como: • Usando-se várias declarações if, recua-se a próxima declaração if alguns espaços para dentro; • Os comentários devem ficar após a declaração end if; • Os blocos de declarações devem ficar recuados alguns espaços para dentro, contando a partir da declaração if; 93 8.5. Evitando erros comuns no uso de if Casa do Código • Se uma condição for muito grande e mudar de linha, recua-se esta linha alguns espaços para dentro; • Deve-se colocar o else sempre abaixo da declaração if ao qual ele é correspondente, assim como o end if do mesmo; 8.5 Evitando erros comuns no uso de if É recomendado que se tomem algumas precauções para que não ocorram erros nas declarações if. A tabela a seguir demonstra alguns cuidados necessários: • Verifique se toda declaração if tem uma declaração end if correspondente, e se você digitou elsif sem o e extra (como “elseif ”). • Não faça loops aninhados muito complexos. A complexidade dificulta o acompanhamento e a depuração quando ocorrerem problemas ou alterações. Avalie sua lógica para ver se uma função realiza a mesma tarefa. • Verifique se você colocou um espaço na declaração end if em vez de não usar espaço ou usar um traço. • Não se esqueça da sua pontuação. Você precisa de pontos e vírgulas depois de end if e depois de cada uma das declarações, mas não depois da palavra-chave then. Nota: a função mod tem o objetivo de retornar o resto da divisão entre dois números passados por parâmetro. Nota: caso não esteja visualizando as saída do comando dbms_output, no SQL*Plus, execute o seguinte comando: set serveroutput on. 94 Capítulo 9 Comandos de repetição Os comandos de repetição são utilizados para que possamos repetir uma determinada ação ou ações dentro de um programa quantas vezes sejam necessárias. As repetições podem ser iniciadas a partir de uma condição e sua finalização também deve acontecer através deste critério. Em PL/SQL temos basicamente três tipos de estruturas de repetição. São elas: loop, while loop e for loop. Cada estrutura possui características que se adequam às mais variadas situações, conforme as necessidades de cada desenvolvimento. Vamos conhecer os comandos que fazem parte destas estruturas: 9.1 for loop Usa-se o for loop para repetir diversas vezes o mesmo bloco de código, até que a condição predefinida seja atendida e impeça a execução do looping. Veja a seguir um exemplo de looping for: 9.1. for loop Casa do Código ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r ✐ ✐♥ ✶✳✳✶✵ ❧♦♦♣ ✸ ✲✲ ✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✺ ❳ ✬⑤⑤✐⑤⑤✬ ❂ ✬⑤⑤✭✺✯✐✮✮❀ ✺ ✲✲ ✻ ❡♥❞ ❧♦♦♣❀ ✼ ❡♥❞❀ ✽ ✴ ✺ ❳ ✶ ❂ ✺ ✺ ❳ ✷ ❂ ✶✵ ✺ ❳ ✸ ❂ ✶✺ ✺ ❳ ✹ ❂ ✷✵ ✺ ❳ ✺ ❂ ✷✺ ✺ ❳ ✻ ❂ ✸✵ ✺ ❳ ✼ ❂ ✸✺ ✺ ❳ ✽ ❂ ✹✵ ✺ ❳ ✾ ❂ ✹✺ ✺ ❳ ✶✵ ❂ ✺✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Nota: caso não esteja conseguindo visualizar resultado na tela execute o comando: ❙◗▲❃ ❙◗▲❃ s❡t s❡r✈❡r♦✉t♣✉t ♦♥ ❙◗▲❃ Este programa imprime na tela a tabuada de cinco. Criamos uma estrutura for loop que repetirá o bloco PL/SQL dez vezes, começando por 1. Cada vez que uma volta acontece, a variável i, que neste caso não necessitou ser declarada, pois o for loop a declara dentro do seu escopo, é incrementada. Quando esta variável chegar a 10, o bloco PL/SQL será executado uma última vez e então o comando é finalizado. Note que utilizamos a variável i como base para nosso cálculo, e assim montamos a saída proposta. Juntamente com o comando for podemos utilizar o comando REVERSE. Este comando faz com que a contagem aconteça de forma contrária. Neste 96 Casa do Código Capítulo 9. Comandos de repetição exemplo, i receberá 10 inicialmente, e será decrementado a cada volta. Quando i chegar a 1, o bloco PL/SQL será executado uma última vez e o comando é finalizado. Veja o exemplo: ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r ✐ ✐♥ ❘❊❱❊❘❙❊ ✶✳✳✶✵ ❧♦♦♣ ✸ ✲✲ ✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✺ ❳ ✬⑤⑤✐⑤⑤✬ ❂ ✬⑤⑤✭✺✯✐✮✮❀ ✺ ✲✲ ✻ ❡♥❞ ❧♦♦♣❀ ✼ ❡♥❞❀ ✽ ✴ ✺ ❳ ✶✵ ❂ ✺✵ ✺ ❳ ✾ ❂ ✹✺ ✺ ❳ ✽ ❂ ✹✵ ✺ ❳ ✼ ❂ ✸✺ ✺ ❳ ✻ ❂ ✸✵ ✺ ❳ ✺ ❂ ✷✺ ✺ ❳ ✹ ❂ ✷✵ ✺ ❳ ✸ ❂ ✶✺ ✺ ❳ ✷ ❂ ✶✵ ✺ ❳ ✶ ❂ ✺ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ O loop for também pode ser executado aninhadamente. Quando se aninha os loops for, o loop externo é executado primeiro e posteriormente os internos. ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r ① ✐♥ ✺✳✳✻ ❧♦♦♣ ✸ ✲✲ ✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❚❛❜✉❛❞❛ ❞❡ ✬⑤⑤①✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬ ✬✮❀ ✻ ✲✲ ✼ ❢♦r ② ✐♥ ✶✳✳✶✵ ❧♦♦♣ ✽ ✲✲ 97 9.1. for loop Casa do Código ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭①⑤⑤✬ ❳ ✬⑤⑤②⑤⑤✬ ❂ ✬⑤⑤✭①✯②✮✮❀ ✶✵ ✲✲ ✶✶ ❡♥❞ ❧♦♦♣❀ ✶✷ ✲✲ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬ ✬✮❀ ✶✹ ✲✲ ✶✺ ❡♥❞ ❧♦♦♣❀ ✶✻ ❡♥❞❀ ✶✼ ✴ ❚❛❜✉❛❞❛ ❞❡ ✺ ✺ ❳ ✶ ❂ ✺ ✺ ❳ ✷ ❂ ✶✵ ✺ ❳ ✸ ❂ ✶✺ ✺ ❳ ✹ ❂ ✷✵ ✺ ❳ ✺ ❂ ✷✺ ✺ ❳ ✻ ❂ ✸✵ ✺ ❳ ✼ ❂ ✸✺ ✺ ❳ ✽ ❂ ✹✵ ✺ ❳ ✾ ❂ ✹✺ ✺ ❳ ✶✵ ❂ ✺✵ ❚❛❜✉❛❞❛ ❞❡ ✻ ✻ ❳ ✶ ❂ ✻ ✻ ❳ ✷ ❂ ✶✷ ✻ ❳ ✸ ❂ ✶✽ ✻ ❳ ✹ ❂ ✷✹ ✻ ❳ ✺ ❂ ✸✵ ✻ ❳ ✻ ❂ ✸✻ ✻ ❳ ✼ ❂ ✹✷ ✻ ❳ ✽ ❂ ✹✽ ✻ ❳ ✾ ❂ ✺✹ ✻ ❳ ✶✵ ❂ ✻✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Neste exemplo, utilizamos os for loops aninhados para mostrar na tela os cálculos das tabuadas de 5 e 6. Pode-se utilizar o incremento de um loop como parte da lógica de um programa, fazendo com que determinadas 98 Casa do Código Capítulo 9. Comandos de repetição ações só sejam executadas tendo como base esta informação. Veja o exemplo a seguir. ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r ① ✐♥ ✶✳✳✶✺ ❧♦♦♣ ✸ ✲✲ ✹ ✐❢ ♠♦❞✭①✱✷✮ ❂ ✵ t❤❡♥ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✬⑤⑤①✮❀ ✻ ❡♥❞ ✐❢❀ ✼ ✲✲ ✽ ❡♥❞ ❧♦♦♣❀ ✾ ❡♥❞❀ ✶✵ ✴ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✷ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✹ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✻ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✽ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✶✵ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✶✷ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✶✹ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Aqui utilizamos uma repetição onde o bloco PL/SQL será executado 15 vezes. Contudo, a impressão em tela será realizada apenas se os critérios do comando if forem verdadeiros. Neste exemplo, estamos solicitando que o programa imprima em tela somente os números divisíveis por 2. Note que estamos utilizando a variável de incremento (neste caso, X) como parte da nossa lógica. Outra opção interessante no uso do for loop é a possibilidade de substituir os números fixos do intervalo por variáveis. Veja o mesmo exemplo utilizando variáveis para definir o intervalo. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✐♥t❡r✶ ♥✉♠❜❡r ❞❡❢❛✉❧t ✶❀ ✸ ✐♥t❡r✷ ♥✉♠❜❡r ❞❡❢❛✉❧t ✶✺❀ 99 9.1. for loop Casa do Código ✹ ❜❡❣✐♥ ✺ ❢♦r ① ✐♥ ✐♥t❡r✶✳✳✐♥t❡r✷ ❧♦♦♣ ✻ ✲✲ ✼ ✐❢ ♠♦❞✭①✱✷✮ ❂ ✵ t❤❡♥ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✬⑤⑤①✮❀ ✾ ❡♥❞ ✐❢❀ ✶✵ ✲✲ ✶✶ ❡♥❞ ❧♦♦♣❀ ✶✷ ❡♥❞❀ ✶✸ ✴ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✷ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✹ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✻ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✽ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✶✵ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✶✷ ◆ú♠❡r♦ ❞✐✈✐sí✈❡❧ ♣♦r ✷✿ ✶✹ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Cuidados ao utilizar o comando for loop • Não se esquecer de colocar um espaço em end loop; • Não se esquecer do ponto e vírgula depois de end loop; • Não inserir o contador do mais alto para o mais baixo ao usar reserve ou definir o intervalo do mais alto para o mais baixo e se esquecer de usar reserve; • Não definir as variáveis de um loop de modo que o limite inferior tenha um valor maior do que o limite superior; • Não permitir que as variáveis dos limites acabem em valores null; • Ao aninhar os loops, verifique se as declarações seguem a lógica pretendida. 100 Casa do Código 9.2 Capítulo 9. Comandos de repetição while loop while loop é usado para avaliar uma condição antes de uma sequência de códigos seja executado. A diferença entre o loop while e o loop for, é que o loop while permite a execução de código apenas se a condição for verdadeira, e o loop for faz com que o código seja executado pelo menos uma vez, independente da condição. Veja a seguir um exemplo do loop while: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ① ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✸ ❧❛❜❡❧❴✈❡rt ✈❛r❝❤❛r✷✭✷✹✵✮ ❞❡❢❛✉❧t ✬✫❧❛❜❡❧✬❀ ✹ t❛♠❴❧❛❜❡❧ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✺ ❜❡❣✐♥ ✻ ✲✲ ✼ t❛♠❴❧❛❜❡❧ ✿❂ ❧❡♥❣t❤✭❧❛❜❡❧❴✈❡rt✮❀ ✽ ✲✲ ✾ ✇❤✐❧❡ ✭① ❁ t❛♠❴❧❛❜❡❧✮ ❧♦♦♣ ✶✵ ✲✲ ✶✶ ① ✿❂ ① ✰ ✶❀ ✶✷ ✲✲ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭s✉❜str✭❧❛❜❡❧❴✈❡rt✱①✱✶✮✮❀ ✶✹ ✲✲ ✶✺ ❡♥❞ ❧♦♦♣❀ ✶✻ ❡♥❞❀ ✶✼ ✴ ■♥❢♦r♠❡ ♦ ✈❛❧♦r ♣❛r❛ ❧❛❜❡❧✿ ❈❯❘❙❖ P▲❙◗▲ ❧❛❜❡❧❴✈❡rt ✈❛r❝❤❛r✷✭✷✹✵✮ ❞❡❢❛✉❧t ✬✫❧❛❜❡❧✬❀ ❛♥t✐❣♦ ✸✿ ♥♦✈♦ ✸✿ ❧❛❜❡❧❴✈❡rt ✈❛r❝❤❛r✷✭✷✹✵✮ ❞❡❢❛✉❧t ✬❈❯❘❙❖ P▲❙◗▲✬❀ ❈ ❯ ❘ ❙ ❖ P ▲ ❙ ◗ ▲ 101 Casa do Código 9.3. loop Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Note que neste exemplo não temos um número determinado de repetições. O número vai depender do tamanho da string informada através da variável label. Este programa imprime na tela em vertical uma string informada via parâmetro. A lógica foi escrita de forma que as repetições ocorram conforme a quantidade de caracteres existente dentro da variável. O controle é realizado pela existência da condição contida no comando while. 9.3 loop O loop é o comando de repetição mais simples e fácil de entender. Seu objetivo é igual aos dos demais comandos de repetição. Entretanto, possui características diferentes de funcionamento. Neste comando não é permitido definir um intervalo de repetição, muito menos uma condição que o faça iniciar e parar sua execução. Em tese, seu funcionamento é infinito, pois ao entrar em uma estrutura como esta não há como sair. Por isso, juntamente com ele utilizamos o comando exit. Este comando é quem vai determinar a finalização das repetições, impedindo que o programa entre em um loop eterno. Declarações exit e exit when Quando uma declaração exit é encontrada, o loop é imediatamente encerrado e o controle é passado para a declaração seguinte. A declaração exit when permite que você especifique a condição requerida para sair da execução do loop. Se o resultado da condição for verdadeiro, o loop é encerrado, e se o resultado for falso, o looping continua. Ao usar exit ou exit when coloque sempre esses comandos no início ou no final do bloco loop. Dessa forma você pode evitar muitos erros lógicos. Seguem exemplos de loop utilizando exit e exit when: 102 Casa do Código Capítulo 9. Comandos de repetição No exemplo a seguir utilizamos a estrutura if para criar uma condição que possa determinar a finalização do comando. Caso a condição contida no if seja verdadeira, chamamos o comando exit para finalizar a sequência de repetições. Caso contrário, o comando continua sua execução. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ① ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✸ ❧❛❜❡❧❴✈❡rt ✈❛r❝❤❛r✷✭✷✹✵✮ ❞❡❢❛✉❧t ✬✫❧❛❜❡❧✬❀ ✹ t❛♠❴❧❛❜❡❧ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✺ ❜❡❣✐♥ ✻ ✲✲ ✼ t❛♠❴❧❛❜❡❧ ✿❂ ❧❡♥❣t❤✭❧❛❜❡❧❴✈❡rt✮❀ ✽ ✲✲ ✾ ❧♦♦♣ ✶✵ ✲✲ ✶✶ ① ✿❂ ① ✰ ✶❀ ✶✷ ✲✲ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭s✉❜str✭❧❛❜❡❧❴✈❡rt✱①✱✶✮✮❀ ✶✹ ✲✲ ✶✺ ✐❢ ① ❂ t❛♠❴❧❛❜❡❧ t❤❡♥ ✶✻ ❡①✐t❀ ✶✼ ❡♥❞ ✐❢❀ ✶✽ ✲✲ ✶✾ ❡♥❞ ❧♦♦♣❀ ✷✵ ❡♥❞❀ ✷✶ ✴ ■♥❢♦r♠❡ ♦ ✈❛❧♦r ♣❛r❛ ❧❛❜❡❧✿ ❖❘❆❈▲❊ P▲❙◗▲ ❧❛❜❡❧❴✈❡rt ✈❛r❝❤❛r✷✭✷✹✵✮ ❞❡❢❛✉❧t ✬✫❧❛❜❡❧✬❀ ❛♥t✐❣♦ ✸✿ ♥♦✈♦ ✸✿ ❧❛❜❡❧❴✈❡rt ✈❛r❝❤❛r✷✭✷✹✵✮ ❞❡❢❛✉❧t ✬❖❘❆❈▲❊ P▲❙◗▲✬❀ ❖ ❘ ❆ ❈ ▲ ❊ P ▲ ❙ ◗ 103 9.3. loop Casa do Código ▲ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Já no exemplo a seguir utilizamos exit when, que nos permite incluir uma condição que possa finalizar o comando. Note que com isso não precisamos utilizar estruturas auxiliares, como o if, como foi utilizado no exemplo anterior. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ① ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✸ ❧❛❜❡❧❴✈❡rt ✈❛r❝❤❛r✷✭✷✹✵✮ ❞❡❢❛✉❧t ✬✫❧❛❜❡❧✬❀ ✹ t❛♠❴❧❛❜❡❧ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✺ ❜❡❣✐♥ ✻ ✲✲ ✼ t❛♠❴❧❛❜❡❧ ✿❂ ❧❡♥❣t❤✭❧❛❜❡❧❴✈❡rt✮❀ ✽ ✲✲ ✾ ❧♦♦♣ ✶✵ ✲✲ ✶✶ ① ✿❂ ① ✰ ✶❀ ✶✷ ✲✲ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭s✉❜str✭❧❛❜❡❧❴✈❡rt✱①✱✶✮✮❀ ✶✹ ✲✲ ✶✺ ❡①✐t ✇❤❡♥ ① ❂ t❛♠❴❧❛❜❡❧❀ ✶✻ ✲✲ ✶✼ ❡♥❞ ❧♦♦♣❀ ✶✽ ❡♥❞❀ ✶✾ ✴ ■♥❢♦r♠❡ ♦ ✈❛❧♦r ♣❛r❛ ❧❛❜❡❧✿ ❈❯❘❙❖ P▲❙◗▲ ❧❛❜❡❧❴✈❡rt ✈❛r❝❤❛r✷✭✷✹✵✮ ❞❡❢❛✉❧t ✬✫❧❛❜❡❧✬❀ ❛♥t✐❣♦ ✸✿ ♥♦✈♦ ✸✿ ❧❛❜❡❧❴✈❡rt ✈❛r❝❤❛r✷✭✷✹✵✮ ❞❡❢❛✉❧t ✬❈❯❘❙❖ P▲❙◗▲✬❀ ❈ ❯ ❘ ❙ ❖ P 104 Casa do Código Capítulo 9. Comandos de repetição ▲ ❙ ◗ ▲ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Em outras linguagens de programação é comum encontrar o comando repeat until (repita até). Na PL/SQL não existe este comando. Contudo, utilizamos os comandos loop e exit when para sanar esta necessidade. 9.4 Qual loop deve-se usar? Conforme visto até aqui, temos disponíveis três opções de loops. Mas como saber se estamos fazendo uso do tipo correto de loop para determinada situação? A tabela a seguir ajuda a esclarecer esta dúvida. • for: use sempre o loop for se você souber especificamente quantas vezes o loop deve ser executado. Se tiver de codificar uma declaração exit ou exit when em um loop for, você pode reconsiderar seu código e usar um loop ou uma abordagem diferente. • while: use este loop quando não há certeza se ele será executado. Embora seja possível conseguir esse resultado em um loop for usando exit ou exit when, essa situação é mais adequada para o loop while. O loop while é o loop mais usado porque ele fornece mais flexibilidade. • loop: você pode usar o loop simples se quiser criar um loop do tipo repeat until. O loop simples é perfeito para executar essa tarefa. Orientações sobre os loopS A lista a seguir apresentará algumas orientações sobre os loops. 105 9.4. Qual loop deve-se usar? Casa do Código • Verifique ao usar um loop com uma declaração exit ou exit when se a condição será atendida pelo menos uma vez; caso contrário, você terá um loop infinito. • Nunca crie um loop infinito. • Use sempre os nomes de rótulos nos loops. Isso torna o código muito mais fácil de acompanhar, além de lhe dar flexibilidade. • Não use uma declaração return dentro de um loop ao usar os loops em uma função. Embora isso funcione, essa é uma prática ruim de programação que tem alguns resultados indesejados, e é o modo errado de encerrar um loop. • Use exit when em vez de exit. exit when é muito mais fácil de acompanhar e requer menos código. • Verifique se a pontuação dos seus loops está adequada. Selecione o tipo de loop que vai usar com os incrementos. Você pode lidar com qualquer tipo de incremento em qualquer loop. • Crie variáveis de limite superior e inferior nos loops for se um dos limites puder ser alterado no futuro. Você pode atribuir esses limites imediatamente ao seu código. Na verdade, muito provavelmente você nem terá um limite fixo, de modo que você deve seguir este conselho automaticamente. 106 Capítulo 10 Cursores O cursor é um comando do PL/SQL que permite a construção de uma estrutura de repetição, ou seja, pode-se varrer uma tabela, linha por linha, coluna por coluna através da utilização deste comando, e assim, podemos manipular todos os dados de uma determinada tabela. O cursor deve ser declarado no início do bloco, onde será utilizado. Depois de declará-lo, ele deve ser criado dentro da mesma estrutura. As informações contidas no cursor são baseadas nos dados pelos quais sua estrutura foi definida. Por exemplo, se definirmos um cursor com base na tabela de empregados, será com os dados referentes aos empregados desta tabela em que vamos trabalhar quando estivermos manipulando tal cursor. Portanto, os retornos dos dados apresentados pelo cursor provem de comandos selects feitos em determinadas tabelas e que trazem dados de linhas e colunas específicas. Existem dois tipos de cursores no PL/SQL, os explícitos e os implícitos. O 10.1. Cursores explícitos Casa do Código cursor explícito é o que definimos nos programas, e o implícito, como o nome já diz é declarado implicitamente pelo Oracle, ou seja, quando usado o cursor explícito, o desenvolvedor, no caso quem está escrevendo a aplicação, além de declará-lo deve inserir comandos que especifiquem a sua inicialização e finalização, bem como a manipulação dos dados. Quando não existir um cursor explícito associado para o comando SQL, o Oracle o cria implicitamente. Um exemplo disto é quando temos um comando update ou delete, dentro de uma aplicação. Embora, não seja visível explicitamente, o Oracle cria um cursor para executar tal comando. Os cursores implícitos e explícitos podem existir na mesma aplicação em um mesmo bloco. Neste livro daremos ênfase nos cursores explícitos. Através deles podemos atender a situações bem específicas no desenvolvimento de nossos programas. Contudo, serão mostradas as características e o funcionamento destes dois tipos. 10.1 Cursores explícitos Para utilizarmos um cursor explícito, algumas regras devem ser obedecidas. Primeiramente, temos que declará-lo. Fazemos isto da mesma forma que com as variáveis e constantes. Veja a seguir algumas formas de declaração: ❝✉rs♦r ❝✶ ✐s s❡❧❡❝t ❡♥❛♠❡ ✱❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✸✵❀ É na declaração que definimos a estrutura do cursor. Esta estrutura inicia com a expressão cursor <nome cursor> is. O <nome cursor> segue as mesmas regras da definição de variáveis. Com isto estamos definindo o cabeçalho do cursor, rotulando-o. Logo após a expressão is vem o comando select que será a base do nosso cursor. Este select pode ser escrito normalmente como se fôssemos executá-lo pelo SQL*Plus, por exemplo. Os comandos select podem conter várias tabelas e colunas. Também pode ser usada a expressão asterisco * para se referir a todas as colunas de uma ou mais tabelas. Vale ressaltar que, quando utilizamos cursor, não é necessário usar 108 Casa do Código Capítulo 10. Cursores o comando into no select. Também podemos passar parâmetros para o select através dos cursores. Isso torna nossa estrutura mais organizada e possibilita utilizá-la para execução de diferentes critérios. Olhe o próximo exemplo. ❝✉rs♦r ❝✶✭ ♣❞❡♣t♥♦ ♥✉♠❜❡r ✱♣❥♦❜ ✈❛r❝❤❛r✷✮ ✐s s❡❧❡❝t ❡♠♣♥♦ ✱❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ♣❞❡♣t♥♦ ❛♥❞ ❥♦❜ ❃ ♣❥♦❜❀ O que difere nesta declaração é a definição de parâmetros. Note que, após ser informado o nome do nosso cursor, são definidos parâmetros os quais serão utilizados dentro comando select. A definição de parâmetros é idêntica a definição de variáveis. A única diferença é que não é necessário informar a quantidade de caracteres para o tipo do parâmetro. Por exemplo, o parâmetro pjob foi definido apenas como varchar2, não importando a quantidade de caracteres. Nestes casos, o Oracle considera o máximo de caracteres que o tipo suporta. Neste exemplo foram definidos dois parâmetros e os mesmos foram utilizados na cláusula where do comando select. Depois que definimos o cursor, precisamos declarar uma variável que receberá esta definição. Esta variável funcionará como um array, ou seja, ao abrirmos o cursor os registros serão jogados para este array para trabalharmos com eles. Vejamos a declaração a seguir. ❞❡❝❧❛r❡ ✲✲ ❝✉rs♦r ❝✶ ✐s ✲✲ ❧✐st❛ t♦❞♦s ♦s ❡♠♣r❡❣❛❞♦s ❞♦ ❞❡♣❛rt❛♠❡♥t♦ ✸✵✳ s❡❧❡❝t ❡♥❛♠❡ ✱❥♦❜ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✸✵❀ ✲✲ r✶ ❝✶✪r♦✇t②♣❡❀ ✲✲ ❜❡❣✐♥ 109 10.1. Cursores explícitos Casa do Código Neste exemplo, é declarado o cursor C1 que seleciona todos os empregados do departamento 30. Depois de definido nosso cursor, foi declarada uma variável chamada R1 que é do tipo c1%rowtype. C1 vem do nosso cursor. Já o %rowtype, indica que nossa variável será um array de linhas vindas do cursor. Com isto, nossa declaração está completa e já podemos usar nosso cursor. Quando utilizamos no select do cursor apenas uma tabela, podemos optar por usar a própria estrutura da tabela como sendo o array para nossa variável. Como a PL/SQL mantém uma conexão direta (chamamos de nativa) com o banco de dados e seus objetos, ela consegue reconhecer a compatibilidade entre as duas estruturas, a do array e a do cursor. Veja o exemplo a seguir. ❞❡❝❧❛r❡ ✲✲ ❝✉rs♦r ❝✶ ✐s ✲✲ ❧✐st❛ t♦❞♦s ♦s ❡♠♣r❡❣❛❞♦s ❞♦ ❞❡♣❛rt❛♠❡♥t♦ ✸✵✳ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✸✵❀ ✲✲ r✶ ❡♠♣✪r♦✇t②♣❡❀ ✲✲ ❜❡❣✐♥ Veja que neste exemplo, declaramos a nossa variável R1 do tipo EMP em vez do tipo C1 referente ao nosso cursor. Quando informamos que R1 é do tipo emp%rowtype, estamos dizendo que nossa variável array é do mesmo tipo, ou melhor, terá a mesma definição baseada na estrutura da tabela EMP. Logo, em nosso cursor, trazemos todas as colunas desta tabela. Assim sendo, o Oracle compara a estrutura do cursor com a estrutura da tabela EMP e valida esta definição. Note que, neste caso, não poderíamos suprimir colunas no select do cursor, pois na comparação entre as estruturas o Oracle acusaria uma diferença. Portanto, resumindo, os nomes, as quantidades e os tipos das colunas devem ser iguais entre as estruturas. 110 Casa do Código Capítulo 10. Cursores Usando o cursor explícito O uso de cursores basicamente envolve três passos. Abertura, recuperação e manipulação dos registros e fechamento do cursor. Segue o exemplo mostrando o uso do cursor que declaramos anteriormente. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✲✲ ❧✐st❛ t♦❞♦s ♦s ❡♠♣r❡❣❛❞♦s ❞♦ ❞❡♣❛rt❛♠❡♥t♦ ✸✵✳ ✹ s❡❧❡❝t ❡♥❛♠❡ ✺ ✱❥♦❜ ✻ ❢r♦♠ ❡♠♣ ✼ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✸✵❀ ✽ ✲✲ ✾ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✵ ✲✲ ✶✶ ❜❡❣✐♥ ✶✷ ✲✲ ✶✸ ♦♣❡♥ ❝✶❀ ✶✹ ❧♦♦♣ ✶✺ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✻ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✶✼ ✲✲ ✶✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✶✾ ✲✲ ✷✵ ❡♥❞ ❧♦♦♣❀ ✷✶ ✲✲ ✷✷ ❝❧♦s❡ ❝✶❀ ✷✸ ✲✲ ✷✹ ❡♥❞❀ ✷✺ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ As linhas 3 a 7 mostram a declaração do cursor visto anteriormente. Na linha 9 está declarada a variável array R1 do tipo C1, que é nosso cursor. Na 111 10.1. Cursores explícitos Casa do Código linha 13 está presente o comando open c1;. Este comando abre o cursor. Já na linha 15, temos o retorno das linhas referentes ao select através da linha de comando fetch c1 into r1;. Em linhas gerais este comando significa: retorne a primeira linha de registro do select. Na linha 18 temos o comando put_line do pacote dbms_output que imprime na tela o nome e cargo do empregado. Note que o programa recupera estas informações através do array R1. Note também que as mesmas colunas definidas no select do cursor agora podem ser usadas através de R1. Para encerrar, na linha 22 temos o fechamento do cursor. Vale lembrar que estas delimitações não servem apenas para tornar mais fácil a visualização do código, mas principalmente para demarcar o uso dos dados vindos do cursor através do array. Por exemplo, não podemos utilizar r1.ename antes da abertura e fetch do cursor, nem após o fechamento. Vamos a uma observação interessante. Você deve estar se perguntando sobre o porquê do loop presente dentro da estrutura, certo? Pois bem, anteriormente, para recuperar um registro utilizamos o comando fetch. Este comando dentro do nosso programa retornará apenas um registro, entretanto, nosso comando select pode retornar mais de um registro. Por isso, em conjunto com cursor precisamos sempre solicitar o retorno dos demais registros. O cursor por si só não retorna todos os registros resultante do comando select. Por isso utilizamos uma estrutura de repetição para nos auxiliar. Só para vocês entenderem, cada vez que abrimos um cursor o Oracle aponta-o para o primeiro registro do select. Todavia, ele só é recuperado quando chamamos o fetch. Este por sua vez traz apenas o primeiro registro. Para que os próximos registros sejam recuperados, temos que executar o fetch novamente. É aí que entra a estrutura de repetição. Repetimos o comando fetch até que não haja mais registros retornados. Para que o programa saiba quando não há mais registros para retornar, podemos utilizar a linha de comando exit when c1%notfound. Esta linha indica quando se deve sair da estrutura loop, ou seja, quando o cursor C1 não tiver mais registros para retornar. %notfound é um atributo de cursor que indica a não existência de mais registros a serem lidos dentro de um cursor. Mais adiante veremos mais sobre 112 Casa do Código Capítulo 10. Cursores este assunto. Note que a estrutura de repetição deve obedecer às delimitações de abertura e fechamento do cursor. A ausência de uma estrutura de repetição não caracteriza um erro. Contudo, apenas um registro seria retornado. No uso de cursor é mais comum vermos a estrutura do tipo loop simples, mas podemos utilizar também as estruturas while e for loop, sendo que este último torna a manipulação do cursor bem mais fácil, pois ele já faz alguns controles automaticamente. Mais à frente nós veremos um exemplo. Vamos ver outro exemplo utilizando passagem de valores por parâmetro. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷ ✹ ✱♣♠❣r ♥✉♠❜❡r✮ ✐s ✺ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✻ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✼ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✽ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✾ ❛♥❞ ❡♠♣✳♠❣r ❂ ♣♠❣r❀ ✶✵ ✲✲ ✶✶ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ✲✲ ✶✺ ♦♣❡♥ ❝✶✭✬❈❍■❈❆●❖✬✱✼✻✾✽✮❀ ✶✻ ❧♦♦♣ ✶✼ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✽ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✶✾ ✲✲ ✷✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✷✶ ✲✲ ✷✷ ❡♥❞ ❧♦♦♣❀ ✷✸ ✲✲ ✷✹ ❝❧♦s❡ ❝✶❀ ✷✺ ✲✲ ✷✻ ❡♥❞❀ ✷✼ ✴ 113 10.1. Cursores explícitos Casa do Código Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ A declaração de cursores com passagem de parâmetro, nós já havíamos visto anteriormente. O que devemos prestar atenção é como e quando devemos passar os valores para o cursor. Observando a linha 15 do programa anterior é possível verificar a abertura do cursor. É nesta abertura que devemos passar os valores para os parâmetros. Ao abrir o cursor, o Oracle já leva os valores de entrada para serem utilizados dentro do select. Os valores informados devem seguir a mesma ordem definida para os parâmetros. Uma alternativa a isso é a chamada passagem de parâmetro nomeada, onde ao informar os valores também é informado qual parâmetro deve recebê-los. Nestes casos, a ordem não precisa ser respeitada. Veja o mesmo programa, agora utilizando passagem de parâmetros nomeada. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷ ✹ ✱♣♠❣r ♥✉♠❜❡r✮ ✐s ✺ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✻ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✼ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✽ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✾ ❛♥❞ ❡♠♣✳♠❣r ❂ ♣♠❣r❀ ✶✵ ✲✲ ✶✶ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ✲✲ ✶✺ ♦♣❡♥ ❝✶✭ ♣♠❣r ❂❃ ✼✻✾✽ ✶✻ ✱♣❞♥❛♠❡ ❂❃ ✬❈❍■❈❆●❖✬✮❀ ✶✼ ❧♦♦♣ ✶✽ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✾ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✷✵ ✲✲ ✷✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ 114 Casa do Código Capítulo 10. Cursores ✷✷ ✲✲ ✷✸ ❡♥❞ ❧♦♦♣❀ ✷✹ ✲✲ ✷✺ ❝❧♦s❡ ❝✶❀ ✷✻ ✲✲ ✷✼ ❡♥❞❀ ✷✽ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Note as linhas 15 e 16. A passagem nomeada consiste em informar o nome do parâmetro e o valor que ele deve receber. Deve ser informado o nome do parâmetro seguido dos sinais =>, seguido do valor a ser passado como parâmetro. Veja também que a ordem foi invertida com relação ao que foi definido na declaração do cursor. Contudo, como estamos informando qual parâmetro recebe tal valor, não teremos problema se os parâmetros estiverem em uma ordem contrária. O uso deste artifício é bem interessante quando temos uma grande quantidade de parâmetros. Se a quantidade for grande corre-se o risco de colocar algum parâmetro fora da ordem correta, que certamente ocasionará um erro na abertura do cursor ou na lógica do programa. 10.2 Cursor FOR LOOP Anteriormente, mencionei algo sobre o cursor com uso do for loop. Pois bem. Conforme eu já havia falado, o uso de cursores com for loop torna o trabalho mais cômodo, pois não precisamos nos preocupar em abrir e fechar o cursor, nem realizar o fetch. Ele faz tudo sozinho. Para melhor entendimento vamos ver o programa a seguir. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷ ✹ ✱♣♠❣r ♥✉♠❜❡r✮ ✐s ✺ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ 115 Casa do Código ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ❛♥❞ ❡♠♣✳♠❣r ❂ ♣♠❣r❀ ✲✲ ❜❡❣✐♥ ✲✲ ❢♦r r✶ ✐♥ ❝✶✭ ♣♠❣r ❂❃ ✼✻✾✽ ✱♣❞♥❛♠❡ ❂❃ ✬❈❍■❈❆●❖✬✮ ❧♦♦♣ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✲✲ ❡♥❞ ❧♦♦♣❀ ✲✲ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ É nítida a diferença entre um método e outro. Veja que eliminamos algumas linhas de código. O próprio for se encarrega de abrir o cursor, realizar a busca dos registros, verificar quando não há mais registros e fechar o cursor. Mais um detalhe: utilizando o for loop, não é necessário declarar a variável do tipo rowtype com base no cursor, o próprio for loop faz isto mediante um nome informado. Veja que no exemplo, só foi preciso informar um nome, no caso R1, após o comando for, que o resto ele se encarregou de fazer. Assim como no uso do loop, o for também delimita uma área que deve respeitada. Agora você deve estar se questionando: por que usar loop se for loop traz mais facilidade sem falar que não é necessário que se controle uma série de coisas? Na verdade você tem razão, nada impede de você utilizar sempre o cursor com for loop. Contudo, à medida que você for trabalhando com cursores, vai sentir a necessidade de usar um ou outro. Por exemplo, quando temos um cursor onde não necessariamente temos que ler todas as linhas 116 Casa do Código Capítulo 10. Cursores vindas do select, podemos utilizar o loop, pois neste método somos nós que controlamos a busca das linhas. Neste caso, é bem mais prático utilizar um loop. Vale ressaltar que com o uso de for loop, devemos informar quando ele deve parar sua execução, caso não for de nossa vontade que ele leia todos os registros resultantes do select. Já com o uso do loop é o contrário, se quisermos que ele leia os registros, devemos comandá-lo através do fetch. Quando quiser parar uma execução for loop, utilizamos o comando exit ou exit when. Veja um exemplo. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷ ✹ ✱♣♠❣r ♥✉♠❜❡r✮ ✐s ✺ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✻ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✼ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✽ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✾ ❛♥❞ ❡♠♣✳♠❣r ❂ ♣♠❣r❀ ✶✵ ✲✲ ✶✶ ✲✲ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ✲✲ ✶✺ ❢♦r r✶ ✐♥ ❝✶✭ ♣♠❣r ❂❃ ✼✻✾✽ ✶✻ ✱♣❞♥❛♠❡ ❂❃ ✬❈❍■❈❆●❖✬✮ ❧♦♦♣ ✶✼ ✲✲ ✶✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✶✾ ✲✲ ✷✵ ✴✯ ✷✶ ✐❢ r✶✳❡♥❛♠❡ ❂ ✬▼❆❘❚■◆✬ t❤❡♥ ✷✷ ❡①✐t❀ ✷✸ ❡♥❞ ✐❢❀ ✷✹ ✯✴ ✷✺ ✲✲ ✷✻ ❡①✐t ✇❤❡♥ r✶✳❡♥❛♠❡ ❂ ✬▼❆❘❚■◆✬❀ ✷✼ ✲✲ 117 Casa do Código ✷✽ ❡♥❞ ❧♦♦♣❀ ✷✾ ✲✲ ✸✵ ❡♥❞❀ ✸✶ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Mais à frente nós também veremos que às vezes pode ser mais performático utilizar um cursor para retornar um único registro em vez de utilizar into. Neste caso não utilizamos estruturas de repetição. 10.3 Cursor for loop com definição interna 10.3. CURSOR FOR LOOP COM DEFINIÇÃO INTERNA Com o uso de cursores com for loop temos disponível mais um recurso que é a possibilidade de declararmos o comando select do cursor dentro do próprio comando for loop. Desta forma, não precisamos declarar o cursor no escopo de declarações, conforme visto nos exemplos anteriores, e sim, na própria definição do for loop. O único inconveniente é que se nós tivermos que chamar este cursor for loop várias vezes dentro do programa, teremos o comando select escrito repetidamente em todas as aberturas. No caso de uma alteração nele, teremos que modificar em todas as chamadas, enquanto na declaração fora do for loop (no bloco declare) a alteração será em um único lugar. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡ ✻ ❢r♦♠ ❡♠♣ ✼ ✇❤❡r❡ ❥♦❜ ❂ ✬▼❆◆❆●❊❘✬✮ ❧♦♦♣ ✽ ✲✲ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬●❡r❡♥t❡✿ ✬⑤⑤r✶✳❡♠♣♥♦⑤⑤✬ ✲ ✬⑤⑤r✶✳❡♥❛♠❡✮❀ 118 Casa do Código ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ Capítulo 10. Cursores ✲✲ ❢♦r r✷ ✐♥ ✭s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡✱ ❞♥❛♠❡ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ❛♥❞ ♠❣r ❂ r✶✳❡♠♣♥♦✮ ❧♦♦♣ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬ ❙✉❜♦r❞✐♥❛❞♦✿ ✬⑤⑤r✷✳❡♠♣♥♦⑤⑤✬ ✲ ✬⑤⑤r✷✳❡♥❛♠❡✮❀ ✲✲ ❡♥❞ ❧♦♦♣❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✬✮❀ ✲✲ ❡♥❞ ❧♦♦♣❀ ✲✲ ❡♥❞❀ ✴ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ❙◗▲❃ 10.4 Cursores implícitos 10.4. CURSORES IMPLÍCITOS Em vias gerais quando não criamos um cursor explicito o Oracle cria um cursor automaticamente. A este cursor se dá o nome de cursor implícito. Implícito porque é criado, aberto, manipulado e fechado pelo próprio Oracle. Mas como sabemos, ou melhor, como vemos o uso de tal cursor? Na verdade não vemos, pelo menos não na sua totalidade. O cursor implícito é criado quando dentro do nosso programa PL/SQL utilizamos algum dos comandos: delete, update, insert ou select into. Quando executamos os comandos delete, insert ou update, o Oracle cria um cursor implícito, abre este cursor, executa o comando e depois o fecha. Quando executamos um select into dentro do nosso programa, por exemplo, o Oracle vai além e abre um cursor implicitamente e executa vários passos e verificações adicionais. Veja os passos a seguir. 119 Casa do Código Cursor implícito: passos realizados pelo Oracle 1) Cria um cursor implícito. 2) Realiza um primeiro fetch para retornar uma linha. 3) Realiza um segundo fetch para verificar se o comando não retorna mais de uma linha. 4) Fecha o cursor. Note que no caso do select into o Oracle precisa tratar determinadas situações, pois o uso do comando select dentro dos programas PL/SQL podem gerar exceptions. Quando não é retornada nenhuma linha uma exception de no_data_found é disparada. Já quando várias linhas são retornadas outra exception chamada too_many_rows precisa ser acionada também. Desta forma, quando se há certeza de que o select em questão vai retornar apenas uma linha, pode ser usado um cursor explícito. Neste caso, menos passos serão utilizados, pois quem tratará estas situações somos nós dentro do programa. Entretanto, esta forma parece ser mais trabalhosa, e com certeza é! Contudo, quando estamos falando de performance, os ganhos podem ser bem consideráveis. É óbvio que estamos falando aqui para os casos onde os comandos selects são complexos com muitas tabelas e grandes quantidades de dados. Para um cursor explícito os passos ficariam assim: Cursor explícito: passos realizados pelo programa 1) Cria um cursor implícito. 2) Realiza um primeiro fetch para retornar a linha. 3) Fecha o cursor. Com isto, fazemos com que pelo menos um passo não seja executado. Para um select que trabalhe com milhões de registros isso pode nos dar um ótimo ganho de tempo de execução. 120 Casa do Código 10.5 Capítulo 10. Cursores Atributos de cursor explícito e implícito 10.5. ATRIBUTOS DE CURSOR EXPLÍCITO E IMPLÍCITO Nos exemplos anteriores vimos alguns atributos que auxiliam na hora de se utilizar cursores. Estes atributos trazem informações que podem ajudar o desenvolvedor a tomar decisões e a fazer com que o programa tome certos caminhos. Estes atributos estão disponíveis tanto para cursores explícitos como para os implícitos, com exceção do atributo %isopen que só pode ser utilizado em cursores explícitos. Estes atributos são utilizados da seguinte forma: Quando estamos trabalhando com os cursores explícitos usamos o nome do cursor seguido do atributo, por exemplo, c1%found. Para os cursores implícitos, o Oracle disponibiliza o cursor “SQL” que aponta sempre para o comando que está sendo executado no momento. Desta forma, usa-se o nome deste cursor seguido do atributo, exemplo, sql%found. Observe que o Oracle utiliza sempre o mesmo cursor para uma ou mais execuções. Portanto, ele deve ser utilizado sempre após a execução do comando, pois as informações de um cursor recém-executado sobrescreverão as informações da execução anterior. A seguir os atributos que podemos utilizar. %found Este atributo é utilizado para indicar se a última operação realizada pelo fetch foi concluída com êxito ou se uma determinada linha foi alterada através de algum comando insert, update ou delete, ou se, no caso de um select into ouve algum retorno de uma ou mais linhas. Para cursores explícitos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷ ✹ ✱♣♠❣r ♥✉♠❜❡r✮ ✐s ✺ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✻ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✼ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✽ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✾ ❛♥❞ ❡♠♣✳♠❣r ❂ ♣♠❣r❀ ✶✵ ✲✲ 121 Casa do Código ✶✶ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ✲✲ ✶✺ ♦♣❡♥ ❝✶✭ ♣♠❣r ❂❃ ✼✻✾✽✱ ♣❞♥❛♠❡ ❂❃ ✬❈❍■❈❆●❖✬✮❀ ✶✻ ❧♦♦♣ ✶✼ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✽ ✲✲ ✶✾ ✐❢ ❝✶✪❢♦✉♥❞ t❤❡♥ ✷✵ ✲✲ ✷✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✷✷ ✲✲ ✷✸ ❡❧s❡ ✷✹ ✲✲ ✷✺ ❡①✐t❀ ✷✻ ✲✲ ✷✼ ❡♥❞ ✐❢❀ ✷✽ ❡♥❞ ❧♦♦♣❀ ✷✾ ✲✲ ✸✵ ❝❧♦s❡ ❝✶❀ ✸✶ ✲✲ ✸✷ ❡♥❞❀ ✸✸ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Para cursores implícitos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇❡♥❛♠❡ ❡♠♣✳❡♥❛♠❡✪t②♣❡❀ ✹ ✇❥♦❜ ❡♠♣✳❥♦❜✪t②♣❡❀ ✺ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✻ ✲✲ ✼ ❜❡❣✐♥ ✽ ✲✲ ✾ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ 122 Casa do Código ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ Capítulo 10. Cursores ✐♥t♦ ✇❡♥❛♠❡✱ ✇❥♦❜✱ ✇❞♥❛♠❡ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ✬❈❍■❈❆●❖✬ ❛♥❞ ❡♠♣✳♠❣r ❂ ✼✻✾✽ ❛♥❞ ❥♦❜ ❂ ✬❈▲❊❘❑✬❀ ✲✲ ✐❢ ❙◗▲✪❢♦✉♥❞ t❤❡♥ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❖ s❡❧❡❝t r❡t♦r♥♦✉ ♦ s❡❣✉✐♥t❡ r❡❣✐str♦✿ ◆♦♠❡✿ ✬⑤⑤ ✇❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤✇❥♦❜✮❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ %notfound Este outro atributo mostra exatamente o contrário ao atributo %found, pois o comando %notfound retorna sempre false se o último comando fetch não retornar uma linha no caso de um cursor explícito, ou se o último comando de update, insert, delete não alterar nenhuma linha. O mesmo não serve para o não retorno de uma linha em um comando select into, pois neste caso a exception no_data_found é disparada. Para cursores explícitos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷ ✹ ✱♣♠❣r ♥✉♠❜❡r✮ ✐s ✺ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✻ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✼ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ 123 Casa do Código ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ❛♥❞ ❡♠♣✳♠❣r ❂ ♣♠❣r❀ ✲✲ r✶ ❝✶✪r♦✇t②♣❡❀ ✲✲ ❜❡❣✐♥ ✲✲ ♦♣❡♥ ❝✶✭ ♣♠❣r ❂❃ ✼✻✾✽✱ ♣❞♥❛♠❡ ❂❃ ✬❈❍■❈❆●❖✬✮❀ ❧♦♦♣ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✲✲ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✷✷ ✲✲ ✷✸ ❡♥❞ ❧♦♦♣❀ ✷✹ ✲✲ ✷✺ ❝❧♦s❡ ❝✶❀ ✷✻ ✲✲ ✷✼ ❡♥❞❀ ✷✽ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Para cursores implícitos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇❡♥❛♠❡ ❡♠♣✳❡♥❛♠❡✪t②♣❡❀ ✹ ✇❥♦❜ ❡♠♣✳❥♦❜✪t②♣❡❀ ✺ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✻ ✲✲ ✼ ❜❡❣✐♥ ✽ ✲✲ ✾ ✉♣❞❛t❡ ❡♠♣ ✶✵ s❡t ❞❡♣t♥♦ ❂ ✶✵✵ ✶✶ ✇❤❡r❡ ❥♦❜ ❂ ✬❆◆❆▲■❙❚❆❴✶✬❀ 124 Casa do Código ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ Capítulo 10. Cursores ✲✲ ✐❢ ❙◗▲✪♥♦t❢♦✉♥❞ t❤❡♥ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆❡♥❤✉♠ r❡❣✐str♦ ❢♦✐ ❛t✉❛❧✐③❛❞♦✳✬✮❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ %rowcount Este atributo é utilizado para fazer a contagem do número de linhas lidas, ou para linhas que foram afetadas por algum comando insert, update ou delete, ou, por algum retorno ocasionado por um comando select into. Vale salientar que a utilização deles segue as mesmas regras para os tipos de cursores mencionados nos outros atributos anteriores. Para cursores explícitos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷ ✹ ✱♣♠❣r ♥✉♠❜❡r✮ ✐s ✺ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✻ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✼ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✽ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✾ ❛♥❞ ❡♠♣✳♠❣r ❂ ♣♠❣r❀ ✶✵ ✲✲ ✶✶ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ✲✲ ✶✺ ♦♣❡♥ ❝✶✭ ♣♠❣r ❂❃ ✼✻✾✽✱ ♣❞♥❛♠❡ ❂❃ ✬❈❍■❈❆●❖✬✮❀ ✶✻ ✲✲ 125 Casa do Código ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ❧♦♦♣ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✲✲ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✷✸ ✲✲ ✷✹ ❡♥❞ ❧♦♦♣❀ ✷✺ ✲✲ ✷✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✬✮❀ ✷✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❘❡❣✐str♦s r❡❝✉♣❡r❛❞♦s✿ ✬⑤⑤❝✶✪r♦✇❝♦✉♥t⑤⑤✬✳✬✮❀ ✷✽ ✲✲ ✷✾ ❝❧♦s❡ ❝✶❀ ✸✵ ✲✲ ✸✶ ❡♥❞❀ ✸✷ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Para cursores implícitos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇❡♥❛♠❡ ❡♠♣✳❡♥❛♠❡✪t②♣❡❀ ✹ ✇❥♦❜ ❡♠♣✳❥♦❜✪t②♣❡❀ ✺ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✻ ✲✲ ✼ ❜❡❣✐♥ ✽ ✲✲ ✾ ❞❡❧❡t❡ ❡♠♣ ✶✵ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✭s❡❧❡❝t ❞❡♣t♥♦ ✶✶ ❢r♦♠ ❞❡♣t ✶✷ ✇❤❡r❡ ❞♥❛♠❡ ❂ ✬❙❆▲❊❙✬✮❀ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ❙◗▲✪r♦✇❝♦✉♥t⑤⑤✬ r❡❣✐str♦✭s✮ ❢♦r❛♠ ❡①❝❧✉í❞♦s✳✬✮❀ 126 Casa do Código Capítulo 10. Cursores ✶✺ ✲✲ ✶✻ ❝♦♠♠✐t❀ ✶✼ ✲✲ ✶✽ ❡♥❞❀ ✶✾ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ %isopen Este atributo é utilizado para verificar se um cursor está ou não aberto. Ele estará como verdadeiro se o cursor estiver aberto, e falso se estiver fechado. Este atributo só pode ser usado em cursores explícitos. Para cursores explícitos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷ ✹ ✱♣♠❣r ♥✉♠❜❡r✮ ✐s ✺ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✻ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✼ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✽ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✾ ❛♥❞ ❡♠♣✳♠❣r ❂ ♣♠❣r❀ ✶✵ ✲✲ ✶✶ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ✲✲ ✶✺ ❧♦♦♣ ✶✻ ✐❢ ❝✶✪✐s♦♣❡♥ t❤❡♥ ✶✼ ✲✲ ✶✽ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✾ ✲✲ ✷✵ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ✷✶ ✲✲ ✷✷ ❝❧♦s❡ ❝✶❀ 127 Casa do Código ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ❡①✐t❀ ✲✲ ❡❧s❡ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ❡❧s❡ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ ❈✉rs♦r ♥ã♦ ❢♦✐ ❛❜❡rt♦✦✬✮❀ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❆❜r✐♥❞♦ ❝✉rs♦r✳✳✳✬✮❀ ♦♣❡♥ ❝✶✭ ♣♠❣r ❂❃ ✼✻✾✽✱ ♣❞♥❛♠❡ ❂❃ ✬❈❍■❈❆●❖✬✮❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞ ❧♦♦♣❀ ✲✲ ❡♥❞❀ ✴ ✷✽ ✷✾ ✸✵ ✸✶ ✸✷ ✸✸ ✸✹ ✸✺ ✸✻ ✸✼ ✸✽ ✸✾ ✹✵ ✹✶ ✹✷ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ 10.6 Cursores encadeados 10.6. CURSORES ENCADEADOS Outro recurso dos cursores é a possibilidade de serem usados de forma encadeada, ou seja, podemos ter cursores sendo manipulados dentro de outros cursores. Veja um exemplo. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡ ✺ ❢r♦♠ ❡♠♣ 128 Casa do Código Capítulo 10. Cursores ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✇❤❡r❡ ❥♦❜ ❂ ✬▼❆◆❆●❊❘✬❀ ✲✲ ❝✉rs♦r ❝✷✭♣♠❣r ♥✉♠❜❡r✮ ✐s s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡✱ ❞♥❛♠❡ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ❛♥❞ ♠❣r ❂ ♣♠❣r❀ ✲✲ ❜❡❣✐♥ ✲✲ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬●❡r❡♥t❡✿ ✬⑤⑤r✶✳❡♠♣♥♦⑤⑤✬ ✲ ✬⑤⑤r✶✳❡♥❛♠❡✮❀ ✶✾ ✲✲ ✷✵ ❢♦r r✷ ✐♥ ❝✷✭r✶✳❡♠♣♥♦✮ ❧♦♦♣ ✷✶ ✲✲ ✷✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬ ❙✉❜♦r❞✐♥❛❞♦✿ ✬⑤⑤r✷✳❡♠♣♥♦⑤⑤✬ ✲ ✬⑤⑤r✷✳❡♥❛♠❡✮❀ ✷✸ ✲✲ ✷✹ ❡♥❞ ❧♦♦♣❀ ✷✺ ✲✲ ✷✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✬✮❀ ✷✼ ✲✲ ✷✽ ❡♥❞ ❧♦♦♣❀ ✷✾ ✲✲ ✸✵ ❡♥❞❀ ✸✶ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Neste exemplo estamos selecionando todos os empregados gerentes com seus respectivos subordinados. O primeiro cursor C1 localiza os gerentes. Para cada gerente encontrado é listado todos os seus subordinados pelo cursor C2. Note que o cursor C2 recebe como parâmetro o código do gerente vindo de C1. Para cada linha retornada de C1 são recuperadas todas as linhas de C2. O for loop se encarrega de abrir e fechar os cursores quantas vezes for 129 Casa do Código necessário até que a leitura de todos os registros em ambos os cursores chegue ao fim. 10.7 Cursor com for update 10.7. CURSOR COM FOR UPDATE Quando queremos atualizar ou excluir linhas de uma tabela, podemos fazer isto com o auxílio de um cursor for update. Podemos criar um cursor baseado na tabela em questão e utilizar a instrução for update para garantir que enquanto ele estiver varrendo as linhas da tabela, nenhuma outra sessão possa estar manipulando os mesmos dados. Isso também acontece mesmo que você não venha a atualizá-los. O simples fato de estar abrindo um cursor for update já faz com que o acesso seja exclusivo. Veja a seguir um exemplo de cursor for update. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷✮ ✐s ✹ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✺ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✻ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✼ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✽ ❢♦r ✉♣❞❛t❡❀ ✾ ✲✲ ✶✵ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✶ ✲✲ ✶✷ ❜❡❣✐♥ ✶✸ ♦♣❡♥ ❝✶✭ ♣❞♥❛♠❡ ❂❃ ✬❉❆▲▲❆❙✬✮❀ ✶✹ ❧♦♦♣ ✶✺ ✐❢ ❝✶✪✐s♦♣❡♥ t❤❡♥ ✶✻ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✼ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ✶✽ ❝❧♦s❡ ❝✶❀ ✶✾ ❡①✐t❀ ✷✵ ❡❧s❡ ✷✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✷✷ ❡♥❞ ✐❢❀ 130 Casa do Código Capítulo 10. Cursores ✷✸ ❡❧s❡ ✷✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ ❈✉rs♦r ♥ã♦ ❢♦✐ ❛❜❡rt♦✦✬✮❀ ✷✺ ❡①✐t❀ ✷✻ ❡♥❞ ✐❢❀ ✷✼ ❡♥❞ ❧♦♦♣❀ ✷✽ ❡♥❞❀ ✷✾ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Utilizando for update, o Oracle realiza um lock nas linhas da tabela garantindo exclusividade para manipulá-las. Após um rollback ou commit, as linhas voltam a ser liberadas. Este comando pode ser utilizado de duas formas, sendo acompanhado ou não por nomes de colunas específicas. Quando temos um select com várias tabelas na cláusula from nós podemos determinar quais, ou qual, tabelas devem ser locadas informando suas colunas. Caso queira que todas as tabelas sejam locadas use somente for update. Agora veja o mesmo exemplo, informando as colunas para a locação da tabela. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷✮ ✐s ✹ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✺ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✻ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✼ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✽ ❢♦r ✉♣❞❛t❡ ♦❢ ❡♥❛♠❡✱ ❞♥❛♠❡❀ ✾ ✲✲ ✶✵ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✶ ✲✲ ✶✷ ❜❡❣✐♥ ✶✸ ♦♣❡♥ ❝✶✭ ♣❞♥❛♠❡ ❂❃ ✬❉❆▲▲❆❙✬✮❀ ✶✹ ❧♦♦♣ ✶✺ ✐❢ ❝✶✪✐s♦♣❡♥ t❤❡♥ ✶✻ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ 131 Casa do Código ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ❝❧♦s❡ ❝✶❀ ❡①✐t❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ❡♥❞ ✐❢❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ ❈✉rs♦r ♥ã♦ ❢♦✐ ❛❜❡rt♦✦✬✮❀ ❡①✐t❀ ❡♥❞ ✐❢❀ ❡♥❞ ❧♦♦♣❀ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Neste exemplo estamos locando as tabelas EMP e DEPT, pois estamos informando colunas de ambas às tabelas. Contudo, podemos locar uma única tabela informando uma ou mais colunas que fazem parte dela. Segue um exemplo. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷✮ ✐s ✹ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✺ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✻ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✼ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✽ ❢♦r ✉♣❞❛t❡ ♦❢ ❡♥❛♠❡❀ ✾ ✲✲ ✶✵ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✶ ✲✲ ✶✷ ❜❡❣✐♥ ✶✸ ♦♣❡♥ ❝✶✭ ♣❞♥❛♠❡ ❂❃ ✬❉❆▲▲❆❙✬✮❀ ✶✹ ❧♦♦♣ ✶✺ ✐❢ ❝✶✪✐s♦♣❡♥ t❤❡♥ 132 Casa do Código ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ Capítulo 10. Cursores ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ❝❧♦s❡ ❝✶❀ ❡①✐t❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ❡♥❞ ✐❢❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ ❈✉rs♦r ♥ã♦ ❢♦✐ ❛❜❡rt♦✦✬✮❀ ❡①✐t❀ ❡♥❞ ✐❢❀ ❡♥❞ ❧♦♦♣❀ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Enquanto a tabela estiver em lock qualquer sessão que tentar manipular seus dados, exceto select, não terá êxito. A sessão ficará esperando a liberação até que o programa que lockou as linhas as libere. Feito isso, qualquer outra sessão poderá efetuar alterações. Embora o programa que contém um cursor for update tenha exclusividade de acesso, ele só conseguirá realizar um lock caso as tabelas que fazem parte deste lock não estejam lockadas por outras sessões. Se isso estiver ocorrendo, o programa também sofrerá uma espera até que outra sessão libere tais tabelas. Quando executamos alguma operação em uma determinada tabela, e a mesma está lockada, acontece uma “espera” pelo recurso. Isso quer dizer que sua sessão ficará tentando executar os comandos até que o recurso esteja disponível ou caso você cancele a operação. Quando você estiver utilizando um cursor com for update e não quiser que, ao executá-lo, ele fique esperando por um recurso, por exemplo, uma tabela que esteja sendo locada por outra sessão, use a diretriz nowait. Feito isto, o programa não ficará em espera e será disparado uma exception in133 Casa do Código formando que o recurso em questão está ocupado. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞♥❛♠❡ ✈❛r❝❤❛r✷✮ ✐s ✹ s❡❧❡❝t ❡♥❛♠❡✱ ❥♦❜✱ ❞♥❛♠❡ ✺ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✻ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✼ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞♥❛♠❡ ✽ ❢♦r ✉♣❞❛t❡ ♦❢ ❡♥❛♠❡ ♥♦✇❛✐t❀ ✾ ✲✲ ✶✵ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✶ ✲✲ ✶✷ ❜❡❣✐♥ ✶✸ ♦♣❡♥ ❝✶✭ ♣❞♥❛♠❡ ❂❃ ✬❉❆▲▲❆❙✬✮❀ ✶✹ ❧♦♦♣ ✶✺ ✐❢ ❝✶✪✐s♦♣❡♥ t❤❡♥ ✶✻ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✼ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ✶✽ ❝❧♦s❡ ❝✶❀ ✶✾ ❡①✐t❀ ✷✵ ❡❧s❡ ✷✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜✮❀ ✷✷ ❡♥❞ ✐❢❀ ✷✸ ❡❧s❡ ✷✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ ❈✉rs♦r ♥ã♦ ❢♦✐ ❛❜❡rt♦✦✬✮❀ ✷✺ ❡①✐t❀ ✷✻ ❡♥❞ ✐❢❀ ✷✼ ❡♥❞ ❧♦♦♣❀ ✷✽ ❡♥❞❀ ✷✾ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖ ♥❛ ❧✐♥❤❛ ✶✿ ❖❘❆✲✵✵✵✺✹✿ ♦ r❡❝✉rs♦ ❡stá ♦❝✉♣❛❞♦ ❡ é ♦❜t✐❞♦ ❝♦♠ ♦ ◆❖❲❆■❚ ❡s♣❡❝✐❢✐❝❛❞♦ ❖❘❆✲✵✻✺✶✷✿ ❡♠ ❧✐♥❡ ✹ ❖❘❆✲✵✻✺✶✷✿ ❡♠ ❧✐♥❡ ✶✸ 134 Casa do Código Capítulo 10. Cursores ❙◗▲❃ Com o for update para auxiliar na exclusão e atualização das linhas de uma tabela, é possível utilizar um recurso muito poderoso que traz simplicidade e ótimos ganhos de performance. Quando você estiver executando um comando update ou delete para atualizar linhas de uma tabela existente no próprio cursor, use current of. Esta cláusula faz com que o Oracle utilize o rowid da linha, que é o acesso mais direto e rápido ao registro. Observe o exemplo. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞❡♣t♥♦ ♥✉♠❜❡r✮ ✐s ✹ s❡❧❡❝t ✯ ✺ ❢r♦♠ ❡♠♣ ✻ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ♣❞❡♣t♥♦ ✼ ❢♦r ✉♣❞❛t❡ ♦❢ s❛❧ ♥♦✇❛✐t❀ ✽ ✲✲ ✾ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✵ ✲✲ ✶✶ ✇r❡❣❴❡①❝❧✉✐❞♦s ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ♦♣❡♥ ❝✶✭ ♣❞❡♣t♥♦ ❂❃ ✶✵✮❀ ✶✺ ❧♦♦♣ ✶✻ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✼ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✶✽ ✲✲ ✶✾ ✉♣❞❛t❡ ❡♠♣ s❡t s❛❧ ❂ s❛❧ ✰ ✶✵✵✳✵✵ ✷✵ ✇❤❡r❡ ❝✉rr❡♥t ♦❢ ❝✶❀ ✷✶ ✲✲ ✷✷ ✇r❡❣❴❡①❝❧✉✐❞♦s ✿❂ ✇r❡❣❴❡①❝❧✉✐❞♦s ✰ sq❧✪r♦✇❝♦✉♥t❀ ✷✸ ✲✲ ✷✹ ❡♥❞ ❧♦♦♣❀ ✷✺ ✲✲ ✷✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇r❡❣❴❡①❝❧✉✐❞♦s⑤⑤✬ r❡❣✐str♦s ❡①❝❧✉í❞♦s✦✬✮❀ 135 Casa do Código ✷✼ ✲✲ ✷✽ ❡♥❞❀ ✷✾ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Note no código que, ao utilizar o comando update, não foi preciso informar uma cláusula where baseada em alguma chave da tabela, como por exemplo, empno. Como os registros estão reservados para o programa, através do for update, podemos atualizar as linhas usando como critério a referencia da linha do cursor. Dessa forma, o Oracle garante a integridade dos dados. O mesmo pode ser usado para o comando delete. Este recurso também funciona para quando estivermos usando mais de uma tabela na cláusula from. O único ponto de observação é que não podemos deixar de definir as colunas para o for update, tão pouco definir colunas de diferentes tabelas se quisermos utilizar o current of. Isso porque, nestes casos, o Oracle só pode trabalhar com rowids de uma única tabela. Veja alguns exemplos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞❧♦❝ ✈❛r❝❤❛r✷✮ ✐s ✹ s❡❧❡❝t ❡♥❛♠❡✱ ❞♥❛♠❡ ✺ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✻ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✼ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞❧♦❝ ✽ ❢♦r ✉♣❞❛t❡ ♦❢ ❡♠♣✳❡♥❛♠❡✱ ❞❡♣t✳❧♦❝❀ ✾ ✲✲ ✶✵ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✶ ✲✲ ✶✷ ✇r❡❣❴❛t✉❛❴❞❡♣ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✶✸ ✇r❡❣❴❡①❝❧❴❡♠♣ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✶✹ ✲✲ ✶✺ ❜❡❣✐♥ ✶✻ ♦♣❡♥ ❝✶✭ ♣❞❧♦❝ ❂❃ ✬◆❊❲ ❨❖❘❑✬ ✮❀ ✶✼ ❧♦♦♣ 136 Casa do Código Capítulo 10. Cursores ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ ✸✵ ✸✶ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✲✲ ✉♣❞❛t❡ ❞❡♣t s❡t ❧♦❝ ❂ ✬❋▲❖❘■❉❆✬ ✇❤❡r❡ ❝✉rr❡♥t ♦❢ ❝✶❀ ✲✲ ✇r❡❣❴❛t✉❛❴❞❡♣ ✿❂ ✇r❡❣❴❛t✉❛❴❞❡♣ ✰ sq❧✪r♦✇❝♦✉♥t❀ ✲✲ ❞❡❧❡t❡ ❡♠♣ ✇❤❡r❡ ❝✉rr❡♥t ♦❢ ❝✶❀ ✲✲ ✇r❡❣❴❡①❝❧❴❡♠♣ ✿❂ ✇r❡❣❴❡①❝❧❴❡♠♣ ✰ sq❧✪r♦✇❝♦✉♥t❀ ✲✲ ❡♥❞ ❧♦♦♣❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇r❡❣❴❛t✉❛❴❞❡♣⑤⑤✬ r❡❣✐str♦s ❞❡ ❞❡♣❛rt❛♠❡♥t♦s ❛t✉❛❧✐③❛❞♦s✦✬✮❀ ✸✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇r❡❣❴❡①❝❧❴❡♠♣⑤⑤✬ r❡❣✐str♦s ❞❡ ❡♠♣r❡❣❛❞♦s ❡①❝❧✉í❞♦s✦✬✮❀ ✸✸ ✲✲ ✸✹ ❡♥❞❀ ✸✺ ✴ ✵ r❡❣✐str♦s ❞❡ ❞❡♣❛rt❛♠❡♥t♦s ❛t✉❛❧✐③❛❞♦s✦ ✵ r❡❣✐str♦s ❞❡ ❡♠♣r❡❣❛❞♦s ❡①❝❧✉í❞♦s✦ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Neste exemplo estamos tentando atualizar a tabela DEPT e também excluir registros da tabela EMP. Entretanto, mesmo informando uma coluna de cada tabela no for update, e o Oracle não apresentando qualquer problema na execução, os registros não sofreram qualquer modificação. Vamos tentar algo diferente no exemplo a seguir. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞❧♦❝ ✈❛r❝❤❛r✷✮ ✐s ✹ s❡❧❡❝t ❡♥❛♠❡✱ ❞♥❛♠❡ ✺ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✻ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ 137 Casa do Código ✼ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞❧♦❝ ✽ ❢♦r ✉♣❞❛t❡ ♦❢ ❡♠♣✳❡♥❛♠❡✱ ❞❡♣t✳❧♦❝❀ ✾ ✲✲ ✶✵ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✶ ✲✲ ✶✷ ✇r❡❣❴❛t✉❛❴❞❡♣ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✶✸ ✇r❡❣❴❡①❝❧❴❡♠♣ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✶✹ ✲✲ ✶✺ ❜❡❣✐♥ ✶✻ ♦♣❡♥ ❝✶✭ ♣❞❧♦❝ ❂❃ ✬◆❊❲ ❨❖❘❑✬ ✮❀ ✶✼ ❧♦♦♣ ✶✽ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✾ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✷✵ ✲✲ ✷✶ ❞❡❧❡t❡ ❡♠♣ ✇❤❡r❡ ❝✉rr❡♥t ♦❢ ❝✶❀ ✷✷ ✲✲ ✷✸ ✇r❡❣❴❡①❝❧❴❡♠♣ ✿❂ ✇r❡❣❴❡①❝❧❴❡♠♣ ✰ sq❧✪r♦✇❝♦✉♥t❀ ✷✹ ✲✲ ✷✺ ❡♥❞ ❧♦♦♣❀ ✷✻ ✲✲ ✷✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇r❡❣❴❡①❝❧❴❡♠♣⑤⑤✬ r❡❣✐str♦s ❞❡ ❡♠♣r❡❣❛❞♦s ❡①❝❧✉í❞♦s✦✬✮❀ ✷✽ ✲✲ ✷✾ ❡♥❞❀ ✸✵ ✴ ✵ r❡❣✐str♦s ❞❡ ❡♠♣r❡❣❛❞♦s ❡①❝❧✉í❞♦s✦ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Mesmo retirando um dos comandos, o Oracle não consegue concretizar as alterações. Portanto, o problema não está na quantidade ou distinção de comandos dentro do bloco do cursor e, sim, na sua definição. Vamos deixar na cláusula for update somente a coluna referente à tabela EMP. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞❧♦❝ ✈❛r❝❤❛r✷✮ ✐s 138 Casa do Código Capítulo 10. Cursores ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ s❡❧❡❝t ❡♥❛♠❡✱ ❞♥❛♠❡ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞❧♦❝ ❢♦r ✉♣❞❛t❡ ♦❢ ❡♠♣✳❡♥❛♠❡❀ ✲✲ r✶ ❝✶✪r♦✇t②♣❡❀ ✲✲ ✇r❡❣❴❛t✉❛❴❞❡♣ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✇r❡❣❴❡①❝❧❴❡♠♣ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✲✲ ❜❡❣✐♥ ♦♣❡♥ ❝✶✭ ♣❞❧♦❝ ❂❃ ✬◆❊❲ ❨❖❘❑✬ ✮❀ ❧♦♦♣ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✲✲ ❞❡❧❡t❡ ❡♠♣ ✇❤❡r❡ ❝✉rr❡♥t ♦❢ ❝✶❀ ✲✲ ✇r❡❣❴❡①❝❧❴❡♠♣ ✿❂ ✇r❡❣❴❡①❝❧❴❡♠♣ ✰ sq❧✪r♦✇❝♦✉♥t❀ ✲✲ ❡♥❞ ❧♦♦♣❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇r❡❣❴❡①❝❧❴❡♠♣⑤⑤✬ r❡❣✐str♦s ❞❡ ❡♠♣r❡❣❛❞♦s ❡①❝❧✉í❞♦s✦✬✮❀ ✷✽ ✲✲ ✷✾ ❡♥❞❀ ✸✵ ✴ ✸ r❡❣✐str♦s ❞❡ ❡♠♣r❡❣❛❞♦s ❡①❝❧✉í❞♦s✦ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Agora nosso comando funcionou com êxito. Foi utilizada mais de uma tabela na cláusula from, todavia, na cláusula for update definimos apenas a coluna relacionada à tabela EMP. Lembre-se que nos casos onde o select possua mais de uma tabela na cláusula from, se não relacionarmos a coluna na cláusula for update, lockando a tabela, não poderemos utilizar a cláu139 Casa do Código sula current of. Se isso acontecer, o Oracle dispara uma exception gerando um erro. Nos casos onde temos apenas uma tabela na cláusula from podemos utilizar somente for update. Veja os exemplos. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞❧♦❝ ✈❛r❝❤❛r✷✮ ✐s ✹ s❡❧❡❝t ❡♥❛♠❡✱ ❞♥❛♠❡ ✺ ❢r♦♠ ❡♠♣✱ ❞❡♣t ✻ ✇❤❡r❡ ❡♠♣✳❞❡♣t♥♦ ❂ ❞❡♣t✳❞❡♣t♥♦ ✼ ❛♥❞ ❞❡♣t✳❧♦❝ ❂ ♣❞❧♦❝ ✽ ❢♦r ✉♣❞❛t❡ ♦❢ ❞❡♣t✳❧♦❝❀ ✾ ✲✲ ✶✵ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✶ ✲✲ ✶✷ ✇r❡❣❴❛t✉❛❴❞❡♣ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✶✸ ✇r❡❣❴❡①❝❧❴❡♠♣ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✶✹ ✲✲ ✶✺ ❜❡❣✐♥ ✶✻ ♦♣❡♥ ❝✶✭ ♣❞❧♦❝ ❂❃ ✬◆❊❲ ❨❖❘❑✬ ✮❀ ✶✼ ❧♦♦♣ ✶✽ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✾ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✷✵ ✲✲ ✷✶ ❞❡❧❡t❡ ❡♠♣ ✇❤❡r❡ ❝✉rr❡♥t ♦❢ ❝✶❀ ✷✷ ✲✲ ✷✸ ✇r❡❣❴❡①❝❧❴❡♠♣ ✿❂ ✇r❡❣❴❡①❝❧❴❡♠♣ ✰ sq❧✪r♦✇❝♦✉♥t❀ ✷✹ ✲✲ ✷✺ ❡♥❞ ❧♦♦♣❀ ✷✻ ✲✲ ✷✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇r❡❣❴❡①❝❧❴❡♠♣⑤⑤✬ r❡❣✐str♦s ❞❡ ❡♠♣r❡❣❛❞♦s ❡①❝❧✉í❞♦s✦✬✮❀ ✷✽ ✲✲ ✷✾ ❡♥❞❀ ✸✵ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖ ♥❛ ❧✐♥❤❛ ✶✿ ❖❘❆✲✵✶✹✶✵✿ ❘❖❲■❉ ✐♥✈á❧✐❞♦ 140 Casa do Código Capítulo 10. Cursores ❖❘❆✲✵✻✺✶✷✿ ❡♠ ❧✐♥❡ ✷✶ ❙◗▲❃ Aqui tentamos utilizar current of em um delete na tabela EMP, sendo que em nosso for update definimos uma coluna da tabela DEPT. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶✭ ♣❞❧♦❝ ✈❛r❝❤❛r✷✮ ✐s ✹ s❡❧❡❝t ❞♥❛♠❡ ✺ ❢r♦♠ ❞❡♣t ✻ ✇❤❡r❡ ❞❡♣t✳❧♦❝ ❂ ♣❞❧♦❝ ✼ ❢♦r ✉♣❞❛t❡❀ ✽ ✲✲ ✾ r✶ ❝✶✪r♦✇t②♣❡❀ ✶✵ ✲✲ ✶✶ ✇r❡❣❴❛t✉❛❴❞❡♣ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ♦♣❡♥ ❝✶✭ ♣❞❧♦❝ ❂❃ ✬◆❊❲ ❨❖❘❑✬ ✮❀ ✶✺ ❧♦♦♣ ✶✻ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✶✼ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✶✽ ✲✲ ✶✾ ✉♣❞❛t❡ ❞❡♣t s❡t ❧♦❝ ❂ ✬❋▲❖❘■❉❆✬ ✇❤❡r❡ ❝✉rr❡♥t ♦❢ ❝✶❀ ✷✵ ✲✲ ✷✶ ✇r❡❣❴❛t✉❛❴❞❡♣ ✿❂ ✇r❡❣❴❛t✉❛❴❞❡♣ ✰ sq❧✪r♦✇❝♦✉♥t❀ ✷✷ ✲✲ ✷✸ ❡♥❞ ❧♦♦♣❀ ✷✹ ✲✲ ✷✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇r❡❣❴❛t✉❛❴❞❡♣⑤⑤✬ r❡❣✐str♦s ❞❡ ❞❡♣❛rt❛♠❡♥t♦s ❛t✉❛❧✐③❛❞♦s✦✬✮❀ ✷✻ ✲✲ ✷✼ ❡♥❞❀ ✷✽ ✴ ✶ r❡❣✐str♦s ❞❡ ❞❡♣❛rt❛♠❡♥t♦s ❛t✉❛❧✐③❛❞♦s✦ 141 Casa do Código Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Aqui o comando foi executado de forma correta e com sucesso. Como o select do nosso cursor é formado apenas por uma tabela, não foi preciso especificar colunas na cláusula for update. 142 Capítulo 11 Funções de caracteres e operadores aritméticos Funções de caracteres e de cálculos também podem ser usadas nas expressões SQL. Através delas podem-se modificar os dados, tanto no que diz respeito aos valores selecionados, como também na forma que são apresentados, por exemplo, separar informações dentro de uma determinada String, concatenar caracteres, definir a caixa das letras (maiúsculas, minúsculas e intercaladas) etc. Já os operadores aritméticos podem ser utilizados para a inserção de cálculos dentro dos comandos SQL. Cálculos estes referentes à soma, subtração, divisão e multiplicação. Vale salientar que estas funções e operadores podem ser utilizados em qualquer cláusula SQL exceto na cláusula from. 11.1. Funções de caracteres Casa do Código 11.1 Funções de caracteres • INITCAP: retorna o primeiro caractere de cada palavra em maiúscula. • LOWER: força caracteres maiúsculos aparecerem em minúsculos. • UPPER: força caracteres minúsculos aparecerem em maiúsculos. • SUBSTR: extrai um trecho de uma string, começando por uma posição inicial e a partir desta posição conta com base na quantidade solicitada. • to_char: converte um valor numérico para uma string de caracteres. Também é utilizada para inserir máscara em campos numéricos e de data. • INSTR: retorna a posição do primeiro caractere encontrado, passado como parâmetro. • LENGTH: traz o tamanho dos caracteres em bytes. • RPAD: faz alinhamento à esquerda e preenche com caracteres à direita, até uma determinada posição. Ambos os valores são passados como parâmetro. • LPAD: faz alinhamento à direita e preenche com caracteres à esquerda, até uma determinada posição. Ambos os valores são passados como parâmetro. Seguem exemplos do uso destas funções: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇♥♦♠❡✶ ✹ ✇♥♦♠❡✷ ✺ ✇♥♦♠❡✸ ✻ ✲✲ ✼ ❜❡❣✐♥ ✽ ✲✲ ✾ ✇♥♦♠❡✶ ✶✵ ✇♥♦♠❡✷ 144 ✈❛r❝❤❛r✷✭✶✵✵✮ ❞❡❢❛✉❧t ✬❛♥❛❧✐st❛ ❞❡ s✐st❡♠❛s✬❀ ✈❛r❝❤❛r✷✭✶✵✵✮ ❞❡❢❛✉❧t ✬P❊❉❘❊■❘❖✬❀ ✈❛r❝❤❛r✷✭✶✵✵✮ ❞❡❢❛✉❧t ✬♣❛❞❡✐r♦✬❀ ✿❂ ✐♥✐t❝❛♣✭✇♥♦♠❡✶✮❀ ✿❂ ❧♦✇❡r✭✇♥♦♠❡✷✮❀ Casa do Código Capítulo 11. Funções de caracteres e operadores aritméticos ✶✶ ✇♥♦♠❡✸ ✿❂ ✉♣♣❡r✭✇♥♦♠❡✸✮❀ ✶✷ ✲✲ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇♥♦♠❡✶✮❀ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇♥♦♠❡✷✮❀ ✶✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇♥♦♠❡✸✮❀ ✶✻ ✲✲ ✶✼ ❡♥❞❀ ✶✽ ✴ ❆♥❛❧✐st❛ ❉❡ ❙✐st❡♠❛s ♣❡❞r❡✐r♦ P❆❉❊■❘❖ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso das funções initcap, lower e upper. Note que os valores iniciais das variáveis wnome1, wnome2 e wnome3 são alterados conforme a ação de cada função. ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ r❡❣✐♦♥s❀ ❘❊●■❖◆❴■❉ ✲✲✲✲✲✲✲✲✲ ✶ ✷ ✸ ✹ ❘❊●■❖◆❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❊✉r♦♣❡ ❆♠❡r✐❝❛s ❆s✐❛ ▼✐❞❞❧❡ ❊❛st ❛♥❞ ❆❢r✐❝❛ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇r❡❣✐♦♥❴♥❛♠❡❴s❤♦rt ✈❛r❝❤❛r✷✭✺✵✵✮❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t r❡❣✐♦♥❴♥❛♠❡ ❢r♦♠ r❡❣✐♦♥s✮ ❧♦♦♣ ✻ ✲✲ ✼ ✇r❡❣✐♦♥❴♥❛♠❡❴s❤♦rt ✿❂ ✉♣♣❡r✭s✉❜str✭r✶✳r❡❣✐♦♥❴♥❛♠❡✱✶✱✷✮✮❀ ✽ ✲✲ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇r❡❣✐♦♥❴♥❛♠❡❴s❤♦rt✮❀ ✶✵ ✲✲ 145 11.1. Funções de caracteres Casa do Código ✶✶ ❡♥❞ ❧♦♦♣❀ ✶✷ ✲✲ ✶✸ ❡♥❞❀ ✶✹ ✴ ❊❯ ❆▼ ❆❙ ▼■ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso das funções substr e upper. O exemplo retorna os nomes das regiões mostrando apenas parte da string referente a estes nomes. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧❛r✐♦ ✈❛r❝❤❛r✷✭✷✵✵✮❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❡♥❛♠❡✱ s❛❧ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❝♦♠♠ ✐s ♥✉❧❧✮ ❧♦♦♣ ✻ ✲✲ ✼ ✇s❛❧❛r✐♦ ✿❂ ✬❘✩ ✬⑤⑤t♦❴❝❤❛r✭r✶✳s❛❧✱✬❢♠✾✾✾●✾✾✵❉✵✵✬✮❀ ✽ ✲✲ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤✇s❛❧❛r✐♦✮❀ ✶✵ ✲✲ ✶✶ ❡♥❞ ❧♦♦♣❀ ✶✷ ✲✲ ✶✸ ❡♥❞❀ ✶✹ ✴ ◆♦♠❡✿ ❙▼■❚❍ ❙❛❧ár✐♦✿ ❘✩ ✽✵✵✳✵✵ ◆♦♠❡✿ ❏❖◆❊❙ ❙❛❧ár✐♦✿ ❘✩ ✷✱✾✼✺✳✵✵ ◆♦♠❡✿ ❇▲❆❑❊ ❙❛❧ár✐♦✿ ❘✩ ✷✱✽✺✵✳✵✵ ◆♦♠❡✿ ❈▲❆❘❑ ❙❛❧ár✐♦✿ ❘✩ ✷✱✹✺✵✳✵✵ ◆♦♠❡✿ ❙❈❖❚❚ ❙❛❧ár✐♦✿ ❘✩ ✸✱✵✵✵✳✵✵ ◆♦♠❡✿ ❑■◆● ❙❛❧ár✐♦✿ ❘✩ ✺✱✵✵✵✳✵✵ ◆♦♠❡✿ ❆❉❆▼❙ ❙❛❧ár✐♦✿ ❘✩ ✶✱✶✵✵✳✵✵ 146 Casa do Código Capítulo 11. Funções de caracteres e operadores aritméticos ◆♦♠❡✿ ❏❆▼❊❙ ❙❛❧ár✐♦✿ ❘✩ ✾✺✵✳✵✵ ◆♦♠❡✿ ❋❖❘❉ ❙❛❧ár✐♦✿ ❘✩ ✸✱✵✵✵✳✵✵ ◆♦♠❡✿ ▼■▲▲❊❘ ❙❛❧ár✐♦✿ ❘✩ ✶✱✸✵✵✳✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso da função to_char. A função foi utilizada para formatar os valores da coluna SAL (salários). ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✈❛❧♦r ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ✈❛❧♦r ✿❂ ✐♥str✭✸✼✹✻✷✳✶✷✱✬✻✷✬✮❀ ✻ ✲✲ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬P♦s✐çã♦✿ ✬⑤⑤✈❛❧♦r✮❀ ✽ ✲✲ ✾ ❡♥❞❀ ✶✵ ✴ P♦s✐çã♦✿ ✹ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso da função instr. ❙◗▲❃ ❜❡❣✐♥ ✷ ✲✲ ✸ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❢✐rst❴♥❛♠❡ ❢r♦♠ ❡♠♣❧♦②❡❡s ✇❤❡r❡ ❧❡♥❣t❤✭❢✐rst❴♥❛♠❡✮ ❃ ✶✵✮ ❧♦♦♣ ✹ ✲✲ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❢✐rst❴♥❛♠❡✮❀ ✻ ✲✲ ✼ ❡♥❞ ❧♦♦♣❀ ✽ ✲✲ ✾ ❡♥❞❀ ✶✵ ✴ 147 11.1. Funções de caracteres Casa do Código ◆♦♠❡✿ ❈❤r✐st♦♣❤❡r ◆♦♠❡✿ ❏♦s❡ ▼❛♥✉❡❧ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso da função length. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❧❛st❴♥❛♠❡ ✈❛r❝❤❛r✷✭✷✵✵✮❀ ✸ ✇s❛❧❛r② ✈❛r❝❤❛r✷✭✺✵✮❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❧❛st❴♥❛♠❡✱ s❛❧❛r② ✼ ❢r♦♠ ❡♠♣❧♦②❡❡s ✇❤❡r❡ ❞❡♣❛rt♠❡♥t❴✐❞ ❂ ✸✵✮ ❧♦♦♣ ✽ ✲✲ ✾ ✇❧❛st❴♥❛♠❡ ✿❂ r♣❛❞✭r✶✳❧❛st❴♥❛♠❡✱✶✷✱✬✰✰✰✰✬✮❀ ✶✵ ✇s❛❧❛r② ✿❂ ❧♣❛❞✭r✶✳s❛❧❛r②✱✼✱✬✵✬✮❀ ✶✶ ✲✲ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬Ú❧t✐♠♦ ◆♦♠❡✿ ✬⑤⑤✇❧❛st❴♥❛♠❡⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤✇s❛❧❛r②✮❀ ✶✸ ✲✲ ✶✹ ❡♥❞ ❧♦♦♣❀ ✶✺ ✲✲ ✶✻ ❡♥❞❀ ✶✼ ✴ Ú❧t✐♠♦ ◆♦♠❡✿ ❘❛♣❤❛❡❧②✰✰✰✰ ❙❛❧ár✐♦✿ ✵✵✶✶✵✵✵ Ú❧t✐♠♦ ◆♦♠❡✿ ❑❤♦♦✰✰✰✰✰✰✰✰ ❙❛❧ár✐♦✿ ✵✵✵✸✶✵✵ Ú❧t✐♠♦ ◆♦♠❡✿ ❇❛✐❞❛✰✰✰✰✰✰✰ ❙❛❧ár✐♦✿ ✵✵✵✷✾✵✵ Ú❧t✐♠♦ ◆♦♠❡✿ ❚♦❜✐❛s✰✰✰✰✰✰ ❙❛❧ár✐♦✿ ✵✵✵✷✽✵✵ Ú❧t✐♠♦ ◆♦♠❡✿ ❍✐♠✉r♦✰✰✰✰✰✰ ❙❛❧ár✐♦✿ ✵✵✵✷✻✵✵ Ú❧t✐♠♦ ◆♦♠❡✿ ❈♦❧♠❡♥❛r❡s✰✰ ❙❛❧ár✐♦✿ ✵✵✵✷✺✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso das funções rpad e lpad. 148 Casa do Código 11.2 Capítulo 11. Funções de caracteres e operadores aritméticos Funções de cálculos • ROUND: arredonda valores com casas decimais. • TRUNC: trunca valores com casas decimais. • MOD: mostra o resto da divisão de dois valores. • SQRT: retorna a raiz quadrada de um valor. • POWER: retorna um valor elevado a outro valor. • ABS: retorna o valor absoluto. • CEIL: retorna o menor inteiro, maior ou igual a valor. • FLOOR: retorna o maior inteiro, menor ou igual a valor. • SIGN: se valor maior que 0 retornar +1. Se valor menor que 0 retornar -1. Se valor igual a 0 retorna 0. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧❴❝❛❧❝ ♥✉♠❜❡r❀ ✸ ✇❝♦♠♠ ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t s❛❧✱ ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵✮ ❧♦♦♣ ✼ ✲✲ ✽ ✇s❛❧❴❝❛❧❝ ✿❂ ✭r✶✳s❛❧ ✴ ✷✳✼✮❀ ✾ ✲✲ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤✇s❛❧❴❝❛❧❝✮❀ ✶✶ ✲✲ ✶✷ ❡♥❞ ❧♦♦♣❀ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✲✬✮❀ ✶✺ ✲✲ ✶✻ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❝♦♠♠✱ ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❝♦♠♠ ✐s ♥♦t ♥✉❧❧✮ ❧♦♦♣ ✶✼ ✲✲ 149 11.2. Funções de cálculos ✶✽ ✶✾ ✷✵ Casa do Código ✇❝♦♠♠ ✿❂ r♦✉♥❞✭✭r✶✳❝♦♠♠ ✴ ✷✳✼✮✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❈♦♠✐ssã♦✿ ✬⑤⑤✇❝♦♠♠✮❀ ✷✶ ✲✲ ✷✷ ❡♥❞ ❧♦♦♣❀ ✷✸ ✲✲ ✷✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✲✬✮❀ ✷✺ ✲✲ ✷✻ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t s❛❧✱ ❡♥❛♠❡ ✷✼ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❜❡t✇❡❡♥ ✼✺✵✵ ❛♥❞ ✼✼✵✵✮ ❧♦♦♣ ✷✽ ✲✲ ✷✾ ✇s❛❧❴❝❛❧❝ ✿❂ r♦✉♥❞✭✭r✶✳s❛❧ ✴ ✷✳✼✮✱✷✮❀ ✸✵ ✲✲ ✸✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤ ✸✷ r✶✳s❛❧⑤⑤✬ ❙❛❧ár✐♦ ❈❛❧❝✿ ✬⑤⑤✇s❛❧❴❝❛❧❝✮❀ ✸✸ ✲✲ ✸✹ ❡♥❞ ❧♦♦♣❀ ✸✺ ✲✲ ✸✻ ❡♥❞❀ ✸✼ ✴ ◆♦♠❡✿ ❙▼■❚❍ ❙❛❧ár✐♦✿ ✷✾✻✳✷✾✻✷✾✻✷✾✻✷✾✻✷✾✻✷✾✻✷✾✻✷✾✻✷✾✻✷✾✻✷✾✻✷✾✻ ◆♦♠❡✿ ❏❖◆❊❙ ❙❛❧ár✐♦✿ ✶✶✵✶✳✽✺✶✽✺✶✽✺✶✽✺✶✽✺✶✽✺✶✽✺✶✽✺✶✽✺✶✽✺✶✽✺✶✽✺✷ ◆♦♠❡✿ ❙❈❖❚❚ ❙❛❧ár✐♦✿ ✶✶✶✶✳✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶ ◆♦♠❡✿ ❆❉❆▼❙ ❙❛❧ár✐♦✿ ✹✵✼✳✹✵✼✹✵✼✹✵✼✹✵✼✹✵✼✹✵✼✹✵✼✹✵✼✹✵✼✹✵✼✹✵✼✹✵✼ ◆♦♠❡✿ ❋❖❘❉ ❙❛❧ár✐♦✿ ✶✶✶✶✳✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶✶ ✲ ◆♦♠❡✿ ❆▲▲❊◆ ❈♦♠✐ssã♦✿ ✶✶✶ ◆♦♠❡✿ ❲❆❘❉ ❈♦♠✐ssã♦✿ ✶✽✺ ◆♦♠❡✿ ▼❆❘❚■◆ ❈♦♠✐ssã♦✿ ✺✶✾ ◆♦♠❡✿ ❚❯❘◆❊❘ ❈♦♠✐ssã♦✿ ✵ ✲ ◆♦♠❡✿ ❲❆❘❉ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦ ❈❛❧❝✿ ✹✻✷✳✾✻ ◆♦♠❡✿ ❏❖◆❊❙ ❙❛❧ár✐♦✿ ✷✾✼✺ ❙❛❧ár✐♦ ❈❛❧❝✿ ✶✶✵✶✳✽✺ ◆♦♠❡✿ ▼❆❘❚■◆ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦ ❈❛❧❝✿ ✹✻✷✳✾✻ ◆♦♠❡✿ ❇▲❆❑❊ ❙❛❧ár✐♦✿ ✷✽✺✵ ❙❛❧ár✐♦ ❈❛❧❝✿ ✶✵✺✺✳✺✻ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ 150 Casa do Código Capítulo 11. Funções de caracteres e operadores aritméticos ❙◗▲❃ Esse exemplo mostra o uso da função round. No exemplo, são mostradas diferentes formas de chamada a esta função. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧❴❝❛❧❝ ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❢✐rst❴♥❛♠❡✱ s❛❧❛r②✱ ❥♦❜❴✐❞ ✻ ❢r♦♠ ❡♠♣❧♦②❡❡s ✇❤❡r❡ ❥♦❜❴✐❞ ❂ ✬▼❑❴▼❆◆✬✮ ❧♦♦♣ ✼ ✲✲ ✽ ✇s❛❧❴❝❛❧❝ ✿❂ ✭r✶✳s❛❧❛r② ✴ ✷✳✼✮❀ ✾ ✲✲ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❢✐rst❴♥❛♠❡⑤⑤✬ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✬⑤⑤ ✇s❛❧❴❝❛❧❝⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤r✶✳s❛❧❛r② ✶✶ ⑤⑤✬ ❏♦❜✿ ✬⑤⑤r✶✳❥♦❜❴✐❞✮❀ ✶✷ ✲✲ ✶✸ ❡♥❞ ❧♦♦♣❀ ✶✹ ✲✲ ✶✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✲✬✮❀ ✶✻ ✲✲ ✶✼ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❧❛st❴♥❛♠❡✱ s❛❧❛r②✱ ❡♠❛✐❧ ✶✽ ❢r♦♠ ❡♠♣❧♦②❡❡s ✇❤❡r❡ ❡♠❛✐❧ ❂ ✬◆❙❆❘❈❍❆◆✬✮ ❧♦♦♣ ✶✾ ✲✲ ✷✵ ✇s❛❧❴❝❛❧❝ ✿❂ tr✉♥❝✭✭r✶✳s❛❧❛r② ✴ ✷✳✼✮✮❀ ✷✶ ✲✲ ✷✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❧❛st❴♥❛♠❡⑤⑤✬ ❙❛❧✳ ❈❛❧❝✿ ✬⑤⑤✇s❛❧❴❝❛❧❝⑤⑤ ✬ ❙❛❧✳ ✿ ✬⑤⑤r✶✳s❛❧❛r②⑤⑤✬ ✷✸ ❊♠❛✐❧✳ ✿ ✬⑤⑤r✶✳❡♠❛✐❧✮❀ ✷✹ ✲✲ ✷✺ ❡♥❞ ❧♦♦♣❀ ✷✻ ✲✲ ✷✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✲✬✮❀ ✷✽ ✲✲ ✷✾ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❧❛st❴♥❛♠❡✱ s❛❧❛r② ✸✵ ❢r♦♠ ❡♠♣❧♦②❡❡s ✇❤❡r❡ ❡♠♣❧♦②❡❡❴✐❞ ❜❡t✇❡❡♥ ✶✵✵ 151 Casa do Código 11.2. Funções de cálculos ✸✶ ✸✷ ✸✸ ✸✹ ❛♥❞ ✶✵✺✮ ❧♦♦♣ ✲✲ ✇s❛❧❴❝❛❧❝ ✿❂ tr✉♥❝✭✭r✶✳s❛❧❛r② ✴ ✷✳✼✮✱✷✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❧❛st❴♥❛♠❡⑤⑤✬ ❙❛❧✳ ❈❛❧❝✿ ✬⑤⑤✇s❛❧❴❝❛❧❝⑤⑤ ✸✺ ✬ ❙❛❧✳ ✿ ✬⑤⑤r✶✳s❛❧❛r②✮❀ ✸✻ ✲✲ ✸✼ ❡♥❞ ❧♦♦♣❀ ✸✽ ✲✲ ✸✾ ❡♥❞❀ ✹✵ ✴ ◆♦♠❡✿ ▼✐❝❤❛❡❧ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✹✽✶✹✳✽✶✹✽✶✹✽✶✹✽✶✹✽✶✹✽✶✹✽✶✹✽✶✹✽✶✹✽✶✹✽✶✹✽✶✺ ❙❛❧ár✐♦✿ ✶✸✵✵✵ ❏♦❜✿ ▼❑❴▼❆◆ ✲ ◆♦♠❡✿ ❙❛r❝❤❛♥❞ ❙❛❧✳ ❈❛❧❝✿ ✶✺✺✺ ❙❛❧✳ ✿ ✹✷✵✵ ❊♠❛✐❧✳ ✿ ◆❙❆❘❈❍❆◆ ✲ ◆♦♠❡✿ ❑✐♥❣ ❙❛❧✳ ❈❛❧❝✿ ✽✽✽✽✳✽✽ ❙❛❧✳ ✿ ✷✹✵✵✵ ◆♦♠❡✿ ❑♦❝❤❤❛r ❙❛❧✳ ❈❛❧❝✿ ✻✷✾✻✳✷✾ ❙❛❧✳ ✿ ✶✼✵✵✵ ◆♦♠❡✿ ❉❡ ❍❛❛♥ ❙❛❧✳ ❈❛❧❝✿ ✻✷✾✻✳✷✾ ❙❛❧✳ ✿ ✶✼✵✵✵ ◆♦♠❡✿ ❍✉♥♦❧❞ ❙❛❧✳ ❈❛❧❝✿ ✸✸✸✸✳✸✸ ❙❛❧✳ ✿ ✾✵✵✵ ◆♦♠❡✿ ❊r♥st ❙❛❧✳ ❈❛❧❝✿ ✷✷✷✷✳✷✷ ❙❛❧✳ ✿ ✻✵✵✵ ◆♦♠❡✿ ❆✉st✐♥ ❙❛❧✳ ❈❛❧❝✿ ✶✼✼✼✳✼✼ ❙❛❧✳ ✿ ✹✽✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso da função trunc. No exemplo, são mostradas diferentes formas de chamada a esta função. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇r❡s ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ✇r❡s ✿❂ ♠♦❞✭✶✵✱✷✮❀ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✬⑤⑤✇r❡s✮❀ ✼ ✲✲ 152 Casa do Código Capítulo 11. Funções de caracteres e operadores aritméticos ✽ ✇r❡s ✿❂ sqrt✭✻✹✮❀ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✬⑤⑤✇r❡s✮❀ ✶✵ ✲✲ ✶✶ ✇r❡s ✿❂ ♣♦✇❡r✭✽✱✷✮❀ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✬⑤⑤✇r❡s✮❀ ✶✸ ✲✲ ✶✹ ❡♥❞❀ ✶✺ ✴ ❘❡s✉❧t❛❞♦✿ ✵ ❘❡s✉❧t❛❞♦✿ ✽ ❘❡s✉❧t❛❞♦✿ ✻✹ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso das funções mod, sqrt e power. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇r❡s ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ✇r❡s ✿❂ ❛❜s✭✲✷✵✮❀ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✬⑤⑤✇r❡s✮❀ ✼ ✲✲ ✽ ✇r❡s ✿❂ ❝❡✐❧✭✶✵✳✷✮❀ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✬⑤⑤✇r❡s✮❀ ✶✵ ✲✲ ✶✶ ✇r❡s ✿❂ ❢❧♦♦r✭✶✵✳✷✮❀ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✬⑤⑤✇r❡s✮❀ ✶✸ ✲✲ ✶✹ ❡♥❞❀ ✶✺ ✴ ❘❡s✉❧t❛❞♦✿ ✷✵ ❘❡s✉❧t❛❞♦✿ ✶✶ ❘❡s✉❧t❛❞♦✿ ✶✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ 153 11.3. Operadores aritméticos Casa do Código Nesse exemplo é mostrado o uso das funções abs, ceil e floor. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇r❡s ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ✇r❡s ✿❂ s✐❣♥✭✲✷✵✵✵✮❀ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✬⑤⑤✇r❡s✮❀ ✼ ✲✲ ✽ ✇r❡s ✿❂ s✐❣♥✭✷✵✵✵✮❀ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✬⑤⑤✇r❡s✮❀ ✶✵ ✲✲ ✶✶ ✇r❡s ✿❂ s✐❣♥✭✵✮❀ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✬⑤⑤✇r❡s✮❀ ✶✸ ✲✲ ✶✹ ❡♥❞❀ ✶✺ ✴ ❘❡s✉❧t❛❞♦✿ ✲✶ ❘❡s✉❧t❛❞♦✿ ✶ ❘❡s✉❧t❛❞♦✿ ✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso da função sign. No exemplo, são mostrados diferentes parâmetros na chamada desta função. 11.3 Operadores aritméticos • * Multiplicação • / Divisão • + Adição • - Subtração ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧❴❝❛❧❝ ♥✉♠❜❡r❀ 154 Casa do Código Capítulo 11. Funções de caracteres e operadores aritméticos ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t s❛❧ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❝♦♠♠ ✐s ♥♦t ♥✉❧❧✮ ❧♦♦♣ ✻ ✲✲ ✼ ✇s❛❧❴❝❛❧❝ ✿❂ ✭r✶✳s❛❧✯✷✴✸✮❀ ✽ ✲✲ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙❛❧ár✐♦ ❈❛❧❝✳✿ ✬⑤⑤✇s❛❧❴❝❛❧❝⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤r✶✳s❛❧✮❀ ✶✵ ✲✲ ✶✶ ❡♥❞ ❧♦♦♣❀ ✶✷ ✲✲ ✶✸ ❡♥❞❀ ✶✹ ✴ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✶✵✻✻✳✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✼ ❙❛❧ár✐♦✿ ✶✻✵✵ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✽✸✸✳✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✽✸✸✳✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸✸ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✶✵✵✵ ❙❛❧ár✐♦✿ ✶✺✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso das funções aritméticas de multiplicação e divisão. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇s❛❧❴❝❛❧❝ ♥✉♠❜❡r❀ ✹ ✲✲ ✺ ❜❡❣✐♥ ✻ ✲✲ ✼ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❡♥❛♠❡✱ s❛❧ ✽ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✸✵✮ ❧♦♦♣ ✾ ✲✲ ✶✵ ✇s❛❧❴❝❛❧❝ ✿❂ r♦✉♥❞✭✭r✶✳s❛❧✯✷✮✴✸✰✶✵✵✳✵✵✱✷✮❀ ✶✶ ✲✲ 155 11.3. Operadores aritméticos Casa do Código ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✬⑤⑤ ✇s❛❧❴❝❛❧❝⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤r✶✳s❛❧✮❀ ✶✸ ✶✹ ✲✲ ✶✺ ❡♥❞ ❧♦♦♣❀ ✶✻ ✲✲ ✶✼ ❡♥❞❀ ✶✽ ✴ ◆♦♠❡✿ ❆▲▲❊◆ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✶✶✻✻✳✻✼ ❙❛❧ár✐♦✿ ✶✻✵✵ ◆♦♠❡✿ ❲❆❘❉ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✾✸✸✳✸✸ ❙❛❧ár✐♦✿ ✶✷✺✵ ◆♦♠❡✿ ▼❆❘❚■◆ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✾✸✸✳✸✸ ❙❛❧ár✐♦✿ ✶✷✺✵ ◆♦♠❡✿ ❇▲❆❑❊ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✷✵✵✵ ❙❛❧ár✐♦✿ ✷✽✺✵ ◆♦♠❡✿ ❚❯❘◆❊❘ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✶✶✵✵ ❙❛❧ár✐♦✿ ✶✺✵✵ ◆♦♠❡✿ ❏❆▼❊❙ ❙❛❧ár✐♦ ❈❛❧❝✳✿ ✼✸✸✳✸✸ ❙❛❧ár✐♦✿ ✾✺✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso das funções aritméticas de multiplicação, divisão e soma. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇❞t❴❡♠✐ss❛♦ ♥✉♠❜❡r❀ ✹ ✇♣r❡♠✐❛❝❛♦ ♥✉♠❜❡r❀ ✺ ✲✲ ✻ ❝✉rs♦r ❝✶ ✐s ✼ s❡❧❡❝t ❡♥❛♠❡ ✽ ✱❞♥❛♠❡ ✾ ✱❤✐r❡❞❛t❡ ✶✵ ✱s❛❧ ✶✶ ❢r♦♠ ❡♠♣ ❡ ✶✷ ✱❞❡♣t ❞ ✶✸ ✇❤❡r❡ ❡✳❞❡♣t♥♦ ❂ ❞✳❞❡♣t♥♦ ✶✹ ❛♥❞ tr✉♥❝✭✭s②s❞❛t❡ ✲ ❤✐r❡❞❛t❡✮ ✴ ✸✻✺✮ ❂ ✸✵❀ ✶✺ ✲✲ ✶✻ ❜❡❣✐♥ ✶✼ ✲✲ 156 Casa do Código Capítulo 11. Funções de caracteres e operadores aritméticos ✶✽ ✶✾ ✷✵ ✷✶ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✲✲ ✇❞t❴❡♠✐ss❛♦ ✿❂ tr✉♥❝✭✭s②s❞❛t❡ ✲ r✶✳❤✐r❡❞❛t❡✮ ✴ ✸✻✺✮❀ ✇♣r❡♠✐❛❝❛♦ ✿❂ ✭r✶✳s❛❧✴✶✵✯tr✉♥❝✭✭s②s❞❛t❡ ✲ r✶✳❤✐r❡❞❛t❡✮ ✴ ✸✻✺✮✮❀ ✷✷ ✲✲ ✷✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❉t✳ ❊♠✐ssã♦✿ ✬⑤⑤ ✇❞t❴❡♠✐ss❛♦⑤⑤✬ Pr❡♠✐❛çã♦✿ ✷✹ ✬⑤⑤✇♣r❡♠✐❛❝❛♦✮❀ ✷✺ ✲✲ ✷✻ ❡♥❞ ❧♦♦♣❀ ✷✼ ✲✲ ✷✽ ❡♥❞❀ ✷✾ ✴ ◆♦♠❡✿ ❑■◆● ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✶✺✵✵✵ ◆♦♠❡✿ ❈▲❆❘❑ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✼✸✺✵ ◆♦♠❡✿ ❋❖❘❉ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✾✵✵✵ ◆♦♠❡✿ ❏❖◆❊❙ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✽✾✷✺ ◆♦♠❡✿ ❙▼■❚❍ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✷✹✵✵ ◆♦♠❡✿ ❏❆▼❊❙ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✷✽✺✵ ◆♦♠❡✿ ❚❯❘◆❊❘ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✹✺✵✵ ◆♦♠❡✿ ❇▲❆❑❊ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✽✺✺✵ ◆♦♠❡✿ ▼❆❘❚■◆ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✸✼✺✵ ◆♦♠❡✿ ❲❆❘❉ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✸✼✺✵ ◆♦♠❡✿ ❆▲▲❊◆ ❉t✳ ❊♠✐ssã♦✿ ✸✵ Pr❡♠✐❛çã♦✿ ✹✽✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso das funções aritméticas de multiplicação, divisão e subtração. 157 Capítulo 12 Funções de agregação (grupo) As funções de agregação são responsáveis por agrupar vários valores e retornar somente um único valor para um determinado grupo. As funções de agregação, também chamadas de funções de grupo, são especificadas no comando select de uma coluna e são seguidas pela coluna à qual se aplicam. A utilização das funções de agregação pode implicar no uso da cláusula group by. Isso acontece porque, ao informarmos colunas com funções e colunas sem funções em um mesmo select, precisamos agrupar as colunas que não estão sendo afetadas pelo agrupamento causado pelas funções. Veja a ilustração: Casa do Código Fig. 12.1: Dados de empregados Nesta ilustração, temos alguns empregados, departamentos e valores de salário. Nosso objetivo aqui é tentar de alguma forma somar todos os salários por departamento, ou seja, ver quanto de salário temos para os empregados referentes aos departamentos RESEARCH, SALES e ACCOUNTING. Da forma como os dados estão dispostos, não conseguimos visualizar isto, pois se tentarmos agrupar departamento, não conseguiremos, visto que o agrupamento consiste em selecionar dados que possuem o mesmo valor e torná-lo único para cada conjunto de dados. Por exemplo, temos os departamentos RESEARCH, SALES e ACCOUNTING aparecendo diversas vezes. Se agruparmos, teremos um único registro para o departamento RESEARCH, outro para SALES, e outro para ACCOUNTING. Entretanto, também estamos selecionando os nomes dos empregados e, na maioria dos casos, cada um possui um nome deferente, impossibilitando que os agrupemos. Se não conseguimos agrupar os empregados, logo não conseguimos agrupar os departamentos. É como se fosse uma sequência. Quando usamos funções de grupo nas colunas de um select, temos que agrupar todas as outras, sendo através de uma função de agregação ou sendo pelo uso do group by. Já vimos que se nós quisermos a somatória de todos os salários por departamento não podemos selecionar os empregados, ou melhor, os nomes deles. 160 Casa do Código Capítulo 12. Funções de agregação (grupo) Logo, a coluna Empregado não poderá aparecer no nosso select. Caso contrário, estaríamos incluindo também por empregados, o que nos daria um agrupamento inútil, tendo em vista que cada nome de empregado é diferente. Sempre quando trabalhamos com agrupamentos, temos que ter em mente a seguinte situação: vai haver colunas que estarão sobre o efeito das funções de agregação, por exemplo, funções de somatória ou de média, e colunas que não estarão sobre o efeito destas funções, mas que precisarão ser agrupadas para que juntas possam formar um conjunto de dados. Veja a próxima ilustração: Fig. 12.2: Dados agrupados parcialmente Nessa outra ilustração, temos dois grupos. Um grupo formado pelas colunas Empregado e Departamento, que sofrerão a ação do group by, e outro grupo formado apenas pela coluna Salário, que sofrerá a ação da nossa função de agregação. Vale ressaltar que nosso objetivo aqui é agrupar os salários por departamento. Pois bem, como pode ser visto na ilustração, neste caso, não conseguimos montar o agrupamento. Note que na coluna de departamento é possível 161 Casa do Código agrupar os valores, mas na coluna de empregados isso não é possível. Como a coluna de empregados faz parte do select, ela acaba comprometendo todo nosso agrupamento. Atenção a um detalhe – o fato de a coluna Empregado estar sendo visualizada primeiro não quer dizer que seja a causa de não conseguirmos agrupar por departamento. A ordem das colunas não altera o resultado. Vamos retirá-la do nosso select. Fig. 12.3: Processo de agrupamento de salários por departamento Agora sim. Tiramos a coluna de empregados e ficamos apenas com as colunas Departamento e Salário. Veja como ficou nosso agrupamento: 162 Casa do Código Capítulo 12. Funções de agregação (grupo) Fig. 12.4: Dados agrupados - Salários x Departamento Fazendo desta forma conseguiremos alcançar nosso objetivo. Resumindo: • Devemos saber que para obter sucesso em nossos agrupamentos, as colunas que não estão sendo agrupadas pelas funções de agrupamento devem ser agrupadas pelo group by; • Também podemos agrupar determinadas colunas, mesmo que elas não estejam presentes na cláusula select; • Somente vamos precisar agrupar colunas através do group by quando desejarmos mostrar um resultado com base em outro. Exemplo: valores de salário por departamento, quantidades de empregados por departamento e assim por diante. Se quisermos apenas saber a somatória de todos os valores de salário independente do departamento ou de qualquer outra informação, não precisaremos utilizar o group by; • Funções de agregação, no geral, ignoram valores nulos; • Para realizar o agrupamento de informações o Oracle poderá ordenar ou não as colunas. Caso a coluna que está sobre a ação da função for uma coluna com índice, o banco poderá utilizar este índice. Como os 163 Casa do Código índices são ordenados, não será necessário ordenar os dados para o agrupamento. Caso contrário, ele vai realizar a ordenação, primeiro, e depois agrupa. Nem todas as funções permitem usar índices. Agora vamos ver estes conceitos na prática. Primeiramente, visualizamos o nome de todos os empregados, os nomes dos seus departamentos e seus respectivos salários. ❙◗▲❃ ✷ ✸ ✹ s❡❧❡❝t ❡♥❛♠❡✱ ❞♥❛♠❡✱ s❛❧ ❢r♦♠ ❡♠♣ ❡✱ ❞❡♣t ❞ ✇❤❡r❡ ❡✳❞❡♣t♥♦ ❂ ❞✳❞❡♣t♥♦ ♦r❞❡r ❜② ❡♥❛♠❡❀ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❆❉❆▼❙ ❆▲▲❊◆ ❇▲❆❑❊ ❈▲❆❘❑ ❋❖❘❉ ❏❆▼❊❙ ❏❖❍◆ ❏❖◆❊❙ ❑■◆● ▼❆❘❚■◆ ▼■▲▲❊❘ ❙❈❖❚❚ ❙▼■❚❍ ❚❯❘◆❊❘ ❲❆❘❉ ❉◆❆▼❊ ❙❆▲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ❘❊❙❊❆❘❈❍ ✶✶✵✵ ❙❆▲❊❙ ✶✻✵✵ ❙❆▲❊❙ ✷✽✺✵ ❆❈❈❖❯◆❚■◆● ✷✹✺✵ ❘❊❙❊❆❘❈❍ ✸✵✵✵ ❙❆▲❊❙ ✾✺✵ ❘❊❙❊❆❘❈❍ ✶✵✵✵ ❘❊❙❊❆❘❈❍ ✷✾✼✺ ❆❈❈❖❯◆❚■◆● ✺✵✵✵ ❙❆▲❊❙ ✶✷✺✵ ❆❈❈❖❯◆❚■◆● ✶✸✵✵ ❘❊❙❊❆❘❈❍ ✸✵✵✵ ❘❊❙❊❆❘❈❍ ✽✵✵ ❙❆▲❊❙ ✶✺✵✵ ❙❆▲❊❙ ✶✷✺✵ ✶✺ r♦✇s s❡❧❡❝t❡❞✳ ❙◗▲❃ Através de um programa PL/SQL selecionamos os mesmos dados do select anterior, mas agora sumarizando os salários. Note que continuamos selecionando as colunas nome do empregado e departamento do empregado. O objetivo do programa é mostrar a soma dos salários por departamento. 164 Casa do Código Capítulo 12. Funções de agregação (grupo) ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❡♥❛♠❡✱ ❞♥❛♠❡✱ s✉♠✭s❛❧✮ s♦♠❛❴s❛❧ ✺ ❢r♦♠ ❡♠♣ ❡✱ ❞❡♣t ❞ ✻ ✇❤❡r❡ ❡✳❞❡♣t♥♦ ❂ ❞✳❞❡♣t♥♦ ✼ ♦r❞❡r ❜② ❡♥❛♠❡❀ ✽ ✲✲ ✾ ❜❡❣✐♥ ✶✵ ✲✲ ✶✶ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✷ ✲✲ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤ ✶✹ r✶✳❞♥❛♠❡⑤⑤✬ ❙♦♠❛ ❙❛❧✳✿ ✬⑤⑤r✶✳s♦♠❛❴s❛❧✮❀ ✶✺ ✲✲ ✶✻ ❡♥❞ ❧♦♦♣❀ ✶✼ ✲✲ ✶✽ ❡♥❞❀ ✶✾ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ ❖❘❆✲✵✵✾✸✼✿ ♥♦t ❛ s✐♥❣❧❡✲❣r♦✉♣ ❣r♦✉♣ ❢✉♥❝t✐♦♥ ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✶✶ ❙◗▲❃ Ao executar o programa, surgiu um erro que, em linhas gerais, quer dizer que o comando select, contido no cursor, está tentando utilizar uma função de grupo, juntamente com outras colunas não agrupadas, sem utilizar a cláusula de agrupamento. Como visto nos conceitos apresentados anteriormente, isso não é permitido. Dessa forma, devemos agrupar as colunas que não estão associadas a funções de agrupamento. Veja a seguir como ficou. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ 165 Casa do Código ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ❝✉rs♦r ❝✶ ✐s s❡❧❡❝t ❡♥❛♠❡✱ ❞♥❛♠❡✱ s✉♠✭s❛❧✮ s♦♠❛❴s❛❧ ❢r♦♠ ❡♠♣ ❡✱ ❞❡♣t ❞ ✇❤❡r❡ ❡✳❞❡♣t♥♦ ❂ ❞✳❞❡♣t♥♦ ❣r♦✉♣ ❜② ❡♥❛♠❡✱ ❞♥❛♠❡ ♦r❞❡r ❜② ❡♥❛♠❡❀ ✲✲ ❜❡❣✐♥ ✲✲ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤ r✶✳❞♥❛♠❡⑤⑤✬ ✶✺ ❙♦♠❛ ❙❛❧✳✿ ✬⑤⑤r✶✳s♦♠❛❴s❛❧✮❀ ✶✻ ✲✲ ✶✼ ❡♥❞ ❧♦♦♣❀ ✶✽ ✲✲ ✶✾ ❡♥❞❀ ✷✵ ✴ ◆♦♠❡✿ ❆❉❆▼❙ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✶✶✵✵ ◆♦♠❡✿ ❆▲▲❊◆ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✶✻✵✵ ◆♦♠❡✿ ❇▲❆❑❊ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✷✽✺✵ ◆♦♠❡✿ ❈▲❆❘❑ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❙♦♠❛ ❙❛❧✳✿ ✷✹✺✵ ◆♦♠❡✿ ❋❖❘❉ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✸✵✵✵ ◆♦♠❡✿ ❏❆▼❊❙ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✾✺✵ ◆♦♠❡✿ ❏❖◆❊❙ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✷✾✼✺ ◆♦♠❡✿ ❑■◆● ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❙♦♠❛ ❙❛❧✳✿ ✺✵✵✵ ◆♦♠❡✿ ▼❆❘❚■◆ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✶✷✺✵ ◆♦♠❡✿ ▼■▲▲❊❘ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❙♦♠❛ ❙❛❧✳✿ ✶✸✵✵ ◆♦♠❡✿ ❙❈❖❚❚ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✸✵✵✵ ◆♦♠❡✿ ❙▼■❚❍ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✽✵✵ ◆♦♠❡✿ ❚❯❘◆❊❘ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✶✺✵✵ ◆♦♠❡✿ ❲❆❘❉ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✶✷✺✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ 166 Casa do Código Capítulo 12. Funções de agregação (grupo) Feitos os agrupamentos necessários, voltamos a executar o programa. O resultado foi apresentado logo em seguida. No entanto, veja que algo não saiu como deveria. Os salários não foram sumarizados por departamento e, sim, por empregado. Seria a mesma coisa que não sumarizar. Vamos alterar o comando retirando a coluna nome do empregado do comando SQL. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❞♥❛♠❡✱ s✉♠✭s❛❧✮ s♦♠❛❴s❛❧ ✺ ❢r♦♠ ❡♠♣ ❡✱ ❞❡♣t ❞ ✻ ✇❤❡r❡ ❡✳❞❡♣t♥♦ ❂ ❞✳❞❡♣t♥♦ ✼ ❣r♦✉♣ ❜② ❡♥❛♠❡✱ ❞♥❛♠❡ ✽ ♦r❞❡r ❜② ❡♥❛♠❡❀ ✾ ✲✲ ✶✵ ❜❡❣✐♥ ✶✶ ✲✲ ✶✷ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤ ✶✺ r✶✳❞♥❛♠❡⑤⑤✬ ❙♦♠❛ ❙❛❧✳✿ ✬⑤⑤r✶✳s♦♠❛❴s❛❧✮❀ ✶✻ ✲✲ ✶✼ ❡♥❞ ❧♦♦♣❀ ✶✽ ✲✲ ✶✾ ❡♥❞❀ ✷✵ ✴ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✶✶✵✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✶✻✵✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✷✽✺✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❙♦♠❛ ❙❛❧✳✿ ✷✹✺✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✸✵✵✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✾✺✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✷✾✼✺ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❙♦♠❛ ❙❛❧✳✿ ✺✵✵✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✶✷✺✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❙♦♠❛ ❙❛❧✳✿ ✶✸✵✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✸✵✵✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✽✵✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✶✺✵✵ 167 Casa do Código ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✶✷✺✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Ao retirar a coluna, o erro persiste. Isso acontece pois não adianta retirar apenas da seleção, mas também é necessário retirar do agrupamento. Veja que na linha 7 ainda consta a coluna ename. Veja a seguir, como deve ficar o select, para que o programa consiga atingir o objetivo proposto. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❞♥❛♠❡✱ s✉♠✭s❛❧✮ s♦♠❛❴s❛❧ ✺ ❢r♦♠ ❡♠♣ ❡✱ ❞❡♣t ❞ ✻ ✇❤❡r❡ ❡✳❞❡♣t♥♦ ❂ ❞✳❞❡♣t♥♦ ✼ ❣r♦✉♣ ❜② ❞♥❛♠❡❀ ✽ ✲✲ ✾ ❜❡❣✐♥ ✶✵ ✲✲ ✶✶ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✷ ✲✲ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤ ✶✹ r✶✳❞♥❛♠❡⑤⑤✬ ❙♦♠❛ ❙❛❧✳✿ ✬⑤⑤r✶✳s♦♠❛❴s❛❧✮❀ ✶✺ ✲✲ ✶✻ ❡♥❞ ❧♦♦♣❀ ✶✼ ✲✲ ✶✽ ❡♥❞❀ ✶✾ ✴ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❙♦♠❛ ❙❛❧✳✿ ✽✼✺✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❙♦♠❛ ❙❛❧✳✿ ✶✵✽✼✺ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❙♦♠❛ ❙❛❧✳✿ ✾✹✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Selecionando apenas a coluna referente ao nome do departamento e su168 Casa do Código Capítulo 12. Funções de agregação (grupo) marizando os salários, através da função de agregação sum, temos como resultado a soma dos salários por departamento. Segue as funções de agregação mais utilizadas: • count: retorna a quantidade de incidências de registros. • sum: exibe a soma dos valores dos registros. • avg: exibe a média dos valores de uma determinada coluna. • min: exibe o menor valor de uma coluna. • max: retorna o maior valor de uma coluna. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❝♦✉♥t✭❡♠♣❧♦②❡❡❴✐❞✮ ❝♦♥t❴❡♠♣✱ ❝♦✉♥tr②❴♥❛♠❡ ✺ ❢r♦♠ ❡♠♣❧♦②❡❡s ❡ ✻ ✱❞❡♣❛rt♠❡♥ts ❞ ✼ ✱❧♦❝❛t✐♦♥s ❧ ✽ ✱❝♦✉♥tr✐❡s ❝ ✾ ✇❤❡r❡ ❡✳❞❡♣❛rt♠❡♥t❴✐❞ ❂ ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ✶✵ ❛♥❞ ❞✳❧♦❝❛t✐♦♥❴✐❞ ❂ ❧✳❧♦❝❛t✐♦♥❴✐❞ ✶✶ ❛♥❞ ❧✳❝♦✉♥tr②❴✐❞ ❂ ❝✳❝♦✉♥tr②❴✐❞ ✶✷ ❣r♦✉♣ ❜② ❝♦✉♥tr②❴♥❛♠❡ ✶✸ ♦r❞❡r ❜② ❝♦✉♥tr②❴♥❛♠❡❀ ✶✹ ✲✲ ✶✺ ❜❡❣✐♥ ✶✻ ✲✲ ✶✼ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✽ ✲✲ ✶✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✬⑤⑤ r✶✳❝♦♥t❴❡♠♣⑤⑤✬ ❈✐❞❛❞❡✿ ✬⑤⑤r✶✳❝♦✉♥tr②❴♥❛♠❡✮❀ ✷✵ ✷✶ ✲✲ ✷✷ ❡♥❞ ❧♦♦♣❀ ✷✸ ✲✲ ✷✹ ❡♥❞❀ ✷✺ ✴ ◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✷ ❈✐❞❛❞❡✿ ❈❛♥❛❞❛ 169 Casa do Código ◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✶ ❈✐❞❛❞❡✿ ●❡r♠❛♥② ◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✸✺ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❑✐♥❣❞♦♠ ◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✻✽ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❙t❛t❡s ♦❢ ❆♠❡r✐❝❛ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso da função: count. No exemplo, o objetivo é selecionar a quantidade de empregados por país. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❝♦✉♥t✭✯✮ ❝♦♥t❴❡♠♣✱ ❝♦✉♥tr②❴♥❛♠❡ ✺ ❢r♦♠ ❡♠♣❧♦②❡❡s ❡ ✻ ✱❞❡♣❛rt♠❡♥ts ❞ ✼ ✱❧♦❝❛t✐♦♥s ❧ ✽ ✱❝♦✉♥tr✐❡s ❝ ✾ ✇❤❡r❡ ❡✳❞❡♣❛rt♠❡♥t❴✐❞ ❂ ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ✶✵ ❛♥❞ ❞✳❧♦❝❛t✐♦♥❴✐❞ ❂ ❧✳❧♦❝❛t✐♦♥❴✐❞ ✶✶ ❛♥❞ ❧✳❝♦✉♥tr②❴✐❞ ❂ ❝✳❝♦✉♥tr②❴✐❞ ✶✷ ❣r♦✉♣ ❜② ❝♦✉♥tr②❴♥❛♠❡ ✶✸ ♦r❞❡r ❜② ❝♦✉♥tr②❴♥❛♠❡❀ ✶✹ ✲✲ ✶✺ ❜❡❣✐♥ ✶✻ ✲✲ ✶✼ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✽ ✲✲ ✶✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✬⑤⑤ r✶✳❝♦♥t❴❡♠♣⑤⑤✬ ❈✐❞❛❞❡✿ ✬⑤⑤r✶✳❝♦✉♥tr②❴♥❛♠❡✮❀ ✷✵ ✷✶ ✲✲ ✷✷ ❡♥❞ ❧♦♦♣❀ ✷✸ ✲✲ ✷✹ ❡♥❞❀ ✷✺ ✴ ◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✷ ❈✐❞❛❞❡✿ ❈❛♥❛❞❛ ◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✶ ❈✐❞❛❞❡✿ ●❡r♠❛♥② ◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✸✺ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❑✐♥❣❞♦♠ 170 Casa do Código Capítulo 12. Funções de agregação (grupo) ◗t❞❡✳ ❊♠♣r❡❣❛❞♦s✿ ✻✽ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❙t❛t❡s ♦❢ ❆♠❡r✐❝❛ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo é quase igual ao anterior, apenas por um detalhe. Note que como conhecemos a tabela employees e sabemos que existe apenas um registro para cada empregado, podemos usar a função count de outra forma, utilizando asterisco ( *) no lugar da coluna employee_id. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❞♥❛♠❡✱ ♠❛①✭❤✐r❡❞❛t❡✮ ❞t❴❛❞♠✐ss❛♦ ✺ ❢r♦♠ ❡♠♣ ❡✱ ❞❡♣t ❞ ✻ ✇❤❡r❡ ❡✳❞❡♣t♥♦ ❂ ❞✳❞❡♣t♥♦ ✼ ❣r♦✉♣ ❜② ❞♥❛♠❡ ✽ ♦r❞❡r ❜② ✷ ❞❡s❝❀ ✾ ✲✲ ✶✵ ❜❡❣✐♥ ✶✶ ✲✲ ✶✷ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤ r✶✳❞♥❛♠❡⑤⑤✬ ❉t✳ ❆❞♠✐ssã♦✿ ✬⑤⑤r✶✳❞t❴❛❞♠✐ss❛♦✮❀ ✶✺ ✶✻ ✲✲ ✶✼ ❡♥❞ ❧♦♦♣❀ ✶✽ ✲✲ ✶✾ ❡♥❞❀ ✷✵ ✴ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❊❙❊❆❘❈❍ ❉t✳ ❆❞♠✐ssã♦✿ ✶✷✲❏❆◆✲✽✸ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❉t✳ ❆❞♠✐ssã♦✿ ✷✸✲❏❆◆✲✽✷ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❉t✳ ❆❞♠✐ssã♦✿ ✵✸✲❉❊❈✲✽✶ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso da função: max. No exemplo, o objetivo é 171 Casa do Código selecionar a maior data de admissão de cada departamento. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇r❡s ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ s❡❧❡❝t ♠✐♥✭❤✐r❡❴❞❛t❡✮ ❤✐r❡❴❞❛t❡❴♠✐♥ ✐♥t♦ ✇r❡s ❢r♦♠ ❡♠♣❧♦②❡❡s❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬▼❡♥♦r ❉t✳ ❊♠✐ssã♦✿ ✬⑤⑤✇r❡s✮❀ ✼ ✲✲ ✽ ❡♥❞❀ ✾ ✴ ▼❡♥♦r ❉t✳ ❊♠✐ssã♦✿ ✶✼✲❏❯◆✲✽✼ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostra o uso da função: min. O objetivo é selecionar a menor data de admissão entre todos os empregados. Além das funções de agregação e do uso do group by, também podemos contar com o having, para nos ajudar a restringir registros com base nos valores retornados pelas funções de agregação. O having existe pois não podemos utilizar funções de agregação na cláusula where. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❝♦✉♥t✭❡♠♣❧♦②❡❡❴✐❞✮ ❝♦♥t❴❡♠♣✱ s✉♠✭s❛❧❛r②✮ s♦♠❛❴s❛❧❛r✐♦✱ ❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✺ ❢r♦♠ ❡♠♣❧♦②❡❡s ❡ ✻ ✱❞❡♣❛rt♠❡♥ts ❞ ✼ ✇❤❡r❡ ❡✳❞❡♣❛rt♠❡♥t❴✐❞ ❂ ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ✽ ❤❛✈✐♥❣ ❝♦✉♥t✭❡♠♣❧♦②❡❡❴✐❞✮ ❃ ✺ ✾ ❣r♦✉♣ ❜② ❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✶✵ ♦r❞❡r ❜② ❞❡♣❛rt♠❡♥t❴♥❛♠❡❀ ✶✶ ✲✲ ✶✷ ❜❡❣✐♥ ✶✸ ✲✲ 172 Casa do Código Capítulo 12. Funções de agregação (grupo) ✶✹ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✺ ✲✲ ✶✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◗t❞❡✳ ❊♠♣r❡❣❛❞♦✿ ✬⑤⑤ ✶✼ r✶✳❝♦♥t❴❡♠♣⑤⑤✬ ❙♦♠❛ ❙❛❧✳✿ ✬⑤⑤r✶✳s♦♠❛❴s❛❧❛r✐♦⑤⑤ ✬ ❉❡♣t♦✳✿ ✬⑤⑤r✶✳❞❡♣❛rt♠❡♥t❴♥❛♠❡✮❀ ✶✽ ✶✾ ✲✲ ✷✵ ❡♥❞ ❧♦♦♣❀ ✷✶ ✲✲ ✷✷ ❡♥❞❀ ✷✸ ✴ ◗t❞❡✳ ❊♠♣r❡❣❛❞♦✿ ✻ ❙♦♠❛ ❙❛❧✳✿ ✺✶✻✵✵ ❉❡♣t♦✳✿ ❋✐♥❛♥❝❡ ◗t❞❡✳ ❊♠♣r❡❣❛❞♦✿ ✻ ❙♦♠❛ ❙❛❧✳✿ ✷✹✾✵✵ ❉❡♣t♦✳✿ P✉r❝❤❛s✐♥❣ ◗t❞❡✳ ❊♠♣r❡❣❛❞♦✿ ✸✹ ❙♦♠❛ ❙❛❧✳✿ ✸✵✹✺✵✵ ❉❡♣t♦✳✿ ❙❛❧❡s ◗t❞❡✳ ❊♠♣r❡❣❛❞♦✿ ✹✺ ❙♦♠❛ ❙❛❧✳✿ ✶✺✻✹✵✵ ❉❡♣t♦✳✿ ❙❤✐♣♣✐♥❣ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo, é mostrado o uso da cláusula having. O objetivo é selecionar a quantidade de empregados e a soma dos salários, agrupados por departamento, onde a quantidade de empregados é maior que 5. Observe que a cláusula having atua somente após o agrupamento das linhas. Por isso, não seria possível utilizar a cláusula where, pois ela atua no momento em que as linhas estão sendo selecionadas, ou seja, antes do agrupamento. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❞❡♣❛rt♠❡♥t❴♥❛♠❡✱ s✉♠✭s❛❧❛r②✮ s♦♠❛❴s❛❧✱ ❝♦✉♥tr②❴♥❛♠❡ ✺ ❢r♦♠ ❡♠♣❧♦②❡❡s ❡ ✻ ✱❞❡♣❛rt♠❡♥ts ❞ ✼ ✱❧♦❝❛t✐♦♥s ❧ ✽ ✱❝♦✉♥tr✐❡s ❝ ✾ ✇❤❡r❡ ❡✳❞❡♣❛rt♠❡♥t❴✐❞ ❂ ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ✶✵ ❛♥❞ ❞✳❧♦❝❛t✐♦♥❴✐❞ ❂ ❧✳❧♦❝❛t✐♦♥❴✐❞ ✶✶ ❛♥❞ ❧✳❝♦✉♥tr②❴✐❞ ❂ ❝✳❝♦✉♥tr②❴✐❞ ✶✷ ❤❛✈✐♥❣ s✉♠✭s❛❧❛r②✮ ❃ ✭s❡❧❡❝t ❛✈❣✭❡♠✳s❛❧❛r②✮ 173 Casa do Código ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ ✸✵ ✸✶ ✸✷ ❡♠♣❧♦②❡❡s ❡♠ ✱❞❡♣❛rt♠❡♥ts ❞♠ ✱❧♦❝❛t✐♦♥s ❧♠ ✱❝♦✉♥tr✐❡s ❝♠ ✇❤❡r❡ ❡♠✳❞❡♣❛rt♠❡♥t❴✐❞ ❂ ❞♠✳❞❡♣❛rt♠❡♥t❴✐❞ ❛♥❞ ❞♠✳❧♦❝❛t✐♦♥❴✐❞ ❂ ❧♠✳❧♦❝❛t✐♦♥❴✐❞ ❛♥❞ ❧♠✳❝♦✉♥tr②❴✐❞ ❂ ❝♠✳❝♦✉♥tr②❴✐❞ ❛♥❞ ❝♠✳❝♦✉♥tr②❴✐❞ ❂ ❝✳❝♦✉♥tr②❴✐❞✮ ❣r♦✉♣ ❜② ❝✳❝♦✉♥tr②❴✐❞ ✱❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✱❝♦✉♥tr②❴♥❛♠❡ ♦r❞❡r ❜② ❝♦✉♥tr②❴♥❛♠❡ ✱❞❡♣❛rt♠❡♥t❴♥❛♠❡❀ ✲✲ ❜❡❣✐♥ ✲✲ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤ r✶✳❞❡♣❛rt♠❡♥t❴♥❛♠❡⑤⑤✬ ❙♦♠❛ ❙❛❧✳✿ ✬⑤⑤r✶✳s♦♠❛❴s❛❧⑤⑤ ✸✸ ✬ ❈✐❞❛❞❡✿ ✬⑤⑤r✶✳❝♦✉♥tr②❴♥❛♠❡✮❀ ✸✹ ✲✲ ✸✺ ❡♥❞ ❧♦♦♣❀ ✸✻ ✲✲ ✸✼ ❡♥❞❀ ✸✽ ✴ ❉❡♣❛rt❛♠❡♥t♦✿ ▼❛r❦❡t✐♥❣ ❙♦♠❛ ❙❛❧✳✿ ✶✾✵✵✵ ❈✐❞❛❞❡✿ ❈❛♥❛❞❛ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❛❧❡s ❙♦♠❛ ❙❛❧✳✿ ✸✵✹✺✵✵ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❑✐♥❣❞♦♠ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❝❝♦✉♥t✐♥❣ ❙♦♠❛ ❙❛❧✳✿ ✷✵✸✵✵ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❙t❛t❡s ♦❢ ❆♠❡r✐❝❛ ❉❡♣❛rt❛♠❡♥t♦✿ ❊①❡❝✉t✐✈❡ ❙♦♠❛ ❙❛❧✳✿ ✺✽✵✵✵ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❙t❛t❡s ♦❢ ❆♠❡r✐❝❛ ❉❡♣❛rt❛♠❡♥t♦✿ ❋✐♥❛♥❝❡ ❙♦♠❛ ❙❛❧✳✿ ✺✶✻✵✵ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❙t❛t❡s ♦❢ ❆♠❡r✐❝❛ ❉❡♣❛rt❛♠❡♥t♦✿ ■❚ ❙♦♠❛ ❙❛❧✳✿ ✷✽✽✵✵ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❙t❛t❡s ♦❢ ❆♠❡r✐❝❛ ❉❡♣❛rt❛♠❡♥t♦✿ P✉r❝❤❛s✐♥❣ ❙♦♠❛ ❙❛❧✳✿ ✷✹✾✵✵ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❙t❛t❡s ♦❢ ❆♠❡r✐❝❛ 174 ❢r♦♠ Casa do Código Capítulo 12. Funções de agregação (grupo) ❉❡♣❛rt❛♠❡♥t♦✿ ❙❤✐♣♣✐♥❣ ❙♦♠❛ ❙❛❧✳✿ ✶✺✻✹✵✵ ❈✐❞❛❞❡✿ ❯♥✐t❡❞ ❙t❛t❡s ♦❢ ❆♠❡r✐❝❛ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Já nesse outro exemplo, o objetivo é selecionar a soma dos salários, agrupados por departamento e país, cuja seja maior que a média dos salários por país. 175 Capítulo 13 Funções de data Funções de data são utilizadas para manipularmos valores do tipo date, como aplicar formatações para uma visualização mais refinada, ou extrair partes de uma data, como as horas, dia do mês ou somente o ano. Seguem algumas delas: • add_months: adiciona meses em uma determinada data. • months_between: retorna a quantidade de meses entre duas datas. • next_day: procura o próximo dia após uma data informada. • last_day: retorna o último dia do mês com base em uma data informada. • trunc: trunca uma data passada por parâmetro. O trunc pode ser feito por dia e mês, utilizando o parâmetro FMT (formato). Casa do Código • sysdate: retorna a data corrente com base no servidor do banco de dados. • sessiontimezone: mostra o fuso horário com base na sessão aberta no banco de dados, mediante sua localização. Vale lembrar que os fusos horários são calculados com base no meridiano de Greenwich. • current_date: mostra a data corrente com base na zona de tempo da sessão do usuário. A zona de tempo é afetada em relação ao Meridiano. Caso não haja mudanças de zona, esta função terá o mesmo valor que sysdate. sysdate busca a hora do servidor do banco de dados; mesmo que a sessão tenha sido aberta em uma zona diferente da qual o servidor encontra-se, ele refletirá o horário da zona onde está o servidor. Já o current_date refletirá a zona onde foi aberta a sessão. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇❞t❴❛❞♠✐ss❛♦ ❞❛t❡❀ ✹ ✇s❡①t❛ ❞❛t❡❀ ✺ ✲✲ ✻ ❝✉rs♦r ❝✶ ✐s ✼ s❡❧❡❝t ❢✐rst❴♥❛♠❡ ✽ ✱❤✐r❡❴❞❛t❡ ✾ ❢r♦♠ ❡♠♣❧♦②❡❡s ✶✵ ✇❤❡r❡ t♦❴❝❤❛r✭❤✐r❡❴❞❛t❡✱✬♠♠✬✮ ❂ t♦❴❝❤❛r✭s②s❞❛t❡✱✬♠♠✬✮ ✶✶ ♦r❞❡r ❜② ✷❀ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ✲✲ ✶✺ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✻ ✲✲ ✶✼ ✇❞t❴❛❞♠✐ss❛♦ ✿❂ t♦❴❞❛t❡✭t♦❴❝❤❛r✭ r✶✳❤✐r❡❴❞❛t❡✱✬❞❞✴♠♠✬✮⑤⑤✬✴✬⑤⑤ ✶✽ t♦❴❝❤❛r✭s②s❞❛t❡✱✬rrrr✬✮✱✬❞❞✴♠♠✴rrrr✬✮❀ ✶✾ ✇s❡①t❛ ✿❂ ♥❡①t❴❞❛②✭t♦❴❞❛t❡✭ t♦❴❝❤❛r✭r✶✳❤✐r❡❴❞❛t❡✱✬❞❞✴♠♠✬✮⑤⑤✬✴✬ ✷✵ ⑤⑤t♦❴❝❤❛r✭s②s❞❛t❡✱✬rrrr✬✮✱✬❞❞✴♠♠✴rrrr✬✮ ✱✬❋❘■❉❆❨✬✮❀ 178 Casa do Código Capítulo 13. Funções de data ✷✶ ✷✷ ✷✸ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤ r✶✳❢✐rst❴♥❛♠❡⑤⑤✬ ❉t✳ ❆❞♠✐ssã♦✿ ✬⑤⑤✇❞t❴❛❞♠✐ss❛♦⑤⑤ ✬ ❙❡①t❛ ❞❡ ❋♦❧❣❛✿ ✬⑤⑤✇s❡①t❛✮❀ ✷✹ ✷✺ ✲✲ ✷✻ ❡♥❞ ❧♦♦♣❀ ✷✼ ✲✲ ✷✽ ❡♥❞❀ ✷✾ ✴ ◆♦♠❡✿ ❈❧❛r❛ ❉t✳ ❆❞♠✐ssã♦✿ ✶✶✲◆❖❱✲✶✶ ❙❡①t❛ ❞❡ ❋♦❧❣❛✿ ✶✽✲◆❖❱✲✶✶ ◆♦♠❡✿ ❙❛r❛t❤ ❉t✳ ❆❞♠✐ssã♦✿ ✵✸✲◆❖❱✲✶✶ ❙❡①t❛ ❞❡ ❋♦❧❣❛✿ ✵✹✲◆❖❱✲✶✶ ◆♦♠❡✿ ●✉② ❉t✳ ❆❞♠✐ssã♦✿ ✶✺✲◆❖❱✲✶✶ ❙❡①t❛ ❞❡ ❋♦❧❣❛✿ ✶✽✲◆❖❱✲✶✶ ◆♦♠❡✿ ❑❡✈✐♥ ❉t✳ ❆❞♠✐ssã♦✿ ✶✻✲◆❖❱✲✶✶ ❙❡①t❛ ❞❡ ❋♦❧❣❛✿ ✶✽✲◆❖❱✲✶✶ ◆♦♠❡✿ ❖❧✐✈❡r ❉t✳ ❆❞♠✐ssã♦✿ ✷✸✲◆❖❱✲✶✶ ❙❡①t❛ ❞❡ ❋♦❧❣❛✿ ✷✺✲◆❖❱✲✶✶ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo foi mostrado o uso da função next_day, onde selecionamos os empregados que têm como mês de admissão o mês corrente. Através dessa função é calculada qual a primeira sexta-feira logo em seguida ao dia da admissão de cada empregado. Este dia será o dia da folga dele. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇❞t❴t❡r♠✐♥♦❴❡①♣ ❞❛t❡❀ ✹ ✇qt❴♠❡s❡s❴tr❛❜❛❧❤♦ ♥✉♠❜❡r❀ ✺ ✲✲ ✻ ❝✉rs♦r ❝✶ ✐s ✼ s❡❧❡❝t ❡♥❛♠❡✱ ❞♥❛♠❡ ✽ ✱❤✐r❡❞❛t❡ ✾ ❢r♦♠ ❡♠♣ ❡✱ ❞❡♣t ❞ ✶✵ ✇❤❡r❡ ❡✳❞❡♣t♥♦ ❂ ❞✳❞❡♣t♥♦ ✶✶ ❛♥❞ ❛❞❞❴♠♦♥t❤s✭❤✐r❡❞❛t❡✱✸✺✵✮ ❃❂ s②s❞❛t❡❀ ✶✷ ✶✸ ✲✲ ✶✹ ❜❡❣✐♥ 179 Casa do Código ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✲✲ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✲✲ ✇❞t❴t❡r♠✐♥♦❴❡①♣ ✿❂ ❛❞❞❴♠♦♥t❤s✭r✶✳❤✐r❡❞❛t❡✱✸✮❀ ✇qt❴♠❡s❡s❴tr❛❜❛❧❤♦ ✿❂ t♦❴❝❤❛r✭♠♦♥t❤s❴❜❡t✇❡❡♥✭ s②s❞❛t❡✱r✶✳❤✐r❡❞❛t❡✮✱✬✾✾✵❉✵✵✬✮❀ ✷✵ ✲✲ ✷✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ✬⑤⑤ ✬❉❡♣t♦✿ ✬⑤⑤r✶✳❞♥❛♠❡⑤⑤✬ ✬⑤⑤ ✷✷ ✷✸ ✬❉t✳ ❆❞♠✐ssã♦✿ ✬⑤⑤r✶✳❤✐r❡❞❛t❡⑤⑤✬ ✬⑤⑤ ✬❚ér♠✐♥♦ ❊①♣✳✿ ✬⑤⑤✇❞t❴t❡r♠✐♥♦❴❡①♣⑤⑤✬ ✬⑤⑤ ✷✹ ✷✺ ✬◗t❞❡✳ ▼❡s❡s ❚r❛❜✳✿ ✬⑤⑤✇qt❴♠❡s❡s❴tr❛❜❛❧❤♦ ✷✻ ✮❀ ✷✼ ✲✲ ✷✽ ❡♥❞ ❧♦♦♣❀ ✷✾ ✲✲ ✸✵ ❡♥❞❀ ✸✶ ✴ ◆♦♠❡✿ ❆❉❆▼❙ ❉❡♣t♦✿ ❘❊❙❊❆❘❈❍ ❉t✳ ❆❞♠✐ssã♦✿ ✶✷✲❏❆◆✲✽✸ ❚ér♠✐♥♦ ❊①♣✳✿ ✶✷✲❆P❘✲✽✸ ◗t❞❡✳ ▼❡s❡s ❚r❛❜✳✿ ✸✹✻✳✻✶ ◆♦♠❡✿ ❙❈❖❚❚ ❉❡♣t♦✿ ❘❊❙❊❆❘❈❍ ❉t✳ ❆❞♠✐ssã♦✿ ✵✾✲❉❊❈✲✽✷ ❚ér♠✐♥♦ ❊①♣✳✿ ✵✾✲▼❆❘✲✽✸ ◗t❞❡✳ ▼❡s❡s ❚r❛❜✳✿ ✸✹✼✳✼✶ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo foi mostrado o uso das funções add_months e months_between. O exemplo seleciona os empregados e suas respectivas datas de término de experiência do cargo. Note que limitamos o número de empregados no select, através da função add_months, para evitar o retorno de todas as linhas da tabela. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❡ss✐♦♥t✐♠❡③♦♥❡ ✈❛r❝❤❛r✭✶✵✮❀ ✸ ✇❝✉rr❡♥t❴❞❛t❡ ❞❛t❡❀ ✹ ✇s②s❞❛t❡ ❞❛t❡❀ 180 Casa do Código Capítulo 13. Funções de data ✺ ❜❡❣✐♥ ✻ ✇s❡ss✐♦♥t✐♠❡③♦♥❡ ✿❂ s❡ss✐♦♥t✐♠❡③♦♥❡❀ ✼ ✇❝✉rr❡♥t❴❞❛t❡ ✿❂ ❝✉rr❡♥t❴❞❛t❡❀ ✽ ✇s②s❞❛t❡ ✿❂ s②s❞❛t❡❀ ✾ ✲✲ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❋✉s♦ ❍♦rár✐♦✿ ✬⑤⑤✇s❡ss✐♦♥t✐♠❡③♦♥❡⑤⑤✬ ✬⑤⑤ ✬❉❛t❛ ❈♦rr❡♥t❡✿ ✬⑤⑤✇❝✉rr❡♥t❴❞❛t❡⑤⑤✬ ✬⑤⑤ ✶✶ ✬❉❛t❛ ❆t✉❛❧✿ ✬⑤⑤✇s②s❞❛t❡✮❀ ✶✷ ✶✸ ✲✲ ✶✹ ❡♥❞❀ ✶✺ ✴ ❋✉s♦ ❍♦rár✐♦✿ ✲✵✸✿✵✵ ❉❛t❛ ❈♦rr❡♥t❡✿ ✸✵✲◆❖❱✲✶✶ ❉❛t❛ ❆t✉❛❧✿ ✸✵✲◆❖❱✲✶✶ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo foi mostrado o uso das funções sessiontimezone, current_date e sysdate.Exibimos o fuso horário, a data corrente local e data atual do servidor. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇❧❛st ❞❛t❡❀ ✹ ✇r♦✉♥❞ ❞❛t❡❀ ✺ ✇tr✉♥❝ ❞❛t❡❀ ✻ ✲✲ ✼ ❝✉rs♦r ❝✶ ✐s ✽ s❡❧❡❝t ❡♥❛♠❡ ✾ ✱❤✐r❡❞❛t❡ ✶✵ ❢r♦♠ ❡♠♣ ✶✶ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵❀ ✶✷ ✲✲ ✶✸ ❜❡❣✐♥ ✶✹ ✲✲ ✶✺ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✻ ✲✲ 181 Casa do Código ✶✼ ✇❧❛st ✿❂ ❧❛st❴❞❛②✭r✶✳❤✐r❡❞❛t❡✮❀ ✶✽ ✇r♦✉♥❞ ✿❂ r♦✉♥❞✭r✶✳❤✐r❡❞❛t❡✱ ✬❨❊❆❘✬✮❀ ✶✾ ✇tr✉♥❝ ✿❂ tr✉♥❝✭r✶✳❤✐r❡❞❛t❡✱ ✬❨❊❆❘✬✮❀ ✷✵ ✲✲ ✷✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ✬⑤⑤ ✷✷ ✬❉t✳ ❆❞♠✐ssã♦✿ ✬⑤⑤r✶✳❤✐r❡❞❛t❡⑤⑤✬ ✬⑤⑤ ✷✸ ✬Ú❧t✐♠♦ ❞✐❛ ▼ês ❆❞♠✐ssã♦✿ ✬⑤⑤✇❧❛st⑤⑤✬ ✬⑤⑤ ✬❆rr❡❞♦♥❞❛ ❆♥♦ ❆❞♠✐ssã♦✳✿ ✬⑤⑤✇r♦✉♥❞⑤⑤✬ ✬⑤⑤ ✷✹ ✬tr✉♥❝ ❆♥♦ ❆❞♠✐ssã♦✿ ✬⑤⑤✇tr✉♥❝ ✷✺ ✷✻ ✮❀ ✷✼ ✲✲ ✷✽ ❡♥❞ ❧♦♦♣❀ ✷✾ ✲✲ ✸✵ ❡♥❞❀ ✸✶ ✴ ◆♦♠❡✿ ❙▼■❚❍ ❉t✳ ❆❞♠✐ssã♦✿ ✶✼✲❉❊❈✲✽✵ Ú❧t✐♠♦ ❞✐❛ ▼ês ❆❞♠✐ssã♦✿ ✸✶✲❉❊❈✲✽✵ ❆rr❡❞♦♥❞❛ ❆♥♦ ❆❞♠✐ssã♦✳✿ ✵✶✲❏❆◆✲✽✶ tr✉♥❝ ❆♥♦ ❆❞♠✐ssã♦✿ ✵✶✲❏❆◆✲✽✵ ◆♦♠❡✿ ❏❖◆❊❙ ❉t✳ ❆❞♠✐ssã♦✿ ✵✷✲❆P❘✲✽✶ Ú❧t✐♠♦ ❞✐❛ ▼ês ❆❞♠✐ssã♦✿ ✸✵✲❆P❘✲✽✶ ❆rr❡❞♦♥❞❛ ❆♥♦ ❆❞♠✐ssã♦✳✿ ✵✶✲❏❆◆✲✽✶ tr✉♥❝ ❆♥♦ ❆❞♠✐ssã♦✿ ✵✶✲❏❆◆✲✽✶ ◆♦♠❡✿ ❙❈❖❚❚ ❉t✳ ❆❞♠✐ssã♦✿ ✵✾✲❉❊❈✲✽✷ Ú❧t✐♠♦ ❞✐❛ ▼ês ❆❞♠✐ssã♦✿ ✸✶✲❉❊❈✲✽✷ ❆rr❡❞♦♥❞❛ ❆♥♦ ❆❞♠✐ssã♦✳✿ ✵✶✲❏❆◆✲✽✸ tr✉♥❝ ❆♥♦ ❆❞♠✐ssã♦✿ ✵✶✲❏❆◆✲✽✷ ◆♦♠❡✿ ❆❉❆▼❙ ❉t✳ ❆❞♠✐ssã♦✿ ✶✷✲❏❆◆✲✽✸ Ú❧t✐♠♦ ❞✐❛ ▼ês ❆❞♠✐ssã♦✿ ✸✶✲❏❆◆✲✽✸ ❆rr❡❞♦♥❞❛ ❆♥♦ ❆❞♠✐ssã♦✳✿ ✵✶✲❏❆◆✲✽✸ tr✉♥❝ ❆♥♦ ❆❞♠✐ssã♦✿ ✵✶✲❏❆◆✲✽✸ ◆♦♠❡✿ ❋❖❘❉ ❉t✳ ❆❞♠✐ssã♦✿ ✵✸✲❉❊❈✲✽✶ Ú❧t✐♠♦ ❞✐❛ ▼ês ❆❞♠✐ssã♦✿ ✸✶✲❉❊❈✲✽✶ ❆rr❡❞♦♥❞❛ ❆♥♦ ❆❞♠✐ssã♦✳✿ ✵✶✲❏❆◆✲✽✷ tr✉♥❝ ❆♥♦ ❆❞♠✐ssã♦✿ ✵✶✲❏❆◆✲✽✶ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo foi mostrado o uso das funções last_day, round e trunc. Perceba várias formas de usar as funções para extrair ou manipular determinadas informações, por exemplo arredondar e truncar datas. 182 Capítulo 14 Funções de conversão Em muitos casos, precisamos converter um determinado dado de um tipo para outro. A Oracle disponibiliza funções de conversão para este trabalho. Essas funções, embora sejam simples de serem usadas, ajudam em muito no momento de converter ou formatar dados provenientes dos seus comandos SQL ou programas PL/SQL. • to_date: converte uma string ( char ou varchar2) de caractere para uma data; • to_number: converte uma string ( char ou varchar2) de caractere para um número; • to_char: converte um número ou uma data para uma string de caractere. 14.1. to_date Casa do Código Cada função possui suas características e é utilizada para cumprir um objetivo diferente. O que elas possuem em comum é o número de parâmetros. O primeiro parâmetro está relacionado ao valor que deve ser convertido, o segundo corresponde ao formato que você deseja aplicar e, por último e opcional, o parâmetro de linguagem. Trata-se de funções muito utilizadas no dia a dia, e é de fundamental importância conhecê-las e entender como se comportam. Além das mencionadas na lista, a Oracle disponibiliza várias outras funções para as mais diversas situações. Contudo, essas três são as que mais comumente utilizamos na escrita de nossos programas. Para saber mais sobre outras funções de conversão, consulte a documentação disponível no site da Oracle. 14.1 to_date Esta função é bem interessante. Com um pouco de treino e criatividade, podemos realizar várias conversões que podem ajudar muito no momento de formatar, selecionar ou criticar os dados retornados de um comando SQL. Ela funciona basicamente da seguinte forma: você vai passar um valor caractere para função, juntamente com um formato, que deve ser compatível com o conjunto de caracteres que você passou. Qualquer incompatibilidade, o Oracle gera um erro de conversão. Exemplo: to_date(‘21/05/2009’,’dd/mm’). Esta conversão vai gerar um erro, pois você está informando dia, mês e ano, como caractere, mas na máscara só mencionou dia e mês. Quando o Oracle vai fazer a conversão, ele analisa o formato que você está passando como parâmetro e verifica o que é elemento de função e o que é caractere. Neste caso, ele sabe que dd e mm são elementos conhecidos de dia e mês, e que / é um caractere que serve como uma espécie de separador. Depois desta identificação, ele pega cada caractere informado e vai convertendo conforme o formato. 2=d, 1=d,/=/,0=m,5=m etc. Mas quando ele chega à segunda / vê que não há formato para o caractere, pois terminou no elemento m. Logo, é gerado um erro de conversão. Veja a execução: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❛ ❞❛t❡❀ 184 Casa do Código Capítulo 14. Funções de conversão ✸ ❜❡❣✐♥ ✹ ✇❞❛t❛ ✿❂ t♦❴❞❛t❡✭✬✷✶✴✵✺✴✷✵✵✾✬✱✬❞❞✴♠♠✬✮❀ ✺ ❡♥❞❀ ✻ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ ❖❘❆✲✵✶✽✸✵✿ ❞❛t❡ ❢♦r♠❛t ♣✐❝t✉r❡ ❡♥❞s ❜❡❢♦r❡ ❝♦♥✈❡rt✐♥❣ ❡♥t✐r❡ ✐♥♣✉t str✐♥❣ ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❙◗▲❃ O contrário também gera outro erro: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❛ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❛ ✿❂ t♦❴❞❛t❡✭✬✷✶✴✵✺✬✱✬❞❞✴♠♠✴②②②②✬✮❀ ✺ ❡♥❞❀ ✻ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ ❖❘❆✲✵✶✽✹✵✿ ✐♥♣✉t ✈❛❧✉❡ ♥♦t ❧♦♥❣ ❡♥♦✉❣❤ ❢♦r ❞❛t❡ ❢♦r♠❛t ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❙◗▲❃ Seguem exemplos do uso do to_date: ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❡♥❛♠❡ ✸ ✱❤✐r❡❞❛t❡ ✹ ❢r♦♠ ❡♠♣ ✺ ✇❤❡r❡ ❤✐r❡❞❛t❡ ❃ t♦❴❞❛t❡✭✬✵✶✵✶✽✷✬✱✬❞❞♠♠rr✬✮✮ ❧♦♦♣ ✻ ✲✲ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤ 185 14.1. to_date Casa do Código ✽ ✬ ✲ ❉❛t❛ ❞❡ ❆❞♠✐ssã♦✿ ✬⑤⑤r✶✳❤✐r❡❞❛t❡✮❀ ✾ ✲✲ ✶✵ ❡♥❞ ❧♦♦♣❀ ✶✶ ❡♥❞❀ ✶✷ ✴ ❊♠♣r❡❣❛❞♦✿ ❙❈❖❚❚ ✲ ❉❛t❛ ❞❡ ❆❞♠✐ssã♦✿ ✵✾✲❉❊❈✲✽✷ ❊♠♣r❡❣❛❞♦✿ ❆❉❆▼❙ ✲ ❉❛t❛ ❞❡ ❆❞♠✐ssã♦✿ ✶✷✲❏❆◆✲✽✸ ❊♠♣r❡❣❛❞♦✿ ▼■▲▲❊❘ ✲ ❉❛t❛ ❞❡ ❆❞♠✐ssã♦✿ ✷✸✲❏❆◆✲✽✷ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo mostrou como é possível converter strings em datas válidas. Veja que na linha 5 do programa temos a função convertendo a string 010182 para uma data utilizando o formato DDMMRR. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✬✷✶✳✵✺✳✷✵✵✾✬✱✬❞❞✳♠♠✳②②②②✬✮❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✼ ❡♥❞❀ ✽ ✴ ❉❛t❛✿ ✷✶✲▼❆❨✲✵✾ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Já nesse outro exemplo, também utilizando to_date, note que na linha 4 do programa, temos a função convertendo outra string em uma data, utilizando um formato diferente. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✬❆♣r✐❧ ✷✶✬✱✬♠♦♥t❤ ❞❞✬✱ 186 Casa do Código Capítulo 14. Funções de conversão ✬♥❧s❴❞❛t❡❴❧❛♥❣✉❛❣❡❂❛♠❡r✐❝❛♥✬✮❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✼ ❡♥❞❀ ✽ ✴ ❉❛t❛✿ ✷✶✲❆P❘✲✶✶ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Podemos também adicionar à chamada da função aspectos referentes à linguagem. Nesse último exemplo, estamos convertendo uma string por extenso em data, utilizando o formato americano. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✬❆❜r✐❧ ✷✶✬✱✬♠♦♥t❤ ❞❞✬✱ ✺ ✬♥❧s❴❞❛t❡❴❧❛♥❣✉❛❣❡❂✬✬❇❘❆❩■▲■❆◆ P❖❘❚❯●❯❊❙❊✬✬✬✮❀ ✻ ✲✲ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✽ ❡♥❞❀ ✾ ✴ ❉❛t❛✿ ✷✶✲❆P❘✲✶✶ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Contudo, como pôde ser visto no exemplo anterior, a visualização continua sendo no formato americano, embora estejamos convertendo a string para data utilizando o formato brasileiro. Lembre-se, conversão não necessariamente, tem a ver com a forma com que o dado será impresso na tela. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✬❆❜r✐❧ ✷✶✬✱✬♠♦♥t❤ ❳❳✬✱ 187 14.1. to_date Casa do Código ✺ ✬♥❧s❴❞❛t❡❴❧❛♥❣✉❛❣❡❂✬✬❇❘❆❩■▲■❆◆ P❖❘❚❯●❯❊❙❊✬✬✬✮❀ ✻ ✲✲ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✽ ❡♥❞❀ ✾ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ ❖❘❆✲✵✶✽✷✶✿ ❞❛t❡ ❢♦r♠❛t ♥♦t r❡❝♦❣♥✐③❡❞ ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❙◗▲❃ Esse exemplo, mostra que devemos informar formatos válidos, ou melhor, formatos conhecidos da linguagem. Caso contrário, a conversão não é realizada e erros ocorrerão. A seguir, algumas limitações com relação a função to_date: • A String a ser passada para a conversão não pode conter mais de 220 caracteres; • Existem vários formatos de máscara disponíveis para a utilização. Qualquer máscara diferente das permitidas pela Oracle gerará um erro de conversão; • Não pode haver confronto de máscaras. Exemplo: caso você queira utilizar a máscara HH24 e também solicitar que seja mostrado AM (indicador de antemeridiano para manhã) ou PM (indicador de pósmeridiano para noite). • Não é permitido especificar elementos de conversão duplicados. Exemplo: ‘DD-MM-MM’. Neste caso, o formato para mês aparece duas vezes. Veja alguns elementos de formatação que podem ser usados: • CC: adiciona 1 aos dois primeiros dígitos do ano (YYYY). • SCC: igual CC, prefixando datas BC com um sinal negativo. 188 Casa do Código Capítulo 14. Funções de conversão • YY: representa o ano com duas casas. • YYYY: representa o ano com quatro casas. • RR: representa os dois últimos dígitos do ano, mas obedecendo à seguinte regra: soma 1 aos dois primeiros dígitos de CC se ano for < 50 e os últimos 2 dígitos do ano corrente forem >= 50. Subtrai 1 de CC se ano >= 50 e os últimos dois dígitos do ano corrente forem < 50. • RRRR: representa o ano. Aceita 2 ou 4 dígitos. Se ano informado com 2 dígitos, segue as mesmas regras de RR. • YEAR: escreve o ano por extenso. • MM: número do mês de 01 a 12. 01 = Janeiro, 02 = Fevereiro etc. • MONTH: nome do mês. • MON: representa o nome do mês abreviado com três caracteres. • DD: dia do mês de 1 a 31. • DDD: representa o dia do ano de 1 a 366. • DAY: representa o nome do dia por extenso. • HH, HH12, HH24: HH e HH12, horas de 1 a 12. HH24, horas de 0 a 23. • MI: equivale aos minutos de 0 a 59. • SS: equivale aos segundos de 0 a 59. • SP: converte o número para seu formato escrito. Disponível apenas para a escrita no idioma inglês. • SPTH: mostra os números de maneira ordinal. 1 = First, 2 = Second etc. • FM: retira espaços em branco proveniente da ausência de caracteres em um formato. 189 14.1. to_date Casa do Código Nota: estes elementos também são utilizados na conversão do tipo date para String. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✬✷✵✵✽✬✱✬②②②②✬✮❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✼ ❡♥❞❀ ✽ ✴ ❉❛t❛✿ ✵✶✲◆❖❱✲✵✽ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ A função to_date, pode converter não só strings representando datas completas, como também strings representando partes de uma data. Esse exemplo mostra a função realizando a conversão da string 2008 em data. Note que, ao ser impresso o valor da variável, a qual recebeu o dado convertido, ele recebeu a atribuição da data atual, modificado apenas pelo ano convertido. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✷✵✵✱✬❞❞❞✬✮❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✼ ❡♥❞❀ ✽ ✴ ❉❛t❛✿ ✶✾✲❏❯▲✲✶✶ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ 190 Casa do Código Capítulo 14. Funções de conversão Esse exemplo é similar ao anterior. Aqui está sendo realizada a conversão com base na representação numérica do dia referente ao total de dias do ano. Uso de YYYY e RRRR Sabemos que a máscara YYYY representa os quatro dígitos do ano. Opcionalmente, pode-se utilizar YY para mostrar apenas os dois últimos dígitos. Contudo, para corrigir problemas de compatibilidade com a virada do século, a Oracle criou as máscaras RR e RRRR. Veja a aplicação a seguir: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ✈❛r❝❤❛r✷✭✺✵✮❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❝❤❛r✭s②s❞❛t❡✱✬❞❞✴♠♠✴②②②②✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✻ ✲✲ ✼ ✇❞❛t❡ ✿❂ t♦❴❝❤❛r✭ t♦❴❞❛t❡✭✬✵✶✴✵✶✴✹✾✬✱✬❞❞✴♠♠✴②②✬✮✱✬❞❞✴♠♠✴②②②②✬✮❀ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✾ ✲✲ ✶✵ ✇❞❛t❡ ✿❂ t♦❴❝❤❛r✭t♦❴❞❛t❡✭ ✬✵✶✴✵✶✴✺✵✬✱✬❞❞✴♠♠✴②②✬✮✱✬❞❞✴♠♠✴②②②②✬✮❀ ✶✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✶✷ ✲✲ ✶✸ ✇❞❛t❡ ✿❂ t♦❴❝❤❛r✭ t♦❴❞❛t❡✭✬✵✶✴✵✶✴✹✾✬✱✬❞❞✴♠♠✴rr✬✮✱✬❞❞✴♠♠✴rrrr✬✮❀ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✶✺ ✲✲ ✶✻ ✇❞❛t❡ ✿❂ t♦❴❝❤❛r✭ t♦❴❞❛t❡✭✬✵✶✴✵✶✴✺✵✬✱✬❞❞✴♠♠✴rr✬✮✱✬❞❞✴♠♠✴rrrr✬✮❀ ✶✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✶✽ ✲✲ ✶✾ ❡♥❞❀ ✷✵ ✴ ❉❛t❛✿ ✸✵✴✶✶✴✷✵✶✶ ❉❛t❛✿ ✵✶✴✵✶✴✷✵✹✾ ❉❛t❛✿ ✵✶✴✵✶✴✷✵✺✵ ❉❛t❛✿ ✵✶✴✵✶✴✷✵✹✾ ❉❛t❛✿ ✵✶✴✵✶✴✶✾✺✵ 191 14.2. to_number Casa do Código P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo, vemos formatações de datas utilizando a função to_char, juntamente com os elementos de formatação YY e RR. Note que podemos ter datas diferentes ao converter utilizando RR e YY, dependendo do ano da data informada. Para mais detalhes e compreensão desse exemplo, consulte as regras do uso do formato RR na lista de elementos de formatação vista anteriormente. 14.2 to_number Muito semelhante à função to_date, esta função também tem o papel de converter determinados valores. Seu objetivo, no entanto, é fazer a conversão de caracteres para numéricos. Quando falamos na função to_date, foi mencionado que o valor do caractere que está sendo informado como parâmetro deve ser compatível com o formato. Pois bem, quando trabalhamos com to_number, o mesmo também acontece. Ao informarmos um valor caractere para a função to_number, ele deve ser compatível com o formato que estamos passando para a função. Todavia, existe uma particularidade quanto ao formato para casas decimais e de grupo (milhar, por exemplo). Para cálculos internos do Oracle, sempre será usado ponto ( .) como separador decimal e vírgula ( ,) para separador de grupo, como padrão americano. Para atribuições de variáveis do tipo caractere ou para visualização, o Oracle pegará a formatação conforme estiver configurado na variável nls_numeric_characters. Uma das razões de o Oracle utilizar esta premissa talvez seja pelo fato de a vírgula ser utilizada para a separação de valores ou colunas em um comando SQL. Veja o exemplo: Fazendo um select do número 111,1 utilizando vírgula como separador decimal. 192 Casa do Código Capítulo 14. Funções de conversão ❙◗▲❃ s❡❧❡❝t ✶✶✶✱✶ ❢r♦♠ ❞✉❛❧❀ ✶✶✶ ✶ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✶✶✶ ✶ ❙◗▲❃ Agora, executando o mesmo select, mas utilizando o ponto como separador decimal. ❙◗▲❃ s❡❧❡❝t ✶✶✶✳✶ ❢r♦♠ ❞✉❛❧❀ ✶✶✶✳✶ ✲✲✲✲✲✲✲✲✲✲ ✶✶✶✳✶ ❙◗▲❃ No primeiro exemplo, o comando SQL acabou entendendo que 111 era um dado e 1 era outro. O mesmo não aconteceu quando, em vez de separarmos por vírgula, separamos por ponto. Vejamos o exemplo a seguir. Nele estamos tentando converter um valor onde temos como separador de decimais a vírgula ( ,), e para milhar, o ponto ( .). Pois bem, já sabemos que para cálculos de conversões internas o Oracle utiliza o ponto como decimal. Logo, o comando SQL a seguir gera um erro. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇✈❛❧♦r ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✇✈❛❧♦r ✿❂ t♦❴♥✉♠❜❡r✭✬✹✳✺✻✾✳✾✵✵✱✽✼✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❱❛❧♦r✿ ✬⑤⑤✇✈❛❧♦r✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ ❖❘❆✲✵✻✺✵✷✿ P▲✴❙◗▲✿ ♥✉♠❡r✐❝ ♦r ✈❛❧✉❡ ❡rr♦r✿ ❝❤❛r❛❝t❡r t♦ ♥✉♠❜❡r 193 Casa do Código 14.2. to_number ❝♦♥✈❡rs✐♦♥ ❡rr♦r ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❙◗▲❃ Ok! O erro acontece porque onde há vírgula deveria ser ponto e onde há ponto deveria ser vírgula. Pois bem, vejamos o select a seguir: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇✈❛❧♦r ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✇✈❛❧♦r ✿❂ t♦❴♥✉♠❜❡r✭✬✹✱✺✻✾✱✾✵✵✳✽✼✬✮ ❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❱❛❧♦r✿ ✬⑤⑤✇✈❛❧♦r✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ ❖❘❆✲✵✻✺✵✷✿ P▲✴❙◗▲✿ ♥✉♠❡r✐❝ ♦r ✈❛❧✉❡ ❡rr♦r✿ ❝❤❛r❛❝t❡r t♦ ♥✉♠❜❡r ❝♦♥✈❡rs✐♦♥ ❡rr♦r ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❙◗▲❃ Agora você deve estar se perguntando: “Mas por que o erro, sendo que tudo indica que agora o formato foi informado corretamente, ponto para decimais e vírgula para milhares?”. Pois bem, veja o select a seguir: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ 194 ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❆▲▲❊◆ ❲❆❘❉ ❏❖◆❊❙ ❏❖❇ ▼●❘ ❍■❘❊❉❆❚❊ ❙❆▲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✼✾✵✷ ✶✼✲❉❊❈✲✽✵ ✽✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✵✲❋❊❇✲✽✶ ✶✻✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✷✲❋❊❇✲✽✶ ✶✷✺✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✷✲❆P❘✲✽✶ ✸✷✼✷✳✺ Casa do Código ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ ✽✵✵✵ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ ❏❖❍◆ Capítulo 14. Funções de conversão ❙❆▲❊❙▼❆◆ ▼❆◆❆●❊❘ ▼❆◆❆●❊❘ ❆◆❆▲❨❙❚ P❘❊❙■❉❊◆❚ ❱❊◆❉❊❉❖❘ ❈▲❊❘❑ ❈▲❊❘❑ ❆◆❆▲❨❙❚ ❈▲❊❘❑ ❈▲❊❘❑ ✼✻✾✽ ✼✽✸✾ ✼✽✸✾ ✼✺✻✻ ✼✻✾✽ ✼✼✽✽ ✼✻✾✽ ✼✺✻✻ ✼✼✽✷ ✼✾✵✷ ✷✽✲❙❊P✲✽✶ ✵✶✲▼❆❨✲✽✶ ✵✾✲❏❯◆✲✽✶ ✵✾✲❉❊❈✲✽✷ ✶✼✲◆❖❱✲✽✶ ✵✽✲❙❊P✲✽✶ ✶✷✲❏❆◆✲✽✸ ✵✸✲❉❊❈✲✽✶ ✵✸✲❉❊❈✲✽✶ ✷✸✲❏❆◆✲✽✷ ✸✵✲▼❆❘✲✶✶ ✶✷✺✵ ✷✽✺✵ ✷✹✺✵ ✸✵✵✵ ✺✵✵✵ ✶✺✵✵ ✶✶✵✵ ✾✺✵ ✸✵✵✵ ✶✸✵✵ ✶✵✵✵ ❈❖▼▼ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✷✵ ✸✵✵ ✸✵ ✺✵✵ ✸✵ ✷✵ ✶✹✵✵ ✸✵ ✸✵ ✶✵ ✷✵ ✶✵ ✵ ✸✵ ✷✵ ✸✵ ✷✵ ✶✵ ✷✵✵ ✷✵ ✶✺ r♦✇s s❡❧❡❝t❡❞✳ ❙◗▲❃ Observe a coluna SAL, mais precisamente o registro EMPNO=7566. Veja que o valor do salário está aparecendo como 3272.5. Este número possui como separador de decimais o caractere ponto, mas não possui separador de grupo de milhar. Isso nos leva à conclusão de que, além de sabermos as regras para pontos 195 14.2. to_number Casa do Código e vírgulas, também devemos estar cientes de como está definida a sessão do Oracle. No Oracle, a formatação de milhar não aparece, a menos que seja aplicada para tal. Vamos voltar ao exemplo anterior, agora com a formatação: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇✈❛❧♦r ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✇✈❛❧♦r ✿❂ t♦❴♥✉♠❜❡r✭✬✹✳✺✻✾✳✾✵✵✱✽✼✬✱✬✾●✾✾✾●✾✾✾❉✵✵✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❱❛❧♦r✿ ✬⑤⑤✇✈❛❧♦r✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ ❖❘❆✲✵✻✺✵✷✿ P▲✴❙◗▲✿ ♥✉♠❡r✐❝ ♦r ✈❛❧✉❡ ❡rr♦r ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❙◗▲❃ Ainda sim o erro persiste. Também pudera, vimos no registro EMPNO=7566 que, na sessão do Oracle, está definido como casa decimal o ponto, e não a vírgula. Vamos trocar: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇✈❛❧♦r ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✇✈❛❧♦r ✿❂ t♦❴♥✉♠❜❡r✭✬✹✱✺✻✾✱✾✵✵✳✽✼✬✱✬✾●✾✾✾●✾✾✾❉✵✵✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❱❛❧♦r✿ ✬⑤⑤✇✈❛❧♦r✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❱❛❧♦r✿ ✹✺✻✾✾✵✵✳✽✼ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ 196 Casa do Código Capítulo 14. Funções de conversão Bingo! Este comando select funcionou por duas razões. Primeira: o valor passado no formato caractere possui um número válido que contém como separador de casas decimais o mesmo definido na sessão do Oracle. Segundo: foi definido um formato onde estipulamos que neste conjunto de caracteres há separadores de grupo o qual representamos com o elemento de função G. Utilizando desta forma, o Oracle entende que o ponto é o separador de decimal e a vírgula é o de milhar. Para provar nossa tese, vamos mudar os separadores na sessão e vamos executar o mesmo select anterior: ❙◗▲❃ ❛❧t❡r s❡ss✐♦♥ s❡t ♥❧s❴♥✉♠❡r✐❝❴❝❤❛r❛❝t❡rs❂✬✳✱✬❀ ❙❡ss✐♦♥ ❛❧t❡r❡❞✳ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇✈❛❧♦r ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✇✈❛❧♦r ✿❂ t♦❴♥✉♠❜❡r✭✬✹✳✺✻✾✳✾✵✵✱✽✼✬✱✬✾●✾✾✾●✾✾✾❉✵✵✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❱❛❧♦r✿ ✬⑤⑤✇✈❛❧♦r✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ ❖❘❆✲✵✻✺✵✷✿ P▲✴❙◗▲✿ ♥✉♠❡r✐❝ ♦r ✈❛❧✉❡ ❡rr♦r ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❙◗▲❃ 197 14.2. to_number Casa do Código Nota: além das alterações referentes aos separadores numéricos, também podemos alterar as sessões para definir um novo formato de data e também para a definição de linguagens. Exemplos: ❛❧t❡r s❡ss✐♦♥ s❡t ♥❧s❴❧❛♥❣✉❛❣❡ ❂ ✬❇❘❆❩■▲■❆◆ P❖❘❚❯●❯❊❙❊✬❀ ❛❧t❡r s❡ss✐♦♥ s❡t ♥❧s❴❞❛t❡❴❧❛♥❣✉❛❣❡ ❂ ✬P❖❘❚❯●❯❊❙❊✬❀ ❛❧t❡r s❡ss✐♦♥ s❡t ♥❧s❴❞❛t❡❴❢♦r♠❛t ❂ ✬❉❉✴▼▼✴❘❘❘❘✬❀ Agora vamos trocar os caracteres de lugar: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇✈❛❧♦r ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✇✈❛❧♦r ✿❂ t♦❴♥✉♠❜❡r✭✬✹✱✺✻✾✱✾✵✵✳✽✼✬✱✬✾●✾✾✾●✾✾✾❉✵✵✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❱❛❧♦r✿ ✬⑤⑤✇✈❛❧♦r✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❱❛❧♦r✿ ✹✺✻✾✾✵✵✳✽✼ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Funcionou. Mas espere um momento. Além de converter, preciso saber como está definido na sessão do Oracle? Não. Não é necessário se você especificar, além do formato, quais caracteres devem ser utilizados para a separação de decimais e grupos. Vejamos novamente o penúltimo exemplo. Nele, definimos que o ponto seria a decimal, e vírgula o grupo. Contudo, isso gerou um erro ao executar nosso select onde estava justamente definido ao contrário da parametrização feita. ❙◗▲❃ ❛❧t❡r s❡ss✐♦♥ s❡t ♥❧s❴♥✉♠❡r✐❝❴❝❤❛r❛❝t❡rs❂✬✳✱✬❀ ❙❡ss✐♦♥ ❛❧t❡r❡❞✳ 198 Casa do Código Capítulo 14. Funções de conversão ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇✈❛❧♦r ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✇✈❛❧♦r ✿❂ t♦❴♥✉♠❜❡r✭✬✹✳✺✻✾✳✾✵✵✱✽✼✬✱✬✾●✾✾✾●✾✾✾❉✵✵✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❱❛❧♦r✿ ✬⑤⑤✇✈❛❧♦r✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ ❖❘❆✲✵✻✺✵✷✿ P▲✴❙◗▲✿ ♥✉♠❡r✐❝ ♦r ✈❛❧✉❡ ❡rr♦r ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❙◗▲❃ Utilizando o parâmetro nls, aquele terceiro parâmetro da função que é opcional, nós conseguimos, em vez de alterar a sessão do Oracle, validar estes caracteres apenas no nosso comando. Vamos executar novamente o select anterior, mas agora incorporando o terceiro parâmetro: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇✈❛❧♦r ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✇✈❛❧♦r ✿❂ t♦❴♥✉♠❜❡r✭✬✹✳✺✻✾✳✾✵✵✱✽✼✬✱✬✾●✾✾✾●✾✾✾❉✵✵✬✱ ✬♥❧s❴♥✉♠❡r✐❝❴❝❤❛r❛❝t❡rs❂✱✳✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❱❛❧♦r✿ ✬⑤⑤✇✈❛❧♦r✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❱❛❧♦r✿ ✹✺✻✾✾✵✵✳✽✼ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Funcionou perfeitamente. Embora pareça complicado no início, você vai se acostumando com as características e logo pega a lógica. Vale salientar que 199 Casa do Código 14.2. to_number esta questão da sessão também é válida para o to_date. Veja o select, agora observando a coluna HIREDATE. ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ ✽✵✵✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❆▲▲❊◆ ❲❆❘❉ ❏❖◆❊❙ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ ❏❖❍◆ ❈❖▼▼ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✷✵ ✸✵✵ ✸✵ ✺✵✵ ✸✵ ✷✵ ✶✹✵✵ ✸✵ ✸✵ ✶✵ ✷✵ ✶✵ ✵ ✸✵ ✷✵ ✸✵ ✷✵ ✶✵ 200 ❏❖❇ ▼●❘ ❍■❘❊❉❆❚❊ ❙❆▲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✼✾✵✷ ✶✼✲❉❊❈✲✽✵ ✽✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✵✲❋❊❇✲✽✶ ✶✻✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✷✲❋❊❇✲✽✶ ✶✷✺✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✷✲❆P❘✲✽✶ ✸✷✼✷✳✺ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✽✲❙❊P✲✽✶ ✶✷✺✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✶✲▼❆❨✲✽✶ ✷✽✺✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✾✲❏❯◆✲✽✶ ✷✹✺✵ ❆◆❆▲❨❙❚ ✼✺✻✻ ✵✾✲❉❊❈✲✽✷ ✸✵✵✵ P❘❊❙■❉❊◆❚ ✶✼✲◆❖❱✲✽✶ ✺✵✵✵ ❱❊◆❉❊❉❖❘ ✼✻✾✽ ✵✽✲❙❊P✲✽✶ ✶✺✵✵ ❈▲❊❘❑ ✼✼✽✽ ✶✷✲❏❆◆✲✽✸ ✶✶✵✵ ❈▲❊❘❑ ✼✻✾✽ ✵✸✲❉❊❈✲✽✶ ✾✺✵ ❆◆❆▲❨❙❚ ✼✺✻✻ ✵✸✲❉❊❈✲✽✶ ✸✵✵✵ ❈▲❊❘❑ ✼✼✽✷ ✷✸✲❏❆◆✲✽✷ ✶✸✵✵ ❈▲❊❘❑ ✼✾✵✷ ✸✵✲▼❆❘✲✶✶ ✶✵✵✵ Casa do Código ✷✵✵ Capítulo 14. Funções de conversão ✷✵ ✶✺ r♦✇s s❡❧❡❝t❡❞✳ ❙◗▲❃ Para o registro EMPNO=7566, o valor da coluna HIREDATE é 02-APR-81. Logo, este é o formato definido na sessão. Vamos olhar o próximo select. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✬✵✷✲❆P❘✲✽✶✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❉❛t❛✿ ✵✷✲❆P❘✲✽✶ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nota-se que no select anterior não foi gerado erro, mesmo não sendo informado o formato. Isso aconteceu porque o valor de caractere informado como string está no mesmo formato da sessão do Oracle. Veja o que acontece quando colocamos a string em outro formato: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✬✵✺✴✷✶✴✷✵✵✾✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❞❡❝❧❛r❡ ✯ ❊❘❘❖❘ ❛t ❧✐♥❡ ✶✿ 201 14.2. to_number Casa do Código ❖❘❆✲✵✶✽✹✸✿ ♥♦t ❛ ✈❛❧✐❞ ♠♦♥t❤ ❖❘❆✲✵✻✺✶✷✿ ❛t ❧✐♥❡ ✹ ❙◗▲❃ Para consertar isso devemos informar um formato compatível com o conjunto de caracteres passado ou trocar o formato da sessão do Oracle. Informando um formato compatível: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✬✵✺✴✷✶✴✷✵✵✾✬✱✬♠♠✴❞❞✴②②②②✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❉❛t❛✿ ✷✶✲▼❆❨✲✵✾ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Alterando a sessão do Oracle: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❡ ❞❛t❡❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❡ ✿❂ t♦❴❞❛t❡✭✬✵✺✴✷✶✴✷✵✵✾✬✮❀ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❛t❛✿ ✬⑤⑤✇❞❛t❡✮❀ ✻ ✲✲ ✼ ❡♥❞❀ ✽ ✴ ❉❛t❛✿ ✵✺✴✷✶✴✷✵✵✾ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ 202 Casa do Código Capítulo 14. Funções de conversão Veja alguns elementos de formatação que podem ser usados: • 9: cada nove representa um caractere que será substituído pelo caractere referente ao valor numérico passado como parâmetro. Os zeros na frente são tratados como espaços em branco. • 0: adicionando 0 como um prefixo ou sufixo ao número, todos os zeros iniciais ou finais são tratados e exibidos como zeros em vez de um espaço em branco. • $: prefixo do símbolo de moeda impresso na primeira posição. • S: exibe um sinal de + inicial ou final quando o valor for positivo e um sinal de - inicial ou final quando o valor for negativo. • D: localização do ponto decimal. Os noves de ambos os lados refletem o número máximo de dígitos permitidos. • G: especifica um separador de grupo (milhar, por exemplo) como uma vírgula. • L: especifica a localização do símbolo de moeda local (tal como $). • ,: coloca uma vírgula na posição especificada, independentemente do separador de grupo. • .: especifica a localização do ponto decimal, independentemente do separador decimal. • FM: remove os espaços em branco inicial e final. Há uma confusão muito comum com o uso do to_date e do to_number no que diz respeito ao resultado mostrado pelo select quando são utilizadas estas duas funções. Embora estejamos informando um formato, o Oracle não apresenta o resultado do SQL baseado nele. Isso acontece porque o formato no uso destas funções é apenas para a conversão e não para a visualização. Par visualizarmos o resultado com base no formato que queremos, utilizamos o to_char. 203 14.3. to_char Casa do Código 14.3 to_char Função utilizada para converter tipos de dados numéricos e datas para caracteres. Além da conversão, ele é muito utilizado para formatação visual de dados. Seguem exemplos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧ ✈❛r❝❤❛r✷✭✺✵✮❀ ✸ ❜❡❣✐♥ ✹ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❡♥❛♠❡ ✺ ✱s❛❧ ✻ ❢r♦♠ ❡♠♣✮ ❧♦♦♣ ✼ ✲✲ ✽ ✇s❛❧ ✿❂ t♦❴❝❤❛r✭r✶✳s❛❧✱✬✾●✾✾✾●✾✾✾❉✵✵✬✱ ✬♥❧s❴♥✉♠❡r✐❝❴❝❤❛r❛❝t❡rs❂✬✬✳✱✬✬✬✮❀ ✾ ✲✲ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤✇s❛❧✮❀ ✶✶ ✲✲ ✶✷ ❡♥❞ ❧♦♦♣❀ ✶✸ ❡♥❞❀ ✶✹ ✴ ◆♦♠❡✿ ❙▼■❚❍ ❙❛❧ár✐♦✿ ✽✵✵✳✵✵ ◆♦♠❡✿ ❆▲▲❊◆ ❙❛❧ár✐♦✿ ✶✱✻✵✵✳✵✵ ◆♦♠❡✿ ❲❆❘❉ ❙❛❧ár✐♦✿ ✶✱✷✺✵✳✵✵ ◆♦♠❡✿ ❏❖◆❊❙ ❙❛❧ár✐♦✿ ✷✱✾✼✺✳✵✵ ◆♦♠❡✿ ▼❆❘❚■◆ ❙❛❧ár✐♦✿ ✶✱✷✺✵✳✵✵ ◆♦♠❡✿ ❇▲❆❑❊ ❙❛❧ár✐♦✿ ✷✱✽✺✵✳✵✵ ◆♦♠❡✿ ❈▲❆❘❑ ❙❛❧ár✐♦✿ ✷✱✹✺✵✳✵✵ ◆♦♠❡✿ ❙❈❖❚❚ ❙❛❧ár✐♦✿ ✸✱✵✵✵✳✵✵ ◆♦♠❡✿ ❑■◆● ❙❛❧ár✐♦✿ ✺✱✵✵✵✳✵✵ ◆♦♠❡✿ ❚❯❘◆❊❘ ❙❛❧ár✐♦✿ ✶✱✺✵✵✳✵✵ ◆♦♠❡✿ ❆❉❆▼❙ ❙❛❧ár✐♦✿ ✶✱✶✵✵✳✵✵ ◆♦♠❡✿ ❏❆▼❊❙ ❙❛❧ár✐♦✿ ✾✺✵✳✵✵ ◆♦♠❡✿ ❋❖❘❉ ❙❛❧ár✐♦✿ ✸✱✵✵✵✳✵✵ ◆♦♠❡✿ ▼■▲▲❊❘ ❙❛❧ár✐♦✿ ✶✱✸✵✵✳✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ 204 Casa do Código Capítulo 14. Funções de conversão ❙◗▲❃ Neste exemplo são selecionados todos os nomes dos empregados e seus respectivos salários. Foi utilizada a função to_char para formatar os valores do salário, com o elemento de formatação para casas decimais e milhar. Note que aqui usamos o parâmetro nls_numeric_characters, para definir quais caracteres devem ser utilizados para cada separador do elemento. ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❝♦✉♥t✭✯✮ qt❴❛❞♠✐t✐❞♦s ✸ ✱t♦❴❝❤❛r✭❤✐r❡❞❛t❡✱✬♠♠✬✮ ▼❊❙ ✹ ❢r♦♠ ❡♠♣ ✺ ❣r♦✉♣ ❜② t♦❴❝❤❛r✭❤✐r❡❞❛t❡✱✬♠♠✬✮✮ ❧♦♦♣ ✻ ✲✲ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❆❞♠✐t✐❞♦s✿ ✬⑤⑤r✶✳qt❴❛❞♠✐t✐❞♦s⑤⑤✬ ▼ês✿ ✬⑤⑤r✶✳♠❡s✮❀ ✽ ✲✲ ✾ ❡♥❞ ❧♦♦♣❀ ✶✵ ❡♥❞❀ ✶✶ ✴ ❆❞♠✐t✐❞♦s✿ ✶ ▼ês✿ ✵✹ ❆❞♠✐t✐❞♦s✿ ✷ ▼ês✿ ✵✾ ❆❞♠✐t✐❞♦s✿ ✹ ▼ês✿ ✶✷ ❆❞♠✐t✐❞♦s✿ ✶ ▼ês✿ ✶✶ ❆❞♠✐t✐❞♦s✿ ✷ ▼ês✿ ✵✶ ❆❞♠✐t✐❞♦s✿ ✷ ▼ês✿ ✵✷ ❆❞♠✐t✐❞♦s✿ ✶ ▼ês✿ ✵✺ ❆❞♠✐t✐❞♦s✿ ✶ ▼ês✿ ✵✻ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Aqui a função to_char foi utilizada para formatar a data de admissão do empregado, mostrando apenas o mês referente esta data. O select agrupa e apresenta quantos empregados foram admitidos em cada mês. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❛❴❡①t❡♥s♦ ✈❛r❝❤❛r✷✭✶✵✵✮❀ 205 14.3. to_char Casa do Código ✸ ❜❡❣✐♥ ✹ ✇❞❛t❛❴❡①t❡♥s♦ ✿❂ ✬✷✷ ❞❡ ❛❣♦st♦ ❞❡ ✷✵✵✾ s❡rá ♦ ❞✐❛ ✬⑤⑤ t♦❴❝❤❛r✭t♦❴❞❛t❡✭✬✷✷✴✵✽✴✷✵✵✾✬✱✬❞❞✴♠♠✴②②②②✬✮✱✬❞❞❞✬✮⑤⑤ ✺ ✻ ✬ ❞♦ ❛♥♦✬❀ ✼ ✲✲ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇❞❛t❛❴❡①t❡♥s♦✮❀ ✾ ✲✲ ✶✵ ❡♥❞❀ ✶✶ ✴ ✷✷ ❞❡ ❛❣♦st♦ ❞❡ ✷✵✵✾ s❡rá ♦ ❞✐❛ ✷✸✹ ❞♦ ❛♥♦ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Outro exemplo com to_char, usado na formatação de datas. Nesse programa, são impressos uma data e o número do dia que ela representa no ano. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞✐❛❴s❡♠❛♥❛ ✈❛r❝❤❛r✷✭✺✵✮❀ ✸ ❜❡❣✐♥ ✹ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❡♥❛♠❡✱ ❤✐r❡❞❛t❡ ❢r♦♠ ❡♠♣✮ ❧♦♦♣ ✺ ✲✲ ✻ ✇❞✐❛❴s❡♠❛♥❛ ✿❂ t♦❴❝❤❛r✭r✶✳❤✐r❡❞❛t❡✱✬❞❛②✬✮❀ ✼ ✲✲ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❆❞♠✐ssã♦✿ ✬⑤⑤ ✾ r✶✳❤✐r❡❞❛t❡⑤⑤✬ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ ✬⑤⑤✇❞✐❛❴s❡♠❛♥❛✮❀ ✶✵ ✲✲ ✶✶ ❡♥❞ ❧♦♦♣❀ ✶✷ ❡♥❞❀ ✶✸ ✴ ◆♦♠❡✿ ❙▼■❚❍ ❆❞♠✐ssã♦✿ ✶✷✴✶✼✴✶✾✽✵ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ ✇❡❞♥❡s❞❛② ◆♦♠❡✿ ❆▲▲❊◆ ❆❞♠✐ssã♦✿ ✵✷✴✷✵✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ ❢r✐❞❛② ◆♦♠❡✿ ❲❆❘❉ ❆❞♠✐ssã♦✿ ✵✷✴✷✷✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ s✉♥❞❛② ◆♦♠❡✿ ❏❖◆❊❙ ❆❞♠✐ssã♦✿ ✵✹✴✵✷✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ t❤✉rs❞❛② ◆♦♠❡✿ ▼❆❘❚■◆ ❆❞♠✐ssã♦✿ ✵✾✴✷✽✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ ♠♦♥❞❛② ◆♦♠❡✿ ❇▲❆❑❊ ❆❞♠✐ssã♦✿ ✵✺✴✵✶✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ ❢r✐❞❛② ◆♦♠❡✿ ❈▲❆❘❑ ❆❞♠✐ssã♦✿ ✵✻✴✵✾✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ t✉❡s❞❛② ◆♦♠❡✿ ❙❈❖❚❚ ❆❞♠✐ssã♦✿ ✶✷✴✵✾✴✶✾✽✷ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ t❤✉rs❞❛② 206 Casa do Código ◆♦♠❡✿ ◆♦♠❡✿ ◆♦♠❡✿ ◆♦♠❡✿ ◆♦♠❡✿ ◆♦♠❡✿ Capítulo 14. Funções de conversão ❑■◆● ❆❞♠✐ssã♦✿ ✶✶✴✶✼✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ t✉❡s❞❛② ❚❯❘◆❊❘ ❆❞♠✐ssã♦✿ ✵✾✴✵✽✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ t✉❡s❞❛② ❆❉❆▼❙ ❆❞♠✐ssã♦✿ ✵✶✴✶✷✴✶✾✽✸ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ ✇❡❞♥❡s❞❛② ❏❆▼❊❙ ❆❞♠✐ssã♦✿ ✶✷✴✵✸✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ t❤✉rs❞❛② ❋❖❘❉ ❆❞♠✐ssã♦✿ ✶✷✴✵✸✴✶✾✽✶ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ t❤✉rs❞❛② ▼■▲▲❊❘ ❆❞♠✐ssã♦✿ ✵✶✴✷✸✴✶✾✽✷ ❉✐❛ ❞❛ ❙❡♠❛♥❛✿ s❛t✉r❞❛② P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo, são mostrados dados referentes à admissão do empregado: nome do empregado, data de admissão e dia da semana. Este último, formatado através da função to_char. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇❞❛t❛❴❡①t❡♥s♦ ✈❛r❝❤❛r✷✭✶✵✵✮❀ ✸ ❜❡❣✐♥ ✹ ✇❞❛t❛❴❡①t❡♥s♦ ✿❂ ✬❏♦✐♥✈✐❧❧❡✱ ✬⑤⑤t♦❴❝❤❛r✭s②s❞❛t❡✱✬❞❞✬✮⑤⑤✬ ❞❡ ✬⑤⑤ ✺ ✐♥✐t❝❛♣✭t♦❴❝❤❛r✭s②s❞❛t❡✱ ✬❢♠♠♦♥t❤✬✮✮⑤⑤✬ ❞❡ ✬ ✻ ⑤⑤t♦❴❝❤❛r✭s②s❞❛t❡✱✬②②②②✬✮⑤⑤✬✳✬❀ ✼ ✲✲ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✇❞❛t❛❴❡①t❡♥s♦✮❀ ✾ ✲✲ ✶✵ ❡♥❞❀ ✶✶ ✴ ❏♦✐♥✈✐❧❧❡✱ ✸✵ ❞❡ ◆♦✈❡♠❜❡r ❞❡ ✷✵✶✶✳ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo, usamos to_char para imprimir em tela a data por extenso. ❙◗▲❃ ❜❡❣✐♥ ✷ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❡♥❛♠❡ ✸ ✱❤✐r❡❞❛t❡ 207 Casa do Código 14.3. to_char ✹ ✺ ✻ ✼ ❢r♦♠ ❡♠♣ ✇❤❡r❡ t♦❴❝❤❛r✭❤✐r❡❞❛t❡✱✬②②②②✬✮ ❂ ✬✶✾✽✷✬✮ ❧♦♦♣ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ❆❞♠✐ssã♦✿ ✬⑤⑤r✶✳❤✐r❡❞❛t❡✮❀ ✽ ✲✲ ✾ ❡♥❞ ❧♦♦♣❀ ✶✵ ❡♥❞❀ ✶✶ ✴ ◆♦♠❡✿ ❙❈❖❚❚ ❆❞♠✐ssã♦✿ ✶✷✴✵✾✴✶✾✽✷ ◆♦♠❡✿ ▼■▲▲❊❘ ❆❞♠✐ssã♦✿ ✵✶✴✷✸✴✶✾✽✷ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Aqui utilizamos a função to_char para restringir dados em um select. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧❴❢♦r♠❛t❛❞♦ ✈❛r❝❤❛r✷✭✺✵✮❀ ✸ ❜❡❣✐♥ ✹ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t s❛❧ ❢r♦♠ ❡♠♣✮ ❧♦♦♣ ✺ ✲✲ ✻ ✇s❛❧❴❢♦r♠❛t❛❞♦ ✿❂ ✬❘✩ ✬⑤⑤t♦❴❝❤❛r✭r✶✳s❛❧✱✬❢♠✾●✾✾✾●✾✾✵❉✵✵✬✮❀ ✼ ✲✲ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙❛❧ár✐♦✿ ✬⑤⑤r✶✳s❛❧⑤⑤✬ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✬⑤⑤✇s❛❧❴❢♦r♠❛t❛❞♦✮❀ ✾ ✲✲ ✶✵ ❡♥❞ ❧♦♦♣❀ ✶✶ ❡♥❞❀ ✶✷ ✴ ❙❛❧ár✐♦✿ ✽✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✽✵✵✳✵✵ ❙❛❧ár✐♦✿ ✶✻✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✶✱✻✵✵✳✵✵ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✶✱✷✺✵✳✵✵ ❙❛❧ár✐♦✿ ✷✾✼✺ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✷✱✾✼✺✳✵✵ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✶✱✷✺✵✳✵✵ ❙❛❧ár✐♦✿ ✷✽✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✷✱✽✺✵✳✵✵ 208 Casa do Código ❙❛❧ár✐♦✿ ❙❛❧ár✐♦✿ ❙❛❧ár✐♦✿ ❙❛❧ár✐♦✿ ❙❛❧ár✐♦✿ ❙❛❧ár✐♦✿ ❙❛❧ár✐♦✿ ❙❛❧ár✐♦✿ Capítulo 14. Funções de conversão ✷✹✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✷✱✹✺✵✳✵✵ ✸✵✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✸✱✵✵✵✳✵✵ ✺✵✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✺✱✵✵✵✳✵✵ ✶✺✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✶✱✺✵✵✳✵✵ ✶✶✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✶✱✶✵✵✳✵✵ ✾✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✾✺✵✳✵✵ ✸✵✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✸✱✵✵✵✳✵✵ ✶✸✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ❘✩ ✶✱✸✵✵✳✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧❴❢♦r♠❛t❛❞♦ ✈❛r❝❤❛r✷✭✺✵✮❀ ✸ ❜❡❣✐♥ ✹ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t s❛❧ ❢r♦♠ ❡♠♣✮ ❧♦♦♣ ✺ ✲✲ ✻ ✇s❛❧❴❢♦r♠❛t❛❞♦ ✿❂ t♦❴❝❤❛r✭r✶✳s❛❧✱✬❢♠▲✾●✾✾✾●✾✾✵❉✵✵✬✮❀ ✼ ✲✲ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙❛❧ár✐♦✿ ✬⑤⑤r✶✳s❛❧⑤⑤✬ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✬⑤⑤✇s❛❧❴❢♦r♠❛t❛❞♦✮❀ ✾ ✲✲ ✶✵ ❡♥❞ ❧♦♦♣❀ ✶✶ ❡♥❞❀ ✶✷ ✴ ❙❛❧ár✐♦✿ ✽✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✽✵✵✳✵✵ ❙❛❧ár✐♦✿ ✶✻✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✶✱✻✵✵✳✵✵ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✶✱✷✺✵✳✵✵ ❙❛❧ár✐♦✿ ✷✾✼✺ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✷✱✾✼✺✳✵✵ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✶✱✷✺✵✳✵✵ ❙❛❧ár✐♦✿ ✷✽✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✷✱✽✺✵✳✵✵ ❙❛❧ár✐♦✿ ✷✹✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✷✱✹✺✵✳✵✵ ❙❛❧ár✐♦✿ ✸✵✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✸✱✵✵✵✳✵✵ ❙❛❧ár✐♦✿ ✺✵✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✺✱✵✵✵✳✵✵ ❙❛❧ár✐♦✿ ✶✺✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✶✱✺✵✵✳✵✵ ❙❛❧ár✐♦✿ ✶✶✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✶✱✶✵✵✳✵✵ ❙❛❧ár✐♦✿ ✾✺✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✾✺✵✳✵✵ ❙❛❧ár✐♦✿ ✸✵✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✸✱✵✵✵✳✵✵ 209 14.3. to_char Casa do Código ❙❛❧ár✐♦✿ ✶✸✵✵ ❙❛❧ár✐♦ ❋♦r♠❛t❛❞♦✿ ✩✶✱✸✵✵✳✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo se parece com o anterior. Contudo, aqui estamos utilizando os elementos de formatação FM e L. O primeiro retira os espaços em branco, onde algum elemento de formatação não tenha sido preenchido, por ausência de valores. O segundo mostra a moeda configurada na sessão do usuário, onde o programa está sendo executado. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇♣♦s✐t✐✈♦ ✈❛r❝❤❛r✷✭✶✵✵✮❀ ✸ ✇♥❡❣❛t✐✈♦ ✈❛r❝❤❛r✷✭✶✵✵✮❀ ✹ ❜❡❣✐♥ ✺ ✇♣♦s✐t✐✈♦ ✿❂ t♦❴❝❤❛r✭✶✼✹✾✽✹✷✽✸✳✼✺✱✬❢♠✾✾✾✱✾✾✾✱✾✾✾✳✵✵❙✬✮❀ ✻ ✇♥❡❣❛t✐✈♦ ✿❂ t♦❴❝❤❛r✭✶✵✵✲✶✵✵✵✱✬❢♠✾✾✾✱✾✾✾✱✾✾✾✳✵✵❙✬✮❀ ✼ ✲✲ ✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬P♦s✐t✐✈♦✿ ✬⑤⑤✇♣♦s✐t✐✈♦⑤⑤✬ ✲ ◆❡❣❛t✐✈♦✿ ✬⑤⑤✇♥❡❣❛t✐✈♦✮❀ ✾ ✲✲ ✶✵ ❡♥❞❀ ✶✶ ✴ P♦s✐t✐✈♦✿ ✶✼✹✱✾✽✹✱✷✽✸✳✼✺✰ ✲ ◆❡❣❛t✐✈♦✿ ✾✵✵✳✵✵✲ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Já nesse exemplo, utilizamos o elemento de formatação S, que indica o sinal referente ao valor formatado. Note que no valor positivo foi impresso, atrás do número, o sinal de positivo ( +), quanto para o valor negativo é impresso o sinal de negativo ( -). 210 Capítulo 15 Funções condicionais O Oracle disponibiliza outros tipos de funções, dentre as quais as funções condicionais. Elas são utilizadas tanto na seleção de dados pela cláusula select como também no uso de cláusulas where. Seu uso é bastante difundido e bem flexível. • decode: esta estrutura funciona como uma estrutura if-else dentro de uma cláusula select. É muito utilizada principalmente para visualização de dados onde é preciso realizar algum teste para saber se estes dados podem ou não aparecer. • nullif: são passados dois parâmetros para esta função. Ela compara os dois, se forem iguais é retornado Null. Caso contrário, ela retorna o primeiro parâmetro. Casa do Código • nvl: para esta função são passados dois parâmetros. Se o primeiro for nulo, ele retorna o segundo, caso contrário, retorna o primeiro. • case: muito parecido com o decode. Seu objetivo também é permitir a utilização de uma estrutura tipo if-else dentro do comando SQL. Ao contrário do decode sua aplicação e visualização são mais inteligíveis (padrão ANSI). • greatest: retorna a maior expressão de uma lista de valores passada como parâmetro. Todas as expressões após a primeira são convertidas para o tipo de dado da primeira antes da comparação ser realizada. • least: funciona o inverso da greatest. Esta traz a menor expressão. Veja alguns exemplos: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ❝✉rs♦r ❝✶ ✐s ✸ s❡❧❡❝t ❥♦❜✱ ✹ s✉♠✭❝❛s❡ ✺ ✇❤❡♥ ❞❡♣t♥♦ ❂ ✶✵ t❤❡♥ s❛❧ ✻ ❡❧s❡ ✼ ✵ ❡♥❞✮ ❞❡♣❛rt❴✶✵✱ ✽ ✾ s✉♠✭❝❛s❡ ✶✵ ✇❤❡♥ ❞❡♣t♥♦ ❂ ✷✵ t❤❡♥ s❛❧ ✶✶ ❡❧s❡ ✶✷ ✵ ❡♥❞✮ ❞❡♣❛rt❴✷✵✱ ✶✸ ✶✹ s✉♠✭❝❛s❡ ✶✺ ✇❤❡♥ ❞❡♣t♥♦ ❂ ✸✵ t❤❡♥ s❛❧ ✶✻ ❡❧s❡ ✶✼ ✵ ✶✽ ❡♥❞✮ ❞❡♣❛rt❴✸✵✱ ✶✾ s✉♠✭s❛❧✮ t♦t❛❧❴❥♦❜ ✷✵ ❢r♦♠ ❡♠♣ ✷✶ ❣r♦✉♣ ❜② ❥♦❜❀ ✷✷ ✲✲ ✷✸ ❜❡❣✐♥ 212 Casa do Código Capítulo 15. Funções condicionais ✷✹ ✷✺ ✷✻ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭r✶✳❥♦❜⑤⑤✬ ✲ ❉❡♣❛rt✳ ✶✵✿ ✬ ⑤⑤r✶✳❞❡♣❛rt❴✶✵⑤⑤✬ ✲ ❉❡♣❛rt✳ ✷✵✿ ✬⑤⑤ r✶✳❞❡♣❛rt❴✷✵⑤⑤✬ ✲ ❉❡♣❛rt✳ ✸✵✿ ✬⑤⑤ ✷✼ r✶✳❞❡♣❛rt❴✸✵⑤⑤✬ ✲ ❚♦t❛❧✿ ✬⑤⑤ ✷✽ r✶✳t♦t❛❧❴❥♦❜✮❀ ✷✾ ✲✲ ✸✵ ❡♥❞ ❧♦♦♣❀ ✸✶ ❡♥❞❀ ✸✷ ✴ ❈▲❊❘❑ ✲ ❉❡♣❛rt✳ ✶✵✿ ✶✸✵✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✶✾✵✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✾✺✵ ✲ ❚♦t❛❧✿ ✹✶✺✵ ❙❆▲❊❙▼❆◆ ✲ ❉❡♣❛rt✳ ✶✵✿ ✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✺✻✵✵ ✲ ❚♦t❛❧✿ ✺✻✵✵ P❘❊❙■❉❊◆❚ ✲ ❉❡♣❛rt✳ ✶✵✿ ✺✵✵✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✵ ✲ ❚♦t❛❧✿ ✺✵✵✵ ▼❆◆❆●❊❘ ✲ ❉❡♣❛rt✳ ✶✵✿ ✷✹✺✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✷✾✼✺ ✲ ❉❡♣❛rt✳ ✸✵✿ ✷✽✺✵ ✲ ❚♦t❛❧✿ ✽✷✼✺ ❆◆❆▲❨❙❚ ✲ ❉❡♣❛rt✳ ✶✵✿ ✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✻✵✵✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✵ ✲ ❚♦t❛❧✿ ✻✵✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo, utilizamos a função case, para somar todos os salários por departamento, agrupando por cargo. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ❝✉rs♦r ❝✶ ✐s ✸ s❡❧❡❝t ❥♦❜ ✹ ✱s✉♠✭❞❡❝♦❞❡✭❞❡♣t♥♦✱ ✶✵✱ s❛❧✱ ✵✮✮ ❞❡♣❛rt❴✶✵ ✺ ✱s✉♠✭❞❡❝♦❞❡✭❞❡♣t♥♦✱ ✷✵✱ s❛❧✱ ✵✮✮ ❞❡♣❛rt❴✷✵ ✻ ✱s✉♠✭❞❡❝♦❞❡✭❞❡♣t♥♦✱ ✸✵✱ s❛❧✱ ✵✮✮ ❞❡♣❛rt❴✸✵ ✼ ✱s✉♠✭s❛❧✮ t♦t❛❧❴❥♦❜ ✽ ❢r♦♠ ❡♠♣ ✾ ❣r♦✉♣ ❜② ❥♦❜❀ ✶✵ ✲✲ 213 Casa do Código ✶✶ ❜❡❣✐♥ ✶✷ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭r✶✳❥♦❜⑤⑤✬ ✲ ❉❡♣❛rt✳ ✶✵✿ ✬⑤⑤ r✶✳❞❡♣❛rt❴✶✵⑤⑤✬ ✲ ❉❡♣❛rt✳ ✷✵✿ ✬⑤⑤ ✶✺ r✶✳❞❡♣❛rt❴✷✵⑤⑤✬ ✲ ❉❡♣❛rt✳ ✸✵✿ ✬⑤⑤ r✶✳❞❡♣❛rt❴✸✵⑤⑤✬ ✲ ❚♦t❛❧✿ ✬⑤⑤ r✶✳t♦t❛❧❴❥♦❜✮❀ ✶✻ ✶✼ ✲✲ ✶✽ ❡♥❞ ❧♦♦♣❀ ✶✾ ❡♥❞❀ ✷✵ ✴ ❈▲❊❘❑ ✲ ❉❡♣❛rt✳ ✶✵✿ ✶✸✵✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✶✾✵✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✾✺✵ ✲ ❚♦t❛❧✿ ✹✶✺✵ ❙❆▲❊❙▼❆◆ ✲ ❉❡♣❛rt✳ ✶✵✿ ✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✺✻✵✵ ✲ ❚♦t❛❧✿ ✺✻✵✵ P❘❊❙■❉❊◆❚ ✲ ❉❡♣❛rt✳ ✶✵✿ ✺✵✵✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✵ ✲ ❚♦t❛❧✿ ✺✵✵✵ ▼❆◆❆●❊❘ ✲ ❉❡♣❛rt✳ ✶✵✿ ✷✹✺✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✷✾✼✺ ✲ ❉❡♣❛rt✳ ✸✵✿ ✷✽✺✵ ✲ ❚♦t❛❧✿ ✽✷✼✺ ❆◆❆▲❨❙❚ ✲ ❉❡♣❛rt✳ ✶✵✿ ✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✻✵✵✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✵ ✲ ❚♦t❛❧✿ ✻✵✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Esse exemplo é idêntico ao anterior. Apenas trocamos a função case pela função decode. Vale lembrar que case é do padrão SQL ANSI e decode é do padrão Oracle. ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ 214 ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❆▲▲❊◆ ❲❆❘❉ ❏❖◆❊❙ ❏❖❇ ▼●❘ ❍■❘❊❉❆❚❊ ❙❆▲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✼✾✵✷ ✶✷✴✶✼✴✶✾✽✵ ✽✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✵✷✴✷✵✴✶✾✽✶ ✶✻✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✵✷✴✷✷✴✶✾✽✶ ✶✷✺✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✹✴✵✷✴✶✾✽✶ ✷✾✼✺ Casa do Código ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ Capítulo 15. Funções condicionais ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ ❙❆▲❊❙▼❆◆ ▼❆◆❆●❊❘ ▼❆◆❆●❊❘ ❆◆❆▲❨❙❚ P❘❊❙■❉❊◆❚ ❙❆▲❊❙▼❆◆ ❈▲❊❘❑ ❈▲❊❘❑ ❆◆❆▲❨❙❚ ❈▲❊❘❑ ✼✻✾✽ ✼✽✸✾ ✼✽✸✾ ✼✺✻✻ ✼✻✾✽ ✼✼✽✽ ✼✻✾✽ ✼✺✻✻ ✼✼✽✷ ✵✾✴✷✽✴✶✾✽✶ ✵✺✴✵✶✴✶✾✽✶ ✵✻✴✵✾✴✶✾✽✶ ✶✷✴✵✾✴✶✾✽✷ ✶✶✴✶✼✴✶✾✽✶ ✵✾✴✵✽✴✶✾✽✶ ✵✶✴✶✷✴✶✾✽✸ ✶✷✴✵✸✴✶✾✽✶ ✶✷✴✵✸✴✶✾✽✶ ✵✶✴✷✸✴✶✾✽✷ ✶✷✺✵ ✷✽✺✵ ✷✹✺✵ ✸✵✵✵ ✺✵✵✵ ✶✺✵✵ ✶✶✵✵ ✾✺✵ ✸✵✵✵ ✶✸✵✵ ❈❖▼▼ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✷✵ ✸✵✵ ✸✵ ✺✵✵ ✸✵ ✷✵ ✶✹✵✵ ✸✵ ✸✵ ✶✵ ✷✵ ✶✵ ✵ ✸✵ ✷✵ ✸✵ ✷✵ ✶✵ ✶✹ r♦✇s s❡❧❡❝t❡❞✳ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇s❛❧❴❝♦♠♠✶ ♥✉♠❜❡r❀ ✸ ✇s❛❧❴❝♦♠♠✷ ♥✉♠❜❡r❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ s❡❧❡❝t s✉♠✭s❛❧✰❝♦♠♠✮ ✐♥t♦ ✇s❛❧❴❝♦♠♠✶ ❢r♦♠ ❡♠♣❀ ✼ ✲✲ ✽ s❡❧❡❝t s✉♠✭s❛❧✰♥✈❧✭❝♦♠♠✱✵✮✮ ✐♥t♦ ✇s❛❧❴❝♦♠♠✷ ❢r♦♠ ❡♠♣❀ ✾ ✲✲ 215 Casa do Código ✶✵ ✶✶ ✶✷ ✶✸ ❙❛❧✳ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙❛❧✳ ❈♦♠♠✶✿ ✬⑤⑤✇s❛❧❴❝♦♠♠✶⑤⑤✬ ✲ ❙❛❧✳ ❈♦♠♠✷✿ ✬⑤⑤✇s❛❧❴❝♦♠♠✷✮❀ ✲✲ ❡♥❞❀ ✴ ❈♦♠♠✶✿ ✼✽✵✵ ✲ ❙❛❧✳ ❈♦♠♠✷✿ ✸✶✷✷✺ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo estamos utilizando a função nvl. Note que quando realizamos cálculos com valores nulos (linha 6) o Oracle não executa tal operação. O Oracle sempre considera como falso quando existem valores NULL (nulo) em cálculos aritméticos ou no uso de restrição de dados, como, por exemplo, em cláusulas where. Quando isso ocorre, ele ignora a ação, mas não gera erros. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇♠❛✐♦r❴❧❡tr❛ ✈❛r❝❤❛r✷✭✶✮❀ ✸ ✇♠❡♥♦r❴❧❡tr❛ ✈❛r❝❤❛r✷✭✶✮❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ s❡❧❡❝t ❣r❡❛t❡st✭✬❜✬✱✬①✬✱✬t✬✱✬✉✬✱✬❛✬✮ ✐♥t♦ ✇♠❛✐♦r❴❧❡tr❛ ❢r♦♠ ❞✉❛❧❀ ✼ ✲✲ ✽ s❡❧❡❝t ❧❡❛st✭✬❜✬✱✬①✬✱✬t✬✱✬✉✬✱✬❛✬✮ ✐♥t♦ ✇♠❡♥♦r❴❧❡tr❛ ❢r♦♠ ❞✉❛❧❀ ✾ ✲✲ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬▼❛✐♦r ▲❡tr❛✿ ✬⑤⑤✇♠❛✐♦r❴❧❡tr❛⑤⑤✬ ✲ ▼❡♥♦r ▲❡tr❛✿ ✬⑤⑤✇♠❡♥♦r❴❧❡tr❛✮❀ ✶✶ ✲✲ ✶✷ ❡♥❞❀ ✶✸ ✴ ▼❛✐♦r ▲❡tr❛✿ ① ✲ ▼❡♥♦r ▲❡tr❛✿ ❛ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ 216 Casa do Código Capítulo 15. Funções condicionais Nesse exemplo, temos o uso das funções greatest e least. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ❝♦♠♣❛r❛❝❛♦✶ ✈❛r❝❤❛r✷✭✶✵✵✮❀ ✸ ❝♦♠♣❛r❛❝❛♦✷ ✈❛r❝❤❛r✷✭✶✵✵✮❀ ✹ ❜❡❣✐♥ ✺ ✲✲ ✻ s❡❧❡❝t ❞❡❝♦❞❡✭♥✉❧❧✐❢✭✬❛❜❛❝❛①✐✬✱✬❛❜❛❝❛①✐✬✮✱♥✉❧❧✱ ✬sã♦ ✐❣✉❛✐s✬✱✬sã♦ ❞✐❢❡r❡♥t❡s✬✮ ✼ ✐♥t♦ ❝♦♠♣❛r❛❝❛♦✶ ❢r♦♠ ❞✉❛❧❀ ✽ ✲✲ ✾ s❡❧❡❝t ❞❡❝♦❞❡✭♥✉❧❧✐❢✭✬❛❜❛❝❛①✐✬✱✬♠♦r❛♥❣♦✬✮✱♥✉❧❧✱ ✬sã♦ ✐❣✉❛✐s✬✱✬sã♦ ❞✐❢❡r❡♥t❡s✬✮ ✶✵ ✐♥t♦ ❝♦♠♣❛r❛❝❛♦✷ ❢r♦♠ ❞✉❛❧❀ ✶✶ ✲✲ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈♦♠♣❛r❛çã♦ ✶✿ ✬⑤⑤❝♦♠♣❛r❛❝❛♦✶⑤⑤✬ ❈♦♠♣❛r❛çã♦ ✷✿ ✬⑤⑤❝♦♠♣❛r❛❝❛♦✷✮❀ ✶✸ ✲✲ ✶✹ ❡♥❞❀ ✶✺ ✴ ❈♦♠♣❛r❛çã♦ ✶✿ sã♦ ✐❣✉❛✐s ✲ ❈♦♠♣❛r❛çã♦ ✷✿ sã♦ ❞✐❢❡r❡♥t❡s ✲ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Nesse exemplo, temos o uso da função nullif. 15.1 decode vs. case Dos comandos condicionais vistos anteriormente, o decode é o mais utilizado. Ele funciona como uma espécie de condição SE ( if) para a linguagem SQL. Este comando é exclusivo do Oracle, entretanto, no padrão ANSI da linguagem SQL existe um comando similar, o case. Você pode usar qualquer um deles. Porém, o uso do case só é permitido nas versões mais novas do banco de dados Oracle. A Oracle, nas versões mais recentes, vem inserindo comandos padrões ANSI enquanto seus comandos específicos mantêm suas 217 15.1. decode vs. case Casa do Código características para questões de compatibilidade. Veja comparações entre estes dois comandos. Exemplo 1 Padrão ANSI (também suportado pelo Oracle nas versões mais novas do banco de dados): ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ❝✉rs♦r ❝✶ ✐s ✸ s❡❧❡❝t ❥♦❜✱ ✹ s✉♠✭❝❛s❡ ✺ ✇❤❡♥ ❞❡♣t♥♦ ❂ ✶✵ t❤❡♥ s❛❧ ✻ ❡❧s❡ ✼ ✵ ❡♥❞✮ ❞❡♣❛rt❴✶✵✱ ✽ ✾ s✉♠✭❝❛s❡ ✶✵ ✇❤❡♥ ❞❡♣t♥♦ ❂ ✷✵ t❤❡♥ s❛❧ ✶✶ ❡❧s❡ ✶✷ ✵ ✶✸ ❡♥❞✮ ❞❡♣❛rt❴✷✵✱ ✶✹ s✉♠✭❝❛s❡ ✶✺ ✇❤❡♥ ❞❡♣t♥♦ ❂ ✸✵ t❤❡♥ s❛❧ ✶✻ ❡❧s❡ ✶✼ ✵ ❡♥❞✮ ❞❡♣❛rt❴✸✵✱ ✶✽ ✶✾ s✉♠✭s❛❧✮ t♦t❛❧❴❥♦❜ ✷✵ ❢r♦♠ ❡♠♣ ✷✶ ❣r♦✉♣ ❜② ❥♦❜❀ ✷✷ ✲✲ ✷✸ ❜❡❣✐♥ ✷✹ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✷✺ ✲✲ ✷✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭r✶✳❥♦❜⑤⑤✬ ✲ ❉❡♣❛rt✳ ✶✵✿ ✬⑤⑤ r✶✳❞❡♣❛rt❴✶✵⑤⑤✬ ✲ ❉❡♣❛rt✳ ✷✵✿ ✬⑤⑤ ✷✼ r✶✳❞❡♣❛rt❴✷✵⑤⑤✬ ✲ ❉❡♣❛rt✳ ✸✵✿ ✬⑤⑤ r✶✳❞❡♣❛rt❴✸✵⑤⑤✬ ✲ ❚♦t❛❧✿ ✬⑤⑤ ✷✽ r✶✳t♦t❛❧❴❥♦❜✮❀ ✷✾ ✲✲ 218 Casa do Código Capítulo 15. Funções condicionais ✸✵ ❡♥❞ ❧♦♦♣❀ ✸✶ ❡♥❞❀ ✸✷ ✴ ❈▲❊❘❑ ✲ ❉❡♣❛rt✳ ✶✵✿ ✶✸✵✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✶✾✵✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✾✺✵ ✲ ❚♦t❛❧✿ ✹✶✺✵ ❙❆▲❊❙▼❆◆ ✲ ❉❡♣❛rt✳ ✶✵✿ ✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✺✻✵✵ ✲ ❚♦t❛❧✿ ✺✻✵✵ P❘❊❙■❉❊◆❚ ✲ ❉❡♣❛rt✳ ✶✵✿ ✺✵✵✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✵ ✲ ❚♦t❛❧✿ ✺✵✵✵ ▼❆◆❆●❊❘ ✲ ❉❡♣❛rt✳ ✶✵✿ ✷✹✺✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✷✾✼✺ ✲ ❉❡♣❛rt✳ ✸✵✿ ✷✽✺✵ ✲ ❚♦t❛❧✿ ✽✷✼✺ ❆◆❆▲❨❙❚ ✲ ❉❡♣❛rt✳ ✶✵✿ ✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✻✵✵✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✵ ✲ ❚♦t❛❧✿ ✻✵✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Padrão Oracle: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ❝✉rs♦r ❝✶ ✐s ✸ s❡❧❡❝t ❥♦❜✱ ✹ s✉♠✭❞❡❝♦❞❡✭❞❡♣t♥♦✱ ✶✵✱ s❛❧✱ ✵✮✮ ❞❡♣❛rt❴✶✵✱ ✺ s✉♠✭❞❡❝♦❞❡✭❞❡♣t♥♦✱ ✷✵✱ s❛❧✱ ✵✮✮ ❞❡♣❛rt❴✷✵✱ ✻ s✉♠✭❞❡❝♦❞❡✭❞❡♣t♥♦✱ ✸✵✱ s❛❧✱ ✵✮✮ ❞❡♣❛rt❴✸✵✱ ✼ s✉♠✭s❛❧✮ t♦t❛❧❴❥♦❜ ✽ ❢r♦♠ ❡♠♣ ✾ ❣r♦✉♣ ❜② ❥♦❜❀ ✶✵ ✲✲ ✶✶ ❜❡❣✐♥ ✶✷ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭r✶✳❥♦❜⑤⑤✬ ✲ ❉❡♣❛rt✳ ✶✵✿ ✬⑤⑤ r✶✳❞❡♣❛rt❴✶✵⑤⑤✬ ✲ ❉❡♣❛rt✳ ✷✵✿ ✬⑤⑤ ✶✺ r✶✳❞❡♣❛rt❴✷✵⑤⑤✬ ✲ ❉❡♣❛rt✳ ✸✵✿ ✬⑤⑤ r✶✳❞❡♣❛rt❴✸✵⑤⑤✬ ✲ ❚♦t❛❧✿ ✬⑤⑤ r✶✳t♦t❛❧❴❥♦❜✮❀ ✶✻ ✶✼ ✲✲ ✶✽ ❡♥❞ ❧♦♦♣❀ 219 Casa do Código 15.1. decode vs. case ✶✾ ❡♥❞❀ ✷✵ ✴ ❈▲❊❘❑ ✲ ❉❡♣❛rt✳ ✶✵✿ ✶✸✵✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✶✾✵✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✾✺✵ ✲ ❚♦t❛❧✿ ✹✶✺✵ ❙❆▲❊❙▼❆◆ ✲ ❉❡♣❛rt✳ ✶✵✿ ✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✺✻✵✵ ✲ ❚♦t❛❧✿ ✺✻✵✵ P❘❊❙■❉❊◆❚ ✲ ❉❡♣❛rt✳ ✶✵✿ ✺✵✵✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✵ ✲ ❚♦t❛❧✿ ✺✵✵✵ ▼❆◆❆●❊❘ ✲ ❉❡♣❛rt✳ ✶✵✿ ✷✹✺✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✷✾✼✺ ✲ ❉❡♣❛rt✳ ✸✵✿ ✷✽✺✵ ✲ ❚♦t❛❧✿ ✽✷✼✺ ❆◆❆▲❨❙❚ ✲ ❉❡♣❛rt✳ ✶✵✿ ✵ ✲ ❉❡♣❛rt✳ ✷✵✿ ✻✵✵✵ ✲ ❉❡♣❛rt✳ ✸✵✿ ✵ ✲ ❚♦t❛❧✿ ✻✵✵✵ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Exemplo 2 Padrão ANSI (também suportado pelo Oracle nas versões mais novas do banco de dados): ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ❝✉rs♦r ❝✶ ✐s ✸ s❡❧❡❝t ❡♥❛♠❡ ✹ ✱ ❥♦❜ ✺ ✱ ♠❣r ✻ ✱ ✼ ❝❛s❡ ✽ ✇❤❡♥ ♠❣r ❂ ✾ ✇❤❡♥ ♠❣r ❂ ✶✵ ✇❤❡♥ ♠❣r ❂ ✶✶ ✇❤❡♥ ♠❣r ❂ ✶✷ ❡❧s❡ ✶✸ ✬❖❯❚❘❖❙✬ ✶✹ ❡♥❞ t✐♣♦ ✶✺ ❢r♦♠ ❡♠♣❀ ✶✻ ✶✼ ✲✲ 220 ✼✾✵✷ ✼✾✵✷ ✼✽✸✾ ✼✺✻✻ t❤❡♥ t❤❡♥ t❤❡♥ t❤❡♥ ✬▼❊◆❙❆▲■❙❚❆✬ ✬▼❊◆❙❆▲■❙❚❆✬ ✬❈❖▼■❙❙■❖◆❆❉❖✬ ✬▼❊◆❙❆▲✴❍❖❘■❙❚❆✬ Casa do Código Capítulo 15. Funções condicionais ✶✽ ❜❡❣✐♥ ✶✾ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✷✵ ✲✲ ✷✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ✲ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜⑤⑤✬ ✲ ●❡r❡♥t❡✿ ✬⑤⑤ ✷✷ r✶✳♠❣r⑤⑤✬ ✲ ❚✐♣♦✿ ✬⑤⑤r✶✳t✐♣♦✮❀ ✷✸ ✲✲ ✷✹ ❡♥❞ ❧♦♦♣❀ ✷✺ ❡♥❞❀ ✷✻ ✴ ◆♦♠❡✿ ❙▼■❚❍ ✲ ❈❛r❣♦✿ ❈▲❊❘❑ ✲ ●❡r❡♥t❡✿ ✼✾✵✷ ✲ ❚✐♣♦✿ ▼❊◆❙❆▲■❙❚❆ ◆♦♠❡✿ ❆▲▲❊◆ ✲ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❲❆❘❉ ✲ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❏❖◆❊❙ ✲ ❈❛r❣♦✿ ▼❆◆❆●❊❘ ✲ ●❡r❡♥t❡✿ ✼✽✸✾ ✲ ❚✐♣♦✿ ❈❖▼■❙❙■❖◆❆❉❖ ◆♦♠❡✿ ▼❆❘❚■◆ ✲ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❇▲❆❑❊ ✲ ❈❛r❣♦✿ ▼❆◆❆●❊❘ ✲ ●❡r❡♥t❡✿ ✼✽✸✾ ✲ ❚✐♣♦✿ ❈❖▼■❙❙■❖◆❆❉❖ ◆♦♠❡✿ ❈▲❆❘❑ ✲ ❈❛r❣♦✿ ▼❆◆❆●❊❘ ✲ ●❡r❡♥t❡✿ ✼✽✸✾ ✲ ❚✐♣♦✿ ❈❖▼■❙❙■❖◆❆❉❖ ◆♦♠❡✿ ❙❈❖❚❚ ✲ ❈❛r❣♦✿ ❆◆❆▲❨❙❚ ✲ ●❡r❡♥t❡✿ ✼✺✻✻ ✲ ❚✐♣♦✿ ▼❊◆❙❆▲✴❍❖❘■❙❚❆ ◆♦♠❡✿ ❑■◆● ✲ ❈❛r❣♦✿ P❘❊❙■❉❊◆❚ ✲ ●❡r❡♥t❡✿ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❚❯❘◆❊❘ ✲ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❆❉❆▼❙ ✲ ❈❛r❣♦✿ ❈▲❊❘❑ ✲ ●❡r❡♥t❡✿ ✼✼✽✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❏❆▼❊❙ ✲ ❈❛r❣♦✿ ❈▲❊❘❑ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❋❖❘❉ ✲ ❈❛r❣♦✿ ❆◆❆▲❨❙❚ ✲ ●❡r❡♥t❡✿ ✼✺✻✻ ✲ ❚✐♣♦✿ ▼❊◆❙❆▲✴❍❖❘■❙❚❆ ◆♦♠❡✿ ▼■▲▲❊❘ ✲ ❈❛r❣♦✿ ❈▲❊❘❑ ✲ ●❡r❡♥t❡✿ ✼✼✽✷ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ Padrão Oracle: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ❝✉rs♦r ❝✶ ✐s ✸ s❡❧❡❝t ❡♥❛♠❡ ✹ ✱❥♦❜ ✺ ✱♠❣r ✻ ✱❞❡❝♦❞❡✭♠❣r✱✼✾✵✷✱✬▼❊◆❙❆▲■❙❚❆✬ ✼ ✱✼✽✸✾✱✬❈❖▼■❙❙■❖◆❆❉❖✬ 221 15.1. decode vs. case Casa do Código ✽ ✱✼✺✻✻✱✬▼❊◆❙❆▲✴❍❖❘■❙❚❆✬ ✾ ✱✬❖❯❚❘❖❙✬✮ t✐♣♦ ✶✵ ❢r♦♠ ❡♠♣❀ ✶✶ ✲✲ ✶✷ ❜❡❣✐♥ ✶✸ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✶✹ ✲✲ ✶✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡✿ ✬⑤⑤r✶✳❡♥❛♠❡⑤⑤✬ ✲ ❈❛r❣♦✿ ✬⑤⑤r✶✳❥♦❜⑤⑤✬ ✲ ●❡r❡♥t❡✿ ✬⑤⑤ r✶✳♠❣r⑤⑤✬ ✲ ❚✐♣♦✿ ✬⑤⑤r✶✳t✐♣♦✮❀ ✶✻ ✶✼ ✲✲ ✶✽ ❡♥❞ ❧♦♦♣❀ ✶✾ ❡♥❞❀ ✷✵ ✴ ◆♦♠❡✿ ❙▼■❚❍ ✲ ❈❛r❣♦✿ ❈▲❊❘❑ ✲ ●❡r❡♥t❡✿ ✼✾✵✷ ✲ ❚✐♣♦✿ ▼❊◆❙❆▲■❙❚❆ ◆♦♠❡✿ ❆▲▲❊◆ ✲ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❲❆❘❉ ✲ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❏❖◆❊❙ ✲ ❈❛r❣♦✿ ▼❆◆❆●❊❘ ✲ ●❡r❡♥t❡✿ ✼✽✸✾ ✲ ❚✐♣♦✿ ❈❖▼■❙❙■❖◆❆❉❖ ◆♦♠❡✿ ▼❆❘❚■◆ ✲ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❇▲❆❑❊ ✲ ❈❛r❣♦✿ ▼❆◆❆●❊❘ ✲ ●❡r❡♥t❡✿ ✼✽✸✾ ✲ ❚✐♣♦✿ ❈❖▼■❙❙■❖◆❆❉❖ ◆♦♠❡✿ ❈▲❆❘❑ ✲ ❈❛r❣♦✿ ▼❆◆❆●❊❘ ✲ ●❡r❡♥t❡✿ ✼✽✸✾ ✲ ❚✐♣♦✿ ❈❖▼■❙❙■❖◆❆❉❖ ◆♦♠❡✿ ❙❈❖❚❚ ✲ ❈❛r❣♦✿ ❆◆❆▲❨❙❚ ✲ ●❡r❡♥t❡✿ ✼✺✻✻ ✲ ❚✐♣♦✿ ▼❊◆❙❆▲✴❍❖❘■❙❚❆ ◆♦♠❡✿ ❑■◆● ✲ ❈❛r❣♦✿ P❘❊❙■❉❊◆❚ ✲ ●❡r❡♥t❡✿ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❚❯❘◆❊❘ ✲ ❈❛r❣♦✿ ❙❆▲❊❙▼❆◆ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❆❉❆▼❙ ✲ ❈❛r❣♦✿ ❈▲❊❘❑ ✲ ●❡r❡♥t❡✿ ✼✼✽✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❏❆▼❊❙ ✲ ❈❛r❣♦✿ ❈▲❊❘❑ ✲ ●❡r❡♥t❡✿ ✼✻✾✽ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ ◆♦♠❡✿ ❋❖❘❉ ✲ ❈❛r❣♦✿ ❆◆❆▲❨❙❚ ✲ ●❡r❡♥t❡✿ ✼✺✻✻ ✲ ❚✐♣♦✿ ▼❊◆❙❆▲✴❍❖❘■❙❚❆ ◆♦♠❡✿ ▼■▲▲❊❘ ✲ ❈❛r❣♦✿ ❈▲❊❘❑ ✲ ●❡r❡♥t❡✿ ✼✼✽✷ ✲ ❚✐♣♦✿ ❖❯❚❘❖❙ P▲✴❙◗▲ ♣r♦❝❡❞✉r❡ s✉❝❝❡ss❢✉❧❧② ❝♦♠♣❧❡t❡❞✳ ❙◗▲❃ A opção entre usar um ou outro vai depender da abrangência dos seus programas. Se eles forem específicos para o uso em Oracle, o decode pode 222 Casa do Código Capítulo 15. Funções condicionais ser usado sem problemas. Inclusive, como pôde ser visto nos exemplos, ele pode se tornar visualmente mais claro para o entendimento do código. Já, se suas aplicações forem abrangentes no que diz respeito a operar em vários bancos de dados, você terá que usar o padrão ANSI, ou seja, usar o case para que eles funcionem em qualquer banco de dados, ou pelo menos naqueles que seguem este padrão. 223 Capítulo 16 Programas armazenados Até aqui, construímos programas em blocos chamados blocos anônimos. Caso quiséssemos guardá-los, teríamos que salvá-los em um ou mais arquivos em algum diretório no computador para não perdê-los. Quando quiséssemos executá-los novamente, teríamos que resgatá-los do computador para então executá-los em uma ferramenta, por exemplo, no SQL*Plus. Pois bem, agora vamos aprender como gravar estes programas no banco de dados. isso nos traz muitos benefícios e abre muitas possibilidades. A seguir vemos algumas delas: • Reaproveitamento de códigos: podemos escrever procedimentos e funções que podem servir como base para as demais partes de um sistema. Por exemplo, podemos criar uma função para validação de números de CPF que possa ser utilizada em vários módulos do sistema, 16.1. procedures e functions Casa do Código como no módulo de RH ou de compras, ou seja, podemos ter um programa gravado no banco de dados ao qual todos podem ter acesso. • Rapidez: tendo o programa armazenado no banco de dados, podemos acessá-lo rapidamente, sem ter que utilizar chamadas externas a arquivos. outro ponto interessante é que as ferramentas de desenvolvimento e análise do Oracle enxergam de forma nativa estes objetos armazenados. • Controle de alterações: um programa armazenado no banco de dados é muito mais fácil de ser alterado. É possível abri-lo e alterá-lo de forma mais rápida, compilando e em seguida efetivando as alterações. Como o programa está em um único lugar, os demais sistemas que o utilizam enxergarão todas as alterações realizadas. • Controle de acesso: através de concessões é possível limitar os acessos a estes programas, permitindo-os a apenas alguns usuários. • Modularização: veremos mais adiante que, pelo fato de estarem armazenados em um banco de dados, os programas podem ser agrupados dentro de pacotes, o que permite que nós os organizemos e estruturemos de acordo com seus escopos, viabilizando a modularização do sistema. Os programas armazenados podem ser de três tipos: procedimentos ( procedures), funções ( functions) e pacotes ( packages). A escolha de um ou de outro vai depender da necessidade ou da característica do programa. Trataremos neste capítulo de procedures e functions. Falaremos sobre packages no capítulo a seguir. 16.1 procedures e functions Para que um programa seja armazenado em um banco de dados, ele precisa receber um nome único, chamado de identificador, que será sua identificação dentro do banco de dados. É por ele que vamos manipulá-lo, localizá-lo no banco de dados, ou executá-lo. A nomenclatura utilizada para nomear este 226 Casa do Código Capítulo 16. Programas armazenados identificador segue as mesmas regras dos identificadores de variáveis e constantes vistos em capítulos anteriores: ele pode ter um tamanho máximo de 30 caracteres, que se restringem a alguns caracteres especiais, na sua maioria, caracteres alfanuméricos; e deve iniciar por uma letra. Depois de criados, os programas armazenados podem ser executados através de ferramentas tais como SQL*Plus, Oracle Forms, Oracle Reports etc., bem como podem ser chamados por outros programas armazenados ou por blocos PL/SQL anônimos. Também temos a opção de criar procedures e functions dentro de blocos PL/SQL anônimos ou dentro de outras procedures, functions, triggers ou packages. Contudo, suas definições não ficam armazenadas dentro do dicionário de objetos do Oracle, apenas dentro do objeto onde estão sendo criadas. Conforme dito anteriormente, a escolha do tipo no momento de criar um programa armazenado depende da necessidade, ou melhor, do escopo em que se encaixa. Por exemplo, quando queremos que um programa retorne uma informação, podemos criá-lo como function. Este tipo de programa armazenado, além de executar alguma ação, pode ainda retornar um tipo de informação para o programa chamador ou para a ferramenta que o executou. Um exemplo seria uma função que retornasse se o número de CPF é válido ou não. Caso não seja necessário retornar uma informação, podemos criar o programa como sendo uma procedure. Neste caso, ela executa suas ações como um programa qualquer, mas não retorna nada (veremos mais adiante que é possível, sim, ter retorno através de procedures). O que deve ficar claro é que funções sempre devem retornar um valor, já procedimentos não possuem esta obrigatoriedade. Veja a seguir um exemplo de procedure. ❙◗▲❃ ❝r❡❛t❡ ♣r♦❝❡❞✉r❡ ❝❛❧❝ ✷ ✲✲ ✸ ①✶ ♥✉♠❜❡r ✿❂ ✹ ①✷ ♥✉♠❜❡r ✿❂ ✺ ♦♣ ✈❛r❝❤❛r✷✭✶✮ ✿❂ ✻ r❡s ♥✉♠❜❡r❀ ✼ ✲✲ ✽ ❜❡❣✐♥ ✐s ✶✵❀ ✺❀ ✬✰✬❀ 227 16.1. procedures e functions Casa do Código ✾ ✐❢ ✭①✶ ✰ ①✷✮ ❂ ✵ t❤❡♥ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✵✬✮❀ ✶✶ ❡❧s✐❢ ♦♣ ❂ ✬✯✬ t❤❡♥ ✶✷ r❡s ✿❂ ①✶ ✯ ①✷❀ ✶✸ ❡❧s✐❢ ♦♣ ❂ ✬✴✬ t❤❡♥ ✶✹ ✐❢ ①✷ ❂ ✵ t❤❡♥ ✶✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❞❡ ❞✐✈✐sã♦ ♣♦r ③❡r♦✦✬✮❀ ✶✻ ❡❧s❡ ✶✼ r❡s ✿❂ ①✶ ✴ ①✷❀ ✶✽ ❡♥❞ ✐❢❀ ✶✾ ❡❧s✐❢ ♦♣ ❂ ✬✲✬ t❤❡♥ ✷✵ r❡s ✿❂ ①✶ ✲ ①✷❀ ✷✶ ✐❢ r❡s ❂ ✵ t❤❡♥ ✷✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ✐❣✉❛❧ ❛ ③❡r♦✦✬✮❀ ✷✸ ❡❧s✐❢ r❡s ❁ ✵ t❤❡♥ ✷✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❡♥♦r q✉❡ ③❡r♦✦✬✮❀ ✷✺ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ✷✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❛✐♦r❧ ❛ ③❡r♦✦✬✮❀ ✷✼ ❡♥❞ ✐❢❀ ✷✽ ❡❧s✐❢ ♦♣ ❂ ✬✰✬ t❤❡♥ ✷✾ r❡s ✿❂ ①✶ ✰ ①✷❀ ✸✵ ❡❧s❡ ✸✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖♣❡r❛❞♦r ✐♥✈á❧✐❞♦✦✬✮❀ ✸✷ ❡♥❞ ✐❢❀ ✸✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✸✹ ❡♥❞❀ ✸✺ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ O procedimento anterior tem o objetivo de realizar cálculos numéricos. Note que basicamente, o que muda de uma procedure para um bloco anônimo é que nela temos um cabeçalho onde informamos um identificador, neste caso, calc, que precede o comando create procedure e antecede o comando is que indica o início do procedimento. Após isso, temos basicamente um bloco PL/SQL comum ao que já vimos até aqui. O mesmo acontece 228 Casa do Código Capítulo 16. Programas armazenados com a criação de funções. Agora vejamos um exemplo de function. ❙◗▲❃ ❝r❡❛t❡ ❢✉♥❝t✐♦♥ ✈❛❧✐❞❛❴❝♣❢ r❡t✉r♥ ✈❛r❝❤❛r✷ ✐s ✷ ✲✲ ✸ ♠❴t♦t❛❧ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✹ ♠❴❞✐❣✐t♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✺ ❝♣❢ ✈❛r❝❤❛r✷✭✺✵✮ ❞❡❢❛✉❧t ✬✵✷✹✶✶✽✹✽✹✸✵✬❀ ✻ ✲✲ ✼ ❜❡❣✐♥ ✽ ❢♦r ✐ ✐♥ ✶✳✳✾ ❧♦♦♣ ✾ ♠❴t♦t❛❧ ✿❂ ♠❴t♦t❛❧ ✰ s✉❜str ✭❝♣❢✱ ✐✱ ✶✮ ✯ ✭✶✶ ✲ ✐✮❀ ✶✵ ❡♥❞ ❧♦♦♣❀ ✶✶ ✲✲ ✶✷ ♠❴❞✐❣✐t♦ ✿❂ ✶✶ ✲ ♠♦❞ ✭♠❴t♦t❛❧✱ ✶✶✮❀ ✶✸ ✲✲ ✶✹ ✐❢ ♠❴❞✐❣✐t♦ ❃ ✾ t❤❡♥ ✶✺ ♠❴❞✐❣✐t♦ ✿❂ ✵❀ ✶✻ ❡♥❞ ✐❢❀ ✶✼ ✲✲ ✶✽ ✐❢ ♠❴❞✐❣✐t♦ ✦❂ s✉❜str ✭❝♣❢✱ ✶✵✱ ✶✮ t❤❡♥ ✶✾ r❡t✉r♥ ✬■✬❀ ✷✵ ❡♥❞ ✐❢❀ ✷✶ ✲✲ ✷✷ ♠❴❞✐❣✐t♦ ✿❂ ✵❀ ✷✸ ♠❴t♦t❛❧ ✿❂ ✵❀ ✷✹ ✲✲ ✷✺ ❢♦r ✐ ✐♥ ✶✳✳✶✵ ❧♦♦♣ ✷✻ ♠❴t♦t❛❧ ✿❂ ♠❴t♦t❛❧ ✰ s✉❜str ✭❝♣❢✱ ✐✱ ✶✮ ✯ ✭✶✷ ✲ ✐✮❀ ✷✼ ❡♥❞ ❧♦♦♣❀ ✷✽ ✲✲ ✷✾ ♠❴❞✐❣✐t♦ ✿❂ ✶✶ ✲ ♠♦❞ ✭♠❴t♦t❛❧✱ ✶✶✮❀ ✸✵ ✲✲ ✸✶ ✐❢ ♠❴❞✐❣✐t♦ ❃ ✾ t❤❡♥ ✸✷ ♠❴❞✐❣✐t♦ ✿❂ ✵❀ ✸✸ ❡♥❞ ✐❢❀ ✸✹ ✲✲ ✸✺ ✐❢ ♠❴❞✐❣✐t♦ ✦❂ s✉❜str ✭❝♣❢✱ ✶✶✱ ✶✮ t❤❡♥ ✸✻ r❡t✉r♥ ✬■✬❀ 229 16.1. procedures e functions Casa do Código ✸✼ ❡♥❞ ✐❢❀ ✸✽ ✲✲ ✸✾ r❡t✉r♥ ✬❱✬❀ ✹✵ ✲✲ ✹✶ ❡♥❞ ✈❛❧✐❞❛❴❝♣❢❀ ✹✷ ✴ ❋✉♥çã♦ ❝r✐❛❞❛✳ ❙◗▲❃ Essa função tem o objetivo de validar um número de CPF e retornar falso ou verdadeiro, dependendo da validação. Igualmente às procedures, têm-se um cabeçalho onde definimos um identificador para a função, neste exemplo, valida_cpf, que precede o comando create function e antecede os comandos return, seguido pelo tipo de dado a ser retornado, e is indicando o início da função. Logo após, temos a codificação da função dentro de um bloco PL/SQL. Como comentamos anteriormente, procedures e functions também podem ser criadas dentro de blocos PL/SQL anônimos ou dentro de objetos. A seguir, utilizamos os mesmos objetos dos exemplos anteriores para mostrar como isso é feito. Procedure criada no bloco: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ♣r♦❝❡❞✉r❡ ❝❛❧❝ ✐s ✹ ✲✲ ✺ ①✶ ♥✉♠❜❡r ✿❂ ✶✵❀ ✻ ①✷ ♥✉♠❜❡r ✿❂ ✺❀ ✼ ♦♣ ✈❛r❝❤❛r✷✭✶✮ ✿❂ ✬✰✬❀ ✽ r❡s ♥✉♠❜❡r❀ ✾ ✲✲ ✶✵ ❜❡❣✐♥ ✶✶ ✐❢ ✭①✶ ✰ ①✷✮ ❂ ✵ t❤❡♥ ✶✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✵✬✮❀ ✶✸ ❡❧s✐❢ ♦♣ ❂ ✬✯✬ t❤❡♥ ✶✹ r❡s ✿❂ ①✶ ✯ ①✷❀ 230 Casa do Código Capítulo 16. Programas armazenados ✶✺ ❡❧s✐❢ ♦♣ ❂ ✬✴✬ t❤❡♥ ✶✻ ✐❢ ①✷ ❂ ✵ t❤❡♥ ✶✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❞❡ ❞✐✈✐sã♦ ♣♦r ③❡r♦✦✬✮❀ ✶✽ ❡❧s❡ ✶✾ r❡s ✿❂ ①✶ ✴ ①✷❀ ✷✵ ❡♥❞ ✐❢❀ ✷✶ ❡❧s✐❢ ♦♣ ❂ ✬✲✬ t❤❡♥ ✷✷ r❡s ✿❂ ①✶ ✲ ①✷❀ ✷✸ ✐❢ r❡s ❂ ✵ t❤❡♥ ✷✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ✐❣✉❛❧ ❛ ③❡r♦✦✬✮❀ ✷✺ ❡❧s✐❢ r❡s ❁ ✵ t❤❡♥ ✷✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❡♥♦r q✉❡ ③❡r♦✦✬✮❀ ✷✼ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ✷✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❛✐♦r❧ ❛ ③❡r♦✦✬✮❀ ✷✾ ❡♥❞ ✐❢❀ ✸✵ ❡❧s✐❢ ♦♣ ❂ ✬✰✬ t❤❡♥ ✸✶ r❡s ✿❂ ①✶ ✰ ①✷❀ ✸✷ ❡❧s❡ ✸✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖♣❡r❛❞♦r ✐♥✈á❧✐❞♦✦✬✮❀ ✸✹ ❡♥❞ ✐❢❀ ✸✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✸✻ ❡♥❞❀ ✸✼ ✲✲ ✸✽ ❜❡❣✐♥ ✸✾ ❝❛❧❝❀ ✹✵ ❡♥❞❀ ✹✶ ✴ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✶✺ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Nesse exemplo, é possível verificar que a procedure foi criada no nível do bloco, ou seja, ele existe apenas dentro do bloco e não está armazenada no banco de dados. Logo, caso seja de nossa vontade utilizá-la novamente, teremos que salvar todo o código do bloco em um arquivo externo. Desta forma, também não é possível que outros programas usem-na. Note também que nestes casos não usamos o comando create. Começamos direto pelo 231 16.1. procedures e functions Casa do Código tipo do programa, a procedure. Function criada em uma procedure. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ r❡s ✈❛r❝❤❛r✷✭✶✮ ❞❡❢❛✉❧t ♥✉❧❧❀ ✹ ✲✲ ✺ ❢✉♥❝t✐♦♥ ✈❛❧✐❞❛❴❝♣❢ r❡t✉r♥ ✈❛r❝❤❛r✷ ✐s ✻ ✲✲ ✼ ♠❴t♦t❛❧ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✽ ♠❴❞✐❣✐t♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✾ ❝♣❢ ✈❛r❝❤❛r✷✭✺✵✮ ❞❡❢❛✉❧t ✬✵✷✹✶✶✽✹✽✹✸✵✬❀ ✶✵ ✲✲ ✶✶ ❜❡❣✐♥ ✶✷ ❢♦r ✐ ✐♥ ✶✳✳✾ ❧♦♦♣ ✶✸ ♠❴t♦t❛❧ ✿❂ ♠❴t♦t❛❧ ✰ s✉❜str ✭❝♣❢✱ ✐✱ ✶✮ ✯ ✭✶✶ ✲ ✐✮❀ ✶✹ ❡♥❞ ❧♦♦♣❀ ✶✺ ✲✲ ✶✻ ♠❴❞✐❣✐t♦ ✿❂ ✶✶ ✲ ♠♦❞ ✭♠❴t♦t❛❧✱ ✶✶✮❀ ✶✼ ✲✲ ✶✽ ✐❢ ♠❴❞✐❣✐t♦ ❃ ✾ t❤❡♥ ✶✾ ♠❴❞✐❣✐t♦ ✿❂ ✵❀ ✷✵ ❡♥❞ ✐❢❀ ✷✶ ✲✲ ✷✷ ✐❢ ♠❴❞✐❣✐t♦ ✦❂ s✉❜str ✭❝♣❢✱ ✶✵✱ ✶✮ t❤❡♥ ✷✸ r❡t✉r♥ ✬■✬❀ ✷✹ ❡♥❞ ✐❢❀ ✷✺ ✲✲ ✷✻ ♠❴❞✐❣✐t♦ ✿❂ ✵❀ ✷✼ ♠❴t♦t❛❧ ✿❂ ✵❀ ✷✽ ✲✲ ✷✾ ❢♦r ✐ ✐♥ ✶✳✳✶✵ ❧♦♦♣ ✸✵ ♠❴t♦t❛❧ ✿❂ ♠❴t♦t❛❧ ✰ s✉❜str ✭❝♣❢✱ ✐✱ ✶✮ ✯ ✭✶✷ ✲ ✐✮❀ ✸✶ ❡♥❞ ❧♦♦♣❀ ✸✷ ✲✲ ✸✸ ♠❴❞✐❣✐t♦ ✿❂ ✶✶ ✲ ♠♦❞ ✭♠❴t♦t❛❧✱ ✶✶✮❀ ✸✹ ✲✲ ✸✺ ✐❢ ♠❴❞✐❣✐t♦ ❃ ✾ t❤❡♥ ✸✻ ♠❴❞✐❣✐t♦ ✿❂ ✵❀ 232 Casa do Código ✸✼ ✸✽ ✸✾ ✹✵ ✹✶ ✹✷ ✹✸ ✹✹ ✹✺ ✹✻ ✹✼ ✹✽ ✹✾ ✺✵ ✺✶ ✺✷ ✺✸ ✺✹ ✺✺ ✺✻ ✺✼ ❈P❋ Capítulo 16. Programas armazenados ❡♥❞ ✐❢❀ ✲✲ ✐❢ ♠❴❞✐❣✐t♦ ✦❂ s✉❜str ✭❝♣❢✱ ✶✶✱ ✶✮ t❤❡♥ r❡t✉r♥ ✬■✬❀ ❡♥❞ ✐❢❀ ✲✲ r❡t✉r♥ ✬❱✬❀ ✲✲ ❡♥❞ ✈❛❧✐❞❛❴❝♣❢❀ ✲✲ ❜❡❣✐♥ r❡s ✿❂ ✈❛❧✐❞❛❴❝♣❢❀ ✲✲ ✐❢ r❡s ❂ ✬❱✬ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈P❋ ✈á❧✐❞♦✬✮❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈P❋ ✐♥✈á❧✐❞♦✬✮❀ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞❀ ✴ ✐♥✈á❧✐❞♦ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ O mesmo acontece aqui com o exemplo desta função. Como ela está criada no nível do bloco, ela não se encontra armazenada no banco de dados. Note também que nestes casos não usamos o comando create. Começamos direto pelo tipo do programa, a function. Uma procedure pode ser chamada de dentro de um bloco PL/SQL, de dentro de programas em Oracle Forms, Oracle Reports etc. Entretanto, elas não podem ser chamadas através de um comando SQL. Já as functions podem ser chamadas também de dentro de comandos SQL, pelo fato de elas retornarem um valor. Contudo, há algumas restrições, por exemplo, ela não pode ter em sua composição comandos DML, DDL e DCL, apenas selects. outra característica das functions é a recursividade, com a qual podemos 233 16.1. procedures e functions Casa do Código criar uma função que chama ela mesma. Os procedimentos podem ser chamados de duas formas. Se estivermos trabalhando com SQL*Plus podemos chamá-la através do comando execute, e através de um bloco PL/SQL anônimo ou programa armazenado. Veja os dois exemplos de chamada a seguir. ❙◗▲❃ ❡①❡❝✉t❡ ❝❛❧❝❀ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✶✺ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ❙◗▲❃ ❜❡❣✐♥ ✷ ❝❛❧❝❀ ✸ ❡♥❞❀ ✹ ✴ ❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✶✺ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Assim como nos procedimentos, as funções também podem ser chamadas de duas formas. Uma através de blocos PL/SQL anônimos ou programas armazenados, e através de comandos SQL ( select, insert, delete ou update). Vale ressaltar que para chamadas via comando SQL existem algumas restrições. Veja os dois exemplos de chamada a seguir. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ r❡s ✈❛r❝❤❛r✷✭✶✮ ❞❡❢❛✉❧t ♥✉❧❧❀ ✹ ✲✲ ✺ ❜❡❣✐♥ ✻ r❡s ✿❂ ✈❛❧✐❞❛❴❝♣❢❀ ✼ ✲✲ ✽ ✐❢ r❡s ❂ ✬❱✬ t❤❡♥ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈P❋ ✈á❧✐❞♦✬✮❀ ✶✵ ❡❧s❡ 234 Casa do Código Capítulo 16. Programas armazenados ✶✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈P❋ ✐♥✈á❧✐❞♦✬✮❀ ✶✷ ❡♥❞ ✐❢❀ ✶✸ ✲✲ ✶✹ ❡♥❞❀ ✶✺ ✴ ❈P❋ ✐♥✈á❧✐❞♦ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ❙◗▲❃ s❡❧❡❝t ❞❡❝♦❞❡✭✈❛❧✐❞❛❴❝♣❢✱✬❱✬✱✬❱á❧✐❞♦✬✱✬✐♥✈á❧✐❞♦✬✮ ❈P❋ ❢r♦♠ ❞✉❛❧❀ ❈P❋ ✲✲✲✲✲✲✲✲✲ ✐♥✈á❧✐❞♦ ❙◗▲❃ Concedendo acesso a procedures e functions Uma vantagem no uso de procedures e functions está relacionada à restrição de acesso. Objetos criados no banco de dados precisam de permissão para acesso, caso quem os queira acessar não seja o dono ou DBA do sistema. Para dar acesso a procedures e functions utilizamos o comando grant execute. ❙◗▲❃ ❣r❛♥t ❡①❡❝✉t❡ ♦♥ ❝❛❧❝ t♦ ♣✉❜❧✐❝❀ ❈♦♥❝❡ssã♦ ❜❡♠✲s✉❝❡❞✐❞❛✳ ❙◗▲❃ ❣r❛♥t ❡①❡❝✉t❡ ♦♥ ✈❛❧✐❞❛❴❝♣❢ t♦ ❚❙◗▲✷❀ ❈♦♥❝❡ssã♦ ❜❡♠✲s✉❝❡❞✐❞❛✳ ❙◗▲❃ Também é possível criarmos sinônimos para facilitar o acesso. Os sinônimos podem ser específicos a um usuário ou público. Vale ressaltar que eles 235 16.2. Uso do comando replace Casa do Código não dão acesso, apenas permitem criar um alias para o objeto. ❙◗▲❃ ❝r❡❛t❡ ♣✉❜❧✐❝ s②♥♦♥②♠ ❝❛❧❝❴✈❛❧♦r❡s ❢♦r tsq❧✳❝❛❧❝❀ ❙✐♥ô♥✐♠♦ ❝r✐❛❞♦✳ ❙◗▲❃ ❝r❡❛t❡ s②♥♦♥②♠ tsq❧✷✳✈❛❧✐❞❛❴❝♣❢ ❢♦r tsq❧✳✈❛❧✐❞❛❴❝♣❢❀ ❙✐♥ô♥✐♠♦ ❝r✐❛❞♦✳ ❙◗▲❃ Note que podemos dar grants e criar sinônimos para o usuário public. Quando fazemos desta forma, todos os usuários do banco de dados terão acesso ao referido objeto. 16.2 Uso do comando replace Quando precisamos dar manutenção em procedures e functions, podemos utilizar a cláusula replace para garantir que algumas definições sejam preservadas. Como esses objetos possuem um identificador único, não é possível criar outro com o mesmo nome. Logo, para recriarmos um objeto como este nós podemos utilizar a cláusula replace. Caso contrário, seria necessário excluir o objeto existente e criá-lo novamente. Com isto, informações referentes a permissões de acesso seriam excluídas também. Já com o comando replace, este tipo de informação permanece, assim como a marcação de objetos dependentes para recompilação. Com relação à dependência de objetos, da qual falaremos mais à frente, só para um entendimento prévio, é comum termos programas que chamam outros programas, acabando por criar dependências entre eles, o que pode invalidar todo um conjunto de objetos caso um seja excluído ou invalidado. Em alguns casos, o Oracle poderá recompilar objetos, automaticamente (dependendo do nível de dependência), quando são recriados, e não excluídos e criados logo em seguida. outra vantagem do comando replace é a possibilidade de criar objetos mesmo com erros de sintaxe em seus códigos. Nesse caso, eles perma236 Casa do Código Capítulo 16. Programas armazenados necem inválidos enquanto tais erros existirem. A seguir o uso do comando replace. ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ ✸✵ ✸✶ ✸✷ ✸✸ ✸✹ ✸✺ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ❝❛❧❝ ✐s ✲✲ ①✶ ♥✉♠❜❡r ✿❂ ✶✵❀ ①✷ ♥✉♠❜❡r ✿❂ ✺❀ ♦♣ ✈❛r❝❤❛r✷✭✶✮ ✿❂ ✬✰✬❀ r❡s ♥✉♠❜❡r❀ ✲✲ ❜❡❣✐♥ ✐❢ ✭①✶ ✰ ①✷✮ ❂ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✵✬✮❀ ❡❧s✐❢ ♦♣ ❂ ✬✯✬ t❤❡♥ r❡s ✿❂ ①✶ ✯ ①✷❀ ❡❧s✐❢ ♦♣ ❂ ✬✴✬ t❤❡♥ ✐❢ ①✷ ❂ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❞❡ ❞✐✈✐sã♦ ♣♦r ③❡r♦✦✬✮❀ ❡❧s❡ r❡s ✿❂ ①✶ ✴ ①✷❀ ❡♥❞ ✐❢❀ ❡❧s✐❢ ♦♣ ❂ ✬✲✬ t❤❡♥ r❡s ✿❂ ①✶ ✲ ①✷❀ ✐❢ r❡s ❂ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ✐❣✉❛❧ ❛ ③❡r♦✦✬✮❀ ❡❧s✐❢ r❡s ❁ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❡♥♦r q✉❡ ③❡r♦✦✬✮❀ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❛✐♦r❧ ❛ ③❡r♦✦✬✮❀ ❡♥❞ ✐❢❀ ❡❧s✐❢ ♦♣ ❂ ✬✰✬ t❤❡♥ r❡s ✿❂ ①✶ ✰ ①✷❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖♣❡r❛❞♦r ✐♥✈á❧✐❞♦✦✬✮❀ ❡♥❞ ✐❢❀ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ❡♥❞❀ ✴ 237 16.3. Recompilando programas armazenados Casa do Código Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ 16.3 Recompilando programas armazenados Quando alteramos uma procedure ou function no banco de dados, pode acontecer de termos que compilá-la novamente. Para isso, utilizamos o comando alter. Veja os exemplos: ❙◗▲❃ ❛❧t❡r ♣r♦❝❡❞✉r❡ ❝❛❧❝ ❝♦♠♣✐❧❡❀ Pr♦❝❡❞✐♠❡♥t♦ ❛❧t❡r❛❞♦✳ ❙◗▲❃ ❛❧t❡r ❢✉♥❝t✐♦♥ ✈❛❧✐❞❛❴❝♣❢ ❝♦♠♣✐❧❡❀ ❋✉♥çã♦ ❛❧t❡r❛❞❛✳ ❙◗▲❃ 16.4 Recuperando informações Para visualizar informações referentes a procedures e functions utilize as views user_objects, all_objects ou dba_objects. Nesta view constam informações como STATUS e data de criação do objeto. ❙◗▲❃ s❡❧❡❝t ♦✇♥❡r✱ ♦❜❥❡❝t❴t②♣❡✱ st❛t✉s✱ ❝r❡❛t❡❞✱ ❧❛st❴❞❞❧❴t✐♠❡ ✷ ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✇❤❡r❡ ♦❜❥❡❝t❴♥❛♠❡ ❂ ✬❈❆▲❈✬❀ ❖❲◆❊❘ ❖❇❏❊❈❚❴❚❨P❊ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲ ❚❙◗▲ ♣r♦❝❡❞✉r❡ ❱❆▲■❉ ❝r❡❛t❡❉ ▲❆❙❚❴❉❉▲ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✷✺✴✶✶✴✶✶ ✷✺✴✶✶✴✶✶ ❙◗▲❃ 238 Casa do Código Capítulo 16. Programas armazenados Outra forma de recuperar dados referentes a procedures e functions é utilizando o comando describe. Este comando mostra informações referentes a estes objetos, como dados do cabeçalho e parâmetros existentes. ❙◗▲❃ ❞❡s❝ ❝❛❧❝ ♣r♦❝❡❞✉r❡ ❝❛❧❝ ◆♦♠❡ ❞♦ ❆r❣✉♠❡♥t♦ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❳✶ ❳✷ ❖P ❘❊❙ ❚✐♣♦ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ◆❯▼❇❊❘ ◆❯▼❇❊❘ ❱❆❘❈❍❆❘✷ ❱❆❘❈❍❆❘✷ ✐♥✴♦✉t ❉❡❢❛✉❧t❄ ✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✐♥ ✐♥ ✐♥ ♦✉t ❙◗▲❃ 16.5 Recuperando códigos Já para visualizar o código dos objetos armazenados no banco de dados, utilize as views user_source, all_source ou dba_source. ❙◗▲❃ ❙◗▲❃ ❙◗▲❃ ✷ ❝♦❧✉♠♥ t❡①t ❢♦r♠❛t ❛✶✵✵ s❡t ♣❛❣❡s ✶✵✵✵ s❡❧❡❝t ❧✐♥❡✱ t❡①t ❢r♦♠ ❛❧❧❴s♦✉r❝❡ ✇❤❡r❡ ♥❛♠❡ ❂ ✬❈❆▲❈✬❀ ▲✐♥❊ ❚❊❳❚ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✶ ♣r♦❝❡❞✉r❡ ❝❛❧❝ ✐s ✷ ✲✲ ✸ ①✶ ♥✉♠❜❡r ✿❂ ✶✵❀ ✹ ①✷ ♥✉♠❜❡r ✿❂ ✺❀ 239 16.6. Visualizando erros de compilação Casa do Código ✺ ♦♣ ✈❛r❝❤❛r✷✭✶✮ ✿❂ ✬✰✬❀ ✻ r❡s ♥✉♠❜❡r❀ ✼ ✲✲ ✽ ❜❡❣✐♥ ✾ ✐❢ ✭①✶ ✰ ①✷✮ ❂ ✵ t❤❡♥ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✵✬✮❀ ✶✶ ❡❧s✐❢ ♦♣ ❂ ✬✯✬ t❤❡♥ ✶✷ r❡s ✿❂ ①✶ ✯ ①✷❀ ✶✸ ❡❧s✐❢ ♦♣ ❂ ✬✴✬ t❤❡♥ ✶✹ ✐❢ ①✷ ❂ ✵ t❤❡♥ ✶✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❞❡ ❞✐✈✐sã♦ ♣♦r ③❡r♦✦✬✮❀ ✶✻ ❡❧s❡ ✶✼ r❡s ✿❂ ①✶ ✴ ①✷❀ ✶✽ ❡♥❞ ✐❢❀ ✶✾ ❡❧s✐❢ ♦♣ ❂ ✬✲✬ t❤❡♥ ✷✵ r❡s ✿❂ ①✶ ✲ ①✷❀ ✷✶ ✐❢ r❡s ❂ ✵ t❤❡♥ ✷✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ✐❣✉❛❧ ❛ ③❡r♦✦✬✮❀ ✷✸ ❡❧s✐❢ r❡s ❁ ✵ t❤❡♥ ✷✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❡♥♦r q✉❡ ③❡r♦✦✬✮❀ ✷✺ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ✷✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❛✐♦r❧ ❛ ③❡r♦✦✬✮❀ ✷✼ ❡♥❞ ✐❢❀ ✷✽ ❡❧s✐❢ ♦♣ ❂ ✬✰✬ t❤❡♥ ✷✾ r❡s ✿❂ ①✶ ✰ ①✷❀ ✸✵ ❡❧s❡ ✸✶ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖♣❡r❛❞♦r ✐♥✈á❧✐❞♦✦✬✮❀ ✸✷ ❡♥❞ ✐❢❀ ✸✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ✸✹ ❡♥❞❀ ✸✹ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ 16.6 Visualizando erros de compilação Para visualizar erros de compilação, use o comando show error. 240 Casa do Código ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ ✸✵ ✸✶ ✸✷ ✸✸ ✸✹ ✸✺ ✸✻ Capítulo 16. Programas armazenados ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ❝❛❧❝ ✐s ✲✲ ①✶ ♥✉♠❜❡r ✿❂ ✶✵❀ ①✷ ♥✉♠❜❡r ✿❂ ✺❀ ♦♣ ✈❛r❝❤❛r✷✭✶✮ ✿❂ ✬✰✬❀ r❡s ♥✉♠❜❡r❀ ✲✲ ❜❡❣✐♥ ✐❢ ✭①✶ ✰ ①✷✮ ❂ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦✿ ✵✬✮❀ ❡❧s✐❢ ♦♣ ❂ ✬✯✬ t❤❡♥ r❡s ✿❂ ①✶ ✯ ①✷❀ ❡❧s✐❢ ♦♣ ❂ ✬✴✬ t❤❡♥ ✐❢ ①✷ ❂ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❞❡ ❞✐✈✐sã♦ ♣♦r ③❡r♦✦✬✮❀ ❡❧s❡ r❡s ✿❂ ①✶ ✴ ①✷❀ ❡♥❞ ✐❢❀ ❡❧s✐❢ ♦♣ ❂ ✬✲✬ t❤❡♥ r❡s ✿❂ ①✶ ✲ ①✷❀ ✐❢ r❡s ❂ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ✐❣✉❛❧ ❛ ③❡r♦✦✬✮❀ ❡❧s✐❢ r❡s ❁ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❡♥♦r q✉❡ ③❡r♦✦✬✮❀ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ♠❛✐♦r❧ ❛ ③❡r♦✦✬✮❀ ❡♥❞ ✐❢❀ ❡❧s✐❢ ♦♣ ❂ ✬✰✬ t❤❡♥ r❡s ✿❂ ①✶ ✰ ①✷❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖♣❡r❛❞♦r ✐♥✈á❧✐❞♦✦✬✮❀ ❡♥❞ ✐❢❀ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❞♦ ❝á❧❝✉❧♦✿ ✬⑤⑤r❡s✮❀ ❀ ✲✲ ♣r♦✈♦❝❛♥❞♦ ✉♠ ❡rr♦ ❞❡ s✐♥t❛①❡✳ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ 241 Casa do Código 16.6. Visualizando erros de compilação ❙◗▲❃ s❤♦✇ ❡rr♦r ❊rr♦s ♣❛r❛ ♣r♦❝❡❞✉r❡ ❈❆▲❈✿ ▲✐♥❊✴❈❖▲ ❊❘❘❖❘ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✸✹✴✸ P▲❙✲✵✵✶✵✸✿ ❊♥❝♦♥tr❛❞♦ ♦ sí♠❜♦❧♦ ✧❀✧ q✉❛♥❞♦ ✉♠ ❞♦s s❡❣✉✐♥t❡s sí♠❜♦❧♦s ❡r❛ ❡s♣❡r❛❞♦✿ ❜❡❣✐♥ ❝❛s❡ ❞❡❝❧❛r❡ ❡♥❞ ❡①❝❡♣t✐♦♥ ❡①✐t ❢♦r ❣♦t♦ ✐❢ ❧♦♦♣ ♠♦❞ ♥✉❧❧ ♣r❛❣♠❛ r❛✐s❡ r❡t✉r♥ s❡❧❡❝t ✉♣❞❛t❡ ✇❤✐❧❡ ✇✐t❤ ❁✉♠ ✐❞❡♥t✐❢✐❝❛❞♦r❃ ❁✉♠ ✐❞❡♥t✐❢✐❝❛❞♦r ❞❡❧✐♠✐t❛❞♦ ♣♦r ❛s♣❛s ❞✉♣❧❛s❃ ❁✉♠❛ ✈❛r✐á✈❡❧ ❞❡ ❧✐❣❛çã♦❃ ❁❁ ❝❧♦s❡ ❝✉rr❡♥t ❞❡❧❡t❡ ❢❡t❝❤ ❧♦❝❦ ✐♥s❡rt ♦♣❡♥ r♦❧❧❜❛❝❦ s❛✈❡♣♦✐♥t s❡t sq❧ ❡①❡❝✉t❡ ❝♦♠♠✐t ❢♦r❛❧❧ ♠❡r❣❡ ♣✐♣❡ ❖ sí♠❜♦❧♦ ✧❡①✐t✧ ❢♦✐ s✉❜st✐t✉í❞♦ ♣♦r ✧❀✧ ♣❛r❛ ❝♦♥t✐♥✉❛r✳ ❙◗▲❃ O comando basicamente mostra duas colunas. A primeira com a linha e a coluna onde ocorreu o erro, e a segunda, a coluna com a descrição. Este erro também pode ser encontrado através das views user_errors, all_errors e dba_errors. ❙◗▲❃ s❡❧❡❝t ❧✐♥❡ ✷ ✱♣♦s✐t✐♦♥ ✸ ✱t❡①t ✹ ❢r♦♠ ✉s❡r❴❡rr♦rs ✺ ✇❤❡r❡ ♥❛♠❡ ❂ ✬❈❆▲❈✬❀ ▲✐♥❊ P❖❙■❚■❖◆ ❚❊❳❚ ✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✸✹ ✸ P▲❙✲✵✵✶✵✸✿ ❊♥❝♦♥tr❛❞♦ ♦ sí♠❜♦❧♦ ✧❀✧ q✉❛♥❞♦ ✉♠ ❞♦s s❡❣✉✐♥t❡s sí♠❜♦❧♦s ❡r❛ ❡s♣❡r❛❞♦✿ ❜❡❣✐♥ ❝❛s❡ ❞❡❝❧❛r❡ ❡♥❞ ❡①❝❡♣t✐♦♥ ❡①✐t ❢♦r ❣♦t♦ ✐❢ ❧♦♦♣ ♠♦❞ ♥✉❧❧ ♣r❛❣♠❛ r❛✐s❡ r❡t✉r♥ s❡❧❡❝t ✉♣❞❛t❡ ✇❤✐❧❡ ✇✐t❤ ❁✉♠ ✐❞❡♥t✐❢✐❝❛❞♦r❃ ❁✉♠ ✐❞❡♥t✐❢✐❝❛❞♦r ❞❡❧✐♠✐t❛❞♦ ♣♦r ❛s♣❛s ❞✉♣❧❛s❃ 242 Casa do Código Capítulo 16. Programas armazenados ❁✉♠❛ ✈❛r✐á✈❡❧ ❞❡ ❧✐❣❛çã♦❃ ❁❁ ❝❧♦s❡ ❝✉rr❡♥t ❞❡❧❡t❡ ❢❡t❝❤ ❧♦❝❦ ✐♥s❡rt ♦♣❡♥ r♦❧❧❜❛❝❦ s❛✈❡♣♦✐♥t s❡tsq❧ ❡①❡❝✉t❡ ❝♦♠♠✐t ❢♦r❛❧❧ ♠❡r❣❡ ♣✐♣❡ ❖ sí♠❜♦❧♦ ✧❡①✐t✧ ❢♦✐ s✉❜st✐t✉í❞♦ ♣♦r ✧❀✧ ♣❛r❛ ❝♦♥t✐♥✉❛r✳ ❙◗▲❃ 16.7 Passando parâmetros Programas armazenados, como procedures e functions, permitem trabalhar com passagem de parâmetros. Quando criamos um procedimento ou uma função, podemos especificar parâmetros de entrada e saída para que valores possam ser levados para dentro destes programas ou recuperados deles. Os parâmetros podem ser do tipo in, out ou in out. in define que se trata de um parâmetro de entrada. Já um parâmetro do tipo out indica que ele é de saída. Logo, in out indica um parâmetro de entrada e saída. Quando estamos falando de parâmetros de entrada ( in), isso quer dizer que os valores contidos neles podem ser atribuídos a outras variáveis ou parâmetros existentes dentro da procedure ou function. Contudo, não podemos atribuir valores a eles. Já quando estamos falando dos parâmetros de saída ( out), estamos dizendo que os valores destes parâmetros podem ser alterados, mas não atribuídos a outras variáveis ou parâmetros existentes dentro destes objetos. Logo, quando temos parâmetros do tipo in out sendo usados, isso indica que tanto podemos atribuir valores a ele como também atribuir seus valores a outras variáveis ou parâmetros existentes dentro dos objetos. Veja isso na prática. ♣r♦❝❡❞✉r❡ ❡①❡♠♣❧♦✭ ♣❛r❛♠✶ ✐♥ ♥✉♠❜❡r ✱♣❛r❛♠✷ ♦✉t ♥✉♠❜❡r ✱♣❛r❛♠✸ ✐♥ ♦✉t ♥✉♠❜❡r✮ ✐s ✲✲ 243 16.7. Passando parâmetros ① ♥✉♠❜❡r❀ ② ♥✉♠❜❡r❀ ③ ♥✉♠❜❡r❀ ✲✲ ❜❡❣✐♥ ✲✲ ① ✿❂ ♣❛r❛♠✶❀ ♣❛r❛♠✶ ✿❂ ①❀ ✲✲ ② ✿❂ ♣❛r❛♠✷❀ ♣❛r❛♠✷ ✿❂ ②❀ ✲✲ ③ ✿❂ ♣❛r❛♠✸❀ ♣❛r❛♠✸ ✿❂ ③❀ ✲✲ ❡♥❞❀ ✴ Casa do Código ✲✲ ✉s♦ ❝♦rr❡t♦ ✲✲ ✉s♦ ✐♥❝♦rr❡t♦ ✲✲ ✉s♦ ✐♥❝♦rr❡t♦ ✲✲ ✉s♦ ❝♦rr❡t♦ ✲✲ ✉s♦ ❝♦rr❡t♦ ✲✲ ✉s♦ ❝♦rr❡t♦ Nota: quando não informamos o tipo do parâmetro, por padrão, ele será do tipo in. O uso de parâmetros em programas armazenados pode tornar nossos programas muito mais flexíveis, possibilitando o reaproveitamento de código. A seguir, são mostrados os mesmos exemplos de procedures e functions anteriores, mas agora recriados utilizando passagem de parâmetros. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ❝❛❧❝ ✭ ①✶ ✐♥ ♥✉♠❜❡r ✷ ✱①✷ ✐♥ ♥✉♠❜❡r ✸ ✱♦♣ ✐♥ ✈❛r❝❤❛r✷ ✹ ✱r❡s ♦✉t ✈❛r❝❤❛r✷✮ ✐s ✺ ✲✲ ✻ ❜❡❣✐♥ ✼ ✲✲ ✽ ✐❢ ✭①✶ ✰ ①✷✮ ❂ ✵ t❤❡♥ ✾ r❡s ✿❂ ✵❀ ✶✵ ❡❧s✐❢ ♦♣ ❂ ✬✯✬ t❤❡♥ ✶✶ r❡s ✿❂ ①✶ ✯ ①✷❀ 244 Casa do Código ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ ✸✵ ✸✶ ✸✷ ✸✸ ✸✹ Capítulo 16. Programas armazenados ❡❧s✐❢ ♦♣ ❂ ✬✴✬ t❤❡♥ ✐❢ ①✷ ❂ ✵ t❤❡♥ r❡s ✿❂ ✬❊rr♦ ❞❡ ❞✐✈✐sã♦ ♣♦r ③❡r♦✦✬❀ ❡❧s❡ r❡s ✿❂ ①✶ ✴ ①✷❀ ❡♥❞ ✐❢❀ ❡❧s✐❢ ♦♣ ❂ ✬✲✬ t❤❡♥ r❡s ✿❂ ①✶ ✲ ①✷❀ ✐❢ r❡s ❂ ✵ t❤❡♥ r❡s ✿❂ ✬❘❡s✉❧t❛❞♦ ✐❣✉❛❧ ❛ ③❡r♦✿ ✬⑤⑤r❡s❀ ❡❧s✐❢ r❡s ❁ ✵ t❤❡♥ r❡s ✿❂ ✬❘❡s✉❧t❛❞♦ ♠❡♥♦r q✉❡ ③❡r♦✿ ✬⑤⑤r❡s❀ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ r❡s ✿❂ ✬❘❡s✉❧t❛❞♦ ♠❛✐♦r q✉❡ ③❡r♦✿ ✬⑤⑤r❡s❀ ❡♥❞ ✐❢❀ ❡❧s✐❢ ♦♣ ❂ ✬✰✬ t❤❡♥ r❡s ✿❂ ①✶ ✰ ①✷❀ ❡❧s❡ r❡s ✿❂ ✬❖♣❡r❛❞♦r ✐♥✈á❧✐❞♦✦✬❀ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ Executando calc: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇r❡s ✈❛r❝❤❛r✷✭✶✵✵✮❀ ✸ ❜❡❣✐♥ ✹ ❝❛❧❝ ✭ ①✶ ❂❃ ✶✵ ✺ ✱①✷ ❂❃ ✺ ✻ ✱♦♣ ❂❃ ✬✯✬ ✼ ✱r❡s ❂❃ ✇r❡s✮❀ ✽ ✲✲ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❈❛❧❝ ✶✿ ✬⑤⑤✇r❡s✮❀ ✶✵ ✲✲ 245 16.7. Passando parâmetros Casa do Código ✶✶ ❝❛❧❝ ✭ ✶✵ ✱✺ ✶✷ ✱✬✴✬ ✶✸ ✶✹ ✱✇r❡s✮❀ ✶✺ ✲✲ ✶✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❘❡s✉❧t❛❞♦ ❈❛❧❝ ✷✿ ✬⑤⑤✇r❡s✮❀ ✶✼ ✲✲ ✶✽ ❡♥❞❀ ✶✾ ✴ ❘❡s✉❧t❛❞♦ ❈❛❧❝ ✶✿ ✺✵ ❘❡s✉❧t❛❞♦ ❈❛❧❝ ✷✿ ✷ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Perceba que nesta execução chamamos duas vezes a procedure. A primeira usando a passagem de parâmetros nomeada, e a segunda sem nomeação. Quando informamos os parâmetros no cabeçalho do programa, o Oracle toma como ordenação a ordem em que os dispomos. Todavia, quando executamos tal programa precisamos respeitar esta ordem. Portanto, quando nomeamos a passagem de parâmetros, no momento da execução do programa, não precisamos necessariamente informá-los na ordem com a qual foram definidos, basta apenas informar seus nomes e os respectivos valores a serem atribuídos. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ❢✉♥❝t✐♦♥ ✈❛❧✐❞❛❴❝♣❢ ✭❝♣❢ ✐♥ ❝❤❛r✮ r❡t✉r♥ ✈❛r❝❤❛r✷ ✐s ✷ ✲✲ ✸ ♠❴t♦t❛❧ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✹ ♠❴❞✐❣✐t♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✺ ✲✲ ✻ ❜❡❣✐♥ ✼ ❢♦r ✐ ✐♥ ✶✳✳✾ ❧♦♦♣ ✽ ♠❴t♦t❛❧ ✿❂ ♠❴t♦t❛❧ ✰ s✉❜str ✭❝♣❢✱ ✐✱ ✶✮ ✯ ✭✶✶ ✲ ✐✮❀ ✾ ❡♥❞ ❧♦♦♣❀ ✶✵ ✲✲ ✶✶ ♠❴❞✐❣✐t♦ ✿❂ ✶✶ ✲ ♠♦❞ ✭♠❴t♦t❛❧✱ ✶✶✮❀ 246 Casa do Código Capítulo 16. Programas armazenados ✶✷ ✲✲ ✶✸ ✐❢ ♠❴❞✐❣✐t♦ ❃ ✾ t❤❡♥ ✶✹ ♠❴❞✐❣✐t♦ ✿❂ ✵❀ ✶✺ ❡♥❞ ✐❢❀ ✶✻ ✲✲ ✶✼ ✐❢ ♠❴❞✐❣✐t♦ ✦❂ s✉❜str ✭❝♣❢✱ ✶✵✱ ✶✮ t❤❡♥ ✶✽ r❡t✉r♥ ✬■✬❀ ✶✾ ❡♥❞ ✐❢❀ ✷✵ ✲✲ ✷✶ ♠❴❞✐❣✐t♦ ✿❂ ✵❀ ✷✷ ♠❴t♦t❛❧ ✿❂ ✵❀ ✷✸ ✲✲ ✷✹ ❢♦r ✐ ✐♥ ✶✳✳✶✵ ❧♦♦♣ ✷✺ ♠❴t♦t❛❧ ✿❂ ♠❴t♦t❛❧ ✰ s✉❜str ✭❝♣❢✱ ✐✱ ✶✮ ✯ ✭✶✷ ✲ ✐✮❀ ✷✻ ❡♥❞ ❧♦♦♣❀ ✷✼ ✲✲ ✷✽ ♠❴❞✐❣✐t♦ ✿❂ ✶✶ ✲ ♠♦❞ ✭♠❴t♦t❛❧✱ ✶✶✮❀ ✷✾ ✲✲ ✸✵ ✐❢ ♠❴❞✐❣✐t♦ ❃ ✾ t❤❡♥ ✸✶ ♠❴❞✐❣✐t♦ ✿❂ ✵❀ ✸✷ ❡♥❞ ✐❢❀ ✸✸ ✲✲ ✸✹ ✐❢ ♠❴❞✐❣✐t♦ ✦❂ s✉❜str ✭❝♣❢✱ ✶✶✱ ✶✮ t❤❡♥ ✸✺ r❡t✉r♥ ✬■✬❀ ✸✻ ❡♥❞ ✐❢❀ ✸✼ ✲✲ ✸✽ r❡t✉r♥ ✬❱✬❀ ✸✾ ✲✲ ✹✵ ❡♥❞ ✈❛❧✐❞❛❴❝♣❢❀ ✹✶ ✴ ❋✉♥çã♦ ❝r✐❛❞❛✳ ❙◗▲❃ Executando valida_cpf: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ r❡s ✈❛r❝❤❛r✷✭✶✮ ❞❡❢❛✉❧t ♥✉❧❧❀ 247 16.7. Passando parâmetros ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ❈P❋ ❈P❋ Casa do Código ✲✲ ❜❡❣✐♥ r❡s ✿❂ ✈❛❧✐❞❛❴❝♣❢✭❝♣❢ ❂❃ ✬✵✷✵✾✶✻✼✽✺✷✵✬✮❀ ✲✲ ✐❢ r❡s ❂ ✬❱✬ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈P❋ ✈á❧✐❞♦✿ ✵✷✵✾✶✻✼✽✺✷✵✬✮❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈P❋ ✐♥✈á❧✐❞♦✿ ✵✷✵✾✶✻✼✽✺✷✵✬✮❀ ❡♥❞ ✐❢❀ ✲✲ r❡s ✿❂ ✈❛❧✐❞❛❴❝♣❢✭✬✵✷✵✶✶✻✹✽✾✷✵✬✮❀ ✲✲ ✐❢ r❡s ❂ ✬❱✬ t❤❡♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈P❋ ✈á❧✐❞♦✿ ✵✷✵✶✶✻✹✽✾✷✵✬✮❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈P❋ ✐♥✈á❧✐❞♦✿ ✵✷✵✶✶✻✹✽✾✷✵✬✮❀ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞❀ ✴ ✐♥✈á❧✐❞♦✿ ✵✷✵✾✶✻✼✽✺✷✵ ✈á❧✐❞♦✿ ✵✷✵✶✶✻✹✽✾✷✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Anteriormente, mencionamos que embora procedures não retornem valores, vimos que através de parâmetros do tipo out isto é possível. Contudo, as procedures não retornam valores implicitamente como as functions. Vale lembrar que, embora as functions retornem valor, nós podemos utilizar parâmetros do tipo out em sua definição, mesmo porque uma function só pode retornar um único valor por chamada, enquanto através dos parâmetros do tipo out é possível ter vários retornos. 248 Casa do Código 16.8 Capítulo 16. Programas armazenados Dependência de objetos É de fundamental importância que o desenvolvedor conheça como o Oracle trata a questão da dependência entre os objetos armazenados no banco de dados. Existem casos em que o próprio desenvolvedor é quem vai liberar os objetos na base de dados, sendo ela uma base teste ou até em uma base de produção. Diante disto, é sempre bom saber o que pode acontecer quando liberamos objetos que possuem dependências entre si. O Oracle trabalha em cima de dois conceitos com relação a este tipo de dependência. Os conceitos de dependência direta e dependência indireta. Conforme está na documentação da Oracle, quando se trata de uma dependência direta o Oracle consegue restabelecer o programa que está inválido. Já quando não se trata de uma dependência direta, o Oracle não garante que este restabelecimento seja feito de forma automática. Vamos verificar as características referentes às dependências diretas e indiretas entre objetos. Para evidenciar as diferenças entre os tipos de dependências, criaremos exemplos práticos. Para começar, vamos partir do ponto onde temos quatro procedures chamadas: proc1, proc2, proc3 e proc4. ❙◗▲❃ ✷ ✸ ✹ ✺ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✹ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✹✦✦✦✬✮❀ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✸ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✸✦✦✦✬✮❀ ♣r♦❝✹❀ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✷ ✐s 249 16.8. Dependência de objetos Casa do Código ✷ ❜❡❣✐♥ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✷✦✦✦✬✮❀ ✹ ♣r♦❝✸❀ ✺ ❡♥❞❀ ✻ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✶ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✶✦✦✦✬✮❀ ♣r♦❝✷❀ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ Observando os scripts anteriores, vemos que a procedure proc1 chama a proc2 e a proc2 chama a proc3 até chegarmos à procedure proc4. Neste caso, podemos identificar os dois casos de dependência os quais estamos abordando. A dependência direta está representada nas seguintes situações: proc1 com proc2, proc2 com proc3 e proc3 com proc4. Ou seja, a procedure proc2 mantém uma dependência com a procedure proc1, pois para a proc2 ser executada é preciso que a proc1 seja executada também. Logo, a proc2 precisa estar válida para que a proc1 esteja validada. Assim acontece com a procedure proc2 que mantém uma dependência com a proc3 e a procedure proc3 com a proc4. A dependência indireta está representada nas situações seguintes: proc1 com proc3, proc2 com proc4, proc1 com proc4. Da mesma forma que na dependência direta, a procedure proc1 precisa ser executada para que a proc3 também seja (indiretamente). Logo, a validação da procedure proc3 precisa existir para que a proc1 também esteja válida. Veja o desenho. 250 Casa do Código Capítulo 16. Programas armazenados Fig. 16.1: Esquema mostrando dependências diretas e indiretas Para verificar as dependências entre os objetos, podemos fazer um select na view all_dependencies, onde constam todas as dependências existentes entres os objetos criados na base de dados. Para limitarmos a pesquisa, vamos selecionar as dependências referentes aos objetos que criamos, informando os nomes dos mesmos na cláusula where do select. 251 Casa do Código 16.8. Dependência de objetos ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ s❡❧❡❝t ❢r♦♠ ✇❤❡r❡ ❛♥❞ ♥❛♠❡ ⑤⑤ ✬ ❂❃ ✬ ⑤⑤r❡❢❡r❡♥❝❡❞❴♥❛♠❡ ✧❘❡❢❡rê♥❝✐❛s✧ ❛❧❧❴❞❡♣❡♥❞❡♥❝✐❡s ♦✇♥❡r ❂ ✬❚❙◗▲✬ ♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✱✬P❘❖❈✷✬ ✱✬P❘❖❈✸✬ ✱✬P❘❖❈✹✬ ✮ ❛♥❞ r❡❢❡r❡♥❝❡❞❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ ♦r❞❡r ❜② ♥❛♠❡ ✴ ❘❡❢❡rê♥❝✐❛s ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ ❂❃ P❘❖❈✷ P❘❖❈✷ ❂❃ P❘❖❈✸ P❘❖❈✸ ❂❃ P❘❖❈✹ ❙◗▲❃ Já para verificar os status dos objetos, devemos fazer um select na view all_objects, selecionando o campo STATUS. ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✱st❛t✉s ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✱✬P❘❖❈✷✬ ✱✬P❘❖❈✸✬ ✱✬P❘❖❈✹✬ ✮ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ ✴ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ 252 ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ❱❆▲■❉ ❱❆▲■❉ Casa do Código P❘❖❈✸ P❘❖❈✹ Capítulo 16. Programas armazenados ❱❆▲■❉ ❱❆▲■❉ ❙◗▲❃ Para tornar mais clara a explanação sobre as dependências entre objetos, na sequência estão alguns exemplos relacionados aos conceitos expostos anteriormente: Criando objetos fora da ordem de dependência. Como já havíamos criado os objetos anteriormente, vamos primeiramente excluí-los. ❙◗▲❃ ❞r♦♣ ♣r♦❝❡❞✉r❡ ♣r♦❝✶❀ Pr♦❝❡❞✐♠❡♥t♦ ❡❧✐♠✐♥❛❞♦✳ ❙◗▲❃ ❞r♦♣ ♣r♦❝❡❞✉r❡ ♣r♦❝✷❀ Pr♦❝❡❞✐♠❡♥t♦ ❡❧✐♠✐♥❛❞♦✳ ❙◗▲❃ ❞r♦♣ ♣r♦❝❡❞✉r❡ ♣r♦❝✸❀ Pr♦❝❡❞✐♠❡♥t♦ ❡❧✐♠✐♥❛❞♦✳ ❙◗▲❃ ❞r♦♣ ♣r♦❝❡❞✉r❡ ♣r♦❝✹❀ Pr♦❝❡❞✐♠❡♥t♦ ❡❧✐♠✐♥❛❞♦✳ ❙◗▲❃ Após excluir cada procedure, vamos criá-las novamente. ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✶ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✶✦✦✦✬✮❀ ♣r♦❝✷❀ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ 253 16.8. Dependência de objetos ❙◗▲❃ ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ Casa do Código ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✷ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✷✦✦✦✬✮❀ ♣r♦❝✸❀ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✸ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✸✦✦✦✬✮❀ ♣r♦❝✹❀ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ ❙◗▲❃ ✷ ✸ ✹ ✺ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✹ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✹✦✦✦✬✮❀ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ Veja que proc1, proc2 e proc3 foram criadas com advertência. Contudo, a proc4 foi criada com sucesso. Agora vamos verificar os status dos objetos. ❙◗▲❃ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✷ ✱st❛t✉s 254 Casa do Código Capítulo 16. Programas armazenados ✸ ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✹ ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ✺ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✻ ✱✬P❘❖❈✷✬ ✼ ✱✬P❘❖❈✸✬ ✽ ✱✬P❘❖❈✹✬ ✾ ✮ ✶✵ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬❀ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙◗▲❃ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ❱❆▲■❉ Como era previsto, as procedures PROC1, PROC2 e PROC3 estão inválidas, enquanto a PROC4 está válida. Isto ocorreu pelo fato de que na ordem em que os objetos foram criados sempre faltava a criação do objeto dependente, com exceção, é claro, do objeto PROC4. Criando os objetos na ordem de dependência: ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✹ ✐s ✷ ❜❡❣✐♥ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✹✦✦✦✬✮❀ ✹ ❡♥❞❀ ✺ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✸ ✐s ✷ ❜❡❣✐♥ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✸✦✦✦✬✮❀ ✹ ♣r♦❝✹❀ ✺ ❡♥❞❀ ✻ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✷ ✐s 255 Casa do Código 16.8. Dependência de objetos ✷ ❜❡❣✐♥ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✷✦✦✦✬✮❀ ✹ ♣r♦❝✸❀ ✺ ❡♥❞❀ ✻ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✶ ✐s ✷ ❜❡❣✐♥ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✶✦✦✦✬✮❀ ✹ ♣r♦❝✷❀ ✺ ❡♥❞❀ ✻ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ Verificando Objetos. ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✱st❛t✉s ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✱✬P❘❖❈✷✬ ✱✬P❘❖❈✸✬ ✱✬P❘❖❈✹✬ ✮ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ ✴ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙◗▲❃ Invalidando o objeto PROC1: 256 ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ❱❆▲■❉ ❱❆▲■❉ ❱❆▲■❉ ❱❆▲■❉ Casa do Código ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ Capítulo 16. Programas armazenados ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✶ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✶✦✦✦✬✮❀ ❀ ✲✲ ♣r♦✈♦❝❛♥❞♦ ✉♠ ❡rr♦ ❞❡ s✐♥t❛①❡ ♣r♦❝✷❀ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✷ ✱st❛t✉s ✸ ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✹ ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ✺ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✻ ✱✬P❘❖❈✷✬ ✼ ✱✬P❘❖❈✸✬ ✽ ✱✬P❘❖❈✹✬ ✾ ✮ ✶✵ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬❀ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙◗▲❃ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ■◆❱❆▲■❉ ❱❆▲■❉ ❱❆▲■❉ ❱❆▲■❉ Invalidando o objeto PROC2: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✷ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✷✦✦✦✬✮❀ ❀ ✲✲ ♣r♦✈♦❝❛♥❞♦ ✉♠ ❡rr♦ ❞❡ s✐♥t❛①❡ ♣r♦❝✸❀ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ 257 Casa do Código 16.8. Dependência de objetos ✷ ✸ ❢r♦♠ ✹ ✇❤❡r❡ ✺ ❛♥❞ ✻ ✼ ✽ ✾ ✶✵ ❛♥❞ ✶✶ ✴ ✱st❛t✉s ❛❧❧❴♦❜❥❡❝ts ♦✇♥❡r ❂ ✬❚❙◗▲✬ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✱✬P❘❖❈✷✬ ✱✬P❘❖❈✸✬ ✱✬P❘❖❈✹✬ ✮ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙◗▲❃ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ❱❆▲■❉ ❱❆▲■❉ Invalidando o objeto PROC3: ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✸ ✐s ✷ ❜❡❣✐♥ ✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✸✦✦✦✬✮❀ ✹ ❀ ✲✲ ♣r♦✈♦❝❛♥❞♦ ✉♠ ❡rr♦ ❞❡ s✐♥t❛①❡ ✺ ♣r♦❝✹❀ ✻ ❡♥❞❀ ✼ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ 258 s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✱st❛t✉s ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✱✬P❘❖❈✷✬ ✱✬P❘❖❈✸✬ ✱✬P❘❖❈✹✬ ✮ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ Casa do Código ✶✶ Capítulo 16. Programas armazenados ✴ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙◗▲❃ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ❱❆▲■❉ Invalidando o objeto PROC4: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✹ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✹✦✦✦✬✮❀ ❀ ✲✲ ♣r♦✈♦❝❛♥❞♦ ✉♠ ❡rr♦ ❞❡ s✐♥t❛①❡ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✷ ✱st❛t✉s ✸ ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✹ ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ✺ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✻ ✱✬P❘❖❈✷✬ ✼ ✱✬P❘❖❈✸✬ ✽ ✱✬P❘❖❈✹✬ ✾ ✮ ✶✵ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ ✶✶ ✴ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙◗▲❃ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ■◆❱❆▲■❉ 259 16.8. Dependência de objetos Casa do Código Corrigindo e recriando o objeto PROC1: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✶ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✶✦✦✦✬✮❀ ♣r♦❝✷❀ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ s❤♦✇ ❡rr♦r ❊rr♦s ♣❛r❛ ♣r♦❝❡❞✉r❡ P❘❖❈✶✿ ▲✐♥❊✴❈❖▲ ✲✲✲✲✲✲✲✲ ✹✴✸ ✹✴✸ ❙◗▲❃ ❊❘❘❖❘ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P▲✴❙◗▲✿ ❙t❛t❡♠❡♥t ✐❣♥♦r❡❞ P▲❙✲✵✵✾✵✺✿ ♦ ♦❜❥❡t♦ ❚❙◗▲✳P❘❖❈✷ é ✐♥✈á❧✐❞♦ Corrigindo e recriando o objeto PROC2: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✷ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✷✦✦✦✬✮❀ ♣r♦❝✸❀ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ s❤♦✇ ❡rr♦r ❊rr♦s ♣❛r❛ ♣r♦❝❡❞✉r❡ P❘❖❈✷✿ ▲✐♥❊✴❈❖▲ ✲✲✲✲✲✲✲✲ ✹✴✸ ✹✴✸ ❙◗▲❃ ❊❘❘❖❘ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P▲✴❙◗▲✿ ❙t❛t❡♠❡♥t ✐❣♥♦r❡❞ P▲❙✲✵✵✾✵✺✿ ♦ ♦❜❥❡t♦ ❚❙◗▲✳P❘❖❈✸ é ✐♥✈á❧✐❞♦ Corrigindo e recriando o objeto PROC3: 260 Casa do Código ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ Capítulo 16. Programas armazenados ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✸ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✸✦✦✦✬✮❀ ♣r♦❝✹❀ ❡♥❞❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ s❤♦✇ ❡rr♦r ❊rr♦s ♣❛r❛ ♣r♦❝❡❞✉r❡ P❘❖❈✸✿ ▲✐♥❊✴❈❖▲ ✲✲✲✲✲✲✲✲ ✹✴✸ ✹✴✸ ❙◗▲❃ ❊❘❘❖❘ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P▲✴❙◗▲✿ ❙t❛t❡♠❡♥t ✐❣♥♦r❡❞ P▲❙✲✵✵✾✵✺✿ ♦ ♦❜❥❡t♦ ❚❙◗▲✳P❘❖❈✹ é ✐♥✈á❧✐❞♦ Verificando objetos: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✱st❛t✉s ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✱✬P❘❖❈✷✬ ✱✬P❘❖❈✸✬ ✱✬P❘❖❈✹✬ ✮ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ ✴ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ❙◗▲❃ 261 Casa do Código 16.8. Dependência de objetos Corrigindo e validando o objeto PROC4: ❙◗▲❃ ✷ ✸ ✹ ✺ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ♣r♦❝✹ ✐s ❜❡❣✐♥ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬♣r♦❝✳ ✹✦✦✦✬✮❀ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✱st❛t✉s ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✱✬P❘❖❈✷✬ ✱✬P❘❖❈✸✬ ✱✬P❘❖❈✹✬ ✮ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ ✴ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ■◆❱❆▲■❉ ❱❆▲■❉ ❙◗▲❃ Recompilando PROC2: ❙◗▲❃ ❛❧t❡r ♣r♦❝❡❞✉r❡ ♣r♦❝✷ ❝♦♠♣✐❧❡❀ Pr♦❝❡❞✐♠❡♥t♦ ❛❧t❡r❛❞♦✳ ❙◗▲❃ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✷ ✱st❛t✉s ✸ ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts 262 Casa do Código Capítulo 16. Programas armazenados ✹ ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ✺ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✻ ✱✬P❘❖❈✷✬ ✼ ✱✬P❘❖❈✸✬ ✽ ✱✬P❘❖❈✹✬ ✾ ✮ ✶✵ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ ✶✶ ✴ ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ■◆❱❆▲■❉ ❱❆▲■❉ ❱❆▲■❉ ❱❆▲■❉ ❙◗▲❃ Executando a PROC1: ❙◗▲❃ ❡①❡❝✉t❡ ♣r♦❝✶❀ ♣r♦❝✳ ✶✦✦✦ ♣r♦❝✳ ✷✦✦✦ ♣r♦❝✳ ✸✦✦✦ ♣r♦❝✳ ✹✦✦✦ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ s❡❧❡❝t ♦❜❥❡❝t❴♥❛♠❡ ✱st❛t✉s ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✇❤❡r❡ ♦✇♥❡r ❂ ✬❚❙◗▲✬ ❛♥❞ ♦❜❥❡❝t❴♥❛♠❡ ✐♥ ✭ ✬P❘❖❈✶✬ ✱✬P❘❖❈✷✬ ✱✬P❘❖❈✸✬ ✱✬P❘❖❈✹✬ ✮ ❛♥❞ ♦❜❥❡❝t❴t②♣❡ ❂ ✬♣r♦❝❡❞✉r❡✬ ✴ 263 Casa do Código 16.8. Dependência de objetos ❖❇❏❊❈❚❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❘❖❈✶ P❘❖❈✷ P❘❖❈✸ P❘❖❈✹ ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ❱❆▲■❉ ❱❆▲■❉ ❱❆▲■❉ ❱❆▲■❉ ❙◗▲❃ Vimos que, embora existam dependências indiretas entre os objetos, o Oracle conseguiu identificar as chamadas e validar os objetos subsequentes. Embora isdo tenha ocorrido, a Oracle não garante que em alguns casos isto venha a acontecer. Diante disto, podemos dizer que o Oracle está preparado para restabelecer as validações em caso de dependência direta e indireta, contudo, não é garantido que ele conseguirá detectar certas ligações. Todavia, é sempre adequado verificar os status dos objetos após a liberação de objetos novos ou novas versões no banco de dados. Dependendo da quantidade de objetos com dependência, invalidá-los poderá nos custar algum tempo até deixar o sistema estável novamente. Vale lembrar que, mesmo existindo objetos inválidos no banco de dados, podemos não ter problemas no funcionamento, caso o Oracle, ao executar alguma operação com um destes objetos, detecte a existência de dependências diretas e as restabeleça. 264 Capítulo 17 packages No capítulo anterior, falamos sobre procedures e functions e como elas são armazenadas e executadas através de um banco de dados. Pois bem, packages, também chamados de pacotes, são programas armazenados, tendo como diferencial a possibilidade de funcionar como repositório para agrupar vários objetos do tipo procedure e function, bem como conter código PL/SQL ou servir de área para definições de variáveis, cursores, exceções, procedimentos e funções. Contudo, talvez sua maior utilização esteja no agrupamento de programas que possuem uma mesma finalidade, como aqueles que façam parte de uma área específica como RH, Financeira ou Comercial. Através de packages conseguimos organizar estes programas dentro de um único objeto e definir como o acesso a estes objetos será realizado. 17.1. Estrutura de um package Casa do Código 17.1 Estrutura de um package Um package pode ser constituído por até duas partes, uma chamada especification e outra chamada body. Podemos ter um package especification sem package body, contudo, não podemos ter o contrário. Obrigatoriamente, para criamos um package body é necessário criar também um package especification. Já vamos entender por quê. Dentro do especification, podemos declarar variáveis, types, cabeçalhos de procedures e functions, exceptions, cursores etc., que podem fazer ou não referência a um package body. Quando estiver fazendo referência a um body, podemos dizer que o especification, como nome sugere, funciona como uma especificação do body. Por exemplo, se temos um body dentro do qual há um código de uma procedure, podemos ter declarado no especification o cabeçalho deste programa, mesmo porque, por definição deste tipo de objeto, só conseguiremos acessar um programa que está armazenado dentro de um body caso sua especificação esteja declarada em um especification. Por isto, um body não pode existir sem um especification. Caso o especification não faça referência a um body, ele pode estar sendo utilizado para declaração de variáveis ou outros tipos de objetos que não necessitariam de um body. Vale salientar que, caso tenhamos cabeçalhos de procedures e functions em um especification, se faz necessário que exista um body relacionado. Já dentro do body é onde colocamos toda a codificação dos nossos programas, como codificações de procedures e functions. Além destes objetos, também podemos declarar variáveis, cursores, exceções, types etc., que podem ser utilizados pelo restante dos objetos criados no body. No entanto, podemos ter objetos dentro do body que não estão declarados no especification, os quais não poderão ser acessados diretamente, somente através de outros objetos contidos no próprio body. Os objetos declarados no especification, por exemplo, variáveis e cursores, podem ser acessados de dentro do body. Além disso, dentro do body podemos ter codificação PL/SQL correspondente ao próprio package, pois o body pode conter sua própria área begin e end. 266 Casa do Código Capítulo 17. packages Podemos ter no especification • Especificação de procedures e functions; • Declaração de variáveis e constantes; • Declaração de cursores; • Declaração de exceptions; • Declaração de types. Podemos ter no body • Códigos PL/SQL; • Códigos de procedures e functions; • Declaração de variáveis e constantes; • Declaração de cursores; • Declaração de exceptions; • Declaração de types. Exemplo de especification: ❙◗▲❃ ❝r❡❛t❡ ♣❛❝❦❛❣❡ ❧✐st❛❣❡♠ ✐s ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ✺ ✱❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✻ ✱❢✐rst❴♥❛♠❡ ✼ ✱❤✐r❡❴❞❛t❡ ✽ ✱s❛❧❛r② ✾ ❢r♦♠ ❞❡♣❛rt♠❡♥ts ❞ ✶✵ ✱❡♠♣❧♦②❡❡s ❡ ✶✶ ✇❤❡r❡ ❞✳♠❛♥❛❣❡r❴✐❞ ❂ ❡✳❡♠♣❧♦②❡❡❴✐❞ ✶✷ ♦r❞❡r ❜② ❞❡♣❛rt♠❡♥t❴♥❛♠❡❀ 267 17.1. Estrutura de um package ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ Casa do Código ✲✲ t②♣❡ t❛❜ ✐s t❛❜❧❡ ♦❢ ❝✶✪r♦✇t②♣❡ ✐♥❞❡① ❜② ❜✐♥❛r②❴✐♥t❡❣❡r❀ ✲✲ t❜❣❡r❡♥t❡ t❛❜❀ ♥ ♥✉♠❜❡r❀ ✲✲ ♣r♦❝❡❞✉r❡ ❧✐st❛❴❣❡r❡♥t❡❴♣♦r❴❞❡♣t♦❀ ✲✲ ❡♥❞ ❧✐st❛❣❡♠❀ ✴ P❛❝♦t❡ ❝r✐❛❞♦✳ ❙◗▲❃ Para criarmos um package especification, utilizamos o comando create. Seguindo nosso exemplo, na primeira linha temos o comando create e logo em seguida o tipo de objeto que estamos criando, no caso, package. Quando não informamos o tipo body, automaticamente o Oracle cria o package como sendo do tipo especification. Logo depois do tipo de objeto, informamos o nome ( listagem) seguido da expressão is (linha 01). is pode ser substituído por as. Sempre que for criar um objeto package especification, você deve utilizar esta sintaxe. Depois da expressão is, são declarados os objetos que poderão ou não ser usados em um package body. Neste exemplo, temos um especification com a declaração de alguns objetos como o cursor c1, o type tab, as variáveis n e tbgerente, e a especificação da procedure lista_gerente_por_depto. Note que só informamos o cabeçalho da procedure. Logo terá que existir um body onde seu código estará criado. Os cabeçalhos dos objetos informados devem ser idênticos aos descritos no corpo do package. Note que, nestes casos, todos os objetos, por estarem no especification, têm seu escopo público, ou seja, qualquer usuário que tenha acesso a este objeto poderá referenciá-los em sua sessão, utilizando-os. Toda a declaração é finalizada por ponto e vírgula. Por fim, 268 Casa do Código Capítulo 17. packages temos o comando end (linha 21), que finaliza o package. Colocar ou não o nome do package logo após o comando end é opcional. Contudo, não podemos ter nomes diferentes no cabeçalho e rodapé do objeto. Exemplo de body: ❙◗▲❃ ❝r❡❛t❡ ♣❛❝❦❛❣❡ ❜♦❞② ❧✐st❛❣❡♠ ✐s ✷ ✲✲ ✸ ♣r♦❝❡❞✉r❡ ❧✐st❛❴❣❡r❡♥t❡❴♣♦r❴❞❡♣t♦ ✐s ✹ ✲✲ ✺ ❜❡❣✐♥ ✻ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ ✼ t❜❣❡r❡♥t❡✭r✶✳❞❡♣❛rt♠❡♥t❴✐❞✮ ✿❂ r✶❀ ✽ ❡♥❞ ❧♦♦♣❀ ✾ ✲✲ ✶✵ ♥ ✿❂ t❜❣❡r❡♥t❡✳❢✐rst❀ ✶✶ ✲✲ ✶✷ ✇❤✐❧❡ ♥ ❁❂ t❜❣❡r❡♥t❡✳❧❛st ❧♦♦♣ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡♣t♦✿ ✬⑤⑤t❜❣❡r❡♥t❡✭♥✮✳❞❡♣❛rt♠❡♥t❴♥❛♠❡⑤⑤✬ ✬⑤⑤ ✬●❡r❡♥t❡✿ ✬⑤⑤t❜❣❡r❡♥t❡✭♥✮✳❢✐rst❴♥❛♠❡⑤⑤✬ ✬⑤⑤ ✶✹ ✶✺ ✬❉t✳ ❆❞♠✐✳✿ ✬⑤⑤t❜❣❡r❡♥t❡✭♥✮✳❤✐r❡❴❞❛t❡⑤⑤✬ ✬⑤⑤ ✬❙❛❧✳✿ ✬⑤⑤t♦❴❝❤❛r✭t❜❣❡r❡♥t❡✭♥✮✳s❛❧❛r②✱ ✶✻ ✬❢♠✩✾✾✾❣✾✾✾❣✾✾✵❞✵✵✬✮✮❀ ✶✼ ♥ ✿❂ t❜❣❡r❡♥t❡✳♥❡①t✭♥✮❀ ✶✽ ❡♥❞ ❧♦♦♣❀ ✶✾ ✲✲ ✷✵ ❡♥❞ ❧✐st❛❴❣❡r❡♥t❡❴♣♦r❴❞❡♣t♦❀ ✷✶ ✲✲ ✷✷ ❡♥❞ ❧✐st❛❣❡♠❀ ✷✸ ✴ ❈♦r♣♦ ❞❡ P❛❝♦t❡ ❝r✐❛❞♦✳ ❙◗▲❃ Igualmente ao utilizado na criação do package especification, para criarmos um package body, nós utilizamos também o comando create. Na primeira linha deste exemplo, temos o comando create e, em seguida, o tipo de objeto que estamos criando, no caso, package body. 269 17.2. Acesso a packages Casa do Código Logo depois do tipo de objeto, informamos um nome para ele ( listagem), seguido da expressão is (linha 01), que pode ser substituído por as. Sempre que for criar um objeto package body, você deve utilizar esta sintaxe. Este objeto body faz referência ao especification criado no exemplo anterior. Nele está o código da procedure lista_gerente_por_depto (linhas 3 a 20), declarada no especification. Note que, neste exemplo, não utilizamos a área begin end do body e também não declaramos qualquer objeto dentro do corpo do package. Contudo, dentro da procedure, estamos utilizando os objetos que foram declarados no especification, por exemplo, o cursor (linha 6 a 8), o type (linha 7, 13 a 17) e as variáveis (linhas 10, 12 e 17). Assim como esta, outras procedures, caso existissem mais dentro do body, poderiam também acessar estes objetos. Todavia, se eles estivessem declarados no body, em vez de no especification, o efeito seria o mesmo. Entretanto, o escopo destes objetos seria interno ao body, não podendo ser acessados externamente. Por fim, temos o comando end (linha 22), que finaliza o package. Como no especification, colocar ou não o nome do package logo após o comando end é opcional. Contudo, não podemos ter nomes diferentes no cabeçalho e rodapé do objeto. Vale ressaltar que toda a declaração deve ser finalizada por ponto e vírgula. 17.2 Acesso a packages Como mencionado anteriormente, só podemos acessar um objeto que se encontra em um body se ele estiver declarado no especification. Logo, o especification tem a característica de ser uma área pública onde todos os usuários que possuam concessão de acesso a este objeto podem referenciar ou executar os objetos do body por intermédio do que está especificado nesta área. Tudo o que estiver declarado no especification e no body tem seu escopo no nível de usuário, ou melhor, na sessão do usuário que executou tal package. Os objetos package só começam a ocupar recursos na memória quando algum objeto é referenciado. A área de begin end do body é exe270 Casa do Código Capítulo 17. packages cutada uma única vez na sessão do usuário, na primeira vez que o package é referenciado. Por isso, quando utilizada, é comum vê-la servir como local para inicialização de variáveis ou para execução de procedimentos que inicializem algum objeto que será utilizado por outros objetos ao longo da vida útil da sessão. Quanto aos objetos definidos dentro das procedures e functions internas ao body, estes têm seu escopo em nível local e os recursos só são ocupados mediante a execução de tais procedures e functions. Às vezes, packages especifications são utilizadas como área para declaração e inicialização de variáveis ou cursores dentro de uma sessão, não existindo um body. Como o especification tem seu escopo em nível de sessão, ele é muito útil para ser usado pelos programas para guardar informações que serão utilizadas em algum processamento ou para determinar padrões em um sistema. Como estas informações ficam na sessão enquanto ela estiver aberta, todos os programas que estiverem sendo executados poderão compartilhar desta área e, consequentemente, dos dados e objetos que estão declarados nela. Resumindo, quando trabalhamos com packages precisamos saber de alguns detalhes: • Packages podem ser constituídas de duas partes: especification e body. • Um especification pode existir sem um body, mas não o contrário. • Quando existirem um especification e um body, os dois objetos devem ter exatamente o mesmo nome. • Para acessar objetos de dentro de um body, é preciso que eles estejam declarados em um especification (acesso direto), ou que, pelo menos, possam ser acessados através de algum objeto que esteja no especification (acesso indireto). • Os objetos pertencentes ao package têm seu escopo em nível de sessão do usuário o qual executou tal package. 271 17.2. Acesso a packages Casa do Código • Os objetos de um package ocuparão recursos somente quando forem referenciados. • Áreas como especification e begin end do body serão executadas uma única vez na sessão do usuário, na primeira vez em que são referenciadas. • Igualmente a procedures e functions, é necessário ter concessão de acesso para executar packages. • Com o uso de especification e body, é possível disponibilizar informações em nível global e em nível de programa, mantendo a integridade e consistência através de encapsulamento. Veja na sequência um exemplo de mais uma package e sua aplicação. O package a seguir é responsável por efetuar cálculos como somatória, subtração, divisão e multiplicação. Para cada operação, existe uma function onde são passados dois parâmetros referentes aos números que se quer calcular. Após o cálculo, a função retorna o resultado. ❙◗▲❃ ❝r❡❛t❡ ♣❛❝❦❛❣❡ ❝❛❧❝✉❧♦ ❛s ✷ ✲✲ ✸ ❢✉♥❝t✐♦♥ s♦♠❛ ✭①✶ ♥✉♠❜❡r✱ ①✷ ♥✉♠❜❡r✮ r❡t✉r♥ ♥✉♠❜❡r❀ ✹ ❢✉♥❝t✐♦♥ s✉❜tr❛✐ ✭①✶ ♥✉♠❜❡r✱ ①✷ ♥✉♠❜❡r✮ r❡t✉r♥ ♥✉♠❜❡r❀ ✺ ❢✉♥❝t✐♦♥ ♠✉❧t✐♣❧✐❝❛ ✭①✶ ♥✉♠❜❡r✱ ①✷ ♥✉♠❜❡r✮ r❡t✉r♥ ♥✉♠❜❡r❀ ✻ ❢✉♥❝t✐♦♥ ❞✐✈✐❞❡ ✭①✶ ♥✉♠❜❡r✱ ①✷ ♥✉♠❜❡r✮ r❡t✉r♥ ♥✉♠❜❡r❀ ✼ ✲✲ ✽ ❡♥❞ ❝❛❧❝✉❧♦❀ ✾ ✴ P❛❝♦t❡ ❝r✐❛❞♦✳ ❙◗▲❃ Na primeira linha deste exemplo, temos o comando create e em seguida o tipo de objeto que estamos criando, no caso, package ( especification). Logo depois do tipo de objeto, informamos o seu nome ( calculo) seguido da expressão as (linha 01). No corpo do 272 Casa do Código Capítulo 17. packages especification, declaramos as funções soma, subtrai, multiplica e divide (linhas 3 a 6). Note que aqui só são informados os cabeçalhos das funções. Por fim, temos o comando end (linha 8) que finaliza o package. Detalhes sobre o package especification calculo: • Foi criado o package especification chamado calculo; • No package especification foram declaradas quatro funções, cada uma responsável por uma operação matemática (soma, subtração, multiplicação e divisão). ❙◗▲❃ ❝r❡❛t❡ ♣❛❝❦❛❣❡ ❜♦❞② ❝❛❧❝✉❧♦ ❛s ✷ ✲✲ ✸ r❡s ♥✉♠❜❡r❀ ✹ ✲✲ ✺ ♣r♦❝❡❞✉r❡ ✐♠♣r✐♠❡❴♠s❣✭♠s❣ ✈❛r❝❤❛r✷✮ ✐s ✻ ❜❡❣✐♥ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭♠s❣✮❀ ✽ ❡♥❞❀ ✾ ✲✲ ✶✵ ❢✉♥❝t✐♦♥ s♦♠❛ ✭①✶ ♥✉♠❜❡r✱ ①✷ ♥✉♠❜❡r✮ r❡t✉r♥ ♥✉♠❜❡r ✐s ✶✶ ❜❡❣✐♥ ✶✷ r❡s ✿❂ ①✶ ✰ ①✷❀ ✶✸ r❡t✉r♥ r❡s❀ ✶✹ ❡♥❞❀ ✶✺ ✲✲ ✶✻ ❢✉♥❝t✐♦♥ s✉❜tr❛✐ ✭①✶ ♥✉♠❜❡r✱ ①✷ ♥✉♠❜❡r✮ r❡t✉r♥ ♥✉♠❜❡r ✐s ✶✼ ❜❡❣✐♥ ✶✽ r❡s ✿❂ ①✶ ✲ ①✷❀ ✶✾ ✲✲ ✷✵ ✐❢ r❡s ❂ ✵ t❤❡♥ ✷✶ ✐♠♣r✐♠❡❴♠s❣✭✬❘❡s✉❧t❛❞♦ ✐❣✉❛❧ ❛ ③❡r♦✿ ✬⑤⑤r❡s✮❀ ✷✷ ❡❧s✐❢ r❡s ❁ ✵ t❤❡♥ ✷✸ ✐♠♣r✐♠❡❴♠s❣✭✬❘❡s✉❧t❛❞♦ ♠❡♥♦r q✉❡ ③❡r♦✿ ✬⑤⑤r❡s✮❀ ✷✹ ❡❧s✐❢ r❡s ❃ ✵ t❤❡♥ ✷✺ ✐♠♣r✐♠❡❴♠s❣✭✬❘❡s✉❧t❛❞♦ ♠❛✐♦r q✉❡ ③❡r♦✿ ✬⑤⑤r❡s✮❀ ✷✻ ❡♥❞ ✐❢❀ ✷✼ ✲✲ ✷✽ r❡t✉r♥ r❡s❀ 273 17.2. Acesso a packages ✷✾ ✸✵ ✸✶ ✸✷ ✸✸ ✸✹ ✸✺ ✸✻ ✸✼ ✸✽ ✸✾ ✹✵ ✹✶ ✹✷ ✹✸ ✹✹ ✹✺ ✹✻ ✹✼ ✹✽ ✹✾ ✺✵ ✺✶ Casa do Código ✲✲ ❡♥❞❀ ✲✲ ❢✉♥❝t✐♦♥ ♠✉❧t✐♣❧✐❝❛ ✭①✶ ♥✉♠❜❡r✱ ①✷ ♥✉♠❜❡r✮ r❡t✉r♥ ♥✉♠❜❡r ✐s ❜❡❣✐♥ r❡s ✿❂ ①✶ ✯ ①✷❀ r❡t✉r♥ r❡s❀ ❡♥❞❀ ✲✲ ❢✉♥❝t✐♦♥ ❞✐✈✐❞❡ ✭①✶ ♥✉♠❜❡r✱ ①✷ ♥✉♠❜❡r✮ r❡t✉r♥ ♥✉♠❜❡r ✐s ❜❡❣✐♥ ✐❢ ①✷ ❂ ✵ t❤❡♥ r❡s ✿❂ ♥✉❧❧❀ ✐♠♣r✐♠❡❴♠s❣✭✬❊rr♦ ❞❡ ❞✐✈✐sã♦ ♣♦r ③❡r♦✦✬✮❀ ❡❧s❡ r❡s ✿❂ ①✶ ✴ ①✷❀ ❡♥❞ ✐❢❀ ✲✲ r❡t✉r♥ r❡s❀ ❡♥❞❀ ✲✲ ❡♥❞ ❝❛❧❝✉❧♦❀ ✴ ❈♦r♣♦ ❞❡ P❛❝♦t❡ ❝r✐❛❞♦✳ ❙◗▲❃ Agora vamos criar o segundo objeto, que é a segunda parte do nosso programa. Na primeira linha temos o comando create e em seguida o tipo do objeto, package body, com seu nome, calculo, e a expressão as (linha 1). Declaramos uma variável chamada res no corpo do package (linha 3). Esta variável está sendo utilizada em todo o programa. Entre as linhas 10 a 46, estão os códigos das funções declaradas no objeto especification. Além destes, também temos um objeto procedure (linhas 5 a 8) utilizado para imprimir mensagens na tela. Se observarmos este objeto, veremos que ele não foi declarado no especification, logo, não poderá ser acessado 274 Casa do Código Capítulo 17. packages de fora do body. Em nosso programa, a procedure imprime_msg está sendo utilizada nas linhas 21,23, 25 e 42, pelas funções subtrai e divide. Vale lembrar mais uma vez que toda a declaração ou codificação de objeto deve ser finalizada por ponto e vírgula. Como no especification, o body também é finalizado com o comando end (linha 48), seguindo as mesmas regras. É importante frisar que os nomes dos objetos especification e body devem ser iguais. Detalhes sobre o package body calculo: • Foi criado o package body chamado calculo; • No package body foi declarada uma variável chamada res que será usada internamente pelos programas existentes (escopo privado); • Foram codificados os objetos referentes às functions soma, subtrai, multiplica e divide, declaradas no especification; estas, de escopo público; • Também foi codificado um objeto procedure chamado imprime_msg, de escopo privado, e que imprime mensagens na tela, vindas das functions. Executando o package calculo: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ r❡s ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ r❡s ✿❂ ❝❛❧❝✉❧♦✳s♦♠❛✭✹✺✵✱ ✺✺✵✮❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✹✺✵ ✰ ✺✺✵ ❂ ✬⑤⑤r❡s✮❀ ✼ ❡♥❞❀ ✽ ✴ ✹✺✵ ✰ ✺✺✵ ❂ ✶✵✵✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ r❡s ♥✉♠❜❡r❀ 275 17.2. Acesso a packages Casa do Código ✸ ❜❡❣✐♥ ✹ r❡s ✿❂ ❝❛❧❝✉❧♦✳s✉❜tr❛✐✭✸✺✵✱ ✻✺✵✮❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✸✺✵ ✲ ✻✺✵ ❂ ✬⑤⑤r❡s✮❀ ✼ ❡♥❞❀ ✽ ✴ ❘❡s✉❧t❛❞♦ ♠❡♥♦r q✉❡ ③❡r♦✿ ✲✸✵✵ ✸✺✵ ✲ ✻✺✵ ❂ ✲✸✵✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✷✵ ✯ ❞❡❝❧❛r❡ r❡s ♥✉♠❜❡r❀ ❜❡❣✐♥ r❡s ✿❂ ❝❛❧❝✉❧♦✳♠✉❧t✐♣❧✐❝❛✭✷✵✱ ✶✵✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✷✵ ✯ ✶✵ ❂ ✬⑤⑤r❡s✮❀ ❡♥❞❀ ✴ ✶✵ ❂ ✷✵✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ r❡s ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ r❡s ✿❂ ❝❛❧❝✉❧♦✳❞✐✈✐❞❡✭✺✵✱ ✺✮❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✺✵ ✴ ✺ ❂ ✬⑤⑤r❡s✮❀ ✼ ❡♥❞❀ ✽ ✴ ✺✵ ✴ ✺ ❂ ✶✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Observe o que acontece quando tentamos acessar algum objeto que não tem escopo no nível público, ou seja, que não se encontra declarado no especification: ❙◗▲❃ ❞❡❝❧❛r❡ 276 Casa do Código Capítulo 17. packages ✷ r❡s ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ r❡s ✿❂ ❝❛❧❝✉❧♦✳❞✐✈✐❞❡✭✺✵✱ ✺✮❀ ✺ ✲✲ ✻ ❝❛❧❝✉❧♦✳✐♠♣r✐♠❡❴♠s❣✭✬✺✵ ✴ ✺ ❂ ✬⑤⑤r❡s✮❀ ✼ ❡♥❞❀ ✽ ✴ ❝❛❧❝✉❧♦✳✐♠♣r✐♠❡❴♠s❣✭✬✺✵ ✴ ✺ ❂ ✬⑤⑤r❡s✮❀ ✯ ❊❘❘❖ ♥❛ ❧✐♥❤❛ ✻✿ ❖❘❆✲✵✻✺✺✵✿ ❧✐♥❤❛ ✻✱ ❝♦❧✉♥❛ ✶✶✿ P▲❙✲✵✵✸✵✷✿ ♦ ❝♦♠♣♦♥❡♥t❡ ✬✐♠♣r✐♠❡❴♠s❣✬ ❞❡✈❡ s❡r ❞❡❝❧❛r❛❞♦ ❖❘❆✲✵✻✺✺✵✿ ❧✐♥❤❛ ✻✱ ❝♦❧✉♥❛ ✸✿ P▲✴❙◗▲✿ ❙t❛t❡♠❡♥t ✐❣♥♦r❡❞ ❙◗▲❃ ❜❡❣✐♥ ✷ ❝❛❧❝✉❧♦✳r❡s ✿❂ ❝❛❧❝✉❧♦✳❞✐✈✐❞❡✭✺✵✱ ✺✮❀ ✸ ✲✲ ✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬✺✵ ✴ ✺ ❂ ✬⑤⑤❝❛❧❝✉❧♦✳r❡s✮❀ ✺ ❡♥❞❀ ✻ ✴ ❝❛❧❝✉❧♦✳r❡s ✿❂ ❝❛❧❝✉❧♦✳❞✐✈✐❞❡✭✺✵✱ ✺✮❀ ✯ ❊❘❘❖ ♥❛ ❧✐♥❤❛ ✷✿ ❖❘❆✲✵✻✺✺✵✿ ❧✐♥❤❛ ✷✱ ❝♦❧✉♥❛ ✶✶✿ P▲❙✲✵✵✸✵✷✿ ♦ ❝♦♠♣♦♥❡♥t❡ ✬❘❊❙✬ ❞❡✈❡ s❡r ❞❡❝❧❛r❛❞♦ ❖❘❆✲✵✻✺✺✵✿ ❧✐♥❤❛ ✷✱ ❝♦❧✉♥❛ ✸✿ P▲✴❙◗▲✿ ❙t❛t❡♠❡♥t ✐❣♥♦r❡❞ ❖❘❆✲✵✻✺✺✵✿ ❧✐♥❤❛ ✹✱ ❝♦❧✉♥❛ ✹✺✿ P▲❙✲✵✵✸✵✷✿ ♦ ❝♦♠♣♦♥❡♥t❡ ✬❘❊❙✬ ❞❡✈❡ s❡r ❞❡❝❧❛r❛❞♦ ❖❘❆✲✵✻✺✺✵✿ ❧✐♥❤❛ ✹✱ ❝♦❧✉♥❛ ✸✿ P▲✴❙◗▲✿ ❙t❛t❡♠❡♥t ✐❣♥♦r❡❞ ❙◗▲❃ Nos casos em que tentarmos acessar objetos não públicos, o Oracle informa que ele deve ser declarado. 277 Casa do Código 17.3. Recompilando packages 17.3 Recompilando packages Quando alteramos um package no banco de dados, pode acontecer de termos que compilá-la, novamente. Para isso, utilizamos o comando alter. Veja os exemplos na sequência: ❙◗▲❃ ❛❧t❡r ♣❛❝❦❛❣❡ ❧✐st❛❣❡♠ ❝♦♠♣✐❧❡❀ P❛❝♦t❡ ❛❧t❡r❛❞♦✳ ❙◗▲❃ 17.4 Recuperando informações Para visualizar informações referentes às packages, utilize as views user_objects, all_objects ou dba_objects. Nesta view constam informações como STATUS e data de criação do objeto. ❙◗▲❃ s❡❧❡❝t ♦✇♥❡r✱ ♦❜❥❡❝t❴t②♣❡✱ st❛t✉s✱ ❝r❡❛t❡❞✱ ❧❛st❴❞❞❧❴t✐♠❡ ✷ ❢r♦♠ ❛❧❧❴♦❜❥❡❝ts ✇❤❡r❡ ♦❜❥❡❝t❴♥❛♠❡ ❂ ✬❧✐st❛❣❡♠✬❀ ❖❲◆❊❘ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❚❙◗▲ ❚❙◗▲ ❝r❡❛t❡❉ ✲✲✲✲✲✲✲✲ ✵✷✴✶✷✴✶✶ ✵✷✴✶✷✴✶✶ ❖❇❏❊❈❚❴❚❨P❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ♣❛❝❦❛❣❡ ♣❛❝❦❛❣❡ ❜♦❞② ❙❚❆❚❯❙ ✲✲✲✲✲✲✲ ❱❆▲■❉ ❱❆▲■❉ ▲❆❙❚❴❉❉▲ ✲✲✲✲✲✲✲✲ ✵✷✴✶✷✴✶✶ ✵✷✴✶✷✴✶✶ ❙◗▲❃ Outra forma de recuperar dados referentes a packages é utilizando o comando describe. Ele mostra a definição de todas as procedures e functions contidas no package. ❙◗▲❃ ❞❡s❝ ❧✐st❛❣❡♠ ♣r♦❝❡❞✉r❡ ▲■❙❚❆❴●❊❘❊◆❚❊❴P❖❘❴❉❊P❚❖ 278 Casa do Código Capítulo 17. packages ❙◗▲❃ 17.5 Recuperando códigos Já para visualizar o código dos objetos package no banco de dados utilize as views user_source, all_source ou dba_source. ❙◗▲❃ ❙◗▲❃ ❙◗▲❃ ❙◗▲❃ ✷ ❝♦❧✉♠♥ t❡①t ❢♦r♠❛t ❛✸✵✵ s❡t ❧✐♥❡s ✶✵✵✵ s❡t ♣❛❣❡s ✶✵✵✵ s❡❧❡❝t ❧✐♥❡✱ t❡①t ❢r♦♠ ❛❧❧❴s♦✉r❝❡ ✇❤❡r❡ ♥❛♠❡ ❂ ✬❧✐st❛❣❡♠✬❀ ▲■◆❊ ❚❊❳❚ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✶ ♣❛❝❦❛❣❡ ❧✐st❛❣❡♠ ✐s ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ✺ ✱❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✻ ✱❢✐rst❴♥❛♠❡ ✼ ✱❤✐r❡❴❞❛t❡ ✽ ✱s❛❧❛r② ✾ ❢r♦♠ ❞❡♣❛rt♠❡♥ts ❞ ✶✵ ✱❡♠♣❧♦②❡❡s ❡ ✶✶ ✇❤❡r❡ ❞✳♠❛♥❛❣❡r❴✐❞ ❂ ❡✳❡♠♣❧♦②❡❡❴✐❞ ✶✷ ♦r❞❡r ❜② ❞❡♣❛rt♠❡♥t❴♥❛♠❡❀ ✶✸ ✲✲ ✶✹ t②♣❡ t❛❜ ✐s t❛❜❧❡ ♦❢ ❝✶✪r♦✇t②♣❡ ✐♥❞❡① ❜② ❜✐♥❛r②❴✐♥t❡❣❡r❀ ✶✺ ✲✲ ✶✻ t❜❣❡r❡♥t❡ t❛❜❀ ✶✼ ♥ ♥✉♠❜❡r❀ ✶✽ ✲✲ ✶✾ ♣r♦❝❡❞✉r❡ ❧✐st❛❴❣❡r❡♥t❡❴♣♦r❴❞❡♣t♦❀ ✷✵ ✲✲ ✷✶ ❡♥❞ ❧✐st❛❣❡♠❀ ✶ ♣❛❝❦❛❣❡ ❜♦❞② ❧✐st❛❣❡♠ ✐s 279 17.6. Visualizando erros de compilação ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ Casa do Código ✲✲ ♣r♦❝❡❞✉r❡ ❧✐st❛❴❣❡r❡♥t❡❴♣♦r❴❞❡♣t♦ ✐s ✲✲ ❜❡❣✐♥ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ t❜❣❡r❡♥t❡✭r✶✳❞❡♣❛rt♠❡♥t❴✐❞✮ ✿❂ r✶❀ ❡♥❞ ❧♦♦♣❀ ✲✲ ♥ ✿❂ t❜❣❡r❡♥t❡✳❢✐rst❀ ✲✲ ✇❤✐❧❡ ♥ ❁❂ t❜❣❡r❡♥t❡✳❧❛st ❧♦♦♣ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡♣t♦✿ ✬⑤⑤t❜❣❡r❡♥t❡✭♥✮✳❞❡♣❛rt♠❡♥t❴♥❛♠❡⑤⑤✬ ✬⑤⑤ ✬●❡r❡♥t❡✿ ✬⑤⑤t❜❣❡r❡♥t❡✭♥✮✳❢✐rst❴♥❛♠❡⑤⑤✬ ✬⑤⑤ ✬❉t✳ ❆❞♠✐✳✿ ✬⑤⑤t❜❣❡r❡♥t❡✭♥✮✳❤✐r❡❴❞❛t❡⑤⑤✬ ✬⑤⑤ ✬❙❛❧✳✿ ✬⑤⑤t♦❴❝❤❛r✭t❜❣❡r❡♥t❡✭♥✮✳s❛❧❛r②✱ ✬❢♠✩✾✾✾❣✾✾✾❣✾✾✵❞✵✵✬✮✮❀ ♥ ✿❂ t❜❣❡r❡♥t❡✳♥❡①t✭♥✮❀ ❡♥❞ ❧♦♦♣❀ ✲✲ ❡♥❞ ❧✐st❛❴❣❡r❡♥t❡❴♣♦r❴❞❡♣t♦❀ ✲✲ ❡♥❞ ❧✐st❛❣❡♠❀ ✹✸ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ 17.6 Visualizando erros de compilação Para visualizar erros de compilação, use o comando show error. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣❛❝❦❛❣❡ ❧✐st❛❣❡♠ ✐s ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ✺ ✱❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✻ ✱❢✐rst❴♥❛♠❡ ✼ ✱❤✐r❡❴❞❛t❡ 280 Casa do Código ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ Capítulo 17. packages ✱s❛❧❛r② ❢r♦♠ ❞❡♣❛rt♠❡♥ts ❞ ✱❡♠♣❧♦②❡❡s ❡ ✇❤❡r❡ ❞✳♠❛♥❛❣❡r❴✐❞ ❂ ❡✳❡♠♣❧♦②❡❡❴✐❞ ♦r❞❡r ❜② ❞❡♣❛rt♠❡♥t❴♥❛♠❡❀ ✲✲ t②♣❡ t❛❜ ✐s t❛❜❧❡ ♦❢ ❝✶✪r♦✇t②♣❡ ✐♥❞❡① ❜② ❜✐♥❛r②❴✐♥t❡❣❡r❀ ✲✲ t❜❣❡r❡♥t❡ t❛❜❀ ♥ ♥✉♠❜❡r❀ ✲✲ ♣r♦❝❡❞✉r❡ ❧✐st❛❴❣❡r❡♥t❡❴♣♦r❴❞❡♣t♦❀ ❀ ✲✲ ♣r♦✈♦❝❛♥❞♦ ✉♠ ❡rr♦ ❞❡ s✐♥t❛①❡✳ ✲✲ ❡♥❞ ❧✐st❛❣❡♠❀ ✴ ❆❞✈❡rtê♥❝✐❛✿ P❛❝♦t❡ ❝r✐❛❞♦ ❝♦♠ ❡rr♦s ❞❡ ❝♦♠♣✐❧❛çã♦✳ ❙◗▲❃ s❤♦✇ ❡rr♦r ❊rr♦s ♣❛r❛ ♣❛❝❦❛❣❡ ❧✐st❛❣❡♠✿ ▲■◆❊✴❈❖▲ ❊❘❘❖❘ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✷✵✴✹ P▲❙✲✵✵✶✵✸✿ ❊♥❝♦♥tr❛❞♦ ♦ sí♠❜♦❧♦ ✧❀✧ q✉❛♥❞♦ ✉♠ ❞♦s s❡❣✉✐♥t❡s sí♠❜♦❧♦s ❡r❛ ❡s♣❡r❛❞♦✿ ❡♥❞ ❢✉♥❝t✐♦♥ ♣❛❝❦❛❣❡ ♣r❛❣♠❛ ♣r✐✈❛t❡ ♣r♦❝❡❞✉r❡ s✉❜t②♣❡ t②♣❡ ✉s❡ ❁✉♠ ✐❞❡♥t✐❢✐❝❛❞♦r❃ ❁✉♠ ✐❞❡♥t✐❢✐❝❛❞♦r ❞❡❧✐♠✐t❛❞♦ ♣♦r ❛s♣❛s ❞✉♣❧❛s❃ ❢♦r♠ ❝✉rr❡♥t ❝✉rs♦r ❙◗▲❃ O comando basicamente mostra duas colunas. A primeira com a linha e a coluna onde ocorreu o erro, e a segunda coluna com a descrição. Estes erros também podem ser visualizados através das views user_errors, 281 Casa do Código 17.6. Visualizando erros de compilação all_errors e dba_errors. ❙◗▲❃ s❡❧❡❝t ❧✐♥❡ ✷ ✱♣♦s✐t✐♦♥ ✸ ✱t❡①t ✹ ❢r♦♠ ✉s❡r❴❡rr♦rs ✺ ✇❤❡r❡ ♥❛♠❡ ❂ ✬❧✐st❛❣❡♠✬❀ ▲■◆❊ P❖❙■❚■❖◆ ❚❊❳❚ ✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✷✵ ✹ P▲❙✲✵✵✶✵✸✿ ❊♥❝♦♥tr❛❞♦ ♦ sí♠❜♦❧♦ ✧❀✧ q✉❛♥❞♦ ✉♠ ❞♦s s❡❣✉✐♥t❡s sí♠❜♦❧♦s ❡r❛ ❡s♣❡r❛❞♦✿ ❡♥❞ ❢✉♥❝t✐♦♥ ♣❛❝❦❛❣❡ ♣r❛❣♠❛ ♣r✐✈❛t❡ ♣r♦❝❡❞✉r❡ s✉❜t②♣❡ t②♣❡ ✉s❡ ❁✉♠ ✐❞❡♥t✐❢✐❝❛❞♦r❃ ❁✉♠ ✐❞❡♥t✐❢✐❝❛❞♦r ❞❡❧✐♠✐t❛❞♦ ♣♦r ❛s♣❛s ❞✉♣❧❛s❃ ❢♦r♠ ❝✉rr❡♥t ❝✉rs♦r ❙◗▲❃ 282 Capítulo 18 Transações autônomas Quando buscamos informações em um banco de dados, esperamos que elas estejam íntegras. Para garantir a integridade e consistências dos dados, o Oracle mantém controles de transações. Quando uma operação DML é disparada, isso indica que os dados de uma tabela, por exemplo, podem estar sendo alterados. Nesse momento, podemos concluir que enquanto as alterações não forem confirmadas os dados que estão sendo manipulados na transação em questão não estão consistentes. Apenas quando forem confirmados, através de um rollback ou de um commit, os dados estarão íntegros. Há situações em que podemos ter várias chamadas a outros objetos que estejam executando comandos DML e efetivando-os logo em seguida. Entretanto, ao fazer isso, corremos o risco de efetivar ações de outros comandos DML, executados anteriormente, que não deveriam ser efetivados, ou pelo menos não naquele momento. Isso acontece pois sabemos que, ao executar um comando de efetivação, como um commit ou um rollback, o Oracle Casa do Código efetiva tudo o que estiver pendente na sessão. Para esses casos, podemos utilizar transações autônomas para isolar ações de determinados programas. Utilizamos este recurso informando-o na declaração dos objetos, como em procedures e functions (dentro ou fora de packages), blocos anônimos (menos em sub-blocos) ou triggers. Sua função é fazer com que o Oracle abra uma nova sessão somente para executar tal objeto, ou seja, neste momento existirão pelo menos duas transações em aberto: a transação original e outra transação autônoma. Veja o exemplo a seguir. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ♣r♦❝❡❞✉r❡ ❧✐st❛❴❞❡♣t ✐s ✹ ✲✲ ✺ ♣r❛❣♠❛ ❛✉t♦♥♦♠♦✉s❴tr❛♥s❛❝t✐♦♥❀ ✻ ❜❡❣✐♥ ✼ ✲✲ ✽ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬✲✲✲✲✲✲✲✲✲✲✲ ▲✐st❛ ❉❡♣❛rt❛♠❡♥t♦s ✲✲✲✲✲✲✲✲✲✲✲✬✮❀ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ✶✶ ✲✲ ✶✷ ❢♦r ✐ ✐♥ ✭s❡❧❡❝t ✯ ❢r♦♠ ❞❡♣t ♦r❞❡r ❜② ❞❡♣t♥♦✮ ❧♦♦♣ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✐✳❞❡♣t♥♦⑤⑤✬ ✲ ✬⑤⑤✐✳❞♥❛♠❡✮❀ ✶✹ ❡♥❞ ❧♦♦♣❀ ✶✺ ✲✲ ✶✻ ❝♦♠♠✐t❀ ✶✼ ✲✲ ✶✽ ❡♥❞❀ ✶✾ ✲✲ ✷✵ ❜❡❣✐♥ ✷✶ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✭❞❡♣t♥♦✱ ❞♥❛♠❡✱ ❧♦❝✮ ✈❛❧✉❡s ✭✹✸✱ ✬❖❘❉❊❘ ▼❆◆❆●❊❘✬✱✬❇❘❆❙■▲✬✮❀ ✷✷ ✲✲ ✷✸ ❧✐st❛❴❞❡♣t❀ ✷✹ ✲✲ ✷✺ ❝♦♠♠✐t❀ ✷✻ ✲✲ 284 Casa do Código Capítulo 18. Transações autônomas ✷✼ ❧✐st❛❴❞❡♣t❀ ✷✽ ✲✲ ✷✾ ❡♥❞❀ ✸✵ ✴ Nesse exemplo, criamos um bloco PL/SQL anônimo e dentro dele declaramos uma procedure chamada lista_dept. Esta procedure lista todos os departamentos existentes. Ela foi declarada como autonomous_transaction, ou seja, quando ela for executada será aberta uma transação autônoma. No corpo do bloco PL/SQL, temos um insert que inclui um departamento novo. Logo depois deste comando, chamamos a procedure lista_dept para listar todos os departamentos que já se encontram cadastrados. Depois disso, efetivamos a alteração realizada pelo insert e mandamos listar os departamentos, novamente. Agora vamos analisar o resultado. ✲✲✲✲✲✲✲✲✲✲✲ ▲✐st❛ ❉❡♣❛rt❛♠❡♥t♦s ✲✲✲✲✲✲✲✲✲✲✲ ✶✵ ✲ ❆❈❈❖❯◆❚■◆● ✸✵ ✲ ❙❆▲❊❙ ✹✵ ✲ ❖P❊❘❆❚■❖◆❙ ✹✶ ✲ ●❊◆❊❘❆▲ ▲❊❉●❊❘ ✹✷ ✲ P❯❘❈❍❆❙■◆● ✲✲✲✲✲✲✲✲✲✲✲ ▲✐st❛ ❉❡♣❛rt❛♠❡♥t♦s ✲✲✲✲✲✲✲✲✲✲✲ ✶✵ ✲ ❆❈❈❖❯◆❚■◆● ✸✵ ✲ ❙❆▲❊❙ ✹✵ ✲ ❖P❊❘❆❚■❖◆❙ ✹✶ ✲ ●❊◆❊❘❆▲ ▲❊❉●❊❘ ✹✷ ✲ P❯❘❈❍❆❙■◆● ✹✸ ✲ ❖❘❉❊❘ ▼❆◆❆●❊❘ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ No resultado, temos duas listagens. Uma impressa após o comando insert, e outra após a efetivação do insert através do comando commit. Note que a impressão realizada antes do commit não mostra o departamento 285 Casa do Código 43, embora, ele já tenha sido inserido neste ponto. Já a impressão após o comando commit mostra o novo departamento. Desta forma, temos que nos atentar para o seguinte cenário. Sabemos que, quando é aberta uma transação no Oracle, ela monta uma imagem, digamos assim, dos objetos e dados disponíveis para o usuário nesta sessão. Com relação aos dados, a visão permite enxergar somente aquilo que está efetivado no banco de dados, ou seja, dados consistentes e íntegros. Isso quer dizer que dados pendentes de efetivação não poderão ser visualizados, isso é, dados excluídos, inseridos ou atualizados que ainda não tenham sido commitados. Logo, quando isto acontece, não conseguimos visualizar as alterações que estão sendo realizadas. Quando temos um objeto utilizando transação autônoma, conseguimos manipular somente os dados efetivados. Dessa forma, se nós realizarmos um comando select a fim de obter os dados alterados na sessão original, mas não efetivados, não conseguiremos enxergá-los. Apenas para ressaltar, isso se dá ao fato de que dentro deste objeto estamos em outro escopo, em uma nova transação. Outro ponto muito importante é que, quando utilizamos objetos com transação autônoma, precisamos efetivar a transação através de um commit ou de um rollback. Como este tipo de ação faz com que uma nova transação seja aberta, temos que finalizá-la. Caso contrário, ela ficaria pendente e isso poderia gerar um erro. Conforme visto no exemplo anterior, utilizamos a seguinte linha de comando pragma autonomous_transaction, na área de declaração, para abrir uma nova transação. Veja outro exemplo a seguir. Para este exemplo, criamos vários objetos. Primeiramente, criamos uma procedure chamada lista_pais, que listará na tela todos os países já cadastrados na tabela countries. Cada lista impressa terá um número indicando o número da impressão. ❙◗▲❃ ❝r❡❛t❡ ♣r♦❝❡❞✉r❡ ❧✐st❛❴♣❛✐s✭♥✉♠❴❧✐st❛ ♥✉♠❜❡r✮ ✐s ✷ ✲✲ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ▲■❙❚❆❴P❆■❙✬✮❀ ✻ ✲✲ 286 Casa do Código ✼ ✽ Capítulo 18. Transações autônomas ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬✲✲✲✲✲✲✲✲✲✲✲ ▲✐st❛ P❛ís ✲ ✬⑤⑤♥✉♠❴❧✐st❛⑤⑤✬✲✲✲✲✲✲✲✲✲✲✲✬✮❀ ❞❜♠s❴♦✉t♣✉t✳♥❡✇❴❧✐♥❡❀ ✲✲ ❢♦r ✐ ✐♥ ✭s❡❧❡❝t ✯ ❢r♦♠ ❝♦✉♥tr✐❡s ✇❤❡r❡ r❡❣✐♦♥❴✐❞ ❂ ✶ ♦r❞❡r ❜② ❝♦✉♥tr②❴♥❛♠❡✮ ❧♦♦♣ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✐✳❝♦✉♥tr②❴✐❞⑤⑤✬ ✲ ✬⑤⑤✐✳❝♦✉♥tr②❴♥❛♠❡✮❀ ❡♥❞ ❧♦♦♣❀ ✲✲ ❡♥❞❀ ✴ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ A procedure a seguir tem o objetivo de inserir um registro na tabela countries referente ao país Portugal. Note que nesta procedure temos declarada uma transação autônoma. No corpo, além do comando insert, temos a chamada à procedure lista_pais, que vai listar os países cadas- trados. Esta listagem será a segunda lista a ser impressa. Logo após, temos um commit que efetivará a ação do comando insert e encerrará a transação autônoma. ❙◗▲❃ ❝r❡❛t❡ ♣r♦❝❡❞✉r❡ ✐♥s❡r❡❴♣❛✐s❴♣♦rt✉❣❛❧ ✐s ✷ ✲✲ ✸ ♣r❛❣♠❛ ❛✉t♦♥♦♠♦✉s❴tr❛♥s❛❝t✐♦♥❀ ✹ ✲✲ ✺ ❜❡❣✐♥ ✻ ✲✲ ✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ■◆❙❊❘❊❴P❆■❙❴P❖❘❚❯●❆▲✬✮❀ ✽ ✲✲ ✾ ✐♥s❡rt ✐♥t♦ ❝♦✉♥tr✐❡s ✭❝♦✉♥tr②❴✐❞✱ ❝♦✉♥tr②❴♥❛♠❡✱ r❡❣✐♦♥❴✐❞✮ ✶✵ ✈❛❧✉❡s ✭✬P❚✬✱ ✬P♦rt✉❣❛❧✬✱✶✮❀ ✶✶ ✲✲ 287 Casa do Código ✶✷ ❧✐st❛❴♣❛✐s✭✷✮❀ ✶✸ ✲✲ ✶✹ ❝♦♠♠✐t❀ ✶✺ ✲✲ ✶✻ ❡♥❞❀ ✶✼ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ A próxima procedure tem a finalidade de apenas chamar a procedure insere_pais_portugal. Ela serve apenas para, digamos assim, estabelecer uma ligação indireta entre as procedures insere_pais_espanha e insere_pais_portugal. ❙◗▲❃ ❝r❡❛t❡ ♣r♦❝❡❞✉r❡ ❝❤❛♠❛❴✐♥s❡r❡❴♣❛✐s❴♣♦rt✉❣❛❧ ✐s ✷ ✲✲ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ❈❍❆▼❆❴■◆❙❊❘❊❴P❆■❙❴P❖❘❚❯●❆▲✬✮❀ ✻ ✲✲ ✼ ✐♥s❡r❡❴♣❛✐s❴♣♦rt✉❣❛❧❀ ✽ ✲✲ ✾ ❡♥❞❀ ✶✵ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ Já a procedure insere_pais_espanha tem o objetivo de inserir um registro na tabela countries referente ao país Espanha. No corpo da procedure, além do comando insert, temos a chamada à procedure lista_pais, que irá listar os países cadastrados. Esta listagem será a primeira lista a ser impressa. Logo após, temos um rollback que desfará a ação do comando insert. Depois do rollback, temos uma nova cha288 Casa do Código Capítulo 18. Transações autônomas mada à procedure lista_pais, a segunda neste objeto, que imprime a terceira listagem. ❙◗▲❃ ❝r❡❛t❡ ♣r♦❝❡❞✉r❡ ✐♥s❡r❡❴♣❛✐s❴❡s♣❛♥❤❛ ✐s ✷ ✲✲ ✸ ❜❡❣✐♥ ✹ ✲✲ ✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ■◆❙❊❘❊❴P❆■❙❴❊❙P❆◆❍❆✬✮❀ ✻ ✲✲ ✼ ✐♥s❡rt ✐♥t♦ ❝♦✉♥tr✐❡s ✭❝♦✉♥tr②❴✐❞✱ ❝♦✉♥tr②❴♥❛♠❡✱ r❡❣✐♦♥❴✐❞✮ ✽ ✈❛❧✉❡s ✭✬❊❙✬✱✬❊s♣❛♥❤❛✬✱✶✮❀ ✾ ✲✲ ✶✵ ❧✐st❛❴♣❛✐s✭✶✮❀ ✶✶ ✲✲ ✶✷ ❝❤❛♠❛❴✐♥s❡r❡❴♣❛✐s❴♣♦rt✉❣❛❧❀ ✶✸ ✲✲ ✶✹ r♦❧❧❜❛❝❦❀ ✶✺ ✲✲ ✶✻ ❧✐st❛❴♣❛✐s✭✸✮❀ ✶✼ ✲✲ ✶✽ ❡♥❞❀ ✶✾ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ Note que em todos os objetos temos chamadas à procedure dbms_output, indicando a execução do objeto corrente. Usaremos esta identificação para saber a ordem cronológica da execução dos programas. Agora vamos executar a procedure insere_pais_espanha, que é a que desencadeará a execução dos demais objetos criados. ❙◗▲❃ ❜❡❣✐♥ ✷ ✐♥s❡r❡❴♣❛✐s❴❡s♣❛♥❤❛❀ ✸ ❡♥❞❀ ✹ ✴ 289 Casa do Código Esse código PL/SQL executa a procedure insere_pais_espanha, que chama as demais procedures onde obtivemos os resultados a seguir. Neste nosso exemplo, ao executarmos essa procedure, primeiramente, o país Espanha foi inserido na tabela countries. Logo após a inserção, mandamos listar os países. O resultado da listagem 1 é mostrado a seguir. ❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ■◆❙❊❘❊❴P❆■❙❴❊❙P❆◆❍❆ ❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ▲■❙❚❆❴P❆■❙ ✲✲✲✲✲✲✲✲✲✲✲ ▲✐st❛ P❛ís ✲ ✶✲✲✲✲✲✲✲✲✲✲✲ ❇❊ ✲ ❇❡❧❣✐✉♠ ❉❑ ✲ ❉❡♥♠❛r❦ ❊❙ ✲ ❊s♣❛♥❤❛ ❋❘ ✲ ❋r❛♥❝❡ ❉❊ ✲ ●❡r♠❛♥② ■❚ ✲ ■t❛❧② ◆▲ ✲ ◆❡t❤❡r❧❛♥❞s ❈❍ ✲ ❙✇✐t③❡r❧❛♥❞ ❯❑ ✲ ❯♥✐t❡❞ ❑✐♥❣❞♦♠ Note que, na terceira linha da listagem, temos o país Espanha inserido. Logo após a execução do procedimento de listagem, continuando a execução da procedure insere_pais_espanha, foi chamada a procedure chama_insere_pais_portugal, que por sua vez, chama a procedure insere_pais_portugal. A procedure insere_pais_portugal será executada em outra transação, pois nela declaramos um pragma autonomous_transaction. Ela executa o insert referente ao país Portugal e logo em seguida executa a impressão da listagem 2. Para encerrar, um commit é executado, efetivando as operações. Veja o resultado. ❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ❈❍❆▼❆❴■◆❙❊❘❊❴P❆■❙❴P❖❘❚❯●❆▲ ❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ■◆❙❊❘❊❴P❆■❙❴P❖❘❚❯●❆▲ ❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ▲■❙❚❆❴P❆■❙ ✲✲✲✲✲✲✲✲✲✲✲ ▲✐st❛ P❛ís ✲ ✷✲✲✲✲✲✲✲✲✲✲✲ ❇❊ ✲ ❇❡❧❣✐✉♠ ❉❑ ✲ ❉❡♥♠❛r❦ ❋❘ ✲ ❋r❛♥❝❡ ❉❊ ✲ ●❡r♠❛♥② ■❚ ✲ ■t❛❧② 290 Casa do Código ◆▲ P❚ ❈❍ ❯❑ ✲ ✲ ✲ ✲ Capítulo 18. Transações autônomas ◆❡t❤❡r❧❛♥❞s P♦rt✉❣❛❧ ❙✇✐t③❡r❧❛♥❞ ❯♥✐t❡❞ ❑✐♥❣❞♦♠ Veja que aqui não apareceu o país Espanha. Isso porque a procedure insere_pais_portugal foi executada dentro de uma transação autônoma, logo, quando ela chama a listagem, apenas os dados efetivados e os da sessão corrente são visualizados. Após o término da execução da procedure insere_pais_portugal, voltamos para a procedure insere_pais_espanha, onde, na sequência do programa, temos um rollback, desfazendo tudo que ficou pendente na sessão. Após desfazer as ações, executamos a listagem de número 3. A seguir, o resultado. ❊①❡❝✉t❛♥❞♦ ♣r♦❝❡❞✉r❡✿ ▲■❙❚❆❴P❆■❙ ✲✲✲✲✲✲✲✲✲✲✲ ▲✐st❛ P❛ís ✲ ✸✲✲✲✲✲✲✲✲✲✲✲ ❇❊ ✲ ❇❡❧❣✐✉♠ ❉❑ ✲ ❉❡♥♠❛r❦ ❋❘ ✲ ❋r❛♥❝❡ ❉❊ ✲ ●❡r♠❛♥② ■❚ ✲ ■t❛❧② ◆▲ ✲ ◆❡t❤❡r❧❛♥❞s P❚ ✲ P♦rt✉❣❛❧ ❈❍ ✲ ❙✇✐t③❡r❧❛♥❞ ❯❑ ✲ ❯♥✐t❡❞ ❑✐♥❣❞♦♠ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Note que na saída da listagem final (listagem 3) temos cadastrado o país Portugal, mas não o país Espanha. O rollback acabou desfazendo a inserção referente ao país Espanha, mas não a inserção referente ao país Portugal, pois esta inserção foi realizada e efetivada via outra transação, a transação autônoma. Não é comum ver transações autônomas sendo utilizadas em programas PL/SQL, contudo, em alguns casos elas se tornam imprescindíveis. Quando 291 Casa do Código estivermos trabalhando com triggers (capítulo mais a seguir), será visto que, para o disparo de determinados tipos de triggers em situações específicas, somos obrigados a usar transações autônomas para poder atender o objetivo. 292 Capítulo 19 Triggers O objeto trigger nada mais é do que um bloco de código PL/SQL armazenado no banco de dados e que é disparado automaticamente mediante uma ação. Este disparo pode ocorrer de duas formas, por intermédio de alterações feitas em registros de uma determinada tabela, neste caso se tratando do disparo de um trigger de banco de dados ou por ações em nível de sistema por um trigger de sistema. Vamos aprender sobre estes dois tipos, mostrando as características dos triggers de banco de dados que são muito utilizados no desenvolvimento de programas e dos triggers de sistema que são mais utilizados pelos administradores de banco de dados. 19.1. Trigger de banco de dados Casa do Código 19.1 Trigger de banco de dados Um trigger de banco de dados sempre está associado a uma tabela. Não existindo tabela, não existe trigger de bando de dados. Quando queremos que uma ação aconteça automaticamente mediante uma alteração em alguma tabela, ou melhor, nos registros que ela possui, podemos utilizá-los para isto. Um trigger pode disparar quando alguma ação ocorre em uma tabela e também em um determinado momento. Por exemplo, podemos criar um trigger que dispare quando fizermos um update em determinada tabela, e que ocorra após o update dos registros. Além disso, podemos definir que este trigger disparará para cada linha afetada pelo comando dml, chamado de trigger de linha, ou se executará uma única vez independente de quantas linhas sofrerem alterações. Este último, nós chamamos de trigger de tabela ou de comando. Também podemos definir cláusulas where para o trigger para que o disparo só aconteça se alguns critérios forem obedecidos. 19.2 Trigger de tabela Vamos analisar a definição do trigger. ❝r❡❛t❡ tr✐❣❣❡r t✐♣♦❴t❛❜❡❧❛ ❜❡❢♦r❡ ❞❡❧❡t❡ ♦r ✐♥s❡rt ♦r ✉♣❞❛t❡ ♦❢ s❛❧ ♦♥ ❡♠♣ ❜❡❣✐♥ ❡♥❞❀ Para criar um trigger, primeiramente damos um nome. Utilizamos o comando create trigger para criar o objeto. Temos obrigatoriamente que definir quando será o disparo. Neste exemplo, informamos que seu disparo ocorrerá antes da ação, neste caso before. Caso tenhamos necessidade que o disparo ocorra depois, informamos after. Vamos abrir um parênteses aqui para explicar melhor esta questão de after e before na especificação do trigger. A expressão before definida no trigger pode ser um pouco confusa, pois dá a impressão que o trigger vai detectar que vamos executar um insert, por exemplo, e antes de acontecer tal ação ele dispara o trigger. 294 Casa do Código Capítulo 19. Triggers Mas não é bem assim. Na verdade, o before quer dizer antes que as alterações sejam feitas nos registros da tabela em questão, ou seja, podemos dizer que o Oracle faz as alterações primeiramente em memória, para depois efetivá-las no banco de dados. Com isso, dependendo do momento tratado, before ou after, podemos ou não alterar estes dados. Quando o trigger é disparado no momento before, os dados ainda não foram efetivados, neste caso podemos alterar os valores antes que eles sejam gravados no banco de dados. Quando é disparado no after não há mais como alterá-los, pois já foram efetivados no banco de dados. Depois de definir quando ocorrerá, precisamos informar em quais situações, ou melhor, ações, o trigger deve disparar. Note que para esta definição foi determinado que o disparo sempre ocorrerá quando a tabela emp sofrer um delete, insert ou update específico na coluna sal. Nos casos de update, podemos ou não informar colunas específicas para determinar o disparo. Neste exemplo, qualquer atualização que não seja na coluna sal da tabela emp o trigger não vai disparar. Caso não queira definir colunas específicas apenas não use a expressão of. Este trigger pode ser caracterizado como um trigger de tabela, pois não informamos que ele vai disparar para cada linha afetada. Portanto, não importa quantas linhas serão excluídas, inseridas ou atualizadas, ele sempre disparará uma única vez. Na sequência, segue um exemplo de trigger de tabela e sua aplicação. Vamos criar um trigger que fará a auditoria da tabela emp. Cada vez que um ou mais registros forem inseridos ou atualizados, este programa vai calcular a quantidade de registros contidos na tabela emp, a soma de todos os salários e comissões. Esses dados serão inseridos em uma tabela chamada tab_audit_emp. Vamos criar a tabela: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ❝r❡❛t❡ t❛❜❧❡ t❛❜❴❛✉❞✐t❴❡♠♣ ✭ ♥r❴r❡❣✐str♦s ♥✉♠❜❡r ✱✈❧❴t♦t❛❧❴s❛❧❛r✐♦ ♥✉♠❜❡r ✱✈❧❴t♦t❛❧❴❝♦♠✐ss❛♦ ♥✉♠❜❡r ✮ ✴ 295 19.2. Trigger de tabela Casa do Código ❚❛❜❡❧❛ ❝r✐❛❞❛✳ ❙◗▲❃ Segue o código da trigger: ❙◗▲❃ ❝r❡❛t❡ tr✐❣❣❡r t✐❣❴❛✉❞✐t❴❡♠♣ ✷ ❛❢t❡r ✐♥s❡rt ♦r ❞❡❧❡t❡ ♦r ✉♣❞❛t❡ ♦❢ s❛❧✱ ❝♦♠♠ ♦♥ ❡♠♣ ✸ ❞❡❝❧❛r❡ ✹ ✇♥r❴r❡❣✐str♦s ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✺ ✇✈❧❴t♦t❛❧❴s❛❧❛r✐♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✻ ✇✈❧❴t♦t❛❧❴❝♦♠✐ss❛♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✼ ✇♥r❴r❡❣✐str♦s❴❛✉❞✐t ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✽ ❜❡❣✐♥ ✾ s❡❧❡❝t ❝♦✉♥t✭✯✮ ✶✵ ✐♥t♦ ✇♥r❴r❡❣✐str♦s ✶✶ ❢r♦♠ ❡♠♣❀ ✶✷ ✲✲ ✶✸ s❡❧❡❝t s✉♠✭s❛❧✮ ✶✹ ✐♥t♦ ✇✈❧❴t♦t❛❧❴s❛❧❛r✐♦ ✶✺ ❢r♦♠ ❡♠♣❀ ✶✻ ✲✲ ✶✼ s❡❧❡❝t s✉♠✭❝♦♠♠✮ ✶✽ ✐♥t♦ ✇✈❧❴t♦t❛❧❴❝♦♠✐ss❛♦ ✶✾ ❢r♦♠ ❡♠♣❀ ✷✵ ✲✲ ✷✶ s❡❧❡❝t ❝♦✉♥t✭✯✮ ✷✷ ✐♥t♦ ✇♥r❴r❡❣✐str♦s❴❛✉❞✐t ✷✸ ❢r♦♠ t❛❜❴❛✉❞✐t❴❡♠♣❀ ✷✹ ✲✲ ✷✺ ✐❢ ✇♥r❴r❡❣✐str♦s❴❛✉❞✐t ❂ ✵ t❤❡♥ ✷✻ ✲✲ ✷✼ ✐♥s❡rt ✐♥t♦ t❛❜❴❛✉❞✐t❴❡♠♣ ✭ ♥r❴r❡❣✐str♦s✱ ✈❧❴t♦t❛❧❴s❛❧❛r✐♦✱ ✈❧❴t♦t❛❧❴❝♦♠✐ss❛♦✮ ✷✽ ✈❛❧✉❡s ✭✇♥r❴r❡❣✐str♦s✱ ✇✈❧❴t♦t❛❧❴s❛❧❛r✐♦✱ ✇✈❧❴t♦t❛❧❴❝♦♠✐ss❛♦✮❀ ✷✾ ✲✲ ✸✵ ❡❧s❡ ✸✶ ✲✲ ✸✷ ✉♣❞❛t❡ t❛❜❴❛✉❞✐t❴❡♠♣ 296 Casa do Código ✸✸ ✸✹ ✸✺ ✸✻ ✸✼ ✸✽ ✸✾ s❡t ✲✲ ❡♥❞ ✐❢❀ ❡♥❞❀ ✴ Capítulo 19. Triggers ♥r❴r❡❣✐str♦s ❂ ✇♥r❴r❡❣✐str♦s ✱✈❧❴t♦t❛❧❴s❛❧❛r✐♦ ❂ ✇✈❧❴t♦t❛❧❴s❛❧❛r✐♦ ✱✈❧❴t♦t❛❧❴❝♦♠✐ss❛♦ ❂ ✇✈❧❴t♦t❛❧❴❝♦♠✐ss❛♦❀ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Vamos entender o que este trigger faz. Primeiramente, chamamos este de tig_audit_emp. Ele vai disparar após a tabela emp sofrer um comando insert, delete ou update, sendo que para este último, somente quando as colunas sal ou comm forem alteradas. Note que a linha for each row não aparece. Isso indica que nosso trigger é um de tabela. Portanto, não importa a quantidade de linhas afetadas pelo comando, ele só vai disparar uma única vez. O trigger também só vai ser disparado após ( after) os comandos insert, delete ou update forem efetivados. Dentro destas condições o trigger dispara e executa comandos SQL para buscar as informações que serão utilizadas para gerar nossa auditoria, como a quantidade de registros na tabela, a soma de todos os salários e comissões. Isso justifica o fato de o trigger ser disparado uma única vez, pois neste disparo ele varre todos os registros da tabela, não necessitando trabalhar registro por registro afetado. Depois de buscar as informações, o programa faz um select para verificar se já existe um registro na tabela de auditoria. Caso exista, ele somente atualiza as informações existentes. Caso contrário, insere um registro. Vamos testá-lo. Primeiramente, verificamos a tabela tab_audit_emp. ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ t❛❜❴❛✉❞✐t❴❡♠♣❀ ♥ã♦ ❤á ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s ❙◗▲❃ 297 Casa do Código 19.2. Trigger de tabela Agora vamos pegar uma massa de teste para realizar uma atualização nos dados da tabela emp. ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵ ✷ ✴ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✺✻✻ ✼✼✽✽ ✼✽✼✻ ✼✾✵✷ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❏❖◆❊❙ ❙❈❖❚❚ ❆❉❆▼❙ ❋❖❘❉ ❏❖❇ ▼●❘ ❍■❘❊❉❆❚❊ ❙❆▲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✼✾✵✷ ✶✼✴✶✷✴✽✵ ✽✽✵ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✷✴✵✹✴✽✶ ✸✷✼✷✱✺ ❆◆❆▲❨❙❚ ✼✺✻✻ ✵✾✴✶✷✴✽✷ ✸✸✵✵ ❈▲❊❘❑ ✼✼✽✽ ✶✷✴✵✶✴✽✸ ✶✷✶✵ ❆◆❆▲❨❙❚ ✼✺✻✻ ✵✸✴✶✷✴✽✶ ✸✸✵✵ ❈❖▼▼ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✷✵ ✷✵ ✷✵ ✷✵ ✷✵ ❙◗▲❃ Vamos atualizar os salários de todos os empregados que estão alocados no departamento 20. ❙◗▲❃ ✷ ✸ ✹ ✉♣❞❛t❡ ❡♠♣ s❡t s❛❧ ❂ s❛❧ ✰ ✭s❛❧ ✯ ✶✵ ✴ ✶✵✵✮ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵ ✴ ✺ ❧✐♥❤❛s ❛t✉❛❧✐③❛❞❛s✳ ❙◗▲❃ ❝♦♠♠✐t❀ ❱❛❧✐❞❛çã♦ ❝♦♠♣❧❡t❛✳ 298 Casa do Código Capítulo 19. Triggers ❙◗▲❃ Vamos verificar as atualizações na tabela emp. ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✺✻✻ ✼✼✽✽ ✼✽✼✻ ✼✾✵✷ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❏❖◆❊❙ ❙❈❖❚❚ ❆❉❆▼❙ ❋❖❘❉ ❏❖❇ ▼●❘ ❍■❘❊❉❆❚❊ ❙❆▲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✼✾✵✷ ✶✼✴✶✷✴✽✵ ✾✻✽ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✷✴✵✹✴✽✶ ✸✺✾✾✱✼✺ ❆◆❆▲❨❙❚ ✼✺✻✻ ✵✾✴✶✷✴✽✷ ✸✻✸✵ ❈▲❊❘❑ ✼✼✽✽ ✶✷✴✵✶✴✽✸ ✶✸✸✶ ❆◆❆▲❨❙❚ ✼✺✻✻ ✵✸✴✶✷✴✽✶ ✸✻✸✵ ❈❖▼▼ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✷✵ ✷✵ ✷✵ ✷✵ ✷✵ ❙◗▲❃ Ok. Os dados foram atualizados. Agora vamos verificar nossa tabela de auditoria. ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ t❛❜❴❛✉❞✐t❴❡♠♣❀ ◆❘❴❘❊●■❙❚❘❖❙ ❱▲❴❚❖❚❆▲❴❙❆▲❆❘■❖ ❱▲❴❚❖❚❆▲❴❈❖▼■❙❙❆❖ ✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✶✹ ✸✶✸✵✽✱✼✺ ✷✷✹✹ ❙◗▲❃ Note que o trigger realizou o cálculo considerando não só as linhas afetadas, mas sim todas as linhas da tabela, como era o esperado, ou seja, foi criado um registro nesta tabela contendo informações referentes a todos os 299 19.2. Trigger de tabela Casa do Código registros de funcionários cadastrados. Agora vamos excluir alguns registros da tabela emp. ❙◗▲❃ ❞❡❧❡t❡ ❢r♦♠ ❡♠♣ ✷ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✶✵ ✸ ✴ ✸ ❧✐♥❤❛s ❞❡❧❡t❛❞❛s✳ ❙◗▲❃ ❝♦♠♠✐t❀ ❱❛❧✐❞❛çã♦ ❝♦♠♣❧❡t❛✳ ❙◗▲❃ Ok. Excluímos os dados com sucesso. Agora vamos verificar nossa tabela de auditoria. ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ t❛❜❴❛✉❞✐t❴❡♠♣❀ ◆❘❴❘❊●■❙❚❘❖❙ ❱▲❴❚❖❚❆▲❴❙❆▲❆❘■❖ ❱▲❴❚❖❚❆▲❴❈❖▼■❙❙❆❖ ✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✶✶ ✷✷✺✺✽✱✼✺ ✷✷✹✹ ❙◗▲❃ Por último, vamos testar a inserção de dados. ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✮ ✷ ✈❛❧✉❡s ✭✼✾✸✺✱ ✬P❆❯▲❖✬✱ ✬❈▲❊❘❑✬✱ ✼✾✵✷✱ t♦❴❞❛t❡✭✬✶✼✴✵✾✴✷✵✶✶✬✱✬❞❞✴♠♠✴②②②②✬✮✱ ✶✵✵✵✱ ♥✉❧❧✱ ✷✵✮❀ ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ Novo resultado. 300 Casa do Código Capítulo 19. Triggers ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ t❛❜❴❛✉❞✐t❴❡♠♣❀ ◆❘❴❘❊●■❙❚❘❖❙ ❱▲❴❚❖❚❆▲❴❙❆▲❆❘■❖ ❱▲❴❚❖❚❆▲❴❈❖▼■❙❙❆❖ ✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✶✷ ✷✸✺✺✽✱✼✺ ✷✷✹✹ ❙◗▲❃ Apresentamos aqui apenas uma forma de como utilizar os triggers de tabela. Contudo, as possibilidades de utilização são muitas. Tudo vai depender da necessidade. 19.3 Trigger de linha Muito parecido com o trigger de tabela, o de linha tem praticamente as mesmas características, sendo por um detalhe: o trigger de linha dispara para cada linha afetada pelo comando dml. Veja o exemplo na sequência. ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ❛❢t❡r ✉♣❞❛t❡ ♦♥ r❡❢❡r❡♥❝✐♥❣ ♦❧❞ ♥❡✇ ❢♦r ❡❛❝❤ r♦✇ ❜❡❣✐♥ tr✐❣❣❡r t✐♣♦❴❧✐♥❤❛ ❢✉♥❝ ❛s ❱ ❛s ◆ ❡♥❞❀ Neste exemplo temos algo mais do que a definição de quando e como o trigger será disparado. Estamos definindo que ele será do tipo linha, ou seja, ele vai disparar para cada linha afetada pelo update. Para isso foi colocado em sua definição a seguinte linha de comando: for each row. Quando trabalhamos com trigger de linha, podemos manipular os valores das linhas afetadas. Em alguns casos, podemos até alterar os valores de certas colunas antes de as mesmas serem salvas. Quando definimos que um trigger é de linha, o Oracle cria duas referências chamadas old e new. Estas referências apontam sempre para os dados anteriores às alterações e para os dados posteriores às alterações, respectivamente. 301 19.3. Trigger de linha Casa do Código Por exemplo, se alteramos o valor da coluna sal de 100 para 500, old.sal conterá o valor 100 e new.sal conterá o valor 500. E assim será para todos os valores das colunas da tabela que estão sendo afetadas ou não pelo comando. Quando temos um trigger sendo disparado no before, ou seja, antes do comando dml, nós podemos alterar o valor de new. O valor de old nunca pode ser alterado. Caso a alteração seja no after, nem old nem new podem ser alterados. Nem sempre teremos os valores de old e new. Quando estamos atualizando os registros em uma tabela teremos o new e o old, pois neste caso estamos atualizando um registro que já existe. Quando estamos inserindo um registro, não temos os valores de old, pois se trata de um registro novo, não havendo assim valores antigos. Quando estamos excluindo um registro temos o old e não temos o new, pois estamos excluindo um registro, não informando dados novos. As referências old e new podem receber apelidos. Neste caso utilizamos a diretriz referencing para definir esta informação. Neste exemplo, estamos criando os seguintes alias: V para old e N para new. Logo, quando formos trabalhar com as colunas devemos usar, por exemplo, v.sal para pegar o valor antigo e n.sal para o novo. Veremos a seguir uma aplicação de trigger de linha onde criaremos um histórico para a troca de cargos dos empregados. Cada vez que um empregado trocar de cargo, um histórico contendo algumas informações será guardado. Neste histórico teremos o código do empregado, o cargo anterior, o novo cargo, a data da alteração e uma descrição. Para isso, vamos criar uma tabela que será o repositório destas informações históricas. ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ 302 ❝r❡❛t❡ t❛❜❧❡ t❛❜❴❤✐st❴❝❛r❣♦❴❡♠♣ ✭ ❡♠♣♥♦ ♥✉♠❜❡r ✱❥♦❜❴❛♥t❡r✐♦r ✈❛r❝❤❛r✷✭✾✮ ✱❥♦❜❴❛t✉❛❧ ✈❛r❝❤❛r✷✭✾✮ ✱❞t❴❛❧t❡r❛❝❛♦❴❝❛r❣♦ ❞❛t❡ ✱❞s❴❤✐st♦r✐❝♦ ✈❛r❝❤❛r✷✭✷✵✵✵✮ ✮ ✴ Casa do Código Capítulo 19. Triggers ❚❛❜❡❧❛ ❝r✐❛❞❛✳ ❙◗▲❃ Criamos a tab_hist_cargo_emp que abrigará as informações que compõem o nosso histórico. Agora vamos para o trigger que fará este controle. ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ❝r❡❛t❡ tr✐❣❣❡r t✐❣❴❤✐st❴❝❛r❣♦❴❡♠♣ ❛❢t❡r ✉♣❞❛t❡ ♦❢ ❥♦❜ ♦♥ ❡♠♣ r❡❢❡r❡♥❝✐♥❣ ♦❧❞ ❛s ✈ ♥❡✇ ❛s ♥ ❢♦r ❡❛❝❤ r♦✇ ❜❡❣✐♥ ✐♥s❡rt ✐♥t♦ t❛❜❴❤✐st❴❝❛r❣♦❴❡♠♣ ✭ ❡♠♣♥♦ ✱❥♦❜❴❛♥t❡r✐♦r ✱❥♦❜❴❛t✉❛❧ ✱❞t❴❛❧t❡r❛❝❛♦❴❝❛r❣♦ ✱❞s❴❤✐st♦r✐❝♦✮ ✈❛❧✉❡s ✭ ✿♥✳❡♠♣♥♦ ✱✿✈✳❥♦❜ ✱✿♥✳❥♦❜ ✱s②s❞❛t❡ ✱✬❖ ❡♠♣r❡❣❛❞♦ ✬⑤⑤✿♥✳❡♥❛♠❡⑤⑤ ✬ ♣❛ss♦✉ ♣❛r❛ ♦ ❝❛r❣♦ ✬⑤⑤✿♥✳❥♦❜⑤⑤ ✬ ❡♠ ❝❛r❛t❡r ❞❡ ♣r♦♠♦çã♦✳✬✮❀ ❡♥❞❀ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Cada vez que o trigger tig_hist_cargo_emp disparar, depois da atualização de um cargo, será gravado um histórico, ou seja, uma linha, na tabela tab_hist_cargo_emp contendo as informações pertinentes à alteração do cargo. O trigger vai disparar para cada linha alterada. Vamos testá-lo. 303 19.3. Trigger de linha ❙◗▲❃ ✷ ✸ ✹ Casa do Código ✉♣❞❛t❡ ❡♠♣ s❡t ❥♦❜ ❂ ✬▼❆◆❆●❊❘✬ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✼✹✾✾ ✴ ✶ ❧✐♥❤❛ ❛t✉❛❧✐③❛❞❛✳ ❙◗▲❃ Verificando o histórico: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ t❛❜❴❤✐st❴❝❛r❣♦❴❡♠♣ ✷ ✴ ❊▼P◆❖ ❏❖❇❴❆◆❚❊❘ ❏❖❇❴❆❚❯❆▲ ❉❚❴❆▲❚❊❘ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✼✹✾✾ ❙❆▲❊❙▼❆◆ ▼❆◆❆●❊❘ ✵✺✴✵✾✴✶✶ ❉❙❴❍■❙❚❖❘■❈❖ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❖ ❡♠♣r❡❣❛❞♦ ❆▲▲❊◆ ♣❛ss♦✉ ♣❛r❛ ♦ ❝❛r❣♦ ▼❆◆❆●❊❘ ❡♠ ❝❛r❛t❡r ❞❡ ♣r♦♠♦çã♦✳ ❙◗▲❃ Muito bem. O histórico foi criado informando que o empregado allen mudou de cargo. Agora vamos a outro exemplo. Criaremos um trigger que irá calcular e guardar na tabela emp o percentual referente à comissão em relação ao salário do empregado. Para isso, vamos incluir uma coluna na tabela emp chamada pc_com_sal. Neste trigger, faremos uso na cláusula when para determinar quais os registros poderão sofre este cálculo. Vale salientar que a cláusula when pode ser usada tanto para os triggers de linhas como para os de tabela. Alterando a tabela emp: ❙◗▲❃ ❛❧t❡r t❛❜❧❡ ❡♠♣ ❛❞❞ ♣❝❴❝♦♠❴s❛❧ ♥✉♠❜❡r❀ ❚❛❜❡❧❛ ❛❧t❡r❛❞❛✳ 304 Casa do Código Capítulo 19. Triggers ❙◗▲❃ Criando o trigger: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ❝r❡❛t❡ tr✐❣❣❡r t✐❣❴♣❝❴❝♦♠❴s❛❧❴❡♠♣ ❜❡❢♦r❡ ✐♥s❡rt ♦r ✉♣❞❛t❡ ♦❢ s❛❧✱ ❝♦♠♠ ♦♥ ❡♠♣ r❡❢❡r❡♥❝✐♥❣ ♦❧❞ ❛s ✈ ♥❡✇ ❛s ♥ ❢♦r ❡❛❝❤ r♦✇ ✇❤❡♥ ✭♥✳❥♦❜ ❂ ✬❙❆▲❊❙▼❆◆✬✮ ❜❡❣✐♥ ✿♥✳♣❝❴❝♦♠❴s❛❧ ✿❂ ♥✈❧✭✿♥✳❝♦♠♠✱✵✮ ✯ ✶✵✵ ✴ ✿♥✳s❛❧❀ ❡♥❞❀ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Note que agora criamos um trigger que vai disparar no before, ou seja, antes das informações serem efetivadas no banco de dados. Usamos o before, pois o programa estará alterando um dado, ou melhor, o valor de uma coluna, referente à mesma linha que vai disparar o trigger. Portanto, isso deve acontecer antes que as informações sejam efetivadas. Se usássemos after, não conseguiríamos fazer tal alteração. Utilizamos a cláusula when para determinar que o trigger só vá disparar quando a linha em questão for de algum empregado que tenha como cargo ( job) igual a salesman. Vamos testá-lo. ❙◗▲❃ s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ❝♦♠♠✱ ♣❝❴❝♦♠❴s❛❧ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ ✼✻✺✹ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❆▲▲❊◆ ❲❆❘❉ ❏❖◆❊❙ ▼❆❘❚■◆ ❏❖❇ ❙❆▲ ❈❖▼▼ P❈❴❈❖▼❴❙❆▲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✾✻✽ ❙❆▲❊❙▼❆◆ ✶✻✵✵ ✸✵✻ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✺✶✵ ▼❆◆❆●❊❘ ✸✺✾✾✱✼✺ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✶✹✷✽ 305 Casa do Código 19.3. Trigger de linha ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ ▼❆◆❆●❊❘ ▼❆◆❆●❊❘ ❆◆❆▲❨❙❚ P❘❊❙■❉❊◆❚ ❙❆▲❊❙▼❆◆ ❈▲❊❘❑ ❈▲❊❘❑ ❆◆❆▲❨❙❚ ❈▲❊❘❑ ✷✽✺✵ ✷✹✺✵ ✸✻✸✵ ✺✵✵✵ ✶✺✵✵ ✶✸✸✶ ✾✺✵ ✸✻✸✵ ✶✸✵✵ ✵ ✶✹ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ ✉♣❞❛t❡ ❡♠♣ s❡t s❛❧ ❂ s❛❧❀ ✶✹ ❧✐♥❤❛s ❛t✉❛❧✐③❛❞❛s✳ ❙◗▲❃ Primeiramente, verificamos os dados da tabela emp. Logo após, executamos um update apenas para que nosso trigger dispare. Note que o update atualiza todos os salários dos empregados com o mesmo salário. Fizemos isso apenas para que todas as linhas sejam varridas e que o cálculo do percentual seja realizado para os registros já cadastrados. Vamos ver o resultado. ❙◗▲❃ s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ❝♦♠♠✱ ♣❝❴❝♦♠❴s❛❧ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ 306 ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❆▲▲❊◆ ❲❆❘❉ ❏❖◆❊❙ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❏❖❇ ❙❆▲ ❈❖▼▼ P❈❴❈❖▼❴❙❆▲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✾✻✽ ❙❆▲❊❙▼❆◆ ✶✻✵✵ ✸✵✻ ✶✾✱✶✷✺ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✺✶✵ ✹✵✱✽ ▼❆◆❆●❊❘ ✸✺✾✾✱✼✺ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✶✹✷✽ ✶✶✹✱✷✹ ▼❆◆❆●❊❘ ✷✽✺✵ ▼❆◆❆●❊❘ ✷✹✺✵ ❆◆❆▲❨❙❚ ✸✻✸✵ P❘❊❙■❉❊◆❚ ✺✵✵✵ ❙❆▲❊❙▼❆◆ ✶✺✵✵ ✵ ✵ Casa do Código ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ Capítulo 19. Triggers ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ ❈▲❊❘❑ ❈▲❊❘❑ ❆◆❆▲❨❙❚ ❈▲❊❘❑ ✶✸✸✶ ✾✺✵ ✸✻✸✵ ✶✸✵✵ ✶✹ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ Veja que a coluna pc_com_sal recebeu o cálculo do percentual, conforme a ação disparada via trigger. Também podemos observar que somente os registros cujos empregados tenham como cargo salesman sofreram esta ação. Agora vamos inserir um novo empregado, com o cargo igual a salesman e outro com o cargo clerk, e vamos ver o que acontece. ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✮ ✷ ✈❛❧✉❡s ✭✼✾✹✵✱✬P❊❉❘❖✬✱✬❈▲❊❘❑✬✱✼✼✽✽✱ t♦❴❞❛t❡✭✬✵✺✴✵✾✴✷✵✶✶✬✱✬❞❞✴♠♠✴rrrr✬✮✱✼✺✵✱✶✵✵✱✸✵✮❀ ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✮ ✷ ✈❛❧✉❡s ✭✼✾✹✶✱✬❏❖❆❖✬✱✬❙❆▲❊❙▼❆◆✬✱✼✻✾✽✱ t♦❴❞❛t❡✭✬✵✺✴✵✾✴✷✵✶✶✬✱✬❞❞✴♠♠✴rrrr✬✮✱✶✷✵✵✱✸✺✵✱✸✵✮ ✸ ✴ ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ Verificando a tabela emp. ❙◗▲❃ s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ❝♦♠♠✱ ♣❝❴❝♦♠❴s❛❧ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ❊◆❆▼❊ ❏❖❇ ❙❆▲ ❈❖▼▼ P❈❴❈❖▼❴❙❆▲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ❙▼■❚❍ ❈▲❊❘❑ ✾✻✽ 307 Casa do Código 19.3. Trigger de linha ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ ✼✾✹✵ ✼✾✹✶ ❆▲▲❊◆ ❲❆❘❉ ❏❖◆❊❙ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ P❊❉❘❖ ❏❖❆❖ ❙❆▲❊❙▼❆◆ ❙❆▲❊❙▼❆◆ ▼❆◆❆●❊❘ ❙❆▲❊❙▼❆◆ ▼❆◆❆●❊❘ ▼❆◆❆●❊❘ ❆◆❆▲❨❙❚ P❘❊❙■❉❊◆❚ ❙❆▲❊❙▼❆◆ ❈▲❊❘❑ ❈▲❊❘❑ ❆◆❆▲❨❙❚ ❈▲❊❘❑ ❈▲❊❘❑ ❙❆▲❊❙▼❆◆ ✶✻✵✵ ✶✷✺✵ ✸✺✾✾✱✼✺ ✶✷✺✵ ✷✽✺✵ ✷✹✺✵ ✸✻✸✵ ✺✵✵✵ ✶✺✵✵ ✶✸✸✶ ✾✺✵ ✸✻✸✵ ✶✸✵✵ ✼✺✵ ✶✷✵✵ ✸✵✻ ✺✶✵ ✶✾✱✶✷✺ ✹✵✱✽ ✶✹✷✽ ✶✶✹✱✷✹ ✵ ✵ ✶✵✵ ✸✺✵ ✷✾✱✶✻✻✻✻✻✼ ✶✻ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ Analisando as informações podemos constatar que o empregado pedro, embora tenha recebido valores de salário e comissão, não sofreu o cálculo do percentual. Isso ocorreu pelo fato de ele não ter como cargo, salesman. Neste caso, o trigger não disparou. Já para o empregado joao, o trigger disparou e calculou o percentual. Aqui apresentamos alguns exemplos simples, apenas para mostrar o funcionamento dos triggers. Contudo, dependendo da necessidade podemos escrever códigos complexos para atender às mais variadas situações que podem surgir. Mesmo porque, como pode ser visto, um trigger nada mais é que um bloco PL/SQL, ou seja, um programa, que é programado para disparar de forma automática. Predicados condicionais para triggers de banco de dados Vimos que um mesmo trigger pode disparar por um ou mais tipos de ações, como no insert, delete e update. Contudo, dependendo da ação ocorrida na tabela, podem surgir necessidades diferentes para cada uma. Para isso, usamos os predicados condicionais que nos dizem qual ação resultou 308 Casa do Código Capítulo 19. Triggers no disparo do trigger. Estes predicados são: inserting, updating e deleting. Seus possíveis valores são true e false. Veja o exemplo a seguir, onde criaremos um histórico para gravar as ações de manipulação dos departamentos cadastrados na tabela dept. Criando a tabela: ❙◗▲❃ ❝r❡❛t❡ t❛❜❧❡ t❛❜❴❤✐st❴❞❡♣t ✷ ✭ ❞❡♣t♥♦ ♥✉♠❜❡r ✸ ✱❞t❴❤✐st♦r✐❝♦ ❞❛t❡ ✹ ✱❞s❴❤✐st♦r✐❝♦ ✈❛r❝❤❛r✷✭✷✵✵✵✮ ✺ ✮ ✻ ✴ ❚❛❜❡❧❛ ❝r✐❛❞❛✳ ❙◗▲❃ Nesta tabela será gravado o código do departamento, a data da ação e também um descritivo do histórico. Vamos criar o trigger que fará o controle de histórico. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r t✐❣❴❤✐st❴❞❡♣t ✷ ❛❢t❡r ✐♥s❡rt ♦r ❞❡❧❡t❡ ♦r ✉♣❞❛t❡ ♦♥ ❞❡♣t ✸ ❢♦r ❡❛❝❤ r♦✇ ✹ ❞❡❝❧❛r❡ ✺ ✇❛❝❛♦ ✈❛r❝❤❛r✷✭✷✵✵✮ ❞❡❢❛✉❧t ♥✉❧❧❀ ✻ ❜❡❣✐♥ ✼ ✲✲ ✽ ✐❢ ✐♥s❡rt✐♥❣ t❤❡♥ ✾ ✇❛❝❛♦ ✿❂ ✬✐♥s❡r✐❞♦✬❀ ✶✵ ❡❧s✐❢ ✉♣❞❛t✐♥❣ t❤❡♥ ✶✶ ✇❛❝❛♦ ✿❂ ✬❛t✉❛❧✐③❛❞♦✬❀ ✶✷ ❡❧s✐❢ ❞❡❧❡t✐♥❣ t❤❡♥ ✶✸ ✇❛❝❛♦ ✿❂ ✬❡①❝❧✉í❞♦✬❀ ✶✹ ❡♥❞ ✐❢❀ ✶✺ ✲✲ ✶✻ ✐♥s❡rt ✐♥t♦ t❛❜❴❤✐st❴❞❡♣t ✭❞❡♣t♥♦✱ ❞t❴❤✐st♦r✐❝♦✱ ❞s❴❤✐st♦r✐❝♦✮ ✶✼ ✈❛❧✉❡s ✭ ♥✈❧✭✿♥❡✇✳❞❡♣t♥♦✱✿♦❧❞✳❞❡♣t♥♦✮ ✶✽ ✱s②s❞❛t❡ ✶✾ ✱✬❖ ❞❡♣❛rt❛♠❡♥t♦ ✬⑤⑤ ♥✈❧✭✿♥❡✇✳❞♥❛♠❡✱✿♦❧❞✳❞♥❛♠❡✮⑤⑤✬ 309 Casa do Código 19.3. Trigger de linha ✷✵ ✲✲ ✷✶ ❡♥❞❀ ✷✷ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ ❢♦✐ ✬⑤⑤✇❛❝❛♦⑤⑤✬✳✬✮❀ O trigger em questão tem o objetivo de verificar qual a ação foi executada na tabela e a partir desta informação montar o histórico. Testando a geração do histórico: ❙◗▲❃ ✉♣❞❛t❡ ❞❡♣t ✷ s❡t ❞♥❛♠❡ ❂ ❞♥❛♠❡❀ ✹ ❧✐♥❤❛s ❛t✉❛❧✐③❛❞❛s✳ ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✈❛❧✉❡s ✭✺✵✱✬❚■✬✱✬❇❘❆❙■▲✬✮❀ ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ ❞❡❧❡t❡ ❞❡♣t ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✺✵❀ ✶ ❧✐♥❤❛ ❞❡❧❡t❛❞❛✳ ❙◗▲❃ Agora executamos uma série de ações em cima da tabela dept, para termos diferentes tipos de histórico. Vamos verificar: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ t❛❜❴❤✐st❴❞❡♣t❀ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✶✵ ✷✵ ✸✵ ✹✵ ✺✵ ✺✵ 310 ❉❚❴❍■❙❚❖ ✲✲✲✲✲✲✲✲ ✵✾✴✵✾✴✶✶ ✵✾✴✵✾✴✶✶ ✵✾✴✵✾✴✶✶ ✵✾✴✵✾✴✶✶ ✵✾✴✵✾✴✶✶ ✵✾✴✵✾✴✶✶ ❉❙❴❍■❙❚❖❘■❈❖ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❖ ❞❡♣❛rt❛♠❡♥t♦ ❆❈❈❖❯◆❚■◆● ❢♦✐ ❛t✉❛❧✐③❛❞♦✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ ❘❊❙❊❆❘❈❍ ❢♦✐ ❛t✉❛❧✐③❛❞♦✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ ❙❆▲❊❙ ❢♦✐ ❛t✉❛❧✐③❛❞♦✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ ❖P❊❘❆❚■❖◆❙ ❢♦✐ ❛t✉❛❧✐③❛❞♦✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ ❚■ ❢♦✐ ✐♥s❡r✐❞♦✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ ❚■ ❢♦✐ ❡①❝❧✉í❞♦✳ Casa do Código Capítulo 19. Triggers ✻ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ Através dos predicados é possível determinar qual ação disparou o trigger e, com isso, fazer com que o programa tome decisões e caminhos diferentes. Devemos observar algumas restrições e características com relação à criação e manipulação dos triggers que diferem de um bloco PL/SQL, sendo este anônimo ou não. Dentro de um trigger não podemos utilizar commit ou rollback, a menos que estejamos utilizando pragma. Seu uso será discutido mais adiante. Fora esta exceção, não é permitida a utilização destes comandos dentro do código dos triggers. Dessa forma, para validar as alterações realizadas pelo trigger é necessária uma efetivação externa, geralmente vindo do programa causador do disparo do seu disparo. Temos as seguintes premissas: • Não são permitidos comandos de ddl dentro de triggers; • Não são permitidos comandos de controle da transação, como rollback, commit, savepoint etc. (exceto com o uso de pragma). Outro ponto que deve ser observado é com relação à criação de um trigger. Quando o criamos, o Oracle faz validações igualmente a quando criamos procedures, functions ou packages. Se este trigger apresentar algum erro de sintaxe, objetos não existentes, erros de referência ou qualquer outro problema que impossibilite seu uso, o Oracle permite a criação, mas o deixa inválido no banco de dados. Desta forma, o trigger não fica apto para o uso e não será disparado mesmo que as ações satisfaçam suas definições. Neste caso, ele deve ser analisado, corrigido e recriado, novamente. Quando isso acontecer, não é necessário excluí-lo, basta recriá-lo. Basta usar o comando replace no momento em que estiver recriando. Na sequência, mostro um exemplo: ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r t✐❣❴❤✐st❴❝❛r❣♦❴❡♠♣ ✷ ❛❢t❡r ✉♣❞❛t❡ ♦❢ ❥♦❜ ♦♥ ❡♠♣ ✸ r❡❢❡r❡♥❝✐♥❣ ♦❧❞ ❛s ✈ 311 19.3. Trigger de linha ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ Casa do Código ♥❡✇ ❛s ♥ ❢♦r ❡❛❝❤ r♦✇ ❜❡❣✐♥ ✐♥s❡rt ✐♥t♦ t❛❜❴❤✐st❴❝❛r❣♦❴❡♠♣ ✭ ❡♠♣♥♦ ✱❥♦❜❴❛♥t❡r✐♦r ✱❥♦❜❴❛t✉❛❧ ✱❞t❴❛❧t❡r❛❝❛♦❴❝❛r❣♦ ✱❞s❴❤✐st♦r✐❝♦✮ ✈❛❧✉❡s ✭ ✿♥✳❡♠♣♥♦ ✱✿✈✳❥♦❜ ✱✿♥✳❥♦❜ ✱s②s❞❛t❡ ✱✬❖ ❡♠♣r❡❣❛❞♦ ✬⑤⑤✿♥✳❡♥❛♠❡⑤⑤ ✬ ♣❛ss♦✉ ♣❛r❛ ♦ ❝❛r❣♦ ✬⑤⑤✿♥✳❥♦❜⑤⑤ ✬ ❡♠ ❝❛r❛t❡r ❞❡ ♣r♦♠♦çã♦✳✬✮❀ ❡♥❞❀ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Caso seja necessário compilar um trigger pelo fato de ele estar inválido, use o comando alter trigger. Todavia, não é comum, pois ao criá-lo ou recriá-lo o Oracle já faz esta validação, a menos que ele tenha sido invalidado via dependência de algum outro objeto. ❙◗▲❃ ❛❧t❡r tr✐❣❣❡r t✐❣❴❤✐st❴❝❛r❣♦❴❡♠♣ ❝♦♠♣✐❧❡❀ ●❛t✐❧❤♦ ❛❧t❡r❛❞♦✳ ❙◗▲❃ Também podemos ativar ou desativar um trigger. Quando o desativamos, ele permanece criado no banco de dados, mas fica inativo. Desta forma, ele não dispara caso a tabela de referência seja manipulada. Para ativar ou desativar um trigger, também utilizamos o comando alter table. 312 Casa do Código Capítulo 19. Triggers ❙◗▲❃ ❛❧t❡r tr✐❣❣❡r t✐❣❴❤✐st❴❝❛r❣♦❴❡♠♣ ❞✐s❛❜❧❡ ✲✲ ❞❡s❛❜✐❧✐t❛ ♦ tr✐❣❣❡r ✷ ✴ ●❛t✐❧❤♦ ❛❧t❡r❛❞♦✳ ❙◗▲❃ ❛❧t❡r tr✐❣❣❡r t✐❣❴❤✐st❴❝❛r❣♦❴❡♠♣ ❡♥❛❜❧❡ ✲✲ ❤❛❜✐❧✐t❛ ♦ tr✐❣❣❡r ✷ ✴ ●❛t✐❧❤♦ ❛❧t❡r❛❞♦✳ ❙◗▲❃ Também é possível habilitar ou desabilitar todos os triggers associados a uma tabela com um comando apenas. ❙◗▲❃ ❛❧t❡r t❛❜❧❡ ❡♠♣ ❞✐s❛❜❧❡ ❛❧❧ tr✐❣❣❡rs❀ ❚❛❜❡❧❛ ❛❧t❡r❛❞❛✳ ❙◗▲❃ ❛❧t❡r t❛❜❧❡ ❡♠♣ ❡♥❛❜❧❡ ❛❧❧ tr✐❣❣❡rs❀ ❚❛❜❡❧❛ ❛❧t❡r❛❞❛✳ ❙◗▲❃ Para eliminar um trigger, utilizamos o comando frop trigger. Esse comando faz com que ele seja eliminado definitivamente. ❙◗▲❃ ❞r♦♣ tr✐❣❣❡r t✐❣❴❤✐st❴❝❛r❣♦❴❡♠♣❀ ●❛t✐❧❤♦ ❡❧✐♠✐♥❛❞♦✳ ❙◗▲❃ Para se criar um trigger, o usuário deve possuir os privilégios de criação: create trigger (ou create any trigger) e alter table. Este último está relacionado à tabela base para o trigger. Quando o usuário tem privilégios para criação de tabelas, implicitamente, já terá o poder 313 19.3. Trigger de linha Casa do Código para alterá-las ou excluí-las. Veja um exemplo de concessão de privilégios para triggers. create any trigger permite que o usuário crie triggers em qualquer esquema, exceto sys. Isso não é recomendado Nota: para a criação deles em tabelas de dicionário de dados. ❙◗▲❃ ❣r❛♥t ❝r❡❛t❡ tr✐❣❣❡r t♦ tsq❧❀ ❈♦♥❝❡ssã♦ ❜❡♠✲s✉❝❡❞✐❞❛✳ ❙◗▲❃ ❣r❛♥t ❝r❡❛t❡ ❛♥② tr✐❣❣❡r t♦ tsq❧❀ ❈♦♥❝❡ssã♦ ❜❡♠✲s✉❝❡❞✐❞❛✳ ❙◗▲❃ Para recuperar a definição e o código de um trigger, use as views user_triggers, all_trigger ou dba_triggers. ❙◗▲❃ s❡❧❡❝t tr✐❣❣❡r❴❜♦❞② ✷ ❢r♦♠ ✉s❡r❴tr✐❣❣❡rs ✇❤❡r❡ tr✐❣❣❡r❴♥❛♠❡ ❂ ✬❚■●❴P❈❴❈❖▼❴❙❆▲❴❊▼P✬❀ ❚❘■●●❊❘❴❇❖❉❨ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❜❡❣✐♥ ✿♥✳♣❝❴❝♦♠❴s❛❧ ✿❂ ♥✈❧✭✿♥✳❝♦♠♠✱✵✮ ✯ ✶✵✵ ✴ ✿♥✳s❛❧❀ ❡♥❞❀ ❙◗▲❃ No geral, os triggers de banco de dados podem servir, por exemplo, para controle, segurança e auditoria de informações de tabelas em um banco de dados, para a realização de backups ou replicação de dados, objetivando sempre a automação de algum processo. 314 Casa do Código Capítulo 19. Triggers Sequência de disparo de um trigger Uma tabela não está limitada a apenas um trigger. Podemos ter vários associados a uma única tabela. Quando isso acontece, temos que nos preocupar com alguns aspectos, por exemplo, se a ordem de execução de um determinado trigger influencia em uma execução de um outro. Para isso, é preciso entender a ordem de execução dos triggers, que depende do tipo e do momento em que será disparado. Olhando o desenho a seguir, fica mais clara a ordem de execução, dependendo do tipo e do momento em que são disparados. Imagine o seguinte cenário: temos dois triggers, um de tabela (chamado de tgrtab) e outro de linha (chamado de tgrlin). O trigger de tabela dispara tanto no momento before quanto no momento after. O trigger de linha segue a mesma lógica. Ambos são disparados na ação update. Vamos ver como fica a ordem de disparo quando executamos um update nos registros. Fig. 19.1: Esquema mostrando a sequência de disparo das triggers de linha de tabela Note que o trigger tgrtab executa uma única vez antes na atualização de todos os registros e uma única vez no final quando todos os registros já foram atualizados. Já o trigger tgrlin executa após a primeira execução do trigger tgrtab e antes e depois da atualização de cada registro. 315 19.4. Mutante table Casa do Código Outro ponto a ser observado é que não há impedimento algum em termos dois triggers exatamente iguais, que sejam do mesmo tipo e que disparem no mesmo momento. Entretanto, para estes casos, não é possível determinar qual a ordem em que cada um será executado. A Oracle não garante a ordem da execução quando há triggers contendo características de disparo iguais. Caso sejam dependentes um do outro, o aconselhável é juntá-los, e que tais dependências sejam tratadas no código. 19.4 Mutante table Existe uma limitação no uso dos triggers de linha, quando selecionamos dados de uma tabela, no evento after, que seja a base do trigger, ou seja, estamos tentando selecionar os dados de uma tabela que está sendo alterada e ao mesmo tempo é a causadora do disparo. Contudo, quando temps este cenário, mas o evento é o before, este problema não acontece. Quando um trigger é disparado, isso indica que os dados de uma tabela estão sendo alterados. Neste momento podemos concluir que, enquanto as alterações não forem confirmadas, os dados que estão sendo manipulados na transação em questão não estão consistentes. Apenas quando forem confirmados, através de um rollback ou de um commit, os dados estarão íntegros. Seguindo esta lógica, no momento antes da efetivação dos dados alterados, não é possível executar a manipulação deles,por exemplo, através de um comando select, mesmo se nossa intenção seja buscar apenas os registros que não estão sofrendo tais alterações. Isso confirma a limitação no nível de tabela e não no nível de dados. Quando tentamos realizar esta operação, um erro chamado mutante table é gerado. Veja o resumo das regras a seguir: • O erro de mutante table não acontece quando a trigger é de linha e o momento de disparo for before, isso tanto para os comandos delete, update, insert ou select. Já no evento after, o erro de mutante table acontece para todos estes comandos (com exceção do uso de transações autônomas); • Para as triggers de tabela, não precisamos nos preocupar com o erro de mutante table, pois independente de o evento ser before 316 Casa do Código Capítulo 19. Triggers ou after, e de qual seja o comando, select, delete, update ou insert, esse tipo de problema não ocorre. Agora veremos o exemplo na sequência: ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r t✐❣❴❡♠♣❴♣r❛❣♠❛ ✷ ❛❢t❡r ✉♣❞❛t❡ ♦♥ ❡♠♣ ✸ ❢♦r ❡❛❝❤ r♦✇ ✹ ❞❡❝❧❛r❡ ✺ ✇❝♦♥t❴r❡❣✐str♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✻ ❜❡❣✐♥ ✼ ✲✲ ✽ s❡❧❡❝t ❝♦✉♥t✭✯✮ ✐♥t♦ ✇❝♦♥t❴r❡❣✐str♦ ❢r♦♠ ❡♠♣❀ ✾ ✲✲ ✶✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ♥❛ t❛❜❡❧❛ ❊▼P✿ ✬⑤⑤✇❝♦♥t❴r❡❣✐str♦✮❀ ✶✶ ✲✲ ✶✷ ❡♥❞❀ ✶✸ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Criamos um trigger do tipo linha, com o qual a cada atualização realizada nos registros da tabela emp é executado um select count para verificar e mostrar a quantidade de registros desta mesma tabela. Agora vamos executar o comando a seguir: ❙◗▲❃ ✉♣❞❛t❡ ❡♠♣ ✷ s❡t s❛❧ ❂ s❛❧ ✸ ✴ ✉♣❞❛t❡ ❡♠♣ ✯ ❊❘❘❖ ♥❛ ❧✐♥❤❛ ✶✿ ❖❘❆✲✵✹✵✾✶✿ ❛ t❛❜❡❧❛ ❚❙◗▲✳❊▼P é ♠✉t❛♥t❡❀ t❛❧✈❡③ ♦ ❣❛t✐❧❤♦✴❢✉♥çã♦ ♥ã♦ ♣♦ss❛ ❧♦❝❛❧✐③á✲❧❛ ❖❘❆✲✵✻✺✶✷✿ ❡♠ ✧❚❙◗▲✳❚■●❴❊▼P❴P❘❆●▼❆✧✱ ❧✐♥❡ ✺ ❖❘❆✲✵✹✵✽✽✿ ❡rr♦ ❞✉r❛♥t❡ ❛ ❡①❡❝✉çã♦ ❞♦ ❣❛t✐❧❤♦ 317 19.4. Mutante table Casa do Código ✬❚❙◗▲✳❚■●❴❊▼P❴P❘❆●▼❆✬ ❙◗▲❃ Como era previsto, o erro ocorreu após tentarmos realizar a alteração. Agora vamos recriar o trigger como sendo um de tabela e executar a atualização novamente. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r t✐❣❴❡♠♣❴♣r❛❣♠❛ ✷ ❛❢t❡r ✉♣❞❛t❡ ♦♥ ❡♠♣ ✸ ❞❡❝❧❛r❡ ✹ ✇❝♦♥t❴r❡❣✐str♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✺ ❜❡❣✐♥ ✻ ✲✲ ✼ s❡❧❡❝t ❝♦✉♥t✭✯✮ ✐♥t♦ ✇❝♦♥t❴r❡❣✐str♦ ❢r♦♠ ❡♠♣❀ ✽ ✲✲ ✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ♥❛ t❛❜❡❧❛ ❊▼P✿ ✬⑤⑤✇❝♦♥t❴r❡❣✐str♦✮❀ ✶✵ ✲✲ ✶✶ ❡♥❞❀ ✶✷ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ ❙◗▲❃ ✉♣❞❛t❡ ❡♠♣ ✷ s❡t s❛❧ ❂ s❛❧❀ ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ♥❛ t❛❜❡❧❛ ❊▼P✿ ✶✹ Note que quando utilizamos um trigger do tipo tabela não temos este problema. Mas aí vem a pergunta: e se tivermos esta necessidade e nos depararmos com este problema? O que fazer? Nestes casos, podemos utilizar o recurso de transações autônomas, informando-o na declaração do trigger. Sua função é fazer com que o Oracle abra uma nova sessão somente para atender o trigger, ou seja, neste momento existirão pelo menos duas transações em aberto. Uma é referente à transação que está realizando as alterações na 318 Casa do Código Capítulo 19. Triggers tabela em questão, e outra referente ao disparo do trigger. Veja o desenho a seguir onde tentamos ilustramos como o Oracle trata esta situação. Fig. 19.2: Abrindo transações através de pragma autonomous_transaction Contudo, conforme já explicado no capítulo anterior sobre transações autônomas, temos que nos atentar para a seguinte situação. Sabemos que, quando é aberta uma transação no Oracle, ela monta uma imagem dos objetos e dados disponíveis para o usuário em questão. Com relação aos dados, isso permite visualizar somente aquilo que está efetivado no banco de dados, ou seja, dados consistentes e íntegros. Isso quer dizer que dados pendentes de efetivação não poderão ser visualizados, isso é, dados excluídos, inseridos ou atualizados que ainda não tenham sido commitados. Logo, quando isso acontece, no caso de um trigger, não conseguimos visualizar as alterações que estão sendo realizadas, pelo menos não as que fogem do escopo old e new. Portanto, quando temos um trigger com transação autônoma, conseguimos manipular os dados de old e new, mas 319 19.4. Mutante table Casa do Código se realizarmos um comando select a fim de obter estes dados, não conseguiremos enxergá-los. Apenas para ressaltar, isto se dá ao fato de que dentro do trigger estamos em outro escopo, em uma nova transação. Outro ponto muito importante é que quando utilizamos trigger com transação autônoma precisamos finalizá-la através de um commit ou de um rollback. Como a autonomous_transaction faz com que uma nova transação seja aberta, temos que finalizá-la. Caso contrário, ela ficaria pendente e isso poderia gerar um erro. Vamos verificar na prática: ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r t✐❣❴❡♠♣❴♣r❛❣♠❛ ✷ ❜❡❢♦r❡ ✉♣❞❛t❡ ♦♥ ❡♠♣ ✸ ❢♦r ❡❛❝❤ r♦✇ ✹ ❞❡❝❧❛r❡ ✺ ✲✲ ✻ ♣r❛❣♠❛ ❛✉t♦♥♦♠♦✉s❴tr❛♥s❛❝t✐♦♥❀ ✼ ✲✲ ✽ ✇❝♦♥t❴r❡❣✐str♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✾ ❜❡❣✐♥ ✶✵ ✲✲ ✶✶ s❡❧❡❝t ❝♦✉♥t✭✯✮ ✐♥t♦ ✇❝♦♥t❴r❡❣✐str♦ ❢r♦♠ ❡♠♣❀ ✶✷ ✲✲ ✶✸ ✐❢ ♥✈❧✭✿♦❧❞✳❝♦♠♠✱✵✮ ❁ ✸✵✵ t❤❡♥ ✶✹ ✿♥❡✇✳❝♦♠♠ ✿❂ ✿♥❡✇✳s❛❧ ✯ ✶✵ ✴ ✶✵✵❀ ✶✺ ❡♥❞ ✐❢❀ ✶✻ ✲✲ ✶✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ♥❛ t❛❜❡❧❛ ❊▼P✿ ✬⑤⑤✇❝♦♥t❴r❡❣✐str♦✮❀ ✶✽ ✲✲ ✶✾ ❝♦♠♠✐t❀ ✷✵ ✲✲ ✷✶ ❡♥❞❀ ✷✷ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Uma observação: para este exemplo alteramos o trigger de after para before para que pudéssemos alterar o valor de new. 320 Casa do Código Capítulo 19. Triggers Note que na área de declaração colocamos a seguinte linha: pragma autonomous_transaction;. Isso faz com que uma nova transação seja aberta para a execução do trigger. Agora vamos executar uma alteração na tabela emp e veremos como ele se comporta. ❙◗▲❃ ✉♣❞❛t❡ ❡♠♣ ✷ s❡t s❛❧ ❂ s❛❧ ✸ ✴ ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ ♥❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ t❛❜❡❧❛ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ❊▼P✿ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ✶✹ ❧✐♥❤❛s ❛t✉❛❧✐③❛❞❛s✳ ❙◗▲❃ A execução não nos gerou erro. Vamos verificar a tabela emp. Antes da execução da atualização e disparo do trigger os dados estavam assim: ❙◗▲❃ s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡✱ s❛❧✱ ❝♦♠♠ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ ✼✻✺✹ ❊◆❆▼❊ ❙❆▲ ❈❖▼▼ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ✾✻✽ ❆▲▲❊◆ ✶✻✵✵ ✸✵✻ ❲❆❘❉ ✶✷✺✵ ✺✶✵ ❏❖◆❊❙ ✸✺✾✾✱✼✺ ▼❆❘❚■◆ ✶✷✺✵ ✶✹✷✽ 321 Casa do Código 19.4. Mutante table ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ ✷✽✺✵ ✷✹✺✵ ✸✻✸✵ ✺✵✵✵ ✶✺✵✵ ✶✸✸✶ ✾✺✵ ✸✻✸✵ ✶✸✵✵ ✵ ✶✹ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ Após a execução da atualização e disparo do trigger os dados ficaram assim: ❙◗▲❃ s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡✱ s❛❧✱ ❝♦♠♠ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ ❊◆❆▼❊ ❙❆▲ ❈❖▼▼ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ✾✻✽ ✾✻✱✽ ❆▲▲❊◆ ✶✻✵✵ ✸✵✻ ❲❆❘❉ ✶✷✺✵ ✺✶✵ ❏❖◆❊❙ ✸✺✾✾✱✼✺ ✸✺✾✱✾✽ ▼❆❘❚■◆ ✶✷✺✵ ✶✹✷✽ ❇▲❆❑❊ ✷✽✺✵ ✷✽✺ ❈▲❆❘❑ ✷✹✺✵ ✷✹✺ ❙❈❖❚❚ ✸✻✸✵ ✸✻✸ ❑■◆● ✺✵✵✵ ✺✵✵ ❚❯❘◆❊❘ ✶✺✵✵ ✶✺✵ ❆❉❆▼❙ ✶✸✸✶ ✶✸✸✱✶ ❏❆▼❊❙ ✾✺✵ ✾✺ ❋❖❘❉ ✸✻✸✵ ✸✻✸ ▼■▲▲❊❘ ✶✸✵✵ ✶✸✵ ✶✹ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ 322 Casa do Código Capítulo 19. Triggers Agora vamos cadastrar um novo empregado através de um insert para vermos bem o controle de transação sendo consistido. Para isso, alteramos novamente nosso trigger, incluindo nas condições de disparo o comando insert. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r t✐❣❴❡♠♣❴♣r❛❣♠❛ ✷ ❜❡❢♦r❡ ✉♣❞❛t❡ ♦r ✐♥s❡rt ♦♥ ❡♠♣ ✸ ❢♦r ❡❛❝❤ r♦✇ ✹ ❞❡❝❧❛r❡ ✺ ✲✲ ✻ ♣r❛❣♠❛ ❛✉t♦♥♦♠♦✉s❴tr❛♥s❛❝t✐♦♥❀ ✼ ✲✲ ✽ ✇❝♦♥t❴r❡❣✐str♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ✾ ❜❡❣✐♥ ✶✵ ✲✲ ✶✶ s❡❧❡❝t ❝♦✉♥t✭✯✮ ✐♥t♦ ✇❝♦♥t❴r❡❣✐str♦ ❢r♦♠ ❡♠♣❀ ✶✷ ✲✲ ✶✸ ✐❢ ♥✈❧✭✿♦❧❞✳❝♦♠♠✱✵✮ ❁ ✸✵✵ t❤❡♥ ✶✹ ✿♥❡✇✳❝♦♠♠ ✿❂ ✿♥❡✇✳s❛❧ ✯ ✶✵ ✴ ✶✵✵❀ ✶✺ ❡♥❞ ✐❢❀ ✶✻ ✲✲ ✶✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ♥❛ t❛❜❡❧❛ ❊▼P✿ ✬⑤⑤✇❝♦♥t❴r❡❣✐str♦✮❀ ✶✽ ✲✲ ✶✾ ❝♦♠♠✐t❀ ✷✵ ✲✲ ✷✶ ❡♥❞❀ ✷✷ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Executando o insert. ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✷ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ ♠❣r✱ ❤✐r❡❞❛t❡✱ s❛❧✱ ❝♦♠♠✱ ❞❡♣t♥♦✱ ♣❝❴❝♦♠❴s❛❧✮ ✸ ✈❛❧✉❡s 323 19.5. Trigger de sistema Casa do Código ✹ ✭✼✾✸✺✱ ✬P❆❯▲✬✱ ✬❙❆▲❊❙▼❆◆✬✱ ✼✻✾✽✱ t♦❴❞❛t❡✭✬✶✺✲▼❆❘✲✶✾✽✵✬✱ ✬❞❞✲♠♦♥✲rrrr✬✮✱ ✶✵✵✵✱ ✶✵✵✱ ✸✵✱ ♥✉❧❧✮❀ ◗✉❛♥t✐❞❛❞❡ ❞❡ r❡❣✐str♦s ♥❛ t❛❜❡❧❛ ❊▼P✿ ✶✹ ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ Note que a mensagem vinda do trigger nos informou que temos 14 registros, ou seja, ele não está contando com este que acabamos de inserir, que seria o registro 15. Mesmo que alteremos o triiger para que dispare no momento after, ele não vai enxergar o novo registro, pois o insert está acontecendo numa transação e a contagem do registro, feita pelo trigger, acontece em outra. Se mesmo com o uso de transações autônomas não for possível resolver problemas de mutante table, talvez mesclar o uso de triggers de linha com os de tabela possa ser uma saída. Considerações sobre triggers • Um trigger tanto de linha quanto de tabela pode agir de forma recursiva. O Oracle garante até 50 níveis de recursividade para estes dois tipos de objeto; • Um trigger não pode contemplar eventos diferentes de execução ( before ou after) em um mesmo objeto. Devem ser criados dois triggers distintos; • Ao excluir uma tabela, triggers associadas a ela também são excluídos automaticamente. 19.5 Trigger de sistema Trigger de sistema são objetos criados em nível de sistema e não de tabelas. Quando falamos em sistemas nos referimos ao banco de dados, mais preci324 Casa do Código Capítulo 19. Triggers samente a ações que ocorrem nele. Seu uso é mais comum pelos DBAs (administradores de banco de dados) e é uma ferramenta poderosa quando utilizada com criatividade. Os triggers de sistema disparam conforme um evento que acontece no banco de dados. Veja a seguir a lista de alguns eventos: • startup: quando o banco de dados é aberto; • shutdown: antes de o banco de dados iniciar o shutdown(fechamento). Se for shutdown abort este evento não é disparado; • servererror: quando um erro ocorre. Com exceção dos erros: ORA1034, ORA-1403, ORA-1422, ORA-1423 e ORA-4030; • after logon: depois de uma conexão ser completada no banco de dados; • before logoff: quando o usuário desconecta do banco de dados; • before create / after create: quando um objeto é criado no banco de dados (comando create), exceto o comando create database; • before alter / after alter: quando um objeto é alterado no banco de dados (comando alter), com exceção do comando alter database; • before drop / after drop: quando um objeto é eliminado do banco de dados (comando drop); • before analyze / after analyze: quando o comando analyze é executado. Este comando é utilizado para gerar estatísticas relacionadas ao desempenho de comandos SQL e processos do banco de dados; • before commit / after commit: quando um commit é executado; 325 19.5. Trigger de sistema Casa do Código • before ddl / after ddl: quando um comando ddl é executado, com exceção dos comandos alter database, create controlfile, create database e ddl executados a partir de interface PL/SQL; • before grant / after grant: quando o comando grant é executado; • before rename / after rename: quando o rename é executado; • before revoke / after revoke: quando o comando revoke é executado; • before truncate / after truncate: quando o truncate é executado. Além de contar com os eventos para determinar quando o trigger de sistema deve disparar, também temos a disposição os atributos de evento que nos dão informações sobre o banco de dados, transações e sobre as operações que disparam o trigger. Veja a lista a seguir. • ora_client_ip_address (tipo: varchar2): retorna o IP da máquina cliente no evento de LOGON, se o protocolo for TCP/IP; • ora_database_name (tipo: varchar2(50)): nome do banco de dados; • ora_dict_obj_name (tipo: varchar(30)): nome do objeto que sofreu o evento ddl; • ora_dict_obj_name_list(name_list out ora_name_list_t) (tipo: binary_integer): retorna lista de objetos afetados no evento; • ora_dict_obj_ownerR (tipo: varchar(30)): proprietário (usuário/schema) do objeto que sofreu o evento ddl; • ora_dict_obj_owner_list(OWNER_LIST OUT ora_name_list_t) (tipo: binary_integer): retorna lista de proprietários (usuário/schemas) dos objetos afetados no evento; 326 Casa do Código Capítulo 19. Triggers • ora_dict_obj_type (tipo: varchar(20)): tipo de objeto que sofreu o evento ddl; • ora_grantee(user_list out ora_name_list_t) (tipo: binary_integer): retorna lista de usuários ou roles que receberam grant; • ora_is_alter_column(column_name in varchar2) (tipo: boolean): retorna true se a coluna especificada foi alterada; • ora_is_drop_column(column_name in varchar2) (tipo: boolean): retorna true se a coluna especificada foi eliminada; • ora_login_user (tipo: varchar2(30)): nome do usuário que acabou de conectar em uma sessão do banco de dados; • ora_privileges(privilege_list out ora_name_list_t) (tipo: binary_integer): retorna lista de privilégios dados ou revogados; • ora_revokee(user_list out ora_name_list_t) (tipo: binary_integer): retorna lista dos que perderam privilégios; • ora_sysevent (tipo: varchar2(20)): retorna o nome do evento que foi disparado. O nome é o mesmo usado na definição do trigger; • ora_with_grant_option (tipo: boolean): retorna true se o grant tem with grant option. Na sequência, alguns exemplos: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ❝r❡❛t❡ t❛❜❧❡ ❤✐st❴✉s✉❛r✐♦ ✭ ♥♠❴✉s✉❛r✐♦ ✈❛r❝❤❛r✷✭✺✵✮ ✱❞t❴❤✐st♦r✐❝♦ ❞❛t❡ ✱❞s❴❤✐st♦r✐❝♦ ✈❛r❝❤❛r✷✭✹✵✵✵✮ ✮ ✴ 327 19.5. Trigger de sistema Casa do Código ❚❛❜❡❧❛ ❝r✐❛❞❛✳ ❙◗▲❃ Criamos uma tabela para guardar os históricos gerados pelos triggers. No exemplo a seguir, temos um que registra quando o usuário conecta no banco de dados. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r t❣r❴❤✐st❴❝♦♥❡①❛♦❴✉s✉❛r✐♦ ✷ ❛❢t❡r ❧♦❣♦♥ ♦♥ ❞❛t❛❜❛s❡ ✸ ❜❡❣✐♥ ✹ ✐♥s❡rt ✐♥t♦ ❤✐st❴✉s✉❛r✐♦ ✈❛❧✉❡s ✺ ✭❖❘❆❴▲❖●■◆❴❯❙❊❘✱s②s❞❛t❡✱✬❈♦♥❡①ã♦ ❝♦♠ ♦ ❜❛♥❝♦ ❞❡ ❞❛❞♦s ✬⑤⑤❖❘❆❴❉❆❚❆❇❆❙❊❴◆❆▼❊✮❀ ✻ ❡♥❞❀ ✼ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Conectando ao banco de dados: ❙◗▲❃ ❞✐s❝♦♥♥❡❝t ❉❡s❝♦♥❡❝t❛❞♦ ❞❡ ❖r❛❝❧❡ ❉❛t❛❜❛s❡ ✶✵❣ ❊①♣r❡ss ❊❞✐t✐♦♥ ❘❡❧❡❛s❡ ✶✵✳✷✳✵✳✶✳✵ ✲ Pr♦❞✉❝t✐♦♥ ❙◗▲❃ ❙◗▲❃ ❝♦♥♥ tsq❧✴tsq❧❅①❡❀ ❈♦♥❡❝t❛❞♦✳ ❙◗▲❃ ❙◗▲❃ Nota: Como já estávamos conectados ao banco de dados, primeiramente, desconectamos e refizemos a conexão logo após. Verificando histórico: 328 Casa do Código Capítulo 19. Triggers ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❤✐st❴✉s✉❛r✐♦❀ ◆▼❴❯❙❯❆❘■❖ ❉❚❴❍■❙❚❖ ❉❙❴❍■❙❚❖❘■❈❖ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❚❙◗▲ ✵✹✴✶✵✴✶✶ ❈♦♥❡①ã♦ ❝♦♠ ♦ ❜❛♥❝♦ ❞❡ ❞❛❞♦s ❳❊ ❙◗▲❃ Como pode ser visto, o trigger gravou o histórico com as informações pertinentes ao usuário que conectou no banco de dados. O próximo registra alterações de dml realizados pelo usuário, mais precisamente a criação de objetos no sistema. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r t❣r❴❤✐st❴❝r✐❛t❛❜❴✉s✉❛r✐♦ ✷ ❛❢t❡r ❝r❡❛t❡ ♦♥ ❞❛t❛❜❛s❡ ✸ ❜❡❣✐♥ ✹ ✐♥s❡rt ✐♥t♦ ❤✐st❴✉s✉❛r✐♦ ✈❛❧✉❡s ✺ ✭❖❘❆❴▲❖●■◆❴❯❙❊❘✱s②s❞❛t❡✱ ✬❖ ❖❜❥❡t♦ ✬⑤⑤❖❘❆❴❉■❈❚❴❖❇❏❴◆❆▼❊⑤⑤✬ ❢♦✐ ❝r✐❛❞♦ ♥♦ ❜❛♥❝♦ ❞❡ ❞❛❞♦s✳✬✮❀ ✻ ❡♥❞❀ ✼ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Criando o objeto tabela teste_trigger: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ❝r❡❛t❡ t❛❜❧❡ t❡st❡❴tr✐❣❣❡r ✭ ✐❞❴❝❛♠♣♦ ✈❛r❝❤❛r✷✭✺✵✮ ✱♥♠❴❝❛♠♣♦ ❞❛t❡ ✱❞s❴❝❛♠♣♦ ✈❛r❝❤❛r✷✭✹✵✵✵✮ ✮ ✴ ❚❛❜❡❧❛ ❝r✐❛❞❛✳ ❙◗▲❃ 329 19.6. Trigger de view Casa do Código Verificando tabela de histórico: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❤✐st❴✉s✉❛r✐♦❀ ◆▼❴❯❙❯❆❘■❖ ❉❚❴❍■❙❚❖ ❉❙❴❍■❙❚❖❘■❈❖ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❚❙◗▲ ✵✹✴✶✵✴✶✶ ❖ ♦❜❥❡t♦ ❚❊❙❚❊❴❚❘■●●❊❘ ❢♦✐ ❝r✐❛❞♦ ♥♦ ❜❛♥❝♦ ❞❡ ❞❛❞♦s✳ ❙◗▲❃ 19.6 Trigger de view Aprendemos anteriormente que um trigger pode estar associado a uma tabela ou ao avento de sistema. Contudo, quando estamos falando de views, que são bem semelhantes a tabelas, pelo menos na forma de apresentação dos dados, existe a possibilidade de criarmos um trigger e o associarmos também a este tipo de objeto. Em regras gerais, só conseguimos criar um trigger para uma determinada view que seja composta de apenas uma tabela. No entanto, se criarmos um trigger usando a cláusula instead of, podemos trabalhar com triggers associadas a views compostas de uma ou mais tabelas. O trigger usado com instead of tem sua definição um pouco diferente, pois esta cláusula substitui os eventos before e after. Outro ponto que deve ser observado é que o uso desta cláusula só pode ser empregado com triggers de linha. A questão de poder ou não criar um trigger para uma view está relacionada às operações que podemos efetuar em cima desta view. Esquecendo um pouco os triggers, sabemos que operações de DML ( insert, delete ou update) só podem ocorrer quando a view for de apenas uma tabela. Portanto, a utilização de triggers em views segue os mesmos princípios. A única diferença é que quando utilizamos triggers para realizar comando DML em views podemos utilizá-los com a opção instead of, o que torna possível tratar de forma diferente as views que possuam mais de uma tabela na sua composição. 330 Casa do Código Capítulo 19. Triggers A seguir, um exemplo de uma view composta pelas tabelas emp e dept onde nós vamos inserir dados. Criando view de empregados por departamento: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ❝r❡❛t❡ ✈✐❡✇ ❡♠♣❴❞❡♣t❴✈ ❛s s❡❧❡❝t ❡✳❡♠♣♥♦✱ ❡✳❡♥❛♠❡✱ ❡✳❥♦❜✱ ❡✳s❛❧✱ ❞✳❞♥❛♠❡ ❢r♦♠ ❡♠♣ ❡ ✱❞❡♣t ❞ ✇❤❡r❡ ❡✳❞❡♣t♥♦ ❂ ❞✳❞❡♣t♥♦ ❀ ❱✐❡✇ ❝r✐❛❞❛✳ ❙◗▲❃ Selecionando dados: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ ✼✾✸✺ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❆▲▲❊◆ ❲❆❘❉ ❏❖◆❊❙ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ P❆❯▲ ❏❖❇ ❙❆▲ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✾✻✽ ❘❊❙❊❆❘❈❍ ❙❆▲❊❙▼❆◆ ✶✻✵✵ ❙❆▲❊❙ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ❙❆▲❊❙ ▼❆◆❆●❊❘ ✸✺✾✾✱✼✺ ❘❊❙❊❆❘❈❍ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ❙❆▲❊❙ ▼❆◆❆●❊❘ ✷✽✺✵ ❙❆▲❊❙ ▼❆◆❆●❊❘ ✷✹✺✵ ❆❈❈❖❯◆❚■◆● ❆◆❆▲❨❙❚ ✸✻✸✵ ❘❊❙❊❆❘❈❍ P❘❊❙■❉❊◆❚ ✺✵✵✵ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙▼❆◆ ✶✺✵✵ ❙❆▲❊❙ ❈▲❊❘❑ ✶✸✸✶ ❘❊❙❊❆❘❈❍ ❈▲❊❘❑ ✾✺✵ ❙❆▲❊❙ ❆◆❆▲❨❙❚ ✸✻✸✵ ❘❊❙❊❆❘❈❍ ❈▲❊❘❑ ✶✸✵✵ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙▼❆◆ ✶✵✵✵ ❙❆▲❊❙ ✶✺ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ 331 19.6. Trigger de view Casa do Código Criando trigger com instead of para manipulação dos dados: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ ✸✵ ✸✶ ✸✷ ✸✸ ✸✹ 332 ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r tr❣❴❡♠♣❴❞❡♣t❴✈ ✐♥st❡❛❞ ♦❢ ✐♥s❡rt ♦r ❞❡❧❡t❡ ♦r ✉♣❞❛t❡ ♦♥ ❡♠♣❴❞❡♣t❴✈ r❡❢❡r❡♥❝✐♥❣ ♥❡✇ ❛s ♥❡✇ ♦❧❞ ❛s ♦❧❞ ❞❡❝❧❛r❡ ❝✉rs♦r ❝✶✭♣❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡✮ ✐s s❡❧❡❝t ❞❡♣t♥♦✱ ❞♥❛♠❡ ❢r♦♠ ❞❡♣t ✇❤❡r❡ ❞❡♣t♥♦ ❂ ♣❞❡♣t♥♦❀ ✲✲ ❝✉rs♦r ❝✷✭♣❡♠♣♥♦ ❡♠♣✳❡♠♣♥♦✪t②♣❡✮ ✐s s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ♣❡♠♣♥♦❀ ✲✲ ✇❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡❀ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✇❡♠♣♥♦ ❡♠♣✳❡♠♣♥♦✪t②♣❡❀ ✇❡♥❛♠❡ ❡♠♣✳❡♥❛♠❡✪t②♣❡❀ ❜❡❣✐♥ ✲✲ ✐❢ ✐♥s❡rt✐♥❣ t❤❡♥ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❞❡♣❛rt❛♠❡♥t♦✳ ♦♣❡♥ ❝✶ ✭✿♥❡✇✳❞❡♣t♥♦✮❀ ❢❡t❝❤ ❝✶ ✐♥t♦ ✇❞❡♣t♥♦✱ ✇❞♥❛♠❡❀ ✲✲ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✭❞❡♣t♥♦✱ ❞♥❛♠❡✱ ❧♦❝✮ ✈❛❧✉❡s ✭✿♥❡✇✳❞❡♣t♥♦✱ ✿♥❡✇✳❞♥❛♠❡✱ ♥✉❧❧✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡♣❛rt❛♠❡♥t♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡♣❛rt❛♠❡♥t♦ ❡①✐st❡♥t❡✿ ✬⑤⑤✇❞❡♣t♥♦⑤⑤✬ ✲ Casa do Código ✸✺ ✸✻ ✸✼ ✸✽ ✸✾ ✹✵ ✹✶ ✹✷ ✹✸ ✹✹ ✹✺ ✹✻ ✹✼ ✹✽ ✹✾ ✺✵ ✺✶ ✺✷ ✺✸ Capítulo 19. Triggers ✬⑤⑤✇❞♥❛♠❡⑤⑤✬✳✬✮❀ ❡♥❞ ✐❢❀ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❡♠♣r❡❣❛❞♦✳ ♦♣❡♥ ❝✷ ✭✿♥❡✇✳❡♠♣♥♦✮❀ ❢❡t❝❤ ❝✷ ✐♥t♦ ✇❡♠♣♥♦✱ ✇❡♥❛♠❡❀ ✲✲ ✐❢ ❝✷✪♥♦t❢♦✉♥❞ t❤❡♥ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ♠❣r✱ ❞❡♣t♥♦✮ ✈❛❧✉❡s ✭✿♥❡✇✳❡♠♣♥♦✱ ✿♥❡✇✳❡♥❛♠❡✱ ✿♥❡✇✳❥♦❜✱ ✿♥❡✇✳s❛❧✱ ✿♥❡✇✳♠❣r✱ ✿♥❡✇✳❞❡♣t♥♦✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❋✉♥❝✐♦♥ár✐♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❋✉♥❝✐♦♥ár✐♦ ❡①✐st❡♥t❡✿ ✬⑤⑤✇❡♠♣♥♦⑤⑤✬ ✲ ✬⑤⑤✇❡♥❛♠❡⑤⑤✬✳✬✮❀ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞❀ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ ❙◗▲❃ Na primeira parte da criação do trigger vamos tratar a ação de insert na view emp_dept_v. A seguir temos várias execuções onde testamos, primeiramente, o comando insert. ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❡♠♣❴❞❡♣t❴✈ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ♠❣r✱ ❞❡♣t♥♦✱ ❞♥❛♠❡✮ ✷ ✈❛❧✉❡s ✭✽✵✵✵✱ ✬❇❘❯❈❊✬✱ ✬▼❆◆❆●❊❘✬✱ ✶✵✵✵✱ ✼✽✸✾✱ ✷✵✱ ✬❘❊❙❊❆❘❈❍✬✮❀ ❉❡♣❛rt❛♠❡♥t♦ ❡①✐st❡♥t❡✿ ✷✵ ✲ ❘❊❙❊❆❘❈❍✳ ❋✉♥❝✐♦♥ár✐♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳ 333 19.6. Trigger de view Casa do Código ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❡♠♣❴❞❡♣t❴✈ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ♠❣r✱ ❞❡♣t♥♦✱ ❞♥❛♠❡✮ ✷ ✈❛❧✉❡s ✭✽✵✵✵✱ ✬❇❘❯❈❊✬✱ ✬▼❆◆❆●❊❘✬✱ ✶✵✵✵✱ ✼✽✸✾✱ ✷✵✱ ✬❘❊❙❊❆❘❈❍✬✮❀ ❉❡♣❛rt❛♠❡♥t♦ ❡①✐st❡♥t❡✿ ✷✵ ✲ ❘❊❙❊❆❘❈❍✳ ❋✉♥❝✐♦♥ár✐♦ ❡①✐st❡♥t❡✿ ✽✵✵✵ ✲ ❇❘❯❈❊✳ ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❡♠♣❴❞❡♣t❴✈ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ♠❣r✱ ❞❡♣t♥♦✱ ❞♥❛♠❡✮ ✷ ✈❛❧✉❡s ✭✽✵✵✶✱ ✬❙■▲❱❊❙❚❊❘✬✱ ✬▼❆◆❆●❊❘✬✱ ✶✵✵✵✱ ✼✽✸✾✱ ✽✵✱ ✬❙✫❊✬✮❀ ❉❡♣❛rt❛♠❡♥t♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳ ❋✉♥❝✐♦♥ár✐♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳ ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❡♠♣❴❞❡♣t❴✈ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ♠❣r✱ ❞❡♣t♥♦✱ ❞♥❛♠❡✮ ✷ ✈❛❧✉❡s ✭✽✵✵✶✱ ✬❙■▲❱❊❙❚❊❘✬✱ ✬▼❆◆❆●❊❘✬✱ ✶✵✵✵✱ ✼✽✸✾✱ ✾✵✱ ✬❋■◆❆◆❈■❆▲✬✮❀ ❉❡♣❛rt❛♠❡♥t♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳ ❋✉♥❝✐♦♥ár✐♦ ❡①✐st❡♥t❡✿ ✽✵✵✶ ✲ ❙■▲❱❊❙❚❊❘✳ ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ ❙◗▲❃ ✐♥s❡rt ✐♥t♦ ❡♠♣❴❞❡♣t❴✈ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ♠❣r✱ ❞❡♣t♥♦✱ ❞♥❛♠❡✮ ✷ ✈❛❧✉❡s ✭✽✵✵✷✱ ✬❲■▲▲✬✱ ✬▼❆◆❆●❊❘✬✱ ✶✵✵✵✱ ✼✽✸✾✱ ✾✵✱ ✬❋■◆❆◆❈■❆▲✬✮❀ 334 Casa do Código Capítulo 19. Triggers ❉❡♣❛rt❛♠❡♥t♦ ❡①✐st❡♥t❡✿ ✾✵ ✲ ❋■◆❆◆❈■❆▲✳ ❋✉♥❝✐♦♥ár✐♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳ ✶ ❧✐♥❤❛ ❝r✐❛❞❛✳ ❙◗▲❃ Agora vamos para a segunda parte do trigger, onde vamos tratar a ação update. Criação do trigger: ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r tr❣❴❡♠♣❴❞❡♣t❴✈ ✷ ✐♥st❡❛❞ ♦❢ ✸ ✐♥s❡rt ♦r ❞❡❧❡t❡ ♦r ✉♣❞❛t❡ ✹ ♦♥ ❡♠♣❴❞❡♣t❴✈ ✺ r❡❢❡r❡♥❝✐♥❣ ♥❡✇ ❛s ♥❡✇ ♦❧❞ ❛s ♦❧❞ ✻ ❞❡❝❧❛r❡ ✼ ❝✉rs♦r ❝✶✭♣❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡✮ ✐s ✽ s❡❧❡❝t ❞❡♣t♥♦✱ ❞♥❛♠❡ ✾ ❢r♦♠ ❞❡♣t ✶✵ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ♣❞❡♣t♥♦❀ ✶✶ ✲✲ ✶✷ ❝✉rs♦r ❝✷✭♣❡♠♣♥♦ ❡♠♣✳❡♠♣♥♦✪t②♣❡✮ ✐s ✶✸ s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡ ✶✹ ❢r♦♠ ❡♠♣ ✶✺ ✇❤❡r❡ ❡♠♣♥♦ ❂ ♣❡♠♣♥♦❀ ✶✻ ✲✲ ✶✼ ✇❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡❀ ✶✽ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✶✾ ✇❡♠♣♥♦ ❡♠♣✳❡♠♣♥♦✪t②♣❡❀ ✷✵ ✇❡♥❛♠❡ ❡♠♣✳❡♥❛♠❡✪t②♣❡❀ ✷✶ ❜❡❣✐♥ ✷✷ ✲✲ ✷✸ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✷✹ ✐❢ ✐♥s❡rt✐♥❣ t❤❡♥ ✷✺ ✲✲ ✷✻ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❞❡♣❛rt❛♠❡♥t♦✳ ✷✼ ♦♣❡♥ ❝✶ ✭✿♥❡✇✳❞❡♣t♥♦✮❀ ✷✽ ❢❡t❝❤ ❝✶ ✐♥t♦ ✇❞❡♣t♥♦✱ ✇❞♥❛♠❡❀ ✷✾ ✲✲ 335 19.6. Trigger de view ✸✵ ✸✶ ✸✷ ✸✸ ✸✹ ✸✺ ✸✻ ✸✼ ✸✽ ✸✾ ✹✵ ✹✶ ✹✷ ✹✸ ✹✹ ✹✺ ✹✻ ✹✼ ✹✽ ✹✾ ✺✵ ✺✶ ✺✷ ✺✸ ✺✹ ✺✺ ✺✻ ✺✼ ✺✽ ✺✾ ✻✵ ✻✶ ✻✷ 336 Casa do Código ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✭❞❡♣t♥♦✱ ❞♥❛♠❡✱ ❧♦❝✮ ✈❛❧✉❡s ✭✿♥❡✇✳❞❡♣t♥♦✱ ✿♥❡✇✳❞♥❛♠❡✱ ♥✉❧❧✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦ ❡①✐st❡♥t❡✿ ✬⑤⑤✇❞❡♣t♥♦⑤⑤✬ ✲ ✬⑤⑤✇❞♥❛♠❡⑤⑤✬✳✬✮❀ ❡♥❞ ✐❢❀ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❡♠♣r❡❣❛❞♦✳ ♦♣❡♥ ❝✷ ✭✿♥❡✇✳❡♠♣♥♦✮❀ ❢❡t❝❤ ❝✷ ✐♥t♦ ✇❡♠♣♥♦✱ ✇❡♥❛♠❡❀ ✲✲ ✐❢ ❝✷✪♥♦t❢♦✉♥❞ t❤❡♥ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ♠❣r✱ ❞❡♣t♥♦✮ ✈❛❧✉❡s ✭✿♥❡✇✳❡♠♣♥♦✱ ✿♥❡✇✳❡♥❛♠❡✱ ✿♥❡✇✳❥♦❜✱ ✿♥❡✇✳s❛❧✱✿♥❡✇✳♠❣r✱ ✿♥❡✇✳❞❡♣t♥♦✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❋✉♥❝✐♦♥ár✐♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❋✉♥❝✐♦♥ár✐♦ ❡①✐st❡♥t❡✿ ✬⑤⑤✇❡♠♣♥♦⑤⑤✬ ✲ ✬⑤⑤✇❡♥❛♠❡⑤⑤✬✳✬✮❀ ❡♥❞ ✐❢❀ ✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❡❧s✐❢ ✉♣❞❛t✐♥❣ t❤❡♥ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❞❡♣❛rt❛♠❡♥t♦✳ ♦♣❡♥ ❝✶ ✭✿♥❡✇✳❞❡♣t♥♦✮❀ ❢❡t❝❤ ❝✶ ✐♥t♦ ✇❞❡♣t♥♦✱ ✇❞♥❛♠❡❀ ✲✲ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦ ♥ã♦ ❡①✐st❡✳✬✮❀ ✲✲ ❡❧s❡ Casa do Código ✻✸ ✻✹ ✻✺ ✻✻ ✻✼ ✻✽ ✻✾ ✼✵ ✼✶ ✼✷ ✼✸ ✼✹ ✼✺ ✼✻ ✼✼ ✼✽ ✼✾ ✽✵ ✽✶ ✽✷ ✽✸ ✽✹ ✽✺ ✽✻ ✽✼ ✽✽ ✽✾ ✾✵ ✾✶ ✾✷ ✾✸ ✾✹ ✾✺ ✾✻ Capítulo 19. Triggers ✲✲ ✉♣❞❛t❡ ❞❡♣t s❡t ❞♥❛♠❡ ❂ ✿♥❡✇✳❞♥❛♠❡ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✿♥❡✇✳❞❡♣t♥♦❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ✬⑤⑤✿♥❡✇✳❞♥❛♠❡⑤⑤✬✳✬✮❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❡♠♣r❡❣❛❞♦✳ ♦♣❡♥ ❝✷ ✭✿♥❡✇✳❡♠♣♥♦✮❀ ❢❡t❝❤ ❝✷ ✐♥t♦ ✇❡♠♣♥♦✱ ✇❡♥❛♠❡❀ ✲✲ ✐❢ ❝✷✪♥♦t❢♦✉♥❞ t❤❡♥ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❋✉♥❝✐♦♥ár✐♦ ♥ã♦ ❝❛❞❛str❛❞♦✳✬✮❀ ✲✲ ❡❧s❡ ✉♣❞❛t❡ ❡♠♣ s❡t ❡♥❛♠❡ ❂ ✿♥❡✇✳❡♥❛♠❡ ✱❥♦❜ ❂ ✿♥❡✇✳❥♦❜ ✱s❛❧ ❂ ✿♥❡✇✳s❛❧ ✱♠❣r ❂ ✿♥❡✇✳♠❣r ✱❞❡♣t♥♦ ❂ ✿♥❡✇✳❞❡♣t♥♦ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✿♥❡✇✳❡♠♣♥♦❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❋✉♥❝✐♦♥ár✐♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ✬⑤⑤✿♥❡✇✳❡♥❛♠❡⑤⑤✬✳✬✮❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ❡♥❞❀ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ 337 19.6. Trigger de view Casa do Código ❙◗▲❃ Testando o trigger: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✽✵✵✵❀ ❊▼P◆❖ ❊◆❆▼❊ ❏❖❇ ❙❆▲ ▼●❘ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✽✵✵✵ ❇❘❯❈❊ ▼❆◆❆●❊❘ ✶✵✵✵ ✼✽✸✾ ❉❊P❚◆❖ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✷✵ ❘❊❙❊❆❘❈❍ ❙◗▲❃ ❙◗▲❃ ✉♣❞❛t❡ ❡♠♣❴❞❡♣t❴✈ ✷ s❡t ❡♥❛♠❡ ❂ ✬❇❘❯❈❊❲✬ ✸ ✱❥♦❜ ❂ ✬❆◆❆▲❨❙❚✬ ✹ ✱s❛❧ ❂ ✶✺✵✵ ✱❞❡♣t♥♦ ❂ ✷✵ ✺ ✻ ✱❞♥❛♠❡ ❂ ✬❘❊❙❊❆❘❈❍✬ ✼ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✽✵✵✵❀ ❉❡♣❛rt❛♠❡♥t♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ❘❊❙❊❆❘❈❍✳ ❋✉♥❝✐♦♥ár✐♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ❇❘❯❈❊❲✳ ✶ ❧✐♥❤❛ ❛t✉❛❧✐③❛❞❛✳ ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✽✵✵✵❀ ❊▼P◆❖ ❊◆❆▼❊ ❏❖❇ ❙❆▲ ▼●❘ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✽✵✵✵ ❇❘❯❈❊❲ ❆◆❆▲❨❙❚ ✶✺✵✵ ✼✽✸✾ ❉❊P❚◆❖ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✷✵ ❘❊❙❊❆❘❈❍ ❙◗▲❃ ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵❀ 338 Casa do Código ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✺✻✻ ✼✼✽✽ ✼✽✼✻ ✼✾✵✷ ✽✵✵✵ Capítulo 19. Triggers ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❏❖◆❊❙ ❙❈❖❚❚ ❆❉❆▼❙ ❋❖❘❉ ❇❘❯❈❊❲ ❏❖❇ ❙❆▲ ▼●❘ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✾✻✽ ✼✾✵✷ ▼❆◆❆●❊❘ ✸✺✾✾✱✼✺ ✼✽✸✾ ❆◆❆▲❨❙❚ ✸✻✸✵ ✼✺✻✻ ❈▲❊❘❑ ✶✸✸✶ ✼✼✽✽ ❆◆❆▲❨❙❚ ✸✻✸✵ ✼✺✻✻ ❆◆❆▲❨❙❚ ✶✺✵✵ ✼✽✸✾ ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵❀ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✷✵ ✷✵ ✷✵ ✷✵ ✷✵ ✷✵ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲ ❘❊❙❊❆❘❈❍ ❘❊❙❊❆❘❈❍ ❘❊❙❊❆❘❈❍ ❘❊❙❊❆❘❈❍ ❘❊❙❊❆❘❈❍ ❘❊❙❊❆❘❈❍ ✻ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ ❙◗▲❃ ✉♣❞❛t❡ ❡♠♣❴❞❡♣t❴✈ ✷ s❡t ❞♥❛♠❡ ❂ ✬P❊❙◗❯■❙❆✬ ✸ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵❀ ❉❡♣❛rt❛♠❡♥t♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ P❊❙◗❯■❙❆✳ ❋✉♥❝✐♦♥ár✐♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ❙▼■❚❍✳ ❉❡♣❛rt❛♠❡♥t♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ P❊❙◗❯■❙❆✳ ❋✉♥❝✐♦♥ár✐♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ❏❖◆❊❙✳ ❉❡♣❛rt❛♠❡♥t♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ P❊❙◗❯■❙❆✳ ❋✉♥❝✐♦♥ár✐♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ❙❈❖❚❚✳ ❉❡♣❛rt❛♠❡♥t♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ P❊❙◗❯■❙❆✳ ❋✉♥❝✐♦♥ár✐♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ❆❉❆▼❙✳ ❉❡♣❛rt❛♠❡♥t♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ P❊❙◗❯■❙❆✳ ❋✉♥❝✐♦♥ár✐♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ❋❖❘❉✳ ❉❡♣❛rt❛♠❡♥t♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ P❊❙◗❯■❙❆✳ ❋✉♥❝✐♦♥ár✐♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ❇❘❯❈❊❲✳ 339 Casa do Código 19.6. Trigger de view ✻ ❧✐♥❤❛s ❛t✉❛❧✐③❛❞❛s✳ ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✺✻✻ ✼✼✽✽ ✼✽✼✻ ✼✾✵✷ ✽✵✵✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❏❖◆❊❙ ❙❈❖❚❚ ❆❉❆▼❙ ❋❖❘❉ ❇❘❯❈❊❲ ❏❖❇ ❙❆▲ ▼●❘ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✾✻✽ ✼✾✵✷ ▼❆◆❆●❊❘ ✸✺✾✾✱✼✺ ✼✽✸✾ ❆◆❆▲❨❙❚ ✸✻✸✵ ✼✺✻✻ ❈▲❊❘❑ ✶✸✸✶ ✼✼✽✽ ❆◆❆▲❨❙❚ ✸✻✸✵ ✼✺✻✻ ❆◆❆▲❨❙❚ ✶✺✵✵ ✼✽✸✾ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✷✵ ✷✵ ✷✵ ✷✵ ✷✵ ✷✵ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲ P❊❙◗❯■❙❆ P❊❙◗❯■❙❆ P❊❙◗❯■❙❆ P❊❙◗❯■❙❆ P❊❙◗❯■❙❆ P❊❙◗❯■❙❆ ✻ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ A exclusão finaliza a última parte do nosso trigger de view. ❙◗▲❃ ❡❞ ●r❛✈♦✉ ❛rq✉✐✈♦ ❛❢✐❡❞t✳❜✉❢ ✶ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ tr✐❣❣❡r tr❣❴❡♠♣❴❞❡♣t❴✈ ✷ ✐♥st❡❛❞ ♦❢ ✸ ✐♥s❡rt ♦r ❞❡❧❡t❡ ♦r ✉♣❞❛t❡ ✹ ♦♥ ❡♠♣❴❞❡♣t❴✈ ✺ r❡❢❡r❡♥❝✐♥❣ ♥❡✇ ❛s ♥❡✇ ♦❧❞ ❛s ♦❧❞ ✻ ❞❡❝❧❛r❡ ✼ ❝✉rs♦r ❝✶✭♣❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡✮ ✐s ✽ s❡❧❡❝t ❞❡♣t♥♦✱ ❞♥❛♠❡ ✾ ❢r♦♠ ❞❡♣t 340 Casa do Código ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✷✽ ✷✾ ✸✵ ✸✶ ✸✷ ✸✸ ✸✹ ✸✺ ✸✻ ✸✼ ✸✽ ✸✾ ✹✵ ✹✶ ✹✷ ✹✸ ✹✹ Capítulo 19. Triggers ✇❤❡r❡ ❞❡♣t♥♦ ❂ ♣❞❡♣t♥♦❀ ✲✲ ❝✉rs♦r ❝✷✭♣❡♠♣♥♦ ❡♠♣✳❡♠♣♥♦✪t②♣❡✮ ✐s s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ♣❡♠♣♥♦❀ ✲✲ ❝✉rs♦r ❝✸✭♣❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡✮ ✐s s❡❧❡❝t ❝♦✉♥t✭✯✮ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ♣❞❡♣t♥♦❀ ✲✲ ✇❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡❀ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✇❡♠♣♥♦ ❡♠♣✳❡♠♣♥♦✪t②♣❡❀ ✇❡♥❛♠❡ ❡♠♣✳❡♥❛♠❡✪t②♣❡❀ qt❴❡♠♣♥♦ ♥✉♠❜❡r ❞❡❢❛✉❧t ✵❀ ❜❡❣✐♥ ✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✐❢ ✐♥s❡rt✐♥❣ t❤❡♥ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❞❡♣❛rt❛♠❡♥t♦✳ ♦♣❡♥ ❝✶ ✭✿♥❡✇✳❞❡♣t♥♦✮❀ ❢❡t❝❤ ❝✶ ✐♥t♦ ✇❞❡♣t♥♦✱ ✇❞♥❛♠❡❀ ✲✲ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✭❞❡♣t♥♦✱ ❞♥❛♠❡✱ ❧♦❝✮ ✈❛❧✉❡s ✭✿♥❡✇✳❞❡♣t♥♦✱ ✿♥❡✇✳❞♥❛♠❡✱ ♥✉❧❧✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡♣❛rt❛♠❡♥t♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡♣❛rt❛♠❡♥t♦ ❡①✐st❡♥t❡✿ ✬⑤⑤✇❞❡♣t♥♦⑤⑤✬ ✲ ✬⑤⑤✇❞♥❛♠❡⑤⑤✬✳✬✮❀ ❡♥❞ ✐❢❀ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❡♠♣r❡❣❛❞♦✳ 341 19.6. Trigger de view ✹✺ ✹✻ ✹✼ ✹✽ ✹✾ ✺✵ ✺✶ ✺✷ ✺✸ ✺✹ ✺✺ ✺✻ ✺✼ ✺✽ ✺✾ ✻✵ ✻✶ ✻✷ ✻✸ ✻✹ ✻✺ ✻✻ ✻✼ ✻✽ ✻✾ ✼✵ ✼✶ ✼✷ ✼✸ ✼✹ ✼✺ ✼✻ ✼✼ ✼✽ ✼✾ 342 Casa do Código ♦♣❡♥ ❝✷ ✭✿♥❡✇✳❡♠♣♥♦✮❀ ❢❡t❝❤ ❝✷ ✐♥t♦ ✇❡♠♣♥♦✱ ✇❡♥❛♠❡❀ ✲✲ ✐❢ ❝✷✪♥♦t❢♦✉♥❞ t❤❡♥ ✐♥s❡rt ✐♥t♦ ❡♠♣ ✭❡♠♣♥♦✱ ❡♥❛♠❡✱ ❥♦❜✱ s❛❧✱ ♠❣r✱ ❞❡♣t♥♦✮ ✈❛❧✉❡s ✭✿♥❡✇✳❡♠♣♥♦✱ ✿♥❡✇✳❡♥❛♠❡✱ ✿♥❡✇✳❥♦❜✱ ✿♥❡✇✳s❛❧✱ ✿♥❡✇✳♠❣r✱ ✿♥❡✇✳❞❡♣t♥♦✮❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❋✉♥❝✐♦♥ár✐♦ ❝❛❞❛str❛❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ❡❧s❡ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❋✉♥❝✐♦♥ár✐♦ ❡①✐st❡♥t❡✿ ✬⑤⑤✇❡♠♣♥♦⑤⑤✬ ✲ ✬⑤⑤✇❡♥❛♠❡⑤⑤✬✳✬✮❀ ❡♥❞ ✐❢❀ ✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❡❧s✐❢ ✉♣❞❛t✐♥❣ t❤❡♥ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❞❡♣❛rt❛♠❡♥t♦✳ ♦♣❡♥ ❝✶ ✭✿♥❡✇✳❞❡♣t♥♦✮❀ ❢❡t❝❤ ❝✶ ✐♥t♦ ✇❞❡♣t♥♦✱ ✇❞♥❛♠❡❀ ✲✲ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦ ♥ã♦ ❡①✐st❡✳✬✮❀ ✲✲ ❡❧s❡ ✲✲ ✉♣❞❛t❡ ❞❡♣t s❡t ❞♥❛♠❡ ❂ ✿♥❡✇✳❞♥❛♠❡ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✿♥❡✇✳❞❡♣t♥♦❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ✬⑤⑤✿♥❡✇✳❞♥❛♠❡⑤⑤✬✳✬✮❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❡♠♣r❡❣❛❞♦✳ ♦♣❡♥ ❝✷ ✭✿♥❡✇✳❡♠♣♥♦✮❀ Casa do Código ✽✵ ✽✶ ✽✷ ✽✸ ✽✹ ✽✺ ✽✻ ✽✼ ✽✽ ✽✾ ✾✵ ✾✶ ✾✷ ✾✸ ✾✹ ✾✺ ✾✻ ✾✼ ✾✽ ✾✾ ✶✵✵ ✶✵✶ ✶✵✷ ✶✵✸ ✶✵✹ ✶✵✺ ✶✵✻ ✶✵✼ ✶✵✽ ✶✵✾ ✶✶✵ ✶✶✶ ✶✶✷ ✶✶✸ ✶✶✹ ✶✶✺ ✶✶✻ Capítulo 19. Triggers ❢❡t❝❤ ❝✷ ✐♥t♦ ✇❡♠♣♥♦✱ ✇❡♥❛♠❡❀ ✲✲ ✐❢ ❝✷✪♥♦t❢♦✉♥❞ t❤❡♥ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❋✉♥❝✐♦♥ár✐♦ ♥ã♦ ❝❛❞❛str❛❞♦✳✬✮❀ ✲✲ ❡❧s❡ ✉♣❞❛t❡ ❡♠♣ s❡t ❡♥❛♠❡ ❂ ✿♥❡✇✳❡♥❛♠❡ ✱❥♦❜ ❂ ✿♥❡✇✳❥♦❜ ✱s❛❧ ❂ ✿♥❡✇✳s❛❧ ✱♠❣r ❂ ✿♥❡✇✳♠❣r ✱❞❡♣t♥♦ ❂ ✿♥❡✇✳❞❡♣t♥♦ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✿♥❡✇✳❡♠♣♥♦❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❋✉♥❝✐♦♥ár✐♦ ❛t✉❛❧✐③❛❞♦ ❝♦♠ s✉❝❡ss♦✿ ✬⑤⑤✿♥❡✇✳❡♥❛♠❡⑤⑤✬✳✬✮❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❡❧s✐❢ ❞❡❧❡t✐♥❣ t❤❡♥ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❡♠♣r❡❣❛❞♦✳ ♦♣❡♥ ❝✷ ✭✿♦❧❞✳❡♠♣♥♦✮❀ ❢❡t❝❤ ❝✷ ✐♥t♦ ✇❡♠♣♥♦✱ ✇❡♥❛♠❡❀ ✲✲ ✐❢ ❝✷✪♥♦t❢♦✉♥❞ t❤❡♥ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❋✉♥❝✐♦♥ár✐♦ ♥ã♦ ❝❛❞❛str❛❞♦✳✬✮❀ ✲✲ ❡❧s❡ ❞❡❧❡t❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✿♦❧❞✳❡♠♣♥♦❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❋✉♥❝✐♦♥ár✐♦ ❡①❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✿ ✬⑤⑤✿♦❧❞✳❡♥❛♠❡⑤⑤✬✳✬✮❀ ✲✲ ❡♥❞ ✐❢❀ ✲✲ 343 19.6. Trigger de view ✶✶✼ ✶✶✽ ✶✶✾ ✶✷✵ ✶✷✶ ✶✷✷ ✶✷✸ ✶✷✹ ✶✷✺ ✶✷✻ ✶✷✼ ✶✷✽ ✶✷✾ ✶✸✵ ✶✸✶ ✶✸✷ ✶✸✸ ✶✸✹ ✶✸✺ Casa do Código ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❞❡♣❛rt❛♠❡♥t♦✳ ♦♣❡♥ ❝✶ ✭✿♦❧❞✳❞❡♣t♥♦✮❀ ❢❡t❝❤ ❝✶ ✐♥t♦ ✇❞❡♣t♥♦✱ ✇❞♥❛♠❡❀ ✲✲ ✐❢ ❝✶✪♥♦t❢♦✉♥❞ t❤❡♥ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦ ♥ã♦ ❡①✐st❡✳✬✮❀ ✲✲ ❡❧s❡ ✲✲ ✲✲ ✈❡r✐❢✐❝❛ s❡ ❡①✐st❡ ❞❡♣❛rt❛♠❡♥t♦✳ ♦♣❡♥ ❝✸ ✭✿♦❧❞✳❞❡♣t♥♦✮❀ ❢❡t❝❤ ❝✸ ✐♥t♦ qt❴❡♠♣♥♦❀ ✲✲ ✐❢ qt❴❡♠♣♥♦ ❂ ✵ t❤❡♥ ✲✲ ❞❡❧❡t❡ ❢r♦♠ ❞❡♣t ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✿♦❧❞✳❞❡♣t♥♦❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦ ❡①❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✿ ✬⑤⑤✿♦❧❞✳❞♥❛♠❡⑤⑤✬✳✬✮❀ ✶✸✻ ✲✲ ✶✸✼ ❡❧s❡ ✶✸✽ ✲✲ ✶✸✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❖ ❞❡♣❛rt❛♠❡♥t♦ ✬⑤⑤✿♦❧❞✳❞♥❛♠❡⑤⑤✬ ♥ã♦ ♣♦❞❡ s❡r ❡①❝❧✉í❞♦✳ ❆✐♥❞❛ ❡①✐st❡♠ ✶✹✵ ✲✲ ✶✹✶ ❡♥❞ ✐❢❀ ✶✹✷ ✲✲ ✶✹✸ ❡♥❞ ✐❢❀ ✶✹✹ ✲✲ ✶✹✺ ❡♥❞ ✐❢❀ ✶✹✻ ✲✲ ✶✹✼✯ ❡♥❞❀ ❙◗▲❃ ✴ ●❛t✐❧❤♦ ❝r✐❛❞♦✳ 344 Casa do Código Capítulo 19. Triggers ❙◗▲❃ Vamos testar a ação de exclusão: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ ✼✾✸✺ ✽✵✵✶ ✽✵✵✵ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❆▲▲❊◆ ❲❆❘❉ ❏❖◆❊❙ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ P❆❯▲ ❙■▲❱❊❙❚❊❘ ❇❘❯❈❊❲ ❏❖❇ ❙❆▲ ▼●❘ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✾✻✽ ✼✾✵✷ ❙❆▲❊❙▼❆◆ ✶✻✵✵ ✼✻✾✽ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✼✻✾✽ ▼❆◆❆●❊❘ ✸✺✾✾✱✼✺ ✼✽✸✾ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✼✻✾✽ ▼❆◆❆●❊❘ ✷✽✺✵ ✼✽✸✾ ▼❆◆❆●❊❘ ✷✹✺✵ ✼✽✸✾ ❆◆❆▲❨❙❚ ✸✻✸✵ ✼✺✻✻ P❘❊❙■❉❊◆❚ ✺✵✵✵ ❙❆▲❊❙▼❆◆ ✶✺✵✵ ✼✻✾✽ ❈▲❊❘❑ ✶✸✸✶ ✼✼✽✽ ❈▲❊❘❑ ✾✺✵ ✼✻✾✽ ❆◆❆▲❨❙❚ ✸✻✸✵ ✼✺✻✻ ❈▲❊❘❑ ✶✸✵✵ ✼✼✽✷ ❙❆▲❊❙▼❆◆ ✶✵✵✵ ✼✻✾✽ ▼❆◆❆●❊❘ ✶✵✵✵ ✼✽✸✾ ❆◆❆▲❨❙❚ ✶✺✵✵ ✼✽✸✾ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✷✵ ✸✵ ✸✵ ✷✵ ✸✵ ✸✵ ✶✵ ✷✵ ✶✵ ✸✵ ✷✵ ✸✵ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❊❙◗❯■❙❆ ❙❆▲❊❙ ❙❆▲❊❙ P❊❙◗❯■❙❆ ❙❆▲❊❙ ❙❆▲❊❙ ❆❈❈❖❯◆❚■◆● P❊❙◗❯■❙❆ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ P❊❙◗❯■❙❆ ❙❆▲❊❙ 345 Casa do Código 19.6. Trigger de view ✷✵ ✶✵ ✸✵ ✽✵ ✷✵ P❊❙◗❯■❙❆ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ ❙✫❊ P❊❙◗❯■❙❆ ✶✼ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ ❙◗▲❃ ❞❡❧❡t❡ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✽✵✵✵❀ ❋✉♥❝✐♦♥ár✐♦ ❡①❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✿ ❇❘❯❈❊❲✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ P❊❙◗❯■❙❆ ♥ã♦ ♣♦❞❡ s❡r ❡①❝❧✉í❞♦✳ ❆✐♥❞❛ ❡①✐st❡♠ ❢✉♥❝✐♦♥ár✐♦s ❛❣r❡❣❛❞♦s ❛ ❡❧❡✳ ✶ ❧✐♥❤❛ ❞❡❧❡t❛❞❛✳ ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✸✻✾ ✼✹✾✾ ✼✺✷✶ ✼✺✻✻ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✼✽✽ ✼✽✸✾ ✼✽✹✹ ✼✽✼✻ ✼✾✵✵ ✼✾✵✷ ✼✾✸✹ ✼✾✸✺ ✽✵✵✶ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❙▼■❚❍ ❆▲▲❊◆ ❲❆❘❉ ❏❖◆❊❙ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❙❈❖❚❚ ❑■◆● ❚❯❘◆❊❘ ❆❉❆▼❙ ❏❆▼❊❙ ❋❖❘❉ ▼■▲▲❊❘ P❆❯▲ ❙■▲❱❊❙❚❊❘ ❉❊P❚◆❖ ❉◆❆▼❊ 346 ❏❖❇ ❙❆▲ ▼●❘ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❈▲❊❘❑ ✾✻✽ ✼✾✵✷ ❙❆▲❊❙▼❆◆ ✶✻✵✵ ✼✻✾✽ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✼✻✾✽ ▼❆◆❆●❊❘ ✸✺✾✾✱✼✺ ✼✽✸✾ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✼✻✾✽ ▼❆◆❆●❊❘ ✷✽✺✵ ✼✽✸✾ ▼❆◆❆●❊❘ ✷✹✺✵ ✼✽✸✾ ❆◆❆▲❨❙❚ ✸✻✸✵ ✼✺✻✻ P❘❊❙■❉❊◆❚ ✺✵✵✵ ❙❆▲❊❙▼❆◆ ✶✺✵✵ ✼✻✾✽ ❈▲❊❘❑ ✶✸✸✶ ✼✼✽✽ ❈▲❊❘❑ ✾✺✵ ✼✻✾✽ ❆◆❆▲❨❙❚ ✸✻✸✵ ✼✺✻✻ ❈▲❊❘❑ ✶✸✵✵ ✼✼✽✷ ❙❆▲❊❙▼❆◆ ✶✵✵✵ ✼✻✾✽ ▼❆◆❆●❊❘ ✶✵✵✵ ✼✽✸✾ Casa do Código ✲✲✲✲✲✲✲✲✲✲ ✷✵ ✸✵ ✸✵ ✷✵ ✸✵ ✸✵ ✶✵ ✷✵ ✶✵ ✸✵ ✷✵ ✸✵ ✷✵ ✶✵ ✸✵ ✽✵ Capítulo 19. Triggers ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ P❊❙◗❯■❙❆ ❙❆▲❊❙ ❙❆▲❊❙ P❊❙◗❯■❙❆ ❙❆▲❊❙ ❙❆▲❊❙ ❆❈❈❖❯◆❚■◆● P❊❙◗❯■❙❆ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ P❊❙◗❯■❙❆ ❙❆▲❊❙ P❊❙◗❯■❙❆ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ ❙✫❊ ✶✻ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ ❙◗▲❃ ❞❡❧❡t❡ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✷✵❀ ❋✉♥❝✐♦♥ár✐♦ ❡①❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✿ ❙▼■❚❍✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ P❊❙◗❯■❙❆ ♥ã♦ ♣♦❞❡ s❡r ❡①❝❧✉í❞♦✳ ❢✉♥❝✐♦♥ár✐♦s ❛❣r❡❣❛❞♦s ❛ ❡❧❡✳ ❋✉♥❝✐♦♥ár✐♦ ❡①❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✿ ❏❖◆❊❙✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ P❊❙◗❯■❙❆ ♥ã♦ ♣♦❞❡ s❡r ❡①❝❧✉í❞♦✳ ❢✉♥❝✐♦♥ár✐♦s ❛❣r❡❣❛❞♦s ❛ ❡❧❡✳ ❋✉♥❝✐♦♥ár✐♦ ❡①❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✿ ❙❈❖❚❚✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ P❊❙◗❯■❙❆ ♥ã♦ ♣♦❞❡ s❡r ❡①❝❧✉í❞♦✳ ❢✉♥❝✐♦♥ár✐♦s ❛❣r❡❣❛❞♦s ❛ ❡❧❡✳ ❋✉♥❝✐♦♥ár✐♦ ❡①❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✿ ❆❉❆▼❙✳ ❖ ❞❡♣❛rt❛♠❡♥t♦ P❊❙◗❯■❙❆ ♥ã♦ ♣♦❞❡ s❡r ❡①❝❧✉í❞♦✳ ✉♥❝✐♦♥ár✐♦s ❛❣r❡❣❛❞♦s ❛ ❡❧❡✳ ❋✉♥❝✐♦♥ár✐♦ ❡①❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✿ ❋❖❘❉✳ ❉❡♣❛rt❛♠❡♥t♦ ❡①❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✿ P❊❙◗❯■❙❆✳ ❆✐♥❞❛ ❡①✐st❡♠ ❆✐♥❞❛ ❡①✐st❡♠ ❆✐♥❞❛ ❡①✐st❡♠ ❆✐♥❞❛ ❡①✐st❡♠ ✺ ❧✐♥❤❛s ❞❡❧❡t❛❞❛s✳ 347 Casa do Código 19.6. Trigger de view ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❴❞❡♣t❴✈❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✹✾✾ ✼✺✷✶ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✽✸✾ ✼✽✹✹ ✼✾✵✵ ✼✾✸✹ ✼✾✸✺ ✽✵✵✶ ❊◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲ ❆▲▲❊◆ ❲❆❘❉ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❑■◆● ❚❯❘◆❊❘ ❏❆▼❊❙ ▼■▲▲❊❘ P❆❯▲ ❙■▲❱❊❙❚❊❘ ❏❖❇ ❙❆▲ ▼●❘ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ❙❆▲❊❙▼❆◆ ✶✻✵✵ ✼✻✾✽ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✼✻✾✽ ❙❆▲❊❙▼❆◆ ✶✷✺✵ ✼✻✾✽ ▼❆◆❆●❊❘ ✷✽✺✵ ✼✽✸✾ ▼❆◆❆●❊❘ ✷✹✺✵ ✼✽✸✾ P❘❊❙■❉❊◆❚ ✺✵✵✵ ❙❆▲❊❙▼❆◆ ✶✺✵✵ ✼✻✾✽ ❈▲❊❘❑ ✾✺✵ ✼✻✾✽ ❈▲❊❘❑ ✶✸✵✵ ✼✼✽✷ ❙❆▲❊❙▼❆◆ ✶✵✵✵ ✼✻✾✽ ▼❆◆❆●❊❘ ✶✵✵✵ ✼✽✸✾ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✸✵ ✸✵ ✸✵ ✸✵ ✶✵ ✶✵ ✸✵ ✸✵ ✶✵ ✸✵ ✽✵ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❙❆▲❊❙ ❙❆▲❊❙ ❙❆▲❊❙ ❙❆▲❊❙ ❆❈❈❖❯◆❚■◆● ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ ❙❆▲❊❙ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ ❙✫❊ ✶✶ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ Com isso, encerramos o assunto sobre triggers. Como pôde ser visto, este tipo de objeto é muito interessante e útil para implementar diversos tipos de rotinas que possam ser executadas sem a intervenção direta do usuário e com segurança, o que faz dele um artifício muito poderoso. 348 Capítulo 20 PL/SQL Tables (estruturas homogêneas) Conforme comentamos anteriormente, a PL/SQL contempla em sua estrutura, todos os recursos encontrados em outras linguagens de programação. Um recurso muito bacana é o uso de dados intrínsecos, através das estruturas homogenias, comumente, chamadas de vetor. Em PL/SQL chamamos este recurso de PL/SQL Table. Para quem não conhece vetores, um vetor é uma estrutura array de um tipo definido de dado. Por exemplo, podemos ter um vetor de numéricos, caracteres ou datas. Podemos imaginar um array, ou melhor, um vetor, como se fosse a coluna de uma determinada tabela que possui um tipo definido, que pudesse ser preenchida por vários valores. A diferença entre um e outro é que os vetores são definidos apenas em Casa do Código memória, bem como os dados que são atribuídos a eles. Contudo, como estão em memória, proporcionam uma velocidade maior de acesso aos dados, ao contrário do uso de tabelas, no qual é necessário, na maioria das vezes, acessálos fisicamente no disco. Para utilizarmos uma PL/SQL Table, temos que primeiro defini-la como se fosse um tipo de dado sendo criado, chamado de type. Isso deve ser feito na área de declaração ( declare) do bloco PL/SQL, sendo um bloco anônimo ou através de uma procedure, function ou package. Após a definição do type PL/SQL Table, é necessário declarar uma variável que utilizará esta definição. Vale salientar que inicialmente a definição do type não ocupa espaço na memória, apenas quando declaramos uma variável com base neste type é que isto acontece. Veja o exemplo a seguir. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ t②♣❡ ❞❡♣t♥♦t❛❜ ✐s t❛❜❧❡ ♦❢ ♥✉♠❜❡r ✐♥❞❡① ❜② ❜✐♥❛r②❴✐♥t❡❣❡r❀ ✹ t②♣❡ ❞♥❛♠❡t❛❜ ✐s t❛❜❧❡ ♦❢ ❞❡♣t✳❞♥❛♠❡✪t②♣❡ ✐♥❞❡① ❜② ❜✐♥❛r②❴✐♥t❡❣❡r❀ ✺ t②♣❡ ❧♦❝t❛❜ ✐s t❛❜❧❡ ♦❢ ✈❛r❝❤❛r✷✭✷✵✵✮ ✐♥❞❡① ❜② ❜✐♥❛r②❴✐♥t❡❣❡r❀ ✻ ✲✲ ✼ ✇❞❡♣t♥♦t❛❜ ❞❡♣t♥♦t❛❜❀ ✽ ✇❞♥❛♠❡t❛❜ ❞♥❛♠❡t❛❜❀ ✾ ✇❧♦❝t❛❜ ❧♦❝t❛❜❀ ✶✵ ✲✲ ✶✶ ✐❞① ❜✐♥❛r②❴✐♥t❡❣❡r ❞❡❢❛✉❧t ✵❀ ✶✷ ❜❡❣✐♥ ✶✸ ✲✲ ✶✹ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ❞❡♣t♥♦✱ ❞♥❛♠❡✱ ❧♦❝ ❢r♦♠ ❞❡♣t✮ ❧♦♦♣ ✶✺ ✐❞① ✿❂ ✐❞① ✰ ✶❀ ✶✻ ✇❞❡♣t♥♦t❛❜✭✐❞①✮ ✿❂ r✶✳❞❡♣t♥♦❀ ✶✼ ✇❞♥❛♠❡t❛❜✭✐❞①✮ ✿❂ r✶✳❞♥❛♠❡❀ ✶✽ ✇❧♦❝t❛❜✭✐❞①✮ ✿❂ r✶✳❧♦❝❀ ✶✾ ❡♥❞ ❧♦♦♣❀ ✷✵ ✲✲ ✷✶ ❢♦r ✐ ✐♥ ✶✳✳✇❞❡♣t♥♦t❛❜✳❧❛st ❧♦♦♣ ✷✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤✇❞❡♣t♥♦t❛❜✭✐✮⑤⑤ 350 Casa do Código Capítulo 20. PL/SQL Tables (estruturas homogêneas) ✷✸ ✷✹ ✷✺ ❡♥❞ ❧♦♦♣❀ ✷✻ ❡♥❞❀ ✷✼ ✴ ❉❡♣❛rt❛♠❡♥t♦✿ ❉❡♣❛rt❛♠❡♥t♦✿ ❉❡♣❛rt❛♠❡♥t♦✿ ❉❡♣❛rt❛♠❡♥t♦✿ ❉❡♣❛rt❛♠❡♥t♦✿ ❉❡♣❛rt❛♠❡♥t♦✿ ❉❡♣❛rt❛♠❡♥t♦✿ ❉❡♣❛rt❛♠❡♥t♦✿ ❉❡♣❛rt❛♠❡♥t♦✿ ✶✵ ✸✵ ✹✵ ✽✵ ✾✵ ✾✾ ✽✽ ✹✶ ✹✷ ✬ ✲ ✬⑤⑤✇❞♥❛♠❡t❛❜✭✐✮⑤⑤ ✬ ✲ ▲♦❝❛❧✿ ✬⑤⑤✇❧♦❝t❛❜✭✐✮✮❀ ✲ ✲ ✲ ✲ ✲ ✲ ✲ ✲ ✲ ❆❈❈❖❯◆❚■◆● ✲ ▲♦❝❛❧✿ ❋▲❖❘■❉❆ ❙❆▲❊❙ ✲ ▲♦❝❛❧✿ ❈❍■❈❆●❖ ❖P❊❘❆❚■❖◆❙ ✲ ▲♦❝❛❧✿ ❇❖❙❚❖◆ ❙✫❊ ✲ ▲♦❝❛❧✿ ❋■◆❆◆❈■❆▲ ✲ ▲♦❝❛❧✿ ❘❍ ✲ ▲♦❝❛❧✿ ❆❘●❊◆❚■◆❆ ❘❍ ✲ ▲♦❝❛❧✿ ❆❘●❊◆❚■◆❆ ●❊◆❊❘❆▲ ▲❊❉●❊❘ ✲ ▲♦❝❛❧✿ P❯❘❈❍❆❙■◆● ✲ ▲♦❝❛❧✿ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Pois bem, o exemplo anterior é muito simples. Ele seleciona dados da tabela dept. A intenção aqui não é mostrar exemplos complexos que dificultem o entendimento do assunto. Pelo contrário, utilizamos exemplos simples, focando nos pontos que devemos aprender. Desta forma, analisando o programa, temos nas linhas 3 a 4, três definições de tabela PL/SQL. A definição de uma tabela PL/SQL deve iniciar pelo comando type seguido do nome do tipo que queremos criar. Por exemplo, na linha 3, criamos com o nome deptnotab. Logo após o nome, colocamos a expressão is table of, que vai nos indicar de que tipo será nossa PL/SQL Table, que neste caso definimos que é do tipo number. Depois de informarmos o tipo, devemos utilizar a cláusula index by binary_integer, que é uma cláusula padrão para a criação de PL/SQL Tables. Ela tem a a ver com o tipo de indexação (no caso, binária) usada para a criação da tabela e acesso aos dados na memória. As linhas 4 e 5 seguem o mesmo formato de definição, sendo que uma foi definida com o mesmo tipo da coluna deptno da tabela dept e a outra com o tipo varchar2(200). Veja que, nesse exemplo, a definição do type da 351 Casa do Código tabela PL/SQL é parecida com as definições usadas em variáveis. Nas linhas 7 a 8, estão declaradas variáveis dos tipos criados nas linhas 3 a 5, ou seja, variáveis definidas com o tipo PL/SQL Table. São estas, as variáveis que serão manipuladas em nosso programa. Nas linhas 14 a 19, temos um cursor for loop que lê todas as informações da tabela dept e as armazena em nossas tabelas PL/SQL. Uma observação importante é que, embora neste exemplo tenha sido criado um type de tabela PL/SQL para cada informação (código do departamento, nome do departamento e localização) é possível criar uma tabela PL/SQL usando %rowtype referenciando cursores ou tabelas. Nesses casos, é possível definir um type de tabela PL/SQL constituído por vários arrays, ou melhor, campos, para uma única PL/SQL Table. Note que, dessa forma, a tabela PL/SQL ficará limitada à definição da tabela ou cursor utilizados na declaração. Contudo, neste capítulo, estamos falando de vetores, ou seja, estruturas homogêneas de dados. Assim sendo, como nesse exemplo foram recuperados dados referentes a três colunas da tabela dept, foi preciso definir três tabelas PL/SQL para guardá-los, e assim mantermos os conceitos referentes a vetores. Continuando, conforme pode ser visto nas linhas 16 a 18, a forma de armazenamento precisa ser do tipo indexada para que possamos navegar entre as posições da tabela PL/SQL. Para isso, criamos uma variável chamada idx que será alimentada dentro do loop e servirá como índice de navegação dentro das nossas PL/SQL Tables. Para armazenar determinado valor, informamos o nome da tabela PL/SQL seguido do indexador entre parênteses, conforme pôde ser visto no exemplo (linhas 16 a 18). Seguindo o exemplo, utilizamos outro for loop que lê nossas tabelas PL/SQL e imprime os valores na tela (linhas 21 a 25). Algumas funções estão disponíveis para o type PL/SQL Table. Uma delas é a função last que retorna o último registro preenchido no array. Também temos a função count que retorna a quantidade de registros contidos na tabela. No exemplo, foi utilizada a função last para indicar a posição final do for loop, ou seja, ele deve varrer a tabela PL/SQL da posição 1 até a última posição dela. Repare que usamos o próprio indexador do for loop (i) para navegar pelos valores das tabelas, gravados anteriormente. Como nossas tabelas 352 Casa do Código Capítulo 20. PL/SQL Tables (estruturas homogêneas) foram preenchidas utilizando o mesmo for loop, ou seja, todas possuindo a mesma quantidade de registros, nós utilizamos apenas uma delas para servir como base para sabermos a quantidade exata que deve ser lida pelo cursor for loop. No entanto, através do indexador (i) do cursor, todos os registros de todas as tabelas foram lidos e utilizados na geração da saída feita pelo dbms_output. Veja a figura a seguir para melhor entendimento de como é realizada a gravação e leitura dos dados, usando como base o programa do exemplo. Cursor: gravação da tabela PL/SQL Fig. 20.1: Esquema de gravação de uma PL/SQL Table Cursor: leitura da tabela PL/SQL 353 Casa do Código Fig. 20.2: Esquema de leitura de uma PL/SQL Table Para concluir, seguem dois exemplos onde foram definidas PL/SQL Tables com base em tabelas e cursores. Exemplo utilizando cursor: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ❝✉rs♦r ❝✶ ✐s ✹ s❡❧❡❝t ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ✺ ✱❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✻ ✱❢✐rst❴♥❛♠❡ ✼ ✱❤✐r❡❴❞❛t❡ ✽ ✱s❛❧❛r② ✾ ❢r♦♠ ❞❡♣❛rt♠❡♥ts ❞ ✶✵ ✱❡♠♣❧♦②❡❡s ❡ ✶✶ ✇❤❡r❡ ❞✳♠❛♥❛❣❡r❴✐❞ ❂ ❡✳❡♠♣❧♦②❡❡❴✐❞ ✶✷ ♦r❞❡r ❜② ❞❡♣❛rt♠❡♥t❴♥❛♠❡❀ 354 Casa do Código Capítulo 20. PL/SQL Tables (estruturas homogêneas) ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ ✶✾ ✷✵ ✷✶ ✷✷ ✷✸ ✷✹ ✷✺ ✷✻ ✷✼ ✲✲ t②♣❡ t❛❜ ✐s t❛❜❧❡ ♦❢ ❝✶✪r♦✇t②♣❡ ✐♥❞❡① ❜② ❜✐♥❛r②❴✐♥t❡❣❡r❀ ✲✲ t❜❣❡r❡♥t❡ t❛❜❀ ♥ ♥✉♠❜❡r❀ ✲✲ ❜❡❣✐♥ ❢♦r r✶ ✐♥ ❝✶ ❧♦♦♣ t❜❣❡r❡♥t❡✭r✶✳❞❡♣❛rt♠❡♥t❴✐❞✮ ✿❂ r✶❀ ❡♥❞ ❧♦♦♣❀ ✲✲ ♥ ✿❂ t❜❣❡r❡♥t❡✳❢✐rst❀ ✲✲ ✇❤✐❧❡ ♥ ❁❂ t❜❣❡r❡♥t❡✳❧❛st ❧♦♦♣ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡♣t♦✿ ✬⑤⑤t❜❣❡r❡♥t❡✭♥✮✳❞❡♣❛rt♠❡♥t❴♥❛♠❡⑤⑤✬ ✬⑤⑤ ✬●❡r❡♥t❡✿ ✬⑤⑤t❜❣❡r❡♥t❡✭♥✮✳❢✐rst❴♥❛♠❡⑤⑤✬ ✬⑤⑤ ✷✽ ✬❉t✳ ❆❞♠✐✳✿ ✬⑤⑤t❜❣❡r❡♥t❡✭♥✮✳❤✐r❡❴❞❛t❡⑤⑤✬ ✬⑤⑤ ✷✾ ✸✵ ✬❙❛❧✳✿ ✬⑤⑤t♦❴❝❤❛r✭t❜❣❡r❡♥t❡✭♥✮✳s❛❧❛r②✱ ✬❢♠✩✾✾✾❣✾✾✾❣✾✾✵❞✵✵✬✮✮❀ ✸✶ ♥ ✿❂ t❜❣❡r❡♥t❡✳♥❡①t✭♥✮❀ ✸✷ ❡♥❞ ❧♦♦♣❀ ✸✸ ❡♥❞❀ ✸✹ ✴ ❉❡♣t♦✿ ❆❞♠✐♥✐str❛t✐♦♥ ●❡r❡♥t❡✿ ❏❡♥♥✐❢❡r ❉t✳ ❆❞♠✐✳✿ ✶✼✴✵✾✴✾✼ ❙❛❧✳✿ ✩✹✳✹✵✵✱✵✵ ❉❡♣t♦✿ ▼❛r❦❡t✐♥❣ ●❡r❡♥t❡✿ ▼✐❝❤❛❡❧ ❉t✳ ❆❞♠✐✳✿ ✶✼✴✵✷✴✵✻ ❙❛❧✳✿ ✩✶✸✳✵✵✵✱✵✵ ❉❡♣t♦✿ P✉r❝❤❛s✐♥❣ ●❡r❡♥t❡✿ ❉❡♥ ❉t✳ ❆❞♠✐✳✿ ✵✼✴✶✷✴✵✹ ❙❛❧✳✿ ✩✶✶✳✵✵✵✱✵✵ ❉❡♣t♦✿ ❍✉♠❛♥ ❘❡s♦✉r❝❡s ●❡r❡♥t❡✿ ❙✉s❛♥ ❉t✳ ❆❞♠✐✳✿ ✵✼✴✵✻✴✵✹ ❙❛❧✳✿ ✩✻✳✺✵✵✱✵✵ ❉❡♣t♦✿ ❙❤✐♣♣✐♥❣ ●❡r❡♥t❡✿ ❆❞❛♠ ❉t✳ ❆❞♠✐✳✿ ✶✵✴✵✹✴✵✼ ❙❛❧✳✿ ✩✽✳✷✵✵✱✵✵ ❉❡♣t♦✿ ■❚ ●❡r❡♥t❡✿ ❆❧❡①❛♥❞❡r ❉t✳ ❆❞♠✐✳✿ ✵✸✴✵✶✴✵✵ ❙❛❧✳✿ ✩✾✳✵✵✵✱✵✵ ❉❡♣t♦✿ P✉❜❧✐❝ ❘❡❧❛t✐♦♥s ●❡r❡♥t❡✿ ❍❡r♠❛♥♥ ❉t✳ ❆❞♠✐✳✿ ✵✼✴✵✻✴✵✹ ❙❛❧✳✿ ✩✶✵✳✵✵✵✱✵✵ ❉❡♣t♦✿ ❙❛❧❡s ●❡r❡♥t❡✿ ❏♦❤♥ ❉t✳ ❆❞♠✐✳✿ ✵✶✴✶✵✴✵✻ ❙❛❧✳✿ ✩✶✹✳✵✵✵✱✵✵ ❉❡♣t♦✿ ❊①❡❝✉t✐✈❡ ●❡r❡♥t❡✿ ❙t❡✈❡♥ ❉t✳ ❆❞♠✐✳✿ ✶✼✴✵✻✴✾✼ 355 Casa do Código ❙❛❧✳✿ ✩✷✹✳✵✵✵✱✵✵ ❉❡♣t♦✿ ❋✐♥❛♥❝❡ ●❡r❡♥t❡✿ ◆❛♥❝② ❉t✳ ❆❞♠✐✳✿ ✶✼✴✵✽✴✵✹ ❙❛❧✳✿ ✩✶✷✳✵✵✵✱✵✵ ❉❡♣t♦✿ ❆❝❝♦✉♥t✐♥❣ ●❡r❡♥t❡✿ ❙❤❡❧❧❡② ❉t✳ ❆❞♠✐✳✿ ✵✼✴✵✻✴✵✹ ❙❛❧✳✿ ✩✶✷✳✵✵✵✱✵✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ No exemplo anterior, temos um programa que lê as informações de departamento e seus gerentes. Para tal, criamos um cursor (linhas 3 a 12) que busca cada departamento cadastrado na tabela departments que possua gerente associado na tabela employees. São trazidas pelo cursor as informações: código do departamento, nome do departamento, primeiro nome do gerente do departamento, data de admissão e salário do gerente. Na linha 14, definimos um type PL/SQL Table chamado tab e atribuímos a ele o tipo c1%rowtype. Este tipo consiste em montar a mesma estrutura do cursor c1 para o tipo tab, ou seja, serão criados para a PL/SQL Table os seguintes arrays: department_id, department_name, first_name, hire_date e salary. Nas linhas 20 a 22, encontra-se a abertura do cursor e atribuição dos resultados do mesmo para a tabela PL/SQL tbgerente, que foi declarada como sendo do tipo tab na linha 16 do programa. Note que usamos como indexador o próprio valor do campo department_id, sendo que ele é único para cada linha. Veja também, que atribuímos à PL/SQL Table o array r1. r1 possui os dados de todas as colunas do cursor. Logo, nossa tabela PL/SQL recebe todos estes valores, respeitando a estrutura definida. Na linha 24, temos o uso da função first indicando que queremos que o ponteiro, que indica a posição em que o foco se encontra na PL/SQL Table, volte para a primeira posição. Só para entendimento, cada vez que um dado é carregado em uma linha da PL/SQL Table, o foco permanece nesta linha. Este retorno para a primeira linha da tabela PL/SQL tem a ver com o loop while que temos entre as linhas 26 a 32. No exemplo, com o for loop, nós utilizamos a própria estrutura de repetição para controlar a faixa de início e fim das linhas. 356 Casa do Código Capítulo 20. PL/SQL Tables (estruturas homogêneas) Como agora estamos utilizando o while, nós precisamos controlar isso. Para tanto, testamos a variável N, que recebe a primeira posição do array na linha 24. Logo, estamos solicitando que a estrutura while fique em loop enquanto não chegar a última linha do array. O comando utiliza a função last da tabela PL/SQL. Veja também que, na linha 31, utilizamos a função next para fazer com que o ponteiro vá para a próxima linha da tabela, fazendo sucessivamente com que todas as linhas sejam varridas. Exemplo utilizando tabela ( %rowtype): ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ t②♣❡ ❞❡♣t❛❜ ✐s t❛❜❧❡ ♦❢ ❞❡♣t✪r♦✇t②♣❡ ✐♥❞❡① ❜② ❜✐♥❛r②❴✐♥t❡❣❡r❀ ✹ ✲✲ ✺ ✇❞❡♣t❛❜ ❞❡♣t❛❜❀ ✻ ✲✲ ✼ ✐❞① ❜✐♥❛r②❴✐♥t❡❣❡r ❞❡❢❛✉❧t ✵❀ ✽ ❜❡❣✐♥ ✾ ✲✲ ✶✵ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ✯ ❢r♦♠ ❞❡♣t✮ ❧♦♦♣ ✶✶ ✐❞① ✿❂ ✐❞① ✰ ✶❀ ✶✷ ✇❞❡♣t❛❜✭✐❞①✮ ✿❂ r✶❀ ✶✸ ❡♥❞ ❧♦♦♣❀ ✶✹ ✲✲ ✶✺ ❢♦r ✐ ✐♥ ✶✳✳✇❞❡♣t❛❜✳❧❛st ❧♦♦♣ ✶✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤✇❞❡♣t❛❜✭✐✮✳❞❡♣t♥♦⑤⑤ ✶✼ ✬ ✲ ✬⑤⑤✇❞❡♣t❛❜✭✐✮✳❞♥❛♠❡⑤⑤ ✶✽ ✬ ✲ ▲♦❝❛❧✿ ✬⑤⑤✇❞❡♣t❛❜✭✐✮✳❧♦❝✮❀ ✶✾ ❡♥❞ ❧♦♦♣❀ ✷✵ ❡♥❞❀ ✷✶ ✴ ❉❡♣❛rt❛♠❡♥t♦✿ ✶✵ ✲ ❆❈❈❖❯◆❚■◆● ✲ ▲♦❝❛❧✿ ❋▲❖❘■❉❆ ❉❡♣❛rt❛♠❡♥t♦✿ ✸✵ ✲ ❙❆▲❊❙ ✲ ▲♦❝❛❧✿ ❈❍■❈❆●❖ ❉❡♣❛rt❛♠❡♥t♦✿ ✹✵ ✲ ❖P❊❘❆❚■❖◆❙ ✲ ▲♦❝❛❧✿ ❇❖❙❚❖◆ ❉❡♣❛rt❛♠❡♥t♦✿ ✽✵ ✲ ❙✫❊ ✲ ▲♦❝❛❧✿ ❉❡♣❛rt❛♠❡♥t♦✿ ✾✵ ✲ ❋■◆❆◆❈■❆▲ ✲ ▲♦❝❛❧✿ ❉❡♣❛rt❛♠❡♥t♦✿ ✾✾ ✲ ❘❍ ✲ ▲♦❝❛❧✿ ❆❘●❊◆❚■◆❆ 357 Casa do Código ❉❡♣❛rt❛♠❡♥t♦✿ ✽✽ ✲ ❘❍ ✲ ▲♦❝❛❧✿ ❆❘●❊◆❚■◆❆ ❉❡♣❛rt❛♠❡♥t♦✿ ✹✶ ✲ ●❊◆❊❘❆▲ ▲❊❉●❊❘ ✲ ▲♦❝❛❧✿ ❉❡♣❛rt❛♠❡♥t♦✿ ✹✷ ✲ P❯❘❈❍❆❙■◆● ✲ ▲♦❝❛❧✿ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Esse exemplo é muito semelhante aos demais. A única diferença é a forma como foi criado o type PL/SQL Table. Note que a tabela foi definida como tendo a mesma estrutura da tabela dept. Logo, estamos criando em memória a mesma estrutura da dept que existe fisicamente no banco de dados. 358 Capítulo 21 PL/SQL Records (estruturas heterogêneas) Vimos que em PL/SQL Table trabalhamos com dados intrínsecos através das estruturas homogêneas. Em PL/SQL Records, vamos trabalhar com estruturas heterogêneas. Com PL/SQL Table, estávamos limitados a criar types Table constituídas apenas de um tipo de dado (numérico, caractere ou data), ou utilizando tabelas e cursores, onde, embora, tivéssemos vários campos com tipos de dados diferentes, cada qual possuía seus tipos já definidos, sem a possibilidade de alterarmos conforme a necessidade. Com o recurso de PL/SQL Records, podemos definir tipos e estruturas de dados distintas dentro de um mesmo type, sem precisar criar vários types para cada um, ou sem necessitar associá-los a tabelas ou cursores. Veja o exemplo a seguir: Casa do Código ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ t②♣❡ ❞❡♣r❡❝ ✐s r❡❝♦r❞ ✭ ❞❡♣t♥♦ ♥✉♠❜❡r✭✷✱✵✮ ✹ ✱❞♥❛♠❡ ✈❛r❝❤❛r✷✭✶✹✮ ✺ ✱❧♦❝ ✈❛r❝❤❛r✷✭✶✸✮✮❀ ✻ ✲✲ ✼ ✇❞❡♣r❡❝ ❞❡♣r❡❝❀ ✽ ✲✲ ✾ ❜❡❣✐♥ ✶✵ ✲✲ ✶✶ s❡❧❡❝t ✯ ✶✷ ✐♥t♦ ✇❞❡♣r❡❝ ✶✸ ❢r♦♠ ❞❡♣t ✶✹ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✶✵❀ ✶✺ ✲✲ ✶✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤✇❞❡♣r❡❝✳❞❡♣t♥♦⑤⑤ ✬ ✲ ✬⑤⑤✇❞❡♣r❡❝✳❞♥❛♠❡⑤⑤ ✶✼ ✬ ✲ ▲♦❝❛❧✿ ✬⑤⑤✇❞❡♣r❡❝✳❧♦❝✮❀ ✶✽ ✶✾ ❡♥❞❀ ✷✵ ✴ ❉❡♣❛rt❛♠❡♥t♦✿ ✶✵ ✲ ❆❈❈❖❯◆❚■◆● ✲ ▲♦❝❛❧✿ ❋▲❖❘■❉❆ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Nesse exemplo, começamos pela criação, linha 3, onde informamos a expressão type seguida pelo nome, deprec. Logo após, informamos o tipo do type, is record, que o define como PL/SQL Record. Após isto, entre parênteses, informamos qual a estrutura que este type terá. Aqui, definimos que ele será constituído por três campos, deptno, dname e loc. Desta forma, nos é permitido, através deste type, definir quantos campos quisermos e utilizar tipos diferentes para eles, possibilitando criar uma estrutura heterogênea. Vale salientar que, embora os nomes dos campos sejam semelhantes aos da tabela dept existente no banco de dados, eles não estão referenciandoos. Aqui poderíamos colocar qualquer nome, respeitando apenas as mesmas regras para definição de variáveis. 360 Casa do Código Capítulo 21. PL/SQL Records (estruturas heterogêneas) Depois da criação do type, declaramos uma variável chamada wdeprec que será definida com este tipo (linha 7). Nas linhas 11 a 14, estamos selecionando os dados da tabela dept cujo departamento seja igual a 10. Estamos utilizando a cláusula into, onde os dados vindos do select estão sendo atribuídos ao nosso PL/SQL Record. Nas linhas 16 a 18, temos a impressão do resultado contido em nosso type Record. Veja a imagem a seguir, onde é mostrada de forma simbólica a definição e armazenamento dos dados em memória no PL/SQL Record. Fig. 21.1: Esquema de gravação de um PL/SQL Record Você deve ter notado que não utilizamos estruturas de repetição e que, ao contrário disto, nosso exemplo trouxe apenas uma linha de registro. Pois bem, uma característica do type Record é que ele por si só pode guardar apenas um registro por vez, ao contrário do type Table, no qual podemos inserir várias linhas. Desta forma, na maioria das vezes vemos os types Record sendo utilizados em conjunto com os types Table, sendo que este último nos permite gravar várias linhas. Vamos utilizar o exemplo anterior, agora, trazendo todos os dados da tabela dept e usando o recurso de type Table juntamente com o type Record. 361 Casa do Código ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ t②♣❡ ❞❡♣r❡❝ ✐s r❡❝♦r❞ ✭ ❞❡♣t♥♦ ♥✉♠❜❡r✭✷✱✵✮ ✹ ✱❞♥❛♠❡ ✈❛r❝❤❛r✷✭✶✹✮ ✺ ✱❧♦❝ ✈❛r❝❤❛r✷✭✶✸✮✮❀ ✻ ✲✲ ✼ t②♣❡ ❞❡♣t❛❜ ✐s t❛❜❧❡ ♦❢ ❞❡♣r❡❝ ✐♥❞❡① ❜② ❜✐♥❛r②❴✐♥t❡❣❡r❀ ✽ ✲✲ ✾ ✇❞❡♣t❛❜ ❞❡♣t❛❜❀ ✶✵ ✐❞① ❜✐♥❛r②❴✐♥t❡❣❡r ❞❡❢❛✉❧t ✵❀ ✶✶ ✲✲ ✶✷ ❜❡❣✐♥ ✶✸ ✲✲ ✶✹ ❢♦r r✶ ✐♥ ✭s❡❧❡❝t ✯ ❢r♦♠ ❞❡♣t✮ ❧♦♦♣ ✶✺ ✲✲ ✶✻ ✐❞① ✿❂ ✐❞① ✰ ✶❀ ✶✼ ✇❞❡♣t❛❜✭✐❞①✮ ✿❂ r✶❀ ✶✽ ✲✲ ✶✾ ❡♥❞ ❧♦♦♣❀ ✷✵ ✲✲ ✷✶ ❢♦r ✐ ✐♥ ✶✳✳✇❞❡♣t❛❜✳❧❛st ❧♦♦♣ ✷✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤✇❞❡♣t❛❜✭✐✮✳❞❡♣t♥♦⑤⑤ ✷✸ ✬ ✲ ✬⑤⑤✇❞❡♣t❛❜✭✐✮✳❞♥❛♠❡⑤⑤ ✷✹ ✬ ✲ ▲♦❝❛❧✿ ✬⑤⑤✇❞❡♣t❛❜✭✐✮✳❧♦❝✮❀ ✷✺ ❡♥❞ ❧♦♦♣❀ ✷✻ ❡♥❞❀ ✷✼ ✴ ❉❡♣❛rt❛♠❡♥t♦✿ ✶✵ ✲ ❆❈❈❖❯◆❚■◆● ✲ ▲♦❝❛❧✿ ❋▲❖❘■❉❆ ❉❡♣❛rt❛♠❡♥t♦✿ ✸✵ ✲ ❙❆▲❊❙ ✲ ▲♦❝❛❧✿ ❈❍■❈❆●❖ ❉❡♣❛rt❛♠❡♥t♦✿ ✹✵ ✲ ❖P❊❘❆❚■❖◆❙ ✲ ▲♦❝❛❧✿ ❇❖❙❚❖◆ ❉❡♣❛rt❛♠❡♥t♦✿ ✽✵ ✲ ❙✫❊ ✲ ▲♦❝❛❧✿ ❉❡♣❛rt❛♠❡♥t♦✿ ✾✵ ✲ ❋■◆❆◆❈■❆▲ ✲ ▲♦❝❛❧✿ ❉❡♣❛rt❛♠❡♥t♦✿ ✾✾ ✲ ❘❍ ✲ ▲♦❝❛❧✿ ❆❘●❊◆❚■◆❆ ❉❡♣❛rt❛♠❡♥t♦✿ ✽✽ ✲ ❘❍ ✲ ▲♦❝❛❧✿ ❆❘●❊◆❚■◆❆ ❉❡♣❛rt❛♠❡♥t♦✿ ✹✶ ✲ ●❊◆❊❘❆▲ ▲❊❉●❊❘ ✲ ▲♦❝❛❧✿ ❉❡♣❛rt❛♠❡♥t♦✿ ✹✷ ✲ P❯❘❈❍❆❙■◆● ✲ ▲♦❝❛❧✿ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ 362 Casa do Código Capítulo 21. PL/SQL Records (estruturas heterogêneas) ❙◗▲❃ Conforme mencionado, neste exemplo empregamos o uso de dois recursos em um mesmo programa, para que pudéssemos definir uma estrutura heterogênea e poder armazenar mais de um registro em memória. Vale salientar que os type Tables e Records podem guardar qualquer tipo de dados, não necessariamente, dados vindos de tabelas do banco de dados. Podemos gerar e processar dados dentro de um programa e ir alimentando dentro destes objetos sem ter a necessidade de varrer dados que estão armazenados em tabelas, por exemplo. Mas, voltando ao exemplo, vemos que nas linhas 3 a 5, está criado o type Record deprec, igualmente ao exemplo anterior. Já na linha 7 temos um type Table criado com base no type Record deprec. Dessa forma, é possível termos registros em forma de tabela, podendo armazenar mais de uma linha na PL/SQL Table, conforme a estrutura do PL/SQL Record criado. Veja a seguir a imagem representativa do uso destes recursos juntos. 363 Casa do Código Fig. 21.2: Esquema do uso combinado de PL/SQL Table e PL/SQL Record Ficou visto que a forma de definição e manipulação dos type Tables e Records é bastante semelhante. O entendimento dos conceitos apresentado no capítulo referente a PL/SQL Tables se faz necessário para compreender todo o contexto apresentado nestes dois capítulos. No mais, salientamos que o uso destes recursos pode ajudar e muito na manipulação dos dados, principalmente, em grandes volumes, quando o desempenho pode ser prejudicado, devido a muitos acessos a rede ou ao disco na busca pelas informações. 364 Capítulo 22 Pacote utl_file Um recurso bem interessante e muito utilizado em PL/SQL é a leitura e escrita de arquivos. Em muitas empresas a exportação e importação de arquivos são muito utilizadas para alimentar sistemas paralelos (também chamados de sistemas satélites) ou para gerar informações gerenciais. A possibilidade de extrair informações do sistema e trabalhá-las usando ferramentas específicas para análise é uma prática muito comum. Para este trabalho existe um pacote dentro do Oracle chamado utl_file. Este pacote trabalha com recursos que possibilita a comunicação entre o banco de dados Oracle e o sistema operacional, fazendo com que consigamos ler ou gerar arquivos externamente ao banco de dados. Este pacote possui uma série de funções e procedimentos que são utilizados dentro dos blocos PL/SQL para a geração ou leitura de dados. De forma bem estruturada e clara, é possível não só ler as informações como também Casa do Código trabalhar com elas, alterando-as e formatando-as antes de inseri-las em tabelas ou gravá-las em arquivo. Algumas premissas devem ser observadas antes de utilizar este recurso. A primeira delas é ter privilégio para executar o pacote utl_file. A segunda premissa faz referência a como o utl_file faz a comunicação entre o banco de dados e o sistema operacional, para obter acesso aos diretórios do servidor onde serão gravados ou lidos os arquivos com os dados. O banco de dados Oracle possui uma série de parametrizações que garante seu funcionamento. Estes parâmetros podem ser visualizados através da view v$parameter. Esta view lista todos os parâmetros do banco de dados Oracle. Um destes parâmetros é utl_file_dir, responsável por informar ao utl_file a quais diretórios ele tem acesso no servidor. A partir daí, o pacote utl_file só terá acesso em gravar e ler arquivos nestes diretórios. Esses diretórios não necessitam estar no mesmo servidor do banco de dados, entretanto, através de algum compartilhamento, os dois precisam enxergar um ao outro. As opções de configuração deste parâmetro são: • utl_file_dir=C:\sistema\ERP: indica um diretório específico para a gravação e leitura de arquivos (compatível com sistema Windows). • utl_file_dir=/ora/dat: indica um diretório específico para a gravação e leitura de arquivos (compatível com sistema Unix). • utl_file_dir=C:\sistema\ERP, /ora/dat: indica vários diretórios, separados por vírgula, para a gravação e leitura de arquivos. • utl_file_dir=* : indica que a gravação ou leitura de arquivos pode ser realizada em todos os diretórios disponíveis no servidor. Nota: mesmo que os diretórios já estejam devidamente configurados para o parâmetro utl_file_dir, as permissões de acesso aos diretórios no nível de servidor também precisam ser realizadas. 366 Casa do Código Capítulo 22. Pacote utl_file Contudo, esta configuração em nível de parâmetro de banco de dados é meio inconveniente, pois o DBA para alterar esta definição precisa parar o banco de dados para realizá-la. Nem todos os parâmetros do banco de dados Oracle necessitam uma parada do sistema, mas para o parâmetro utl_file_dir é obrigatório que isto seja feito. Cada vez que o utl_file necessita acessar um diretório diferente é necessário realizar todo este trabalho. Para evitar isto, a partir de versões mais novas do banco de dados a Oracle disponibilizou um recurso chamado directory com o qual é possível criar um objeto no banco de dados e apontá-lo para um diretório do servidor, sem a necessidade de alterarmos isso via parâmetro de banco. Com isto, o trabalho ficou muito mais simples, inclusive, não exige conhecimentos específicos de DBA. Desta forma, antes de tudo, vamos aprender como se cria um objeto directory, para utilizarmos em nossa aplicação utl_file. ❙◗▲❃ ❝r❡❛t❡ ❞✐r❡❝t♦r② ❞✐r❴♣r✐♥❝✐♣❛❧ ❛s ✬❈✿❭t♠♣❭❛rq✉✐✈♦s✬❀ ❉✐r❡tór✐♦ ❝r✐❛❞♦✳ ❙◗▲❃ Usamos o comando create directory para criar um objeto que aponte para o diretório onde queremos gravar ou ler determinados arquivos. Em seguida, informamos um nome para o objeto. Este é o nome que será utilizado dentro dos nossos programas. Seguindo a expressão as vem o caminho referente ao diretório. Para nossos exemplos usaremos este recurso. Além de criamos o objeto, precisamos dar privilégios de acesso aos usuários do banco de dados. Caso queria disponibilizar acesso para todos os usuários do banco, dê privilégios através do usuário public. ❙◗▲❃ ❣r❛♥t r❡❛❞✱ ✇r✐t❡ ♦♥ ❞✐r❡❝t♦r② ❞✐r❴♣r✐♥❝✐♣❛❧ t♦ ❚❙◗▲❀ ❈♦♥❝❡ssã♦ ❜❡♠✲s✉❝❡❞✐❞❛✳ ❙◗▲❃ 367 Casa do Código Atenção: para dar acesso ao objeto directory, é necessário estar conectado com o usuário system, que é o usuário administrador do banco de dados Oracle. Para ver os objetos directory cadastrados, use o comando select: ❙◗▲❃ s❡❧❡❝t ✯ ✷ ❢r♦♠ ❛❧❧❴❞✐r❡❝t♦r✐❡s ✸ ✇❤❡r❡ ❞✐r❡❝t♦r②❴♥❛♠❡ ❂ ✬❉■❘❴P❘■◆❈■P❆▲✬❀ ❖❲◆❊❘ ❉■❘❊❈❚❖❘❨❴◆❆▼❊ ❉■❘❊❈❚❖❘❨❴P❆❚❍ ✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❙❨❙ ❉■❘❴P❘■◆❈■P❆▲ ❈✿❭t♠♣❭❛rq✉✐✈♦s ❙◗▲❃ Para alterar um objeto directory, utilizamos o comando replace. Através dele podemos alterar o caminho do diretório. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ❞✐r❡❝t♦r② ❞✐r❴♣r✐♥❝✐♣❛❧ ❛s ✬❈✿❭t♠♣❭✬❀ ❉✐r❡tór✐♦ ❝r✐❛❞♦✳ ❙◗▲❃ Para dar privilégios de execução do utl_file é necessário estar conectado com o usuário sys. ❙◗▲❃ ❣r❛♥t ❡①❡❝✉t❡ ♦♥ ❯❚▲❴❋■▲❊ t♦ ❚❙◗▲❀ ❈♦♥❝❡ssã♦ ❜❡♠✲s✉❝❡❞✐❞❛✳ ❙◗▲❃ Nota: para conectar com o usuário sys utilize o comando concc sys/<senha>@<string_banco> as sysdba;. 368 Casa do Código Capítulo 22. Pacote utl_file Muito bem. Agora já criamos nosso directory e já concedemos privilégio para o usuário. Vamos colocar a mão na massa. Para trabalhar com arquivos, precisamos conhecer um pouco sobre as funções e procedimentos que fazem parte deste pacote. Além disso, precisamos conhecer as exceções que podem ser geradas em caso de erros. Na sequência, veja funções e procedimentos no uso do utl_file. fclose Fecha o arquivo. Exemplo: ♣r♦❝❡❞✉r❡ ❢❝❧♦s❡✭❢✐❧❡ ✐♥ ♦✉t ❢✐❧❡❴t②♣❡✮❀ Onde: file é o nome do arquivo lido ou gerado. fclose_all Fecha todos os arquivos. Exemplo: ♣r♦❝❡❞✉r❡ ❢❝❧♦s❡❴❛❧❧❀ Neste caso todos os arquivos aberto serão fechados. fflush Descarrega todos os dados em buffer para serem gravados em disco imediatamente. Exemplo: ♣r♦❝❡❞✉r❡ ❢❢❧✉s❤✭❢✐❧❡ ✐♥ ❢✐❧❡❴t②♣❡✮❀ Onde: file é o nome do arquivo lido ou gerado. fopen Abre o arquivo. Exemplo: ❢✉♥❝t✐♦♥ ❢♦♣❡♥✭❧♦❝❛t✐♦♥ ✐♥ ✈❛r❝❤❛r✷✱ ❢✐❧❡♥❛♠❡ ✐♥ ✈❛r❝❤❛r✷✱ ♦♣❡♥♠♦❞❡ ✐♥ ✈❛r❝❤❛r✷✮ r❡t✉r♥ ❢✐❧❡❴t②♣❡❀✪✪ 369 Casa do Código Onde: location é o nome do diretório onde se encontra o arquivo ou onde o arquivo deve ser gerado. filename é o nome do arquivo a ser lido ou gerado. openmode indica qual modo deve ser aplicado no arquivo. R = Read (ler), W = Write (escrever) ou A = Append (adicionar). ❢✉♥❝t✐♦♥ ❢♦♣❡♥✭❧♦❝❛t✐♦♥ ✐♥ ✈❛r❝❤❛r✷✱ ❢✐❧❡♥❛♠❡ ✐♥ ✈❛r❝❤❛r✷✱ ♦♣❡♥♠♦❞❡ ✐♥ ✈❛r❝❤❛r✷✱ ♠❛①❴❧✐♥❡s✐③❡ ✐♥ ❜✐♥❛r②❴✐♥t❡❣❡r✮ r❡t✉r♥ ❢✐❧❡❴t②♣❡❀ Onde: location é o nome do diretório onde se encontra o arquivo ou onde o arquivo deve ser gerado. filename nome do arquivo a ser lido ou gerado. openmode indica qual modo deve ser aplicado no arquivo. R = Read (ler), W = Write (escrever) ou A = Append (adicionar). max_linesize permite especificar o tamanho máximo de linha. O intervalo permitido é de 1 até 32.767. Se você omitir esse parâmetro, o padrão 1.023 é usado. get_line Lê uma linha de um arquivo. Exemplo: ♣r♦❝❡❞✉r❡ ❣❡t❴❧✐♥❡✭❢✐❧❡ ✐♥ ❢✐❧❡❴t②♣❡✱ ❜✉❢❢❡r ♦✉t ✈❛r❝❤❛r✷✮❀ Onde: file é o nome do arquivo onde a linha deve ser lida. buffer é o lugar onde o conteúdo lido da linha deve ser inserido. is_open Verifica se um arquivo está aberto. Exemplo: ♣r♦❝❡❞✉r❡ ✐s❴♦♣❡♥✭❢✐❧❡ ✐♥ ❢✐❧❡❴t②♣❡✮ r❡t✉r♥ ❜♦♦❧❡❛♥❀ Onde: file é o nome do arquivo que deve ser verificado. new_line Grava um caractere newline em um arquivo. Exemplo: 370 Casa do Código Capítulo 22. Pacote utl_file ♣r♦❝❡❞✉r❡ ♥❡✇❴❧✐♥❡✭❢✐❧❡ ✐♥ ❢✐❧❡❴t②♣❡✱ ❧✐♥❡s ✐♥ ♥❛t✉r❛❧ ✿❂ ✶✮❀ Onde: file é o nome do arquivo que deve receber a nova linha. lines é o número total de caracteres newline que você quer gravar no arquivo. O padrão é gravar uma newline nova. Este argumento é opcional. put Grava uma string de caracteres em um arquivo, mas não coloca uma newline depois dela. Exemplo: ♣r♦❝❡❞✉r❡ ♣✉t✭❢✐❧❡ ✐♥ ❢✐❧❡❴t②♣❡✱ ❜✉❢❢❡r ✐♥ ✈❛r❝❤❛r✷✮❀ Onde: file é o nome do arquivo que deve receber o conteúdo. buffer é o conteúdo a ser gravado no arquivo. put_line Grava uma linha em um arquivo. Exemplo: ♣r♦❝❡❞✉r❡ ♣✉t❴❧✐♥❡✭❢✐❧❡ ✐♥ ❢✐❧❡❴t②♣❡✱ ❜✉❢❢❡r ✐♥ ✈❛r❝❤❛r✷✮❀ Onde: file é o nome do arquivo que deve receber o conteúdo. buffer contém o texto que você deseja gravar no arquivo. O número máximo de caracteres que você pode gravar usando uma chamada se limita ao tamanho de linha que você especificou na chamada de fopen e tem como padrão 1.023. putf Formata e grava saída. Essa é uma imitação bruta do procedimento PRINTF() do C. Exemplo: ♣r♦❝❡❞✉r❡ ♣✉t❢✭❢✐❧❡ ✐♥ ❢✐❧❡❴t②♣❡✱ ❢♦r♠❛t ✐♥ ✈❛r❝❤❛r✷✱ ❛r❣✶ ✐♥ ✈❛r❝❤❛r✷ ❞❡❢❛✉❧t ♥✉❧❧✱ ❛r❣✷ ✐♥ ✈❛r❝❤❛r✷ ❞❡❢❛✉❧t ♥✉❧❧✱ 371 Casa do Código ❛r❣✸ ✐♥ ✈❛r❝❤❛r✷ ❞❡❢❛✉❧t ♥✉❧❧✱ ❛r❣✹ ✐♥ ✈❛r❝❤❛r✷ ❞❡❢❛✉❧t ♥✉❧❧✱ ❛r❣✺ ✐♥ ✈❛r❝❤❛r✷ ❞❡❢❛✉❧t ♥✉❧❧✮❀ Onde: file é o nome do arquivo que receberá o conteúdo. format representa a string que você deseja gravar no arquivo. arg1 ao arg5 são argumentos opcionais contendo os valores que são substituídos na string de formato antes dela ser gravada no arquivo. Exceções de fclose e fclose_all • utl_file.invalid_filehandle: você passou um handle de arquivo que não representava um arquivo aberto. • utl_file.write_error: o sistema operacional não pode gravar no arquivo. • utl_file.internal_error: um erro interno ocorreu. Exceções de fopen • utl_file.invalid_path: o diretório não é válido. Você deve verificar em utl_file_dir. • utl_file.invalid_mode: um modo inválido foi especificado. O modo open deve ser R, W ou A. • utl_file.invalid_operation: o arquivo não pode ser aberto por algum outro motivo. Verifique se o proprietário do software do Oracle tem acesso ao diretório (isso pode ser uma questão de permissão) e entre em contato com o administrador do seu banco de dados para obter ajuda. • utl_file.internal_error: um erro interno ocorreu. 372 Casa do Código Capítulo 22. Pacote utl_file Exceções de get_line • utl_file.invalid_filehandle: você passou handle de arquivo inválido. Possivelmente você esqueceu de abrir o arquivo primeiro. • utl_file.invalid_operation: o arquivo não está aberto para leitura (modo R), ou existem problemas com as permissões de arquivo. • utl_file.value_error: o buffer não é suficientemente longo para conter a linha que está sendo lida do arquivo. O tamanho do buffer é aumentado. • utl_file.no_data_found: o final do arquivo foi atingido. • utl_file.internal_error: ocorreu um erro interno do sistema utl_file. • utl_file.read_error: ocorreu um erro do sistema operacional durante a leitura do arquivo. Exceções de put, put_line, putf e fflush • utl_file.invalid_filehandle: você usou um handle de arquivo inválido. Essa exceção pode ser levantada quando você esquecer de abrir o arquivo. • utl_file.invalid_operation: você tentou gravar em um arquivo que não estava aberto para gravação (modo W ou A). • utl_file.write_error: ocorreu um erro de sistema operacional, tal como um erro de disco cheio, ao tentar gravar em um arquivo. • utl_file.internal_error: ocorreu um erro interno. Agora vamos ver um exemplo onde vamos ler os registros da tabela emp e dept e gerar um arquivo para ser gravado no diretório definido em nosso directory. Vamos gravar as informações no arquivo de forma linear e separando as informações por ponto e vírgula. 373 Casa do Código ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ❝✉rs♦r ❝✶ ✐s ✸ s❡❧❡❝t ❛✳❞❡♣t♥♦✱ ❞♥❛♠❡✱ ❡♠♣♥♦✱ ❡♥❛♠❡ ✹ ❢r♦♠ ❞❡♣t ❛ ✺ ✱❡♠♣ ❜ ✻ ✇❤❡r❡ ❛✳❞❡♣t♥♦ ❂ ❜✳❞❡♣t♥♦ ✼ ♦r❞❡r ❜② ❛✳❞❡♣t♥♦❀ ✽ r✶ ❝✶✪r♦✇t②♣❡❀ ✾ ✲✲ ✶✵ ♠❡✉❴❛rq✉✐✈♦ ✉t❧❴❢✐❧❡✳❢✐❧❡❴t②♣❡❀ ✶✶ ✲✲ ✶✷ ❇❊●■◆ ✶✸ ✲✲ ✶✹ ♠❡✉❴❛rq✉✐✈♦ ✿❂ ✉t❧❴❢✐❧❡✳❢♦♣❡♥✭✬❉■❘❴P❘■◆❈■P❆▲✬✱ ✬❡♠♣r❡❣❛❞♦s✳t①t✬✱ ✬✇✬✮❀ ✶✺ ✲✲ ✶✻ ♦♣❡♥ ❝✶❀ ✶✼ ✲✲ ✶✽ ❧♦♦♣ ✶✾ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✷✵ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✷✶ ✉t❧❴❢✐❧❡✳♣✉t❴❧✐♥❡✭♠❡✉❴❛rq✉✐✈♦✱ r✶✳❞❡♣t♥♦⑤⑤✬❀✬⑤⑤ r✶✳❞♥❛♠❡⑤⑤✬❀✬⑤⑤ ✷✷ ✷✸ r✶✳❡♠♣♥♦⑤⑤✬❀✬⑤⑤ ✷✹ r✶✳❡♥❛♠❡✮❀ ✷✺ ❡♥❞ ❧♦♦♣❀ ✷✻ ✲✲ ✷✼ ❝❧♦s❡ ❝✶❀ ✷✽ ✲✲ ✷✾ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✸✵ ✲✲ ✸✶ ❡①❝❡♣t✐♦♥ ✸✷ ✇❤❡♥ ✉t❧❴❢✐❧❡✳✐♥✈❛❧✐❞❴♣❛t❤ t❤❡♥ ✸✸ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✸✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬❈❛♠✐♥❤♦ ♦✉ ♥♦♠❡ ❞♦ ❛rq✉✐✈♦ ✐♥✈á❧✐❞♦✬✮❀ ✸✺ ✇❤❡♥ ✉t❧❴❢✐❧❡✳✐♥✈❛❧✐❞❴♠♦❞❡ t❤❡♥ ✸✻ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✸✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬▼♦❞♦ ❞❡ ❛❜❡rt✉r❛ ✐♥✈á❧✐❞♦✬✮❀ 374 Casa do Código Capítulo 22. Pacote utl_file ✸✽ ❡♥❞❀ ✸✾ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Analisando o programa, vemos que na linha 10 declaramos uma variável do tipo utl_file.file_type que vai ser o ponteiro (handle) para o nosso arquivo físico. Quando isso é feito, o Oracle monta uma estrutura de arquivo em memória referente ao arquivo físico com que iremos trabalhar. Já na linha 14, atribuímos à variável declarada à abertura do arquivo passando como parâmetro o directory criado anteriormente, que faz referência ao local do diretório onde o arquivo deve ser gravado, o nome do arquivo e, por último, o modo, que neste caso é modo de escrita, representado por W. Quando executamos um fopen utilizando o modo escrita, caso não exista o arquivo ele o cria. Na linha 21, utilizamos a chamada put_line para inserir linhas ao arquivo. Neste caso, estamos concatenando uma série de informações vindas das tabelas emp e dept e enviando para o arquivo. Após o termino da leitura das tabelas, ou seja, no final do cursor, fechamos o arquivo na linha 29. Note que entre as linhas 31 a 37 estão tratadas as possíveis exceções relacionadas ao pacote utl_file. Segue o resultado: 375 Casa do Código Fig. 22.1: Arquivo gerado através do pacote utl_file Após termos visto o programa que gera as informações e as joga em um arquivo, vamos ver a contrapartida onde lemos o arquivo gerado e mostramos as informações na tela. 376 Casa do Código Capítulo 22. Pacote utl_file ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ♠❡✉❴❛rq✉✐✈♦ ✉t❧❴❢✐❧❡✳❢✐❧❡❴t②♣❡❀ ✹ ❧✐♥❤❛ ✈❛r❝❤❛r✷✭✸✷✵✵✵✮❀ ✺ ✲✲ ✻ ✇❞❡♣t♥♦ ❡♠♣✳❞❡♣t♥♦✪t②♣❡❀ ✼ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✽ ✇❡♠♣♥♦ ❡♠♣✳❡♠♣♥♦✪t②♣❡❀ ✾ ✇❡♥❛♠❡ ❡♠♣✳❡♥❛♠❡✪t②♣❡❀ ✶✵ ✲✲ ✶✶ ❜❡❣✐♥ ✶✷ ✲✲ ✶✸ ♠❡✉❴❛rq✉✐✈♦ ✿❂ ✉t❧❴❢✐❧❡✳❢♦♣❡♥✭✬❉■❘❴P❘■◆❈■P❆▲✬✱ ✬❡♠♣r❡❣❛❞♦s✳t①t✬✱ ✬r✬✮❀ ✶✹ ✲✲ ✶✺ ❧♦♦♣ ✶✻ ✲✲ ✶✼ ✉t❧❴❢✐❧❡✳❣❡t❴❧✐♥❡✭♠❡✉❴❛rq✉✐✈♦✱❧✐♥❤❛✮❀ ✶✽ ✲✲ ✶✾ ❡①✐t ✇❤❡♥ ❧✐♥❤❛ ✐s ♥✉❧❧❀ ✷✵ ✲✲ ✷✶ ✇❞❡♣t♥♦ ✿❂ rtr✐♠✭s✉❜str✭❧✐♥❤❛✱✶✱✭✐♥str✭❧✐♥❤❛✱✬❀✬✱✶✱✶✮ ✲✶✮✮✮❀ ✷✷ ✷✸ ✇❞♥❛♠❡ ✿❂ rtr✐♠✭s✉❜str✭❧✐♥❤❛✱✭✐♥str✭❧✐♥❤❛✱✬❀✬✱✶✱✶✮ ✰ ✶✮ ✷✹ ✱✭✐♥str✭❧✐♥❤❛✱✬❀✬✱✶✱✷✮ ✲✶✮ ✲ ✷✺ ✭✐♥str✭❧✐♥❤❛✱✬❀✬✱✶✱✶✮ ✰ ✭✶ ✲✶✮✮✮✮❀ ✷✻ ✇❡♠♣♥♦ ✿❂ ✷✼ rtr✐♠✭s✉❜str✭❧✐♥❤❛✱✭✐♥str✭❧✐♥❤❛✱✬❀✬✱✶✱✷✮ ✰ ✶✮ ✷✽ ✱✭✐♥str✭❧✐♥❤❛✱✬❀✬✱✶✱✸✮ ✲✶✮ ✲ ✷✾ ✭✐♥str✭❧✐♥❤❛✱✬❀✬✱✶✱✷✮ ✰ ✭✶ ✲✶✮✮✮✮❀ ✸✵ ✇❡♥❛♠❡ ✿❂ rtr✐♠✭rtr✐♠✭s✉❜str✭❧✐♥❤❛✱✭ ✸✶ ✐♥str✭❧✐♥❤❛✱✬❀✬✱✶✱✸✮ ✰ ✶✮✮✱❝❤r✭✶✸✮✮✮❀ ✸✷ ✲✲ ✸✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈ó❞✳ ❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤✇❞❡♣t♥♦✮❀ ✸✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡ ❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤✇❞♥❛♠❡✮❀ 377 Casa do Código ✸✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈ó❞✳ ❊♠♣r❡❣❛❞♦✿ ✬⑤⑤✇❡♠♣♥♦✮❀ ✸✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡ ❊♠♣r❡❣❛❞♦✿ ✬⑤⑤✇❡♥❛♠❡✮❀ ✸✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❴✬✮❀ ✸✽ ✲✲ ✸✾ ❡♥❞ ❧♦♦♣❀ ✹✵ ✲✲ ✹✶ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✹✷ ✲✲ ✹✸ ❡①❝❡♣t✐♦♥ ✹✹ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✹✺ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✹✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬❋✐♥❛❧ ❞♦ ❆rq✉✐✈♦✳✬✮❀ ✹✼ ✇❤❡♥ ✉t❧❴❢✐❧❡✳✐♥✈❛❧✐❞❴♣❛t❤ t❤❡♥ ✹✽ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✹✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬❈❛♠✐♥❤♦ ♦✉ ♥♦♠❡ ❞♦ ❛rq✉✐✈♦ ✐♥✈á❧✐❞♦✬✮❀ ✺✵ ✇❤❡♥ ✉t❧❴❢✐❧❡✳✐♥✈❛❧✐❞❴♠♦❞❡ t❤❡♥ ✺✶ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✺✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬▼♦❞♦ ❞❡ ❛❜❡rt✉r❛ ✐♥✈á❧✐❞♦✬✮❀ ✺✸ ❡♥❞❀ ✺✹ ✴ Vamos analisar o código do programa. Na linha 3, declaramos uma variável do tipo utl_file.file_type que vai ser o ponteiro para o nosso arquivo físico. Na linha criamos uma variável chamada linha que receberá os dados de cada linha vinda do arquivo. Abrimos o arquivo através da função fopen utilizando o modo R (leitura). Já na linha 17, utilizamos a chamada de procedimento get_lines que lê uma linha (a primeira) do arquivo e guarda seu valor dentro da variável linha. Neste caso, ele busca todo o conteúdo da linha e joga dentro da variável, ou seja, todos os valores da linha concatenados por ponto e vírgula. Na linha 19, temos o seguinte código exit when linha is null. Conforme visto nas exceções, vimos que ao chegar ao final de um arquivo a exceção no_data_found é acionada, ou seja, quando não houver mais linhas para ler, é gerada uma exceção informando que não há mais linhas para serem lidas no arquivo. Contudo, dependendo o sistema operacional e/ou da codificação do arquivo gerado, pode acontecer, no caso de termos 378 Casa do Código Capítulo 22. Pacote utl_file um caractere enter no final do arquivo, de o utl_file ler este caractere e considerá-lo como uma linha. Caso o programa não esteja tratando esta situação, erros podem ocorrer. Desta forma, a linha 19 serve para tratar este tipo de situação. Caso a exceção no_data_found não for acionada, esta cláusula garante a saída do loop. Mas atenção: isso serve para arquivos que não estejam considerando linhas em branco em sua estrutura. Caso linhas em branco façam parte da formatação dos dados, esta linha não deve ser colocada. Depois, nas linhas 21 a 31 utilizamos as funções substr e instr para separar os dados, tendo como base o caractere ponto e vírgula. Finalizamos a leitura do arquivo na linha 41. Note que neste exemplo tratamos a exceção no_data_found, na linha 44. Veja o resultado. ❈ó❞✳ ◆♦♠❡ ❈ó❞✳ ◆♦♠❡ ❴ ❈ó❞✳ ◆♦♠❡ ❈ó❞✳ ◆♦♠❡ ❴ ❈ó❞✳ ◆♦♠❡ ❈ó❞✳ ◆♦♠❡ ❴ ❈ó❞✳ ◆♦♠❡ ❈ó❞✳ ◆♦♠❡ ❴ ❈ó❞✳ ◆♦♠❡ ❈ó❞✳ ◆♦♠❡ ❉❡♣❛rt❛♠❡♥t♦✿ ✶✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❊♠♣r❡❣❛❞♦✿ ✼✼✽✷ ❊♠♣r❡❣❛❞♦✿ ❈▲❆❘❑ ❉❡♣❛rt❛♠❡♥t♦✿ ✶✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❊♠♣r❡❣❛❞♦✿ ✼✾✸✹ ❊♠♣r❡❣❛❞♦✿ ▼■▲▲❊❘ ❉❡♣❛rt❛♠❡♥t♦✿ ✶✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❊♠♣r❡❣❛❞♦✿ ✼✽✸✾ ❊♠♣r❡❣❛❞♦✿ ❑■◆● ❉❡♣❛rt❛♠❡♥t♦✿ ✸✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❊♠♣r❡❣❛❞♦✿ ✼✻✾✽ ❊♠♣r❡❣❛❞♦✿ ❇▲❆❑❊ ❉❡♣❛rt❛♠❡♥t♦✿ ✸✵ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❊♠♣r❡❣❛❞♦✿ ✼✾✸✺ ❊♠♣r❡❣❛❞♦✿ P❆❯▲ 379 Casa do Código ❴ ❈ó❞✳ ❉❡♣❛rt❛♠❡♥t♦✿ ✸✵ ◆♦♠❡ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❈ó❞✳ ❊♠♣r❡❣❛❞♦✿ ✼✾✵✵ ◆♦♠❡ ❊♠♣r❡❣❛❞♦✿ ❏❆▼❊❙ ❴ ❈ó❞✳ ❉❡♣❛rt❛♠❡♥t♦✿ ✸✵ ◆♦♠❡ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❈ó❞✳ ❊♠♣r❡❣❛❞♦✿ ✼✽✹✹ ◆♦♠❡ ❊♠♣r❡❣❛❞♦✿ ❚❯❘◆❊❘ ❴ ❈ó❞✳ ❉❡♣❛rt❛♠❡♥t♦✿ ✸✵ ◆♦♠❡ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❈ó❞✳ ❊♠♣r❡❣❛❞♦✿ ✼✻✺✹ ◆♦♠❡ ❊♠♣r❡❣❛❞♦✿ ▼❆❘❚■◆ ❴ ❈ó❞✳ ❉❡♣❛rt❛♠❡♥t♦✿ ✸✵ ◆♦♠❡ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❈ó❞✳ ❊♠♣r❡❣❛❞♦✿ ✼✺✷✶ ◆♦♠❡ ❊♠♣r❡❣❛❞♦✿ ❲❆❘❉ ❴ ❈ó❞✳ ❉❡♣❛rt❛♠❡♥t♦✿ ✸✵ ◆♦♠❡ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ❈ó❞✳ ❊♠♣r❡❣❛❞♦✿ ✼✹✾✾ ◆♦♠❡ ❊♠♣r❡❣❛❞♦✿ ❆▲▲❊◆ ❴ ❋✐♥❛❧ ❞♦ ❆rq✉✐✈♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Por curiosidade, vamos apresentar o mesmo exemplo de geração e leitura de arquivo utilizando a separação de informação não por ponto e vírgula, mas sim, por número de caracteres fixos. Este método visa termos número fixos para o tamanho das colunas. Vale lembrar que não muda em nada a forma de utilizar o pacote utl_file. É apenas para mostrar uma forma diferente, porém muito utilizada, de gerar layouts diferentes para arquivos textos 380 Casa do Código Capítulo 22. Pacote utl_file Geração do arquivo: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ❝✉rs♦r ❝✶ ✐s ✸ s❡❧❡❝t ❛✳❞❡♣t♥♦✱ ❞♥❛♠❡✱ ❡♠♣♥♦✱ ❡♥❛♠❡ ✹ ❢r♦♠ ❞❡♣t ❛ ✺ ✱❡♠♣ ❜ ✻ ✇❤❡r❡ ❛✳❞❡♣t♥♦ ❂ ❜✳❞❡♣t♥♦ ✼ ♦r❞❡r ❜② ❛✳❞❡♣t♥♦❀ ✽ r✶ ❝✶✪r♦✇t②♣❡❀ ✾ ✲✲ ✶✵ ♠❡✉❴❛rq✉✐✈♦ ✉t❧❴❢✐❧❡✳❢✐❧❡❴t②♣❡❀ ✶✶ ✲✲ ✶✷ ❇❊●■◆ ✶✸ ✲✲ ✶✹ ♠❡✉❴❛rq✉✐✈♦ ✿❂ ✉t❧❴❢✐❧❡✳❢♦♣❡♥✭✬❉■❘❴P❘■◆❈■P❆▲✬✱ ✬❡♠♣r❡❣❛❞♦s✳t①t✬✱ ✬✇✬✮❀ ✶✺ ✲✲ ✶✻ ♦♣❡♥ ❝✶❀ ✶✼ ✲✲ ✶✽ ❧♦♦♣ ✶✾ ❢❡t❝❤ ❝✶ ✐♥t♦ r✶❀ ✷✵ ❡①✐t ✇❤❡♥ ❝✶✪♥♦t❢♦✉♥❞❀ ✷✶ ✉t❧❴❢✐❧❡✳♣✉t❴❧✐♥❡✭♠❡✉❴❛rq✉✐✈♦✱ r♣❛❞✭r✶✳❞❡♣t♥♦✱✷✱✬ ✬✮ ⑤⑤ r♣❛❞✭r✶✳❞♥❛♠❡✱✶✹✱✬ ✬✮ ⑤⑤ ✷✷ ✷✸ r♣❛❞✭r✶✳❡♠♣♥♦✱✹✱✬ ✬✮ ⑤⑤ r♣❛❞✭r✶✳❡♥❛♠❡✱✶✵✱✬ ✬✮ ✷✹ ✷✺ ✮❀ ✷✻ ❡♥❞ ❧♦♦♣❀ ✷✼ ✲✲ ✷✽ ❝❧♦s❡ ❝✶❀ ✷✾ ✲✲ ✸✵ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✸✶ ✲✲ ✸✷ ❡①❝❡♣t✐♦♥ ✸✸ ✇❤❡♥ ✉t❧❴❢✐❧❡✳✐♥✈❛❧✐❞❴♣❛t❤ t❤❡♥ ✸✹ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✸✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬❈❛♠✐♥❤♦ ♦✉ ♥♦♠❡ ❞♦ ❛rq✉✐✈♦ ✐♥✈á❧✐❞♦✬✮❀ 381 Casa do Código ✸✻ ✸✼ ✸✽ ✸✾ ✹✵ ✇❤❡♥ ✉t❧❴❢✐❧❡✳✐♥✈❛❧✐❞❴♠♦❞❡ t❤❡♥ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬▼♦❞♦ ❞❡ ❛❜❡rt✉r❛ ✐♥✈á❧✐❞♦✬✮❀ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Leitura do arquivo: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ♠❡✉❴❛rq✉✐✈♦ ✉t❧❴❢✐❧❡✳❢✐❧❡❴t②♣❡❀ ✹ ❧✐♥❤❛ ✈❛r❝❤❛r✷✭✸✷✵✵✵✮❀ ✺ ✲✲ ✻ ✇❞❡♣t♥♦ ❡♠♣✳❞❡♣t♥♦✪t②♣❡❀ ✼ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✽ ✇❡♠♣♥♦ ❡♠♣✳❡♠♣♥♦✪t②♣❡❀ ✾ ✇❡♥❛♠❡ ❡♠♣✳❡♥❛♠❡✪t②♣❡❀ ✶✵ ✲✲ ✶✶ ❜❡❣✐♥ ✶✷ ✲✲ ✶✸ ♠❡✉❴❛rq✉✐✈♦ ✿❂ ✉t❧❴❢✐❧❡✳❢♦♣❡♥✭✬❉■❘❴P❘■◆❈■P❆▲✬✱ ✬❡♠♣r❡❣❛❞♦s✳t①t✬✱ ✬r✬✮❀ ✶✹ ✲✲ ✶✺ ❧♦♦♣ ✶✻ ✲✲ ✶✼ ✉t❧❴❢✐❧❡✳❣❡t❴❧✐♥❡✭♠❡✉❴❛rq✉✐✈♦✱❧✐♥❤❛✮❀ ✶✽ ✲✲ ✶✾ ❡①✐t ✇❤❡♥ ❧✐♥❤❛ ✐s ♥✉❧❧❀ ✷✵ ✲✲ ✷✶ ✇❞❡♣t♥♦ ✿❂ rtr✐♠✭❧tr✐♠✭s✉❜str✭❧✐♥❤❛✱✶✱✷✮✮✮❀ ✷✷ ✇❞♥❛♠❡ ✿❂ rtr✐♠✭❧tr✐♠✭s✉❜str✭❧✐♥❤❛✱✸✱✶✹✮✮✮❀ ✷✸ ✇❡♠♣♥♦ ✿❂ rtr✐♠✭❧tr✐♠✭s✉❜str✭❧✐♥❤❛✱✶✼✱✹✮✮✮❀ ✷✹ ✇❡♥❛♠❡ ✿❂ rtr✐♠✭❧tr✐♠✭s✉❜str✭❧✐♥❤❛✱✷✶✱✶✵✮✮✮❀ ✷✺ ✲✲ ✷✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈ó❞✳ ❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤✇❞❡♣t♥♦✮❀ ✷✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡ ❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤✇❞♥❛♠❡✮❀ 382 Casa do Código Capítulo 22. Pacote utl_file ✷✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈ó❞✳ ❊♠♣r❡❣❛❞♦✿ ✬⑤⑤✇❡♠♣♥♦✮❀ ✷✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬◆♦♠❡ ❊♠♣r❡❣❛❞♦✿ ✬⑤⑤✇❡♥❛♠❡✮❀ ✸✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❴✬✮❀ ✸✶ ✲✲ ✸✷ ❡♥❞ ❧♦♦♣❀ ✸✸ ✲✲ ✸✹ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✸✺ ✲✲ ✸✻ ❡①❝❡♣t✐♦♥ ✸✼ ✇❤❡♥ ♥♦❴❞❛t❛❴❢♦✉♥❞ t❤❡♥ ✸✽ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✸✾ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬❋✐♥❛❧ ❞♦ ❆rq✉✐✈♦✳✬✮❀ ✹✵ ✇❤❡♥ ✉t❧❴❢✐❧❡✳✐♥✈❛❧✐❞❴♣❛t❤ t❤❡♥ ✹✶ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✹✷ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭ ✬❈❛♠✐♥❤♦ ♦✉ ♥♦♠❡ ❞♦ ❛rq✉✐✈♦ ✐♥✈á❧✐❞♦✬✮❀ ✹✸ ✇❤❡♥ ✉t❧❴❢✐❧❡✳✐♥✈❛❧✐❞❴♠♦❞❡ t❤❡♥ ✹✹ ✉t❧❴❢✐❧❡✳❢❝❧♦s❡✭♠❡✉❴❛rq✉✐✈♦✮❀ ✹✺ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡ ✭✬▼♦❞♦ ❞❡ ❛❜❡rt✉r❛ ✐♥✈á❧✐❞♦✬✮❀ ✹✻ ❡♥❞❀ ✹✼ ✴ ❈ó❞✳ ❉❡♣❛rt❛♠❡♥t♦✿ ✶✵ ◆♦♠❡ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ❈ó❞✳ ❊♠♣r❡❣❛❞♦✿ ✼✼✽✷ ◆♦♠❡ ❊♠♣r❡❣❛❞♦✿ ❈▲❆❘❑ ✳✳✳✳ ❴ ❋✐♥❛❧ ❞♦ ❆rq✉✐✈♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Conforme pôde ser visto nesse exemplo, a leitura toma como base, posições fixas que indicam a localização exata de cada informação na linha, extraindo-as. 383 Capítulo 23 SQL dinâmico Na maioria das vezes, trabalharemos com comandos SQL previamente definidos dentro de nossos programas. Geralmente, o corpo dos comandos não se altera, apenas os parâmetros que passamos a eles. Podemos ter o mesmo comando SQL diversas vezes dentro do nosso programa, mas mediante a passagem de parâmetros com valores distintos podemos ter resultados diferentes. Contudo, pode acontecer de, dependendo da situação, não termos estes comandos SQL definidos, ou seja, mediante determinadas ações talvez precisemos modificar a estrutura do comando SQL para atender as necessidades, mas com um detalhe: tudo isso em tempo de execução. Para isso, a linguagem PL/SQL disponibiliza um recurso chamado de SQL dinâmico que nos dá a possibilidade de executar um comando SQL a partir de uma string, ou seja, o comando passa a ser uma string de caracteres armazenados em uma variável. Através de um comando, a variável é lida e o SQL que está dentro dela é executado. Isso é feito através do procedimento execute Casa do Código immediate. Por meio deste procedimento, podemos executar comandos de insert, delete, update, select, create, alter, drop, bem como executar procedimentos e funções. É possível também realizar passagem de parâmetros para esses comandos. Veja os exemplos a seguir. Uso com insert: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇✐♥s❡rt❴❡♠♣ ✈❛r❝❤❛r✷✭✹✵✵✵✮ ❞❡❢❛✉❧t ♥✉❧❧❀ ✹ ✇✐♥s❡rt❴❞❡♣t ✈❛r❝❤❛r✷✭✹✵✵✵✮ ❞❡❢❛✉❧t ♥✉❧❧❀ ✺ ✲✲ ✻ ✇❡♠♣♥♦ ❡♠♣✳❡♠♣♥♦✪t②♣❡❀ ✼ ✇❡♥❛♠❡ ❡♠♣✳❡♥❛♠❡✪t②♣❡❀ ✽ ✇❥♦❜ ❡♠♣✳❥♦❜✪t②♣❡❀ ✾ ✇♠❣r ❡♠♣✳♠❣r✪t②♣❡❀ ✶✵ ✇❤✐r❡❞❛t❡ ❡♠♣✳❤✐r❡❞❛t❡✪t②♣❡❀ ✶✶ ✇s❛❧ ❡♠♣✳s❛❧✪t②♣❡❀ ✶✷ ✇❝♦♠♠ ❡♠♣✳❝♦♠♠✪t②♣❡❀ ✶✸ ✇❞❡♣t♥♦ ❡♠♣✳❞❡♣t♥♦✪t②♣❡❀ ✶✹ ✲✲ ✶✺ ❜❡❣✐♥ ✶✻ ✲✲ ✶✼ ✇❡♠♣♥♦ ✿❂ ✾✾✾✾❀ ✶✽ ✇❡♥❛♠❡ ✿❂ ✬❇❖◆❖✬❀ ✶✾ ✇❥♦❜ ✿❂ ✬❙❆▲❊❙▼❆◆✬❀ ✷✵ ✇♠❣r ✿❂ ✼✻✾✽❀ ✷✶ ✇❤✐r❡❞❛t❡ ✿❂ ❙❨❙❉❆❚❊❀ ✷✷ ✇s❛❧ ✿❂ ✶✵✵✵❀ ✷✸ ✇❝♦♠♠ ✿❂ ✵❀ ✷✹ ✇❞❡♣t♥♦ ✿❂ ✸✵❀ ✷✺ ✲✲ ✷✻ ✇✐♥s❡rt❴❡♠♣ ✿❂ ✬✐♥s❡rt ✐♥t♦ ❡♠♣ ✭ ❡♠♣♥♦ ✷✼ ✱❡♥❛♠❡ ✷✽ ✱❥♦❜ ✷✾ ✱♠❣r ✸✵ ✱❤✐r❡❞❛t❡ ✸✶ ✱s❛❧ ✸✷ ✱❝♦♠♠ ✸✸ ✱❞❡♣t♥♦✮ 386 Casa do Código ✸✹ ✸✺ ✸✻ ✸✼ ✸✽ ✸✾ ✹✵ ✹✶ ✹✷ ✹✸ ✹✹ ✹✺ ✹✻ ✹✼ ✹✽ ✹✾ ✺✵ ✺✶ ✺✷ Capítulo 23. SQL dinâmico ✈❛❧✉❡s ✭ ✿❡♠♣♥♦ ✱✿❡♥❛♠❡ ✱✿❥♦❜ ✱✿♠❣r ✱✿❤✐r❡❞❛t❡ ✱✿s❛❧ ✱✿❝♦♠♠ ✱✿❞❡♣t♥♦✮✬❀ ✲✲ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✇✐♥s❡rt❴❡♠♣ ✉s✐♥❣ ✇❡♠♣♥♦ ✱✇❡♥❛♠❡ ✱✇❥♦❜ ✱✇♠❣r ✱✇❤✐r❡❞❛t❡ ✱✇s❛❧ ✱✇❝♦♠♠ ✱✇❞❡♣t♥♦❀ ✲✲ ✇✐♥s❡rt❴❞❡♣t ✿❂ ✬✐♥s❡rt ✐♥t♦ ❞❡♣t ✈❛❧✉❡s ✭✿❞❡♣t♥♦✱ ✿❞♥❛♠❡✱ ✿❧♦❝✮✬❀ ✺✸ ✲✲ ✺✹ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✇✐♥s❡rt❴❞❡♣t ✉s✐♥❣ ✾✾✱ ✬❘❍✬✱ ✬❇❘❆❙■▲✬❀ ✺✺ ✲✲ ✺✻ ❡♥❞❀ ✺✼ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Neste exemplo, na linha 26, temos a variável winsert_emp que recebe como string o comando insert. Note que os valores que serão inseridos (linha 34 a 41) estão representados por variáveis chamadas bind. Este tipo de variável é caracterizado por iniciar com dois pontos antes do seu nome. Quando declaramos uma variável do tipo bind a PL/SQL interpreta que algum valor deve ser informado para ela, em um dado momento. Caso este valor não seja passado por parâmetro é aberto um prompt para que ele seja digitado. 387 Casa do Código Nas linhas 43 a 50, temos o comando execute immediate. Ele aparece precedido da string ou variável referente ao comando que deve ser executado. Caso parâmetros devam ser passados, utilizamos a cláusula using para isto. Veja no exemplo, que estamos utilizando using para passar os parâmetros para o comando insert, substituindo as variáveis bind. Esta substituição acontece de forma sequencial. Além da inserção de empregados, também temos, no mesmo bloco PL/SQL, a inserção de departamentos. Embora bem parecido com a inserção de empregado, este exemplo serve para mostrar que os valores referentes aos parâmetros podem ser passados diretamente no comando execute immediate. Veja o resultado na sequência: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✹✾✾ ✼✺✷✶ ✾✾✾✾ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✽✸✾ ✼✽✹✹ ✼✾✵✵ ✼✾✸✹ ✼✾✸✺ ❊◆❆▼❊ ✲✲✲✲✲✲✲ ❆▲▲❊◆ ❲❆❘❉ ❇❖◆❖ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❑■◆● ❚❯❘◆❊❘ ❏❆▼❊❙ ▼■▲▲❊❘ P❆❯▲ ❏❖❇ ▼●❘ ❍■❘❊❉❆❚❊ ❙❆▲ ❈❖▼▼ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✵✴✵✷✴✽✶ ✶✻✵✵ ✸✵✻ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✷✴✵✷✴✽✶ ✶✷✺✵ ✺✶✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✺✴✶✵✴✶✶ ✶✵✵✵ ✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✽✴✵✾✴✽✶ ✶✷✺✵ ✶✹✷✽ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✶✴✵✺✴✽✶ ✷✽✺✵ ✷✽✺ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✾✴✵✻✴✽✶ ✷✹✺✵ ✷✹✺ P❘❊❙■❉❊◆❚ ✶✼✴✶✶✴✽✶ ✺✵✵✵ ✺✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✵✽✴✵✾✴✽✶ ✶✺✵✵ ✶✺✵ ❈▲❊❘❑ ✼✻✾✽ ✵✸✴✶✷✴✽✶ ✾✺✵ ✾✺ ❈▲❊❘❑ ✼✼✽✷ ✷✸✴✵✶✴✽✷ ✶✸✵✵ ✶✸✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✶✺✴✵✸✴✽✵ ✶✵✵✵ ✶✵✵ ❉❊P❚◆❖ P❈❴❈❖▼❴❙❆▲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✸✵ ✶✾✱✶✷✺ ✸✵ ✹✵✱✽ ✸✵ ✸✵ ✶✶✹✱✷✹ ✸✵ ✶✵ ✶✵ ✸✵ ✶✵ 388 Casa do Código Capítulo 23. SQL dinâmico ✸✵ ✶✵ ✸✵ ✶✵ ✶✶ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❞❡♣t❀ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✶✵ ✸✵ ✹✵ ✽✵ ✾✵ ✾✾ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ ❖P❊❘❆❚■❖◆❙ ❙✫❊ ❋■◆❆◆❈■❆▲ ❘❍ ▲❖❈ ✲✲✲✲✲✲✲✲✲✲✲✲✲ ❋▲❖❘■❉❆ ❈❍■❈❆●❖ ❇❖❙❚❖◆ ❇❘❆❙■▲ ✻ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ ❈❖▼▼■❚❀ ❱❛❧✐❞❛çã♦ ❝♦♠♣❧❡t❛✳ ❙◗▲❃ Uso com delete e update: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ❞❡❝❧❛r❡ ✲✲ ❜❡❣✐♥ ✲✲ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✬❞❡❧❡t❡ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❡♠♣♥♦ ❂ ✿❡♠♣♥♦ ✬ ✉s✐♥❣ ✾✾✾✾❀ ✲✲ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✬✉♣❞❛t❡ ❞❡♣t s❡t ❧♦❝ ❂ ✿❧♦❝ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✿❞❡♣♥t♦✬ ✉s✐♥❣ ✬❆❯❙❚❘❆▲■❆✬✱ ✾✾❀ ✲✲ ❡♥❞❀ ✴ 389 Casa do Código Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Nesse exemplo, estamos mostrando a exclusão e atualização de registros via execute immediate. A seguir temos o resultado: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣❀ ❊▼P◆❖ ✲✲✲✲✲✲✲✲✲✲ ✼✹✾✾ ✼✺✷✶ ✼✻✺✹ ✼✻✾✽ ✼✼✽✷ ✼✽✸✾ ✼✽✹✹ ✼✾✵✵ ✼✾✸✹ ✼✾✸✺ ❊◆❆▼❊ ✲✲✲✲✲✲✲ ❆▲▲❊◆ ❲❆❘❉ ▼❆❘❚■◆ ❇▲❆❑❊ ❈▲❆❘❑ ❑■◆● ❚❯❘◆❊❘ ❏❆▼❊❙ ▼■▲▲❊❘ P❆❯▲ ❏❖❇ ▼●❘ ❍■❘❊❉❆❚❊ ❙❆▲ ❈❖▼▼ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✵✴✵✷✴✽✶ ✶✻✵✵ ✸✵✻ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✷✴✵✷✴✽✶ ✶✷✺✵ ✺✶✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✷✽✴✵✾✴✽✶ ✶✷✺✵ ✶✹✷✽ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✶✴✵✺✴✽✶ ✷✽✺✵ ✷✽✺ ▼❆◆❆●❊❘ ✼✽✸✾ ✵✾✴✵✻✴✽✶ ✷✹✺✵ ✷✹✺ P❘❊❙■❉❊◆❚ ✶✼✴✶✶✴✽✶ ✺✵✵✵ ✺✵✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✵✽✴✵✾✴✽✶ ✶✺✵✵ ✶✺✵ ❈▲❊❘❑ ✼✻✾✽ ✵✸✴✶✷✴✽✶ ✾✺✵ ✾✺ ❈▲❊❘❑ ✼✼✽✷ ✷✸✴✵✶✴✽✷ ✶✸✵✵ ✶✸✵ ❙❆▲❊❙▼❆◆ ✼✻✾✽ ✶✺✴✵✸✴✽✵ ✶✵✵✵ ✶✵✵ ❉❊P❚◆❖ P❈❴❈❖▼❴❙❆▲ ✲✲✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲ ✸✵ ✶✾✱✶✷✺ ✸✵ ✹✵✱✽ ✸✵ ✶✶✹✱✷✹ ✸✵ ✶✵ ✶✵ ✸✵ ✶✵ ✸✵ ✶✵ ✸✵ ✶✵ ✶✵ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❞❡♣t❀ 390 Casa do Código ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✶✵ ✸✵ ✹✵ ✽✵ ✾✵ ✾✾ Capítulo 23. SQL dinâmico ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ ❖P❊❘❆❚■❖◆❙ ❙✫❊ ❋■◆❆◆❈■❆▲ ❘❍ ▲❖❈ ✲✲✲✲✲✲✲✲✲✲✲✲✲ ❋▲❖❘■❉❆ ❈❍■❈❆●❖ ❇❖❙❚❖◆ ❆❯❙❚❘❆▲■❆ ✻ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ ❈❖▼▼■❚❀ ❱❛❧✐❞❛çã♦ ❝♦♠♣❧❡t❛✳ ❙◗▲❃ Uso com os comandos create e alter. execute immediate pode ser usado também para a criação e alteração dinâmica de tabelas: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ❞❡❝❧❛r❡ ✲✲ ❜❡❣✐♥ ✲✲ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✬❝r❡❛t❡ t❛❜❧❡ ❢✉♥❝ ✭❝❞❴❢✉♥❝ ♥✉♠❜❡r✱ ♥♠❴❢✉♥❝ ✈❛r❝❤❛r✷✭✺✵✮✮✬❀ ✲✲ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✬❛❧t❡r t❛❜❧❡ ❢✉♥❝ ♠♦❞✐❢② ❝❞❴❢✉♥❝ ♥✉♠❜❡r ♥♦t ♥✉❧❧✬❀ ✲✲ ❡♥❞❀ ✴ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ ❞❡s❝ ❢✉♥❝ ◆♦♠❡ ◆✉❧♦❄ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❈❉❴❋❯◆❈ ◆❖❚ ◆❯▲▲ ◆▼❴❋❯◆❈ ❚✐♣♦ ✲✲✲✲✲✲✲✲✲✲✲✲✲ ◆❯▼❇❊❘ ❱❆❘❈❍❆❘✷✭✺✵✮ ❙◗▲❃ 391 Casa do Código Por meio do uso do execute immediate é possível retornar informações provenientes de comandos SQL. Veja este exemplo da execução de um update: ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇❛t✉❛❧✐③❛❴❞❡♣t ✈❛r❝❤❛r✷✭✷✵✵✵✮❀ ✹ ✲✲ ✺ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✻ ✇❧♦❝❴r❡ ❞❡♣t✳❧♦❝✪t②♣❡❀ ✼ ✲✲ ✽ ✇❧♦❝ ❞❡♣t✳❧♦❝✪t②♣❡ ❞❡❢❛✉❧t ✬❈❍■▲❊✬❀ ✾ ✇❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡ ❞❡❢❛✉❧t ✾✾❀ ✶✵ ❜❡❣✐♥ ✶✶ ✲✲ ✶✷ ✇❛t✉❛❧✐③❛❴❞❡♣t ✿❂ ✬✉♣❞❛t❡ ❞❡♣t s❡t ❧♦❝ ❂ ✿✶ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✿✷ ✶✸ r❡t✉r♥✐♥❣ ❞♥❛♠❡✱ ❧♦❝ ✐♥t♦ ✿✸✱ ✿✹✬❀ ✶✹ ✲✲ ✶✺ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✇❛t✉❛❧✐③❛❴❞❡♣t ✉s✐♥❣ ✇❧♦❝✱ ✇❞❡♣t♥♦ ✶✻ ✱♦✉t ✇❞♥❛♠❡✱ ♦✉t ✇❧♦❝❴r❡❀ ✶✼ ✲✲ ✶✽ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬▲♦❝❛❧✐③❛çã♦ ❛t✉❛❧✐③❛❞❛ ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ✬⑤⑤ ✇❞♥❛♠❡⑤⑤✬ ✭▲♦❝✿ ✬⑤⑤✇❧♦❝⑤⑤✬✮✳✬✮❀ ✶✾ ✷✵ ✲✲ ✷✶ ❡♥❞❀ ✷✷ ✴ ▲♦❝❛❧✐③❛çã♦ ❛t✉❛❧✐③❛❞❛ ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ❘❍ ✭▲♦❝✿ ❈❍■▲❊✮✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❞❡♣t❀ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✶✵ ✸✵ ✹✵ 392 ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ ❖P❊❘❆❚■❖◆❙ ▲❖❈ ✲✲✲✲✲✲✲✲✲✲✲✲✲ ❋▲❖❘■❉❆ ❈❍■❈❆●❖ ❇❖❙❚❖◆ Casa do Código ✽✵ ❙✫❊ ✾✵ ❋■◆❆◆❈■❆▲ ✾✾ ❘❍ Capítulo 23. SQL dinâmico ❈❍■▲❊ ✻ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ Analisando esse exemplo, temos na linha 12 a variável watualiza_dept recebendo a string referente ao comando update. Também é possível observar que, na linha 13, está incluída a cláusula returning seguida de dois campos, os quais serão o nosso retorno, seguida da cláusula into informando duas variáveis bind, as quais receberão os valores retornados. Uma observação importante, é que na linha 15 e 16, referentes ao comando execute immediate, temos duas passagens de parâmetros do tipo in (entrada) e duas do tipo out (saída), sendo que estas duas últimas guardam nosso retorno. Vale lembrar que quando não informado o tipo da variável na cláusula using, por padrão, seu tipo será de entrada ( in). Veja outro exemplo utilizando retorno de informação, mas agora com o uso da cláusula returning também no execute immediate. Note que através desta notação não necessitamos informar o tipo das variáveis de retorno. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇❛t✉❛❧✐③❛❴❞❡♣t ✈❛r❝❤❛r✷✭✷✵✵✵✮❀ ✹ ✲✲ ✺ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✻ ✇❧♦❝❴r❡ ❞❡♣t✳❧♦❝✪t②♣❡❀ ✼ ✲✲ ✽ ✇❧♦❝ ❞❡♣t✳❧♦❝✪t②♣❡ ❞❡❢❛✉❧t ✬❆❘●❊◆❚■◆❆✬❀ ✾ ✇❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡ ❞❡❢❛✉❧t ✾✾❀ ✶✵ ❜❡❣✐♥ ✶✶ ✲✲ ✶✷ ✇❛t✉❛❧✐③❛❴❞❡♣t ✿❂ ✬✉♣❞❛t❡ ❞❡♣t s❡t ❧♦❝ ❂ ✿✶ ✇❤❡r❡ ❞❡♣t♥♦ ❂ ✿✷ ✶✸ r❡t✉r♥✐♥❣ ❞♥❛♠❡✱ ❧♦❝ ✐♥t♦ ✿✸✱ ✿✹✬❀ ✶✹ ✲✲ 393 Casa do Código ✶✺ ✶✻ ✶✼ ✶✽ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✇❛t✉❛❧✐③❛❴❞❡♣t ✉s✐♥❣ ✇❧♦❝✱ ✇❞❡♣t♥♦ r❡t✉r♥✐♥❣ ✐♥t♦ ✇❞♥❛♠❡✱ ✇❧♦❝❴r❡❀ ✲✲ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬▲♦❝❛❧✐③❛çã♦ ❛t✉❛❧✐③❛❞❛ ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ✬⑤⑤ ✶✾ ✇❞♥❛♠❡⑤⑤✬ ✭▲♦❝✿ ✬⑤⑤✇❧♦❝⑤⑤✬✮✳✬✮❀ ✷✵ ✲✲ ✷✶ ❡♥❞❀ ✷✷ ✴ ▲♦❝❛❧✐③❛çã♦ ❛t✉❛❧✐③❛❞❛ ♣❛r❛ ♦ ❞❡♣❛rt❛♠❡♥t♦ ❘❍ ✭▲♦❝✿ ❆❘●❊◆❚■◆❆✮✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❞❡♣t❀ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✶✵ ✸✵ ✹✵ ✽✵ ✾✵ ✾✾ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ ❖P❊❘❆❚■❖◆❙ ❙✫❊ ❋■◆❆◆❈■❆▲ ❘❍ ▲❖❈ ✲✲✲✲✲✲✲✲✲✲✲✲✲ ❋▲❖❘■❉❆ ❈❍■❈❆●❖ ❇❖❙❚❖◆ ❆❘●❊◆❚■◆❆ ✻ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ O exemplo a seguir mostra o uso do execute immediate na execução dinâmica de um comando delete: ❙◗▲❃ ❝r❡❛t❡ ❢✉♥❝t✐♦♥ r♦✇s❴❞❡❧❡t❡❞ ✭ t❛❜❧❡❴♥❛♠❡ ✐♥ ✈❛r❝❤❛r✷ ✷ ✱❝♦♥❞✐t✐♦♥ ✐♥ ✈❛r❝❤❛r✷✮ r❡t✉r♥ ✐♥t❡❣❡r ❛s ✸ ❜❡❣✐♥ ✹ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✬❞❡❧❡t❡ ❢r♦♠ ✬ ⑤⑤ t❛❜❧❡❴♥❛♠❡ ⑤⑤ ✬ ✇❤❡r❡ ✬ ⑤⑤ ❝♦♥❞✐t✐♦♥❀ ✺ r❡t✉r♥ sq❧✪r♦✇❝♦✉♥t❀ ✻ ❡♥❞❀ ✼ ✴ 394 Casa do Código Capítulo 23. SQL dinâmico ❋✉♥çã♦ ❝r✐❛❞❛✳ ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✇♥r❴❧✐♥❤❛s ♥✉♠❜❡r❀ ✸ ❜❡❣✐♥ ✹ ✇♥r❴❧✐♥❤❛s ✿❂ r♦✇s❴❞❡❧❡t❡❞✭✬❊▼P✬✱✬ ❡♠♣♥♦ ❂ ✼✾✸✺✬✮❀ ✺ ✲✲ ✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬▲✐♥❤❛s ❡①❝❧✉í❞❛s✿ ✬⑤⑤✇♥r❴❧✐♥❤❛s✮❀ ✼ ✲✲ ✽ ❡♥❞❀ ✾ ✴ ▲✐♥❤❛s ❡①❝❧✉í❞❛s✿ ✶ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Note que utilizamos o cursor implícito sql%rowcount para retornar a quantidade de linhas excluídas. Através deste recurso também é possível executar procedimentos PL/SQL. Para isso, criamos uma procedure para realizar inserções na tabela dept. ❙◗▲❃ ❝r❡❛t❡ ♦r r❡♣❧❛❝❡ ♣r♦❝❡❞✉r❡ ❝r✐❛❴❞❡♣t ✭ ♣❞❡♣t♥♦ ✐♥ ♥✉♠❜❡r ✷ ✱♣❞♥❛♠❡ ✐♥ ✈❛r❝❤❛r✷ ✸ ✱♣❧♦❝ ✐♥ ✈❛r❝❤❛r✷ ✹ ✱♣st❛t✉s ✐♥ ♦✉t ✈❛r❝❤❛r✷✮ ✐s ✺ ❜❡❣✐♥ ✻ ✲✲ ✼ ✐♥s❡rt ✐♥t♦ ❞❡♣t ✈❛❧✉❡s ✭♣❞❡♣t♥♦✱ ♣❞♥❛♠❡✱ ♣❧♦❝✮❀ ✽ ✲✲ ✾ ♣st❛t✉s ✿❂ ✬❖❑✬❀ ✶✵ ✲✲ ✶✶ ❝♦♠♠✐t❀ ✶✷ ✲✲ ✶✸ ❡①❝❡♣t✐♦♥ ✶✹ ✇❤❡♥ ♦t❤❡rs t❤❡♥ ✶✺ ♣st❛t✉s ✿❂ sq❧❡rr♠❀ 395 Casa do Código ✶✻ ❡♥❞❀ ✶✼ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ Agora chamamos a procedure criada através de outro bloco PL/SQL, utilizando uma chamada dinâmica. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ ✲✲ ✸ ✇✐♥s❡r❡❴❞❡♣t ✈❛r❝❤❛r✷✭✷✵✵✵✮❀ ✹ ✲✲ ✺ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡ ❞❡❢❛✉❧t ✬❘❍✬❀ ✻ ✇❧♦❝ ❞❡♣t✳❧♦❝✪t②♣❡ ❞❡❢❛✉❧t ✬❆❘●❊◆❚■◆❆✬❀ ✼ ✇❞❡♣t♥♦ ❞❡♣t✳❞❡♣t♥♦✪t②♣❡ ❞❡❢❛✉❧t ✽✽❀ ✽ ✲✲ ✾ ✇st❛t✉s ✈❛r❝❤❛r✷✭✹✵✵✵✮❀ ✶✵ ✲✲ ✶✶ ❜❡❣✐♥ ✶✷ ✲✲ ✶✸ ✇✐♥s❡r❡❴❞❡♣t ✿❂ ✬❜❡❣✐♥ ❝r✐❛❴❞❡♣t✭✿❛✱ ✿❜✱ ✿❝✱ ✿❞✮❀ ❡♥❞❀✬❀ ✶✹ ✲✲ ✶✺ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✇✐♥s❡r❡❴❞❡♣t ✶✻ ✉s✐♥❣ ✐♥ ✇❞❡♣t♥♦✱ ✐♥ ✇❞♥❛♠❡✱ ✐♥ ✇❧♦❝✱ ✐♥ ♦✉t ✇st❛t✉s❀ ✶✼ ✲✲ ✶✽ ✐❢ ✇st❛t✉s ❂ ✬❖❑✬ t❤❡♥ ✶✾ ✲✲ ✷✵ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳✬✮❀ ✷✶ ✲✲ ✷✷ ❡❧s❡ ✷✸ ✲✲ ✷✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊rr♦ ❛♦ ✐♥s❡r✐r ❞❡♣❛rt❛♠❡♥t♦✳ ❊rr♦✿ ✬⑤⑤✇st❛t✉s✮❀ ✷✺ ✲✲ ✷✻ ❡♥❞ ✐❢❀ ✷✼ ❡♥❞❀ 396 Casa do Código Capítulo 23. SQL dinâmico ✷✽ ✴ ❉❡♣❛rt❛♠❡♥t♦ ✐♥s❡r✐❞♦ ❝♦♠ s✉❝❡ss♦✳ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Veja o resultado: ❙◗▲❃ s❡❧❡❝t ✯ ❢r♦♠ ❞❡♣t❀ ❉❊P❚◆❖ ✲✲✲✲✲✲✲✲✲✲ ✶✵ ✸✵ ✹✵ ✽✵ ✾✵ ✾✾ ✽✽ ❉◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❆❈❈❖❯◆❚■◆● ❙❆▲❊❙ ❖P❊❘❆❚■❖◆❙ ❙✫❊ ❋■◆❆◆❈■❆▲ ❘❍ ❘❍ ▲❖❈ ✲✲✲✲✲✲✲✲✲✲✲✲✲ ❋▲❖❘■❉❆ ❈❍■❈❆●❖ ❇❖❙❚❖◆ ❆❘●❊◆❚■◆❆ ❆❘●❊◆❚■◆❆ ✼ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ A seguir, diferentes usos de SQL dinâmico para comandos select, com retorno de informações. Nestes exemplos, não utilizaremos execute immediate; em vez disso, usaremos cursores do tipo ref cursor. 23.1 Ref cursor Uma variável do tipo ref cursor, como é comumente chamada, é utilizada para referenciar a estrutura de uma query, de forma dinâmica, ou seja, ela não está ligada exatamente a um único comando SQL, diferente do uso de cursores, no qual ao declararmos, necessitamos informar um comando select específico. Variáveis do tipo ref cursor, por não terem uma estrutura predefinida, podem ser usadas várias vezes dentro de um programa para diferentes comandos select e para um número ilimitado de linhas. Variáveis 397 23.1. Ref cursor Casa do Código do tipo ref cursor podem ainda serem definidas como parâmetros em procedures. Sua declaração é semelhante à declaração de variáveis do tipo tabela ou registro ( Index-By Table, Record). A principal vantagem no uso de variáveis do tipo ref cursor se dá pelo fato de ela apenas apontar para a estrutura ou linha retornada pelo comando select. Sendo assim, o resultado não é armazenado, apenas referenciado. Isso é muito útil na passagem de informações entre vários sistemas, pois não há uma passagem de informações propriamente dita, apenas o compartilhamento através do que chamamos de um ponteiro. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ t②♣❡ ❡♠♣❝✉rt②♣ ✐s r❡❢ ❝✉rs♦r❀ ✸ ❡♠♣❴❝✈ ❡♠♣❝✉rt②♣❀ ✹ ✲✲ ✺ ♠②❴❡♥❛♠❡ ✈❛r❝❤❛r✷✭✶✺✮❀ ✻ ♠②❴s❛❧ ♥✉♠❜❡r ❞❡❢❛✉❧t ✶✵✵✵❀ ✼ ❜❡❣✐♥ ✽ ♦♣❡♥ ❡♠♣❴❝✈ ❢♦r ✬s❡❧❡❝t ❡♥❛♠❡✱ s❛❧ ❢r♦♠ ❡♠♣ ✇❤❡r❡ s❛❧ ❃ ✿s✬ ✉s✐♥❣ ♠②❴s❛❧❀ ✾ ❧♦♦♣ ✶✵ ❢❡t❝❤ ❡♠♣❴❝✈ ✐♥t♦ ♠②❴❡♥❛♠❡✱ ♠②❴s❛❧❀ ✶✶ ✶✷ ❡①✐t ✇❤❡♥ ❡♠♣❴❝✈✪♥♦t❢♦✉♥❞❀ ✶✸ ✲✲ ✶✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭ ✬❊♠♣r❡❣❛❞♦✿ ✬⑤⑤♠②❴❡♥❛♠❡⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤♠②❴s❛❧✮❀ ✶✺ ✲✲ ✶✻ ❡♥❞ ❧♦♦♣❀ ✶✼ ❡♥❞❀ ✶✽ ✴ ❊♠♣r❡❣❛❞♦✿ ❆▲▲❊◆ ❙❛❧ár✐♦✿ ✶✻✵✵ ❊♠♣r❡❣❛❞♦✿ ❲❆❘❉ ❙❛❧ár✐♦✿ ✶✷✺✵ ❊♠♣r❡❣❛❞♦✿ ▼❆❘❚■◆ ❙❛❧ár✐♦✿ ✶✷✺✵ ❊♠♣r❡❣❛❞♦✿ ❇▲❆❑❊ ❙❛❧ár✐♦✿ ✷✽✺✵ ❊♠♣r❡❣❛❞♦✿ ❈▲❆❘❑ ❙❛❧ár✐♦✿ ✷✹✺✵ ❊♠♣r❡❣❛❞♦✿ ❑■◆● ❙❛❧ár✐♦✿ ✺✵✵✵ ❊♠♣r❡❣❛❞♦✿ ❚❯❘◆❊❘ ❙❛❧ár✐♦✿ ✶✺✵✵ ❊♠♣r❡❣❛❞♦✿ ▼■▲▲❊❘ ❙❛❧ár✐♦✿ ✶✸✵✵ 398 Casa do Código Capítulo 23. SQL dinâmico Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Neste exemplo, estamos utilizando um ref cursor que recebe uma string de um comando SQL (linha 8). Utilizamos as cláusulas open e for para atribuir o comando à variável ref cursor emp_cv. Depois, utilizamos um loop simples (linha 9) para manipular as informações, que são atribuídas a duas variáveis através da cláusula into (linha 10). Note que também utilizamos a cláusula using para passagem de parâmetro. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ t②♣❡ ❡♠♣❝✉rt②♣ ✐s r❡❢ ❝✉rs♦r❀ ✸ ❡♠♣❴❝✈ ❡♠♣❝✉rt②♣❀ ✹ ❡♠♣❴r❡❝ ❡♠♣✪r♦✇t②♣❡❀ ✺ ✲✲ ✻ sq❧❴st♠t ✈❛r❝❤❛r✷✭✷✵✵✮❀ ✼ ♠②❴❥♦❜ ✈❛r❝❤❛r✷✭✶✺✮ ✿❂ ✬❈▲❊❘❑✬❀ ✽ ❜❡❣✐♥ ✾ sq❧❴st♠t ✿❂ ✬s❡❧❡❝t ✯ ❢r♦♠ ❡♠♣ ✇❤❡r❡ ❥♦❜ ❂ ✿❥✬❀ ✶✵ ✲✲ ✶✶ ♦♣❡♥ ❡♠♣❴❝✈ ❢♦r sq❧❴st♠t ✉s✐♥❣ ♠②❴❥♦❜❀ ✶✷ ❧♦♦♣ ✶✸ ❢❡t❝❤ ❡♠♣❴❝✈ ✐♥t♦ ❡♠♣❴r❡❝❀ ✶✹ ❡①✐t ✇❤❡♥ ❡♠♣❴❝✈✪♥♦t❢♦✉♥❞❀ ✶✺ ✲✲ ✶✻ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❊♠♣r❡❣❛❞♦✿ ✬⑤⑤❡♠♣❴r❡❝✳❡♥❛♠❡⑤⑤✬ ❙❛❧ár✐♦✿ ✬⑤⑤❡♠♣❴r❡❝✳s❛❧✮❀ ✶✼ ✲✲ ✶✽ ❡♥❞ ❧♦♦♣❀ ✶✾ ❝❧♦s❡ ❡♠♣❴❝✈❀ ✷✵ ❡♥❞❀ ✷✶ ✴ ❊♠♣r❡❣❛❞♦✿ ❏❆▼❊❙ ❙❛❧ár✐♦✿ ✾✺✵ ❊♠♣r❡❣❛❞♦✿ ▼■▲▲❊❘ ❙❛❧ár✐♦✿ ✶✸✵✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ 399 23.1. Ref cursor Casa do Código ❙◗▲❃ Esse exemplo é bem semelhante ao anterior. A diferença está nas linhas 4 e 13. Declaramos uma variável do tipo tabela, utilizando a estrutura da tabela emp (linha 4), que receberá o resultado do select através da cláusula into na linha 13. O próximo exemplo mostra que podemos montar um comando SQL através de strings passadas por parâmetro. ❙◗▲❃ ❝r❡❛t❡ ♣r♦❝❡❞✉r❡ ♣r✐♥t❴t❛❜❧❡ ✭t❛❜❴♥❛♠❡ ✈❛r❝❤❛r✷✮ ✐s ✷ t②♣❡ r❡❢❝✉rt②♣ ✐s r❡❢ ❝✉rs♦r❀ ✸ ❝✈ r❡❢❝✉rt②♣❀ ✹ ✇❞♥❛♠❡ ❞❡♣t✳❞♥❛♠❡✪t②♣❡❀ ✺ ✇❧♦❝ ❞❡♣t✳❧♦❝✪t②♣❡❀ ✻ ❜❡❣✐♥ ✼ ♦♣❡♥ ❝✈ ❢♦r ✬s❡❧❡❝t ❞♥❛♠❡✱ ❧♦❝ ❢r♦♠ ✬ ⑤⑤ t❛❜❴♥❛♠❡❀ ✽ ✲✲ ✾ ❧♦♦♣ ✶✵ ❢❡t❝❤ ❝✈ ✐♥t♦ ✇❞♥❛♠❡✱ ✇❧♦❝❀ ✶✶ ❡①✐t ✇❤❡♥ ❝✈✪♥♦t❢♦✉♥❞❀ ✶✷ ✲✲ ✶✸ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❉❡♣❛rt❛♠❡♥t♦✿ ✬⑤⑤✇❞♥❛♠❡⑤⑤✬ ▲♦❝❛❧✐③❛çã♦✿ ✬⑤⑤✇❧♦❝✮❀ ✶✹ ✲✲ ✶✺ ❡♥❞ ❧♦♦♣❀ ✶✻ ✲✲ ✶✼ ❝❧♦s❡ ❝✈❀ ✶✽ ✲✲ ✶✾ ❡♥❞❀ ✷✵ ✴ Pr♦❝❡❞✐♠❡♥t♦ ❝r✐❛❞♦✳ ❙◗▲❃ ❜❡❣✐♥ ♣r✐♥t❴t❛❜❧❡ ✭t❛❜❴♥❛♠❡ ❂❃ ✬❉❊P❚✬✮❀ ❡♥❞❀ ✷ ✴ ❉❡♣❛rt❛♠❡♥t♦✿ ❆❈❈❖❯◆❚■◆● ▲♦❝❛❧✐③❛çã♦✿ ❋▲❖❘■❉❆ ❉❡♣❛rt❛♠❡♥t♦✿ ❙❆▲❊❙ ▲♦❝❛❧✐③❛çã♦✿ ❈❍■❈❆●❖ ❉❡♣❛rt❛♠❡♥t♦✿ ❖P❊❘❆❚■❖◆❙ ▲♦❝❛❧✐③❛çã♦✿ ❇❖❙❚❖◆ ❉❡♣❛rt❛♠❡♥t♦✿ ❙✫❊ ▲♦❝❛❧✐③❛çã♦✿ 400 Casa do Código Capítulo 23. SQL dinâmico ❉❡♣❛rt❛♠❡♥t♦✿ ❋■◆❆◆❈■❆▲ ▲♦❝❛❧✐③❛çã♦✿ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❍ ▲♦❝❛❧✐③❛çã♦✿ ❆❘●❊◆❚■◆❆ ❉❡♣❛rt❛♠❡♥t♦✿ ❘❍ ▲♦❝❛❧✐③❛çã♦✿ ❆❘●❊◆❚■◆❆ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Já no exemplo a seguir temos um mix de variável ref cursor e variáveis table e record. Aqui utilizamos a cláusula bulk collect, que é responsável por preparar toda a coleção de saída de dados. Esta cláusula pode ser usada junto com a cláusula into nos comandos select into, fetch into, returning into e variáveis table. Esta cláusula não pode ser usada para variáveis do tipo record. Dessa forma, caso tenhamos informações referentes a várias colunas, será necessária a criação de uma variável do tipo table para cada uma. ❙◗▲❃ ❞❡❝❧❛r❡ ✷ t②♣❡ ❡♠♣❝✉rt②♣ ✐s r❡❢ ❝✉rs♦r❀ ✸ t②♣❡ ♥✉♠❧✐st ✐s t❛❜❧❡ ♦❢ ♥✉♠❜❡r❀ ✹ t②♣❡ ♥❛♠❡❧✐st ✐s t❛❜❧❡ ♦❢ ✈❛r❝❤❛r✷✭✶✺✮❀ ✺ ✲✲ ✻ ❡♠♣❴❝✈ ❡♠♣❝✉rt②♣❀ ✼ ❡♠♣♥♦s ♥✉♠❧✐st❀ ✽ ❡♥❛♠❡s ♥❛♠❡❧✐st❀ ✾ ✲✲ ✶✵ s❛❧s ♥✉♠❧✐st❀ ✶✶ ❜❡❣✐♥ ✶✷ ♦♣❡♥ ❡♠♣❴❝✈ ❢♦r ✬s❡❧❡❝t ❡♠♣♥♦✱ ❡♥❛♠❡ ❢r♦♠ ❡♠♣✬❀ ✶✸ ❢❡t❝❤ ❡♠♣❴❝✈ ❜✉❧❦ ❝♦❧❧❡❝t ✐♥t♦ ❡♠♣♥♦s✱ ❡♥❛♠❡s❀ ✶✹ ❝❧♦s❡ ❡♠♣❴❝✈❀ ✶✺ ✲✲ ✶✻ ❢♦r r ✐♥ ✶✳✳❡♠♣♥♦s✳❝♦✉♥t ❧♦♦♣ ✶✼ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❈ó❞✳✿ ✬⑤⑤❡♠♣♥♦s✭r✮⑤⑤✬ ✲ ❊♠♣r❡❣❛❞♦✿ ✬⑤⑤❡♥❛♠❡s✭r✮✮❀ ✶✽ ❡♥❞ ❧♦♦♣❀ ✶✾ ✲✲ ✷✵ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✬s❡❧❡❝t s❛❧ ❢r♦♠ ❡♠♣✬ ✷✶ ❜✉❧❦ ❝♦❧❧❡❝t ✐♥t♦ s❛❧s❀ 401 23.1. Ref cursor Casa do Código ✷✷ ✲✲ ✷✸ ❢♦r r ✐♥ ✶✳✳s❛❧s✳❝♦✉♥t ❧♦♦♣ ✷✹ ❞❜♠s❴♦✉t♣✉t✳♣✉t❴❧✐♥❡✭✬❙❛❧ár✐♦✿ ✬⑤⑤s❛❧s✭r✮✮❀ ✷✺ ❡♥❞ ❧♦♦♣❀ ✷✻ ❡♥❞❀ ✷✼ ✴ ❈ó❞✳✿ ✼✹✾✾ ✲ ❊♠♣r❡❣❛❞♦✿ ❆▲▲❊◆ ❈ó❞✳✿ ✼✺✷✶ ✲ ❊♠♣r❡❣❛❞♦✿ ❲❆❘❉ ❈ó❞✳✿ ✼✻✺✹ ✲ ❊♠♣r❡❣❛❞♦✿ ▼❆❘❚■◆ ❈ó❞✳✿ ✼✻✾✽ ✲ ❊♠♣r❡❣❛❞♦✿ ❇▲❆❑❊ ❈ó❞✳✿ ✼✼✽✷ ✲ ❊♠♣r❡❣❛❞♦✿ ❈▲❆❘❑ ❈ó❞✳✿ ✼✽✸✾ ✲ ❊♠♣r❡❣❛❞♦✿ ❑■◆● ❈ó❞✳✿ ✼✽✹✹ ✲ ❊♠♣r❡❣❛❞♦✿ ❚❯❘◆❊❘ ❈ó❞✳✿ ✼✾✵✵ ✲ ❊♠♣r❡❣❛❞♦✿ ❏❆▼❊❙ ❈ó❞✳✿ ✼✾✸✹ ✲ ❊♠♣r❡❣❛❞♦✿ ▼■▲▲❊❘ ❈ó❞✳✿ ✼✾✸✺ ✲ ❊♠♣r❡❣❛❞♦✿ P❆❯▲ ❙❛❧ár✐♦✿ ✶✻✵✵ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦✿ ✶✷✺✵ ❙❛❧ár✐♦✿ ✷✽✺✵ ❙❛❧ár✐♦✿ ✷✹✺✵ ❙❛❧ár✐♦✿ ✺✵✵✵ ❙❛❧ár✐♦✿ ✶✺✵✵ ❙❛❧ár✐♦✿ ✾✺✵ ❙❛❧ár✐♦✿ ✶✸✵✵ ❙❛❧ár✐♦✿ ✶✵✵✵ Pr♦❝❡❞✐♠❡♥t♦ P▲✴❙◗▲ ❝♦♥❝❧✉í❞♦ ❝♦♠ s✉❝❡ss♦✳ ❙◗▲❃ Na linha 2, temos a definição de uma variável do tipo ref cursor que receberá um comando SQL. Já nas linhas 3 e 4, temos a declaração de duas variáveis do tipo table. Esta declaração define dois tipos array, um array numérico e outro de caracteres. Nas linhas 7 e 8, são declaradas duas variáveis com base nestes tipos. Nas linhas 12 e 13, foi utilizado um cursor que lê as informações de um select dinâmico que, através do bulk collect, carrega as informações para as variáveis do tipo array. 402 Casa do Código Capítulo 23. SQL dinâmico Note que não foi necessário utilizar loop para atribuir as linhas vindas do select. O bulk collect já faz esta atribuição. Nas linhas 16 e 18, utilizamos um for loop para ler os dados das variáveis array. Observe que o for loop toma como base a quantidade de linhas que o array possui. Neste caso, utilizamos o count de uma das variáveis para determinar valor final do for loop, mesmo porque carregamos as duas variáveis em um mesmo momento e utilizando o mesmo select. Logo, a quantidade de dados carregados nas duas variáveis é a mesma. Dentro no mesmo programa temos outra execução dinâmica (linhas 20 a 21), onde é possível usar o bulk collect também para receber o resultado vindo através da execução via execute immediate. Por último, um exemplo de function para retornar a quantidade de registros em uma determinada tabela, passada por parâmetro, usando execute immediate com retorno utilizando into. ❙◗▲❃ ❝r❡❛t❡ ❢✉♥❝t✐♦♥ r♦✇❴❝♦✉♥t✭t❛❜❴♥❛♠❡ ✈❛r❝❤❛r✷✮ r❡t✉r♥ ✐♥t❡❣❡r ❛s ✷ r♦✇s ✐♥t❡❣❡r❀ ✸ ❜❡❣✐♥ ✹ ❡①❡❝✉t❡ ✐♠♠❡❞✐❛t❡ ✬s❡❧❡❝t ❝♦✉♥t✭✯✮ ❢r♦♠ ✬ ⑤⑤ t❛❜❴♥❛♠❡ ✐♥t♦ r♦✇s❀ ✺ r❡t✉r♥ r♦✇s❀ ✻ ❡♥❞❀ ✼ ✴ ❋✉♥çã♦ ❝r✐❛❞❛✳ ❙◗▲❃ s❡❧❡❝t r♦✇❴❝♦✉♥t✭✬❊▼P✬✮ ❢r♦♠ ❞✉❛❧❀ ❘❖❲❴❈❖❯◆❚✭✬❊▼P✬✮ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ✶✵ ❙◗▲❃ 403 Capítulo 24 Apêndice: SQL – Primeiros passos 24.1 Como iniciar no SQL Uma das dificuldades que encontramos quando estamos aprendendo uma linguagem de programação é saber por onde começar. No caso do aprendizado da SQL, não seria diferente. É uma situação normal. Até sentirmos segurança e termos conhecimento suficiente sobre a linguagem, é interessante termos um roteiro contendo os primeiros passos para iniciar um programa ou comando SQL. Desta forma, demonstro aqui uma técnica que utilizo bastante, mesmo tendo um bom conhecimento na linguagem. Na verdade, já está implícito na minha forma de pensar, tanto que acabo executando-a mentalmente, en- 24.1. Como iniciar no SQL Casa do Código quanto escrevo nesta linguagem. Este método não foi retirado de nenhum livro, foi algo que, entendendo a lógica, fui seguindo e deu certo. Espero que ajude vocês. Vamos tomar como exemplo a questão a seguir: Escreva um select que apresente as colunas, nome da região ( REGION_NAME: tabela REGIONS), nome da cidade ( CITY: tabela LOCATIONS), nome do departamento ( DEPARTMENT_NAME: tabela DEPARTMENTS) e o nome dos empregados ( FIRST_NAME), mas somente daqueles que possuam o salário maior que 11.000. Ordene os dados pelos mesmos campos do select, seguindo a mesma ordem do enunciado. Primeiro passo Identifico no enunciado as fontes de dados, ou seja, as tabelas que farão parte do comando SQL. Neste nosso exemplo, as tabelas são: REGIONS, COUNTRIES, LOCATIONS, DEPARTMENTS e EMPLOYEES, pois o enunciado nos diz isto. Contudo, se ele não diz os nomes das tabelas, pelo menos deve mencionar do que se tratam tais informações, por exemplo, empregados, departamentos, países etc. Se você tiver o MER (Modelo Entidade Relacionamento, veja anexos 26) fica mais fácil, pois nele você consegue verificar a localização de tais informações referentes aos nomes das tabelas ou os nomes dos campos os quais o enunciado pede. Exemplo: REGION_NAME, CITY etc. Caso não tenha o MER, você pode localizar tais tabelas no banco de dados, executando um select na user_tables ou all_tables para tentar localizá-las através dos seus nomes. Tendo as localizado, você pode executar o comando desc em cima de cada uma delas para visualizar suas colunas e identificar as informações solicitadas. Veja o exemplo a seguir: ❙◗▲❃ s❡❧❡❝t t❛❜❧❡❴♥❛♠❡ ✷ ❢r♦♠ ✉s❡r❴t❛❜❧❡s❀ ❚❆❇▲❊❴◆❆▼❊ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❊▼P 406 Casa do Código Capítulo 24. Apêndice: SQL – Primeiros passos ❉❊P❚ ❇❖◆❯❙ ❙❆▲●❘❆❉❊ ❉❯▼▼❨ ❘❊●■❖◆❙ ▲❖❈❆❚■❖◆❙ ❉❊P❆❘❚▼❊◆❚❙ ❏❖❇❙ ❊▼P▲❖❨❊❊❙ ❏❖❇❴❍■❙❚❖❘❨ ❈❖❯◆❚❘■❊❙ ✷✸ ❧✐♥❤❛s s❡❧❡❝✐♦♥❛❞❛s✳ ❙◗▲❃ Caso você queira ver se há comentários sobre tais tabelas, por exemplo, indicando sua finalidade, você pode executar um select na user_tab_comments ou all_tab_comments, pesquisando pelo nome da tabela. Lembrando que utilizando a tabela com prefixo all você deve informar a que usuário, ou melhor, a qual dono, a tabela pertence. Veja o exemplo: ❙◗▲❃ s❡❧❡❝t ❝♦♠♠❡♥ts ✷ ❢r♦♠ ✉s❡r❴t❛❜❴❝♦♠♠❡♥ts ✸ ✇❤❡r❡ t❛❜❧❡❴♥❛♠❡ ❂ ✬❊▼P▲❖❨❊❊❙✬❀ ❈❖▼▼❊◆❚❙ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❡♠♣❧♦②❡❡s t❛❜❧❡✳ ❈♦♥t❛✐♥s ✶✵✼ r♦✇s✳ ❘❡❢❡r❡♥❝❡s ✇✐t❤ ❞❡♣❛rt♠❡♥ts✱ ❥♦❜s✱ ❥♦❜❴❤✐st♦r② t❛❜❧❡s✳ ❈♦♥t❛✐♥s ❛ s❡❧❢ r❡❢❡r❡♥❝❡✳ ❙◗▲❃ Segundo passo Conectado ao banco de dados, através de uma ferramenta, exemplo SQL*Plus, faço um breve reconhecimento das tabelas envolvidas no enun407 Casa do Código 24.1. Como iniciar no SQL ciado. Seguindo o exemplo, vamos analisar através do comando desc as tabelas e colunas que identificamos, como as tabelas EMPLOYEES e DEPARTMENTS. ❙◗▲❃ ❞❡s❝ ❡♠♣❧♦②❡❡s ◆♦♠❡ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❊▼P▲❖❨❊❊❴■❉ ❋■❘❙❚❴◆❆▼❊ ▲❆❙❚❴◆❆▼❊ ❊▼❆■▲ P❍❖◆❊❴◆❯▼❇❊❘ ❍■❘❊❴❉❆❚❊ ❏❖❇❴■❉ ❙❆▲❆❘❨ ❈❖▼▼■❙❙■❖◆❴P❈❚ ▼❆◆❆●❊❘❴■❉ ❉❊P❆❘❚▼❊◆❚❴■❉ ❇■❘❚❍❴❉❆❚❊ ❍■❘❊❴❉❆❚❊❴❇❑P ❙◗▲❃ ❞❡s❝ ❞❡♣❛rt♠❡♥ts ◆♦♠❡ ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❉❊P❆❘❚▼❊◆❚❴■❉ ❉❊P❆❘❚▼❊◆❚❴◆❆▼❊ ▼❆◆❆●❊❘❴■❉ ▲❖❈❆❚■❖◆❴■❉ ❚✐♣♦ ◆✉❧♦❄ ✲✲✲✲✲✲✲✲ ✲✲✲✲✲✲✲✲✲✲✲✲✲ ◆❖❚ ◆❯▲▲ ◆❯▼❇❊❘✭✻✮ ❱❆❘❈❍❆❘✷✭✷✵✮ ◆❖❚ ◆❯▲▲ ❱❆❘❈❍❆❘✷✭✷✺✮ ◆❖❚ ◆❯▲▲ ❱❆❘❈❍❆❘✷✭✷✺✮ ❱❆❘❈❍❆❘✷✭✷✵✮ ◆❖❚ ◆❯▲▲ ❉❆❚❊ ◆❖❚ ◆❯▲▲ ❱❆❘❈❍❆❘✷✭✶✵✮ ◆❯▼❇❊❘✭✽✱✷✮ ◆❯▼❇❊❘✭✷✱✷✮ ◆❯▼❇❊❘✭✻✮ ◆❯▼❇❊❘✭✹✮ ❉❆❚❊ ❉❆❚❊ ◆✉❧♦❄ ✲✲✲✲✲✲✲✲ ◆❖❚ ◆❯▲▲ ◆❖❚ ◆❯▲▲ ❚✐♣♦ ✲✲✲✲✲✲✲✲✲✲✲✲✲ ◆❯▼❇❊❘✭✹✮ ❱❆❘❈❍❆❘✷✭✸✵✮ ◆❯▼❇❊❘✭✻✮ ◆❯▼❇❊❘✭✹✮ ❙◗▲❃ Terceiro passo Inicio a escrita do comando SQL, preenchendo a cláusula select com as colunas que devo mostrar, e a cláusula from informando às tabelas que vou precisar para recuperar todas as informações. s❡❧❡❝t r✳r❡❣✐♦♥❴♥❛♠❡ 408 Casa do Código Capítulo 24. Apêndice: SQL – Primeiros passos ✱❧✳❝✐t② ✱❞✳❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✱❡✳❢✐rst❴♥❛♠❡ ❢r♦♠ r❡❣✐♦♥s r ❝ ✱❝♦✉♥tr✐❡s ✱❧♦❝❛t✐♦♥s ❧ ✱❞❡♣❛rt♠❡♥ts ❞ ✱❡♠♣❧♦②❡❡s ❡ Note que nem sempre são mencionadas no enunciado todas as tabelas de que precisaremos para retornar todas as informações. Desta forma, precisamos consultar novamente o MER, para entender quais são todas as ligações e de quais objetos vamos necessitar. Vale salientar que entre as tabelas, na maioria dos casos, existe uma ou mais colunas que são as responsáveis pelas ligações entre elas. Necessitamos fazer estas ligações para que o resultado retornado seja o resultado correto, e a integridade seja mantida. Outro fator importante: sempre utilizo apelidos (aliasl) para identificar as tabelas e colunas em um comando SQL. Isso serve para evitar erros de colunas ambíguas (colunas com nomes iguais entre as tabelas, pois, neste caso, o Oracle não sabe dizer quem é quem), e para tornar a leitura do comando SQL mais inteligível. Quarto passo Fazer as ligações entre as tabelas que estamos utilizando na cláusula from. ✶✵ ✶✶ ✶✷ ✶✸ ✇❤❡r❡ ❛♥❞ ❛♥❞ ❛♥❞ r✳r❡❣✐♦♥❴✐❞ ❝✳❝♦✉♥tr②❴✐❞ ❧✳❧♦❝❛t✐♦♥❴✐❞ ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ❂ ❂ ❂ ❂ ❝✳r❡❣✐♦♥❴✐❞ ❧✳❝♦✉♥tr②❴✐❞ ❞✳❧♦❝❛t✐♦♥❴✐❞ ❡✳❞❡♣❛rt♠❡♥t❴✐❞ Caso não se tenha o MER, podemos fazer um select nas views user_constraints e user_cons_columns, para tentar localizar as ligações entre as tabelas. Exemplo: ❙◗▲❃ s❡❧❡❝t ❝♦♥s✳t❛❜❧❡❴♥❛♠❡⑤⑤✬✳✬⑤⑤❝♦♥s❴❝♦❧✳❝♦❧✉♠♥❴♥❛♠❡⑤⑤ ✷ ✬ ❢❛③ ❧✐❣❛çã♦ ❝♦♠ ✬⑤⑤ 409 24.1. Como iniciar no SQL Casa do Código ✸ ❝♦♥s❴❞❡♣❡♥❞✳t❛❜❧❡❴♥❛♠❡⑤⑤✬✳ ✬⑤⑤❝♦♥s❴❝♦❧❴❞❡♣❡♥❞✳❝♦❧✉♠♥❴♥❛♠❡⑤⑤✬ ✬⑤⑤ ✬❛tr❛✈és ❞❛ ❝❤❛✈❡ ✬⑤⑤❝♦♥s✳❝♦♥str❛✐♥t❴♥❛♠❡ ✧ ✹ ❉❡♣❡♥❞ê♥❝✐❛s✧ ✺ ❢r♦♠ ✲✲ t❛❜❡❧❛ ♣❡sq✉✐s❛ ✻ ✉s❡r❴❝♦♥str❛✐♥ts ❝♦♥s ✼ ✱✉s❡r❴❝♦♥s❴❝♦❧✉♠♥s ❝♦♥s❴❝♦❧ ✽ ✲✲ t❛❜❡❧❛ ❞❡♣❡♥❞❡♥❝✐❛ ✾ ✱✉s❡r❴❝♦♥str❛✐♥ts ❝♦♥s❴❞❡♣❡♥❞ ✶✵ ✱✉s❡r❴❝♦♥s❴❝♦❧✉♠♥s ❝♦♥s❴❝♦❧❴❞❡♣❡♥❞ ✶✶ ✇❤❡r❡ ❝♦♥s✳❝♦♥str❛✐♥t❴♥❛♠❡ ❂ ❝♦♥s❴❝♦❧✳❝♦♥str❛✐♥t❴♥❛♠❡ ✶✷ ❛♥❞ ❝♦♥s✳t❛❜❧❡❴♥❛♠❡ ❂ ❝♦♥s❴❝♦❧✳t❛❜❧❡❴♥❛♠❡ ✶✸ ❛♥❞ ❝♦♥s✳t❛❜❧❡❴♥❛♠❡ ❂ ✬❊▼P▲❖❨❊❊❙✬ ✲✲ t❛❜❡❧❛ ♣❛r❛ ♣❡sq✉✐s❛ ✶✹ ❛♥❞ ❝♦♥s✳❝♦♥str❛✐♥t❴t②♣❡ ❂ ✬❘✬ ✲✲ ❋♦r❡✐❣♥ ❦❡② ✭❧✐❣❛çã♦ ❡♥tr❡ ❛s t❛❜❡❧❛s✮ ✶✺ ✲✲ ✶✻ ❛♥❞ ❝♦♥s❴❞❡♣❡♥❞✳❝♦♥str❛✐♥t❴♥❛♠❡ ❂ ❝♦♥s❴❝♦❧❴❞❡♣❡♥❞✳❝♦♥str❛✐♥t❴♥❛♠❡ ✶✼ ❛♥❞ ❝♦♥s❴❞❡♣❡♥❞✳t❛❜❧❡❴♥❛♠❡ ❂ ❝♦♥s❴❝♦❧❴❞❡♣❡♥❞✳t❛❜❧❡❴♥❛♠❡ ✶✽ ❛♥❞ ❝♦♥s❴❞❡♣❡♥❞✳❝♦♥str❛✐♥t❴♥❛♠❡ ❂ ❝♦♥s✳r❴❝♦♥str❛✐♥t❴♥❛♠❡ ✶✾ ♦r❞❡r ❜② ✶ ✷✵ ✴ ❉❡♣❡♥❞ê♥❝✐❛s ✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲✲ ❊▼P▲❖❨❊❊❙✳❉❊P❆❘❚▼❊◆❚❴■❉ ❢❛③ ❧✐❣❛çã♦ ❝♦♠ ❉❊P❆❘❚▼❊◆❚❙✳❉❊P❆❘❚▼❊◆❚❴■❉ ❛tr❛✈és ❞❛ ❝❤❛✈❡ ❊▼P❴❉❊P❚❴❋❑ ❊▼P▲❖❨❊❊❙✳❏❖❇❴■❉ ❢❛③ ❧✐❣❛çã♦ ❝♦♠ ❏❖❇❙✳❏❖❇❴■❉ ❛tr❛✈és ❞❛ ❝❤❛✈❡ ❊▼P❴❏❖❇❴❋❑ ❊▼P▲❖❨❊❊❙✳▼❆◆❆●❊❘❴■❉ ❢❛③ ❧✐❣❛çã♦ ❝♦♠ ❊▼P▲❖❨❊❊❙✳❊▼P▲❖❨❊❊❴■❉ ❛tr❛✈és ❞❛ ❝❤❛✈❡ ❊▼P❴▼❆◆❆●❊❘❴❋❑ ❙◗▲❃ Observação: 410 Você pode utilizar este select sempre que possível. Casa do Código Capítulo 24. Apêndice: SQL – Primeiros passos Guarde-o! Quinto passo Colocar as demais críticas (restrições) solicitadas pelo enunciado. ✶✹ ❛♥❞ ❡✳s❛❧❛r②❃ ✶✶✵✵✵ ✶✺ ♦r❞❡r ❜② r✳r❡❣✐♦♥❴♥❛♠❡ ✶✻ ✱❧✳❝✐t② ✶✼ ✱❞✳❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✶✽ ✱❡✳❢✐rst❴♥❛♠❡❀ Segue o comando SQL completo: ❙◗▲❃ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✶✵ ✶✶ ✶✷ ✶✸ ✶✹ ✶✺ ✶✻ ✶✼ ✶✽ s❡❧❡❝t r✳r❡❣✐♦♥❴♥❛♠❡ ✱❧✳❝✐t② ✱❞✳❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✱❡✳❢✐rst❴♥❛♠❡ ❢r♦♠ r❡❣✐♦♥s r ✱❝♦✉♥tr✐❡s ❝ ✱❧♦❝❛t✐♦♥s ❧ ✱❞❡♣❛rt♠❡♥ts ❞ ✱❡♠♣❧♦②❡❡s ❡ ✇❤❡r❡ r✳r❡❣✐♦♥❴✐❞ ❂ ❝✳r❡❣✐♦♥❴✐❞ ❛♥❞ ❝✳❝♦✉♥tr②❴✐❞ ❂ ❧✳❝♦✉♥tr②❴✐❞ ❛♥❞ ❧✳❧♦❝❛t✐♦♥❴✐❞ ❂ ❞✳❧♦❝❛t✐♦♥❴✐❞ ❛♥❞ ❞✳❞❡♣❛rt♠❡♥t❴✐❞ ❂ ❡✳❞❡♣❛rt♠❡♥t❴✐❞ ❛♥❞ ❡✳s❛❧❛r②❃ ✶✶✵✵✵ ♦r❞❡r ❜② r✳r❡❣✐♦♥❴♥❛♠❡ ✱❧✳❝✐t② ✱❞✳❞❡♣❛rt♠❡♥t❴♥❛♠❡ ✱❡✳❢✐rst❴♥❛♠❡❀ Observações: para os demais comandos, como o insert, o delete e o update, podemos seguir o mesmo raciocínio. Primeiramente, identificamos as tabelas, as colunas para as ligações e restrições, se for o caso, e depois escrevemos o comando. 411 Capítulo 25 Referências bibliográficas • DATE, C. J. Introdução a Sistemas de Bancos de Dados. Rio de Janeiro: Campus, 1991. • FERNANDES, Lúcia. Oracle 9i Para Desenvolvedores - Curso Completo. Rio de Janeiro: Axcel Books, 2002. • GENNICK, Jonathan, LUERS, Tom. Aprenda em 21 dias PL/SQL. 2. ed. Rio de Janeiro: Campus, 2000. • HEUSER, Carlos Alberto. Projeto de Banco de Dados. 4. ed. Porto Alegre: Sagra Luzzatto, 2001. • LIMA, Adilson da Silva. Erwin 4.0 Modelagem de Dados. 2. ed. São Paulo: Érica, 2002. Casa do Código • LONEY, Kevin et al. Oracle 9i: O Manual do DBA. Rio de Janeiro: Campus, 2002. • MOLINARI, Leonardo. BTO Otimização da Tecnologia de Negócio. São Paulo: Érica, 2003. • ORACLE Database Online Documentation 10g Release 1 (10.1). Disponível em: <http://www.oracle.com/pls/db10g/portal.portal_demo3? selected=1> . Acesso em: 16 mar. 2011. • Oracle Database New Features Guide 11g, Release 2 (11.2) • Oracle Database Advanced Application Developer’s Guide 11g Release 2 (11.2) • Oracle Database PL/SQL Language Reference 11g Release 2 (11.2) • Oracle Database Reference 11g Release 2 (11.2) • Oracle Database SQL Language Reference 11g Release 2 (11.2) • Oracle Database Concepts 11g, Release 2 (11.2) • Oracle Database PL/SQL Packages and Types Reference 11g Release 2 (11.2) • Oracle Database SQL Developer User’s Guide Release 3.1 414 Capítulo 26 Casa do Código Anexos Fig. 26.1: Esquema da base de dados SCOTT utilizada nos exemplos 416 Casa do Código Capítulo 26. Anexos Fig. 26.2: Esquema da base de dados HR utilizada nos exemplos 417