Você está na página 1de 200

APRENDENDO BANCO DE DADOS

MYSQL
Do básico ao avançado

Jorge Costa Leite Júnior

Amazon Press.
 
 
Aprendendo banco de dados com mysql

Do básico ao avançado
Jorge Costa Leite Júnior

1a Edição - Salvador/BA

Novembro de 2021
Ficha catalográfica
 

J82  LEITE JR. Jorge Costa

Aprendendo Banco de Dados MYSQL - Do Básico


ao Avançado.  Amazon Press.  2021.

ISBN: 978-65-00-35482-9

1. Técnico. 2. Computação. 3. Banco de Dados.


4. SQL. 5. MySQL. 6. MariaDB. I. Leite Jr,
Jorge Costa. II. Título.

CDU: 004.65 / 42

Direitos autorais © 2021 Jorge Costa Leite Júnior

Nenhuma parte deste livro pode ser reproduzida ou armazenada em um sistema de recuperação,
ou transmitida de qualquer forma ou por qualquer meio, eletrônico, mecânico, fotocópia, gravação ou
outro, sem a permissão expressa por escrito da editora.

ISBN: 978-65-00-35482-9

1. Banco de Dados. 2. SQL 3. MySQL 4.MariaDB

Dedico este livro a todas a pessoas que pude aprender um pouco nessa vida. Todos
aprendemos com todos, ninguém é incapaz de ensinar ou aprender. Este livro é dedicado a
meus pais, irmãos e amigos. Também a todos os meus estudantes, com suas dúvidas e
inquietações me desafiaram a produzir esta obra com o propósito de ajudá-los no seu
progresso nesta área da Computação, em especial, Banco de Dados.

agradecimentos

Aos meus pais, amigos, professores e estudantes. Com todos aprendi,


cresci e me aperfeicoei. A todos os meus professores que sempre me
incetivaram, desafiaram e buscaram meu progresso teórico e profissional.
Agradeço a Deus, por inspiração nos momentos de "branco" criativo
durante o processo de escrita do livro.

Agradecimentos em especial ao estudante, professor e parceiro de


projetos, João Franco, pelo design da capa do livro. Também sou grato aos
colegas que viram o livro, na sua versão e rascunho e sugeriram uma série
de ajustes para o resultado final desta obra.

Que um pouco desse aprendizado possa ser útil a quem ler este livro.

"Não se trata apenas do que estamos passando na vida, mas em


quem estamos nos tornando. Há alegria em prosseguir para o alvo."

Élder Edward Dube


Apresentação

Sistemas gerenciadores de banco de dados (SGBD) surgiram no início da


década de 70 com o objetivo de facilitar a programação de aplicações de
banco de dados (BD). Boa parte de todo desenvolvimento de sistemas,
aplicativos e serviços digitais estão baseados em banco de dados. A
importância e uso de banco de dados ganhou maior importância com o
advindo das redes de internet e a cooperação de sistemas diversos.

Este livro objetiva ensinar um conjunto de conceitos, técnicas e


estratégia para criação, manipulação, manutenção e otimização de banco de
dados através de ferramentas de software (ou SGBD), em especial, o
MySQL e seu derivado MariaDB. A abordagem deste livro busca partir do
concreto ao abstrato, apresentando casos práticos e depois discussões e
cenários para os bancos de dados exemplo, apresentados, tratando não
somente de questões práticas, mas também conceituais. Não é apenas
importante saber como fazer (uso de linguagem de consultas), mas porque e
como está fazendo. De modo, a se obter melhores resultados em seu
trabalho de programador de banco de dados.

Além do que foi dito, este livro tem como objetivo atender (e subsidiar)
à quatro públicos distintos. Primeiramente, estudantes de cursos técnicos de
Informática e áreas afins (normalmente do Ensino Médio), cuja literatura
normalmente é de livros de cursos superiores, dificultando, nos casos e
modelos apresentados uma compreensão dos conceitos adequados. O
segundo grupo é o de alunos de graduação de Ciência da Computação, de
Informática ou cursos semelhantes. Um terceiro público é o de usuários de
SGBD pessoais, que desejem sistematizar o projeto de seus bancos de
dados, que vão desde a criação de tabelas, consultas avançadas até o uso de
gatilhos (triggers). Um quarto público, são de meus colegas docentes, que
possam ter passado por desafios semelhantes aos meus, necessitando de
uma literatura mais adequada aos seus grupos de estudantes, com uma
linguagem mais simples e mais modelos e exercícios práticos,
especialmente nos cursos profissionalizantes de Informática e afins.

O livro está organizado de forma a não exigir conhecimentos prévios na


área de banco de dados ou de engenharia de software, ou até mesmo
iniciantes em programação. Começa tratando dos conceitos básicos de
dados, informação, conhecimento e bancos de dados. A seguir, apresenta
conceitos básicos de tabelas e atributos. Depois disto, apresenta a instalação
do servidor SGBD MySQL, apresentando sua configuração e seus
primeiros comandos. Uma vez com as ferramentas configuradas,
começamos a trabalhar a linguagem SQL – Linguagem estrutura de
consulta para modificar, criar, otimizar e explorar os recursos de vários
bancos de dados contidos no livro. Comandos de Seleção, inserção,
exclusão, alteração de dados são apresentados, bem como, outros comandos
de criação de bancos de dados, tabelas, atributos, com alterações em suas
estruturas de atributos, etc.

No avançar do livro, são apresentadas consultas mais bem sofisticadas


com filtros, ordenações, agrupamentos, sub-consultas. Nesse caminhar, são
apresentadas junções de tabelas com JOINS, visões de dados (Views),
programação estruturada no SGBD e banco de dados com apresentação dos
conceitos de Procedimentos (Stored Procedures) e funções (Functions). São
apresentados conceitos básicos de programação estruturada PL/SQL, com
exemplos práticos. Finalmente, finalizamos o livro com uma discussão de
gatilhos (Triggers) com exemplos de aplicação, conceitos teóricos, e
cenários de uso. Deste modo esse livro busca ir do básico ao avançado na
programação de banco de dados, numa crescente de exemplos, conceitos e
exercícios, num processo de exercício contínuo de práticas na busca da
formação de um bom programador de banco de dados.

Prefácio

Com muita honra recebo o convite de JORGE COSTA LEITE JÚNIOR


para prefaciar “Aprendendo Banco de Dados MYSQL: Do básico ao
avançado”, esta obra se propõe a ser uma referência bastante interessante no
aprendizado prático de banco de dados.

Há várias obras de referência que abordam bancos de dados com


aspectos mais focados ao meio acadêmico ou focados exclusivamente em
questões profissionais. Esta obra se diferencia por ter o olhar de um
profissional de educação experiente na Educação Profissional, em que é
necessário material com alta qualidade técnica, mas que ao mesmo tempo
esteja alinhado com os aspectos práticos necessários para a formação
profissional.

Esta obra foca nos elementos essenciais para o ensino de banco de


dados e ao mesmo tempo busca instanciar com o uso de um sistema
gerenciador de banco de dados livre e de amplo uso na comunidade, o
MYSQL. As perspectivas trazidas por esta obra são bem interessantes,
trazendo a visão do autor com vasta experiência na formação de pessoas e
no fazer e gestão de sistemas de banco de dados.
Por estas razões, entre outras que se desvelam no conteúdo prático,
claro e didático deste livro, é com orgulho e grata satisfação que apresento e
recomendo a presente obra. Boa leitura!

Prof. ALLAN EDGARD SILVA FREITAS


Doutor e Bacharel em Ciência da Computação e Mestre em Engenharia Elétrica (UFBA);
Professor Titular do Instituto Federal da Bahia e Docente Permanente do Programa de Pós-
Graduação em Engenharia de Sistemas e Produtos; Membro do Comitê Técnico em Blockchain da
RNP (CT-Blockchain).

Índice
Página do título
Aprendendo banco de dados com mysql
Direitos autorais
Dedicatória
agradecimentos
Epígrafe
Apresentação
Prefácio
1. Introdução
2. Bancos de dados
3. Um pouco sobre o uso do MySQL
4. Explorando um banco de dados real
5. Como Modificar dados de um banco?
6. Criando nossos próprios bancos e tabelas
7. Ampliando nossos conhecimentos sobre o Select, Delete, Insert e
Update
8. Junções de tabelas
9. Visões (Views) ou visualização de dados de tabelas
10. Procedimentos Armazenados no servidor – Stored Procedures
11. Programação estruturada em PL/SQL
12. Funções armazenadas ou Functions
13. Gatilhos ou Triggers
Sobre o autor
1. Introdução

No contexto atual da sociedade, a quantidade de informação e dados é


gigantesca, indo desde meros dados pessoais, como data de nascimento e
nome de pessoas, ou bits, a um conjunto enorme de informações em fichas,
históricos médicos, dados escolares, censos demográficos, dados registrados
em redes sociais na forma de imagens, sons, vídeos, textos e todo tipo de
mídia capaz de representar alguma informação ou representar conhecimento.

Para entender a importância dos bancos de dados, precisamos primeiro


compreender os conceitos básicos, que nos conduzem a toda uma sistemática
de armazenamento e organização de toda informação, que parte de dados
unitários à conjuntos de informações representados, conhecimentos
armazenados e disponibilizados nas diversas fontes de dados e redes
telemáticas.
Basicamente, boa parte da informação está armazenada em dispositivos
digitais, compartilhadas por redes de computadores, servidores e toda sorte
de dispostivos informacionais. Tal enormidade de dados são controladas por
sistemas computacionais, conhecidos, principalmente como sistemas
gerenciadores de bancos de dados (SGBD).

Ao longo deste livro, voltado principalmente para cursos técnicos,


motivo pelo qual a linguagem e estilo de escrita, buscará afastamento do
rigor acadêmico, sendo concentrado na manipulação de dados através do
SGBD MySQL, e seu banco derivado MariaDB.

Partindo do concreto para o abstrato, o objetivo aqui é através de


exemplos simples e exercícios práticos ajudar o estudante de informática ou
computação a se adentrar nessa área de conhecimento importantíssima no
contexto atual da sociedade, buscando uma aprendizagem significativa.
2. Bancos de dados

Para começar, precisamos entender o que é um dado. Dado é a menor


unidade de informação. Poderíamos dizer que é uma forma atômica de
informação. Por exemplo, numa carteira de identidade temos um conjunto de
dados diversos (data de nascimento, nome, local de nascimento, data da
emissão, etc.). Cada uma dessas informações isoladamente, representam a
menor unidade de informação possível, e separadamente (e desassociados)
representam valores isolados.

Quando um conjunto de dados se associam com um propósito, como, por


exemplo, um registro geral expresso numa carteira de identidade, temos
informações sobre uma pessoa. Numa linguagem simples, dados associados
representam uma informação.

Uma pergunta que pode vir a mente é: “então o que é Conhecimento?”.

Essa questão pode ter várias respostas filosóficas, mas aqui no nosso
contexto, conhecimento é como eu trabalho (técnicas, abordagens, etc.) o
conjunto de informações disponíveis para solucionar uma situação-
problema.
Os Bancos de dados ou Base de Dados (BD) são conjuntos de dados que
contém informações ou registros sobre coisas (objetos da realidade),
pessoas, lugares, situações. São organizados de tal forma, a dar sentido ao
conjunto de dados correlacionados. Isso significa que um BD de uma
clínica é completamente diferente de um BD de uma escola, já que o
conjunto de dados e a forma como se relacionam, e seu propósito são
completamente distintos, pois os dados ali representam uma realidade do dia
a dia completamente diferente entre uma escola e clínica.

Deste modo, não se imagina um banco de dados de propósito geral.


Ainda que bancos de dados diferentes possam se comunicar por meio de
redes de computadores e trocar dados e informações entre si para propósitos
além dos quais foram projetados.

Vale ressaltar que todo BD é projetado (ou modelado) para que se


obtenha um um conjunto mínimo de dados, que possa dar conta da
representação abstrata (focada nos dados) de uma realidade. Um modelo
busca simplificar as complexidades da realidade, concentrando-se no que é
essencial para solucionar um problema.

Talvez você lembre, que nos problemas e exercícios de Física, na escola,


por exemplo, que você despreze o vento, atritos, influência da temperatura e
outras variáveis (ou dados) para calcular a velocidade média de um corpo
que se move ou o tempo de queda de um objeto. Neste sentido, modelar uma
realidade significa selecionar um conjunto mínimo de dados ou variáveis
capazes de dar conta da solução de um problema. Essa solução é sempre
baseada num ponto de vista, conjunto de conhecimentos ee/ou técnicas, ou
perspectivas. Pois, a realidada é muito mais complexa.

A forma mais comum de um banco de dados ser representado é na forma


de tabelas de dados. Provavelmente você já viu uma tabela contendo um
conjunto de informações como a tabela a seguir: Tabela 1.1 – Dados de Pessoas
Observe, que a tabela 1.1 contém dados de pessoas (nome, idade, sexo) é
dividida em três colunas (ou atributos). Vários autores de livros de bancos de
dados chamam tais colunas de campo ou atributo. Cada linha da tabela é
chamada de registro, que é onde, de fato, os dados estão guardados. Outro
nome comum para tabela é ENTIDADE.

Uma Entidade é uma representação de um conjunto de dados


(informações) sobre um determinado objeto de uma realidade (sistema)
modelada. No caso da tabela 1.1, poderíamos chamar essa Entidade de
PESSOA, uma vez que seu objetivo (didático) é representar um conjunto de
informações de uma ou várias pessoas. Toda entidade é constituída de
atributos (ou variáveis, como em linguagens de programação) que objetivam
representar alguma informação unitária (dado) pertinente a um determinado
contexto ou realidade modelada.

Uma pergunta que pode surgir é: “basta ter uma tabela ou planilha para
termos um banco de dados?”

A resposta para esta pergunta não é tão simples, mas podemos ter banco
(ou base) de dados com apenas uma tabela (ou entidade) ou dezenas delas,
dependendo do problema ou situação modelada para o qual o banco de dados
foi projetado. Mas sim, podemos ter bancos de dados com várias tabelas que
se relacionam entre si com propósitos específicos. Na figura a seguir vamos
ver uma representação de um banco de dados com várias tabelas.

Figura 2.1 – Representação de um modelo de dados com três


tabelas.

Daqui em diante, vamos usar o termo tabela como sinônimo de entidade


para facilitar o entendimento dos exemplos a seguir. Vamos tomar como
sinônimos também coluna, campo e atributo. Na figura 2.1, temos três
tabelas: CLIENTES, FATURAS, VENDEDORES. A tabela CLIENTES é
composta pelos atributos: idclientes, nome, endereço, cidade, CEP.

Percebam que nesta notação de modelo, temos uma chave ao lado do


atributo idclientes. Neste caso dizemos que este atributo é um atributo-chave
ou uma chave primária. Geralmente, a chave primária é um atributo que
nunca se repete o valor (do dado) e serve para ser vinculado a outras
informações. No dia a dia, por exemplo o CPF pode ser considerado um
atributo-chave, uma vez que um carro comprado é vinculado ao CPF do
dono, casa, bens etc. Esse atributo acaba atuando de duas maneiras: a
primeira é uma busca para não duplicidade de dados (duas pessoas não
podem ter o mesmo CPF). Mas por outro lado um mesmo CPF pode ter
vários bens, etc. Observem que na tabela FATURAS temos também o
atributo idclientes, que associa uma ou mais faturas a um cliente. Além disso
também temos o atributo idvendedores que associa aquela fatura ao
vendedor responsável. Se observarmos a tabela VENDEDORES temos uma
chave primária (ou atributo-chave) chamado idvendedores.

A aparente coincidência aqui é que as chaves primárias das tabelas


CLIENTES e VENDEDORES também estão presentes na tabela
FATURAS. Por associar clientes e vendedores a faturas, tais chaves têm
papel associativos, e como tem origem em outras tabelas, tais atributos são
chamados de chaves estrangeiras.

Observem que ao lado de cada atributo temos um tipo de dados definido


para aquele atributo. Se você veio de alguma linguagem de programação
anterior, possivelmente já tenha conhecido os tipos básicos de dados ou
variáveis como: Integer, Boolean, String, Char, Double, Float e outros.
Nos BD existem inúmeros tipos de dados dentre os quais podemos citar:

Tabela 2 – Tipos básicos de dados no MySQL


Esses são apenas alguns tipos de dados possíveis. Ao longo deste livro,
vamos apresentar tipos diferentes de dados, os quais podem ser utilizados em
diferentes cenários de dados.

Agora você pode estar se perguntando: como eu uso isso tudo?

Bem, para acessar os dados de um banco de dados precisamos usar um


programa de computador (software) que gerencie e manipule o acesso a tais
dados. Esses programas são conhecidos como Sistemas Gerenciadores de
Bancos de Dados – SGBD, cujos objetivos principais são:

1.
Separar dados da aplicação cliente, evitando a mistura de dados e
programa, permitindo compartilhamento de dados
2. Prover uma interface (gráfica, normalmente) para que os usuários
possam incluir, alterar, remover ou consultar dados já armazenados
3. Controlar o acesso aos dados, aumentando a segurança
4. Simplificar ao programador e usuário uma forma de projetar e
visualizar a estrutura de dados (modelo) para o BD através de
ferramentas de gestão, modelagem e manipulação de dados.

No decorrer deste livro, vamos adotar um SGBD para iniciar nossos


conhecimentos sobre bancos de dados e manipulação de dados. Esse SGBD
será o MySQL SERVER, que é um gerenciador de banco de dados que
utiliza a linguagem SQL (linguagem estruturada de consulta) para acessar e
manipular dados. Todos os exemplos funcionam no MariaDB.

O MYSQL (assim como seu derivado MariaDB) é um dos mais


populares SGBD do mundo, e tem como características interessantes sua
portabilidade (roda em vários sistemas operacionais), compatível com várias
linguagens de programação, trabalha em rede, com excelente desempenho e
estabilidade a baixo custo computacional.

Além disso, também é um software livre, com curva de aprendizagem


baixa, e facilidade no uso, e grande documentação na internet. Os recursos
do MySQL o permitem suportar grandes quantidades de dados, estando ele
presente em grandes e sistemas complexos diversos espalhados pelo mundo.

Questões Teóricas

1. Qual a diferença entre informação e dado?


2. Qual o significado de um conjunto de dados associados?
3. O que é conhecimento? Qual sua relação com dados e informações?
4. O que é um Banco de Dados? Qual seu propósito?
5. Existe Banco de Dados de propósito geral? Justifique sua resposta.
6. Qual a forma mais comum de representação de bancos de dados?
7. O que são atributos e tabelas?
8. O que é atributo-chave, chave primária e chave estrangeira?
9. Quais são os principais tipos de dados para atributos de bancos de
dados?
10. O que são Sistemas Gerenciadores de Banco de Dados - SGBD?
11. Quais as principais funcionalidades de um SGBD?
12. O que é o MySql? Quais suas características?
3. Um pouco sobre o uso do MySQL

Instalação do MySQL

Para instalação do MySQL, é importante seguir as orientações da


documentação oficial e no link de download oficial[1]. É muito importante
ficar atento aos passos gerais da instalação. O guia de instalação é bem
interativo e, é possível, que no Windows algumas bibliotecas sejam
requeridas para o processo de instalação ser bem-sucedido. Para instalar o
MariaDB, basta seguir este link. Considere essa possibilidade, muito mais
simples.

Um ALERTA IMPORTANTE é que durante o processo de instalação,


o usuário nunca esquecer de definir a senha do super usuário (administrador
do servidor) chamado root na instalação do programa. Sendo esse o erro
mais comum no processo de instalação. A Figura 3.1 mostra a tela crítica na
instalação. Neste momento se pode criar outros usuários (não
administradores, inclusive) para acessar recursos limitados do SGBD.
Lembrando que MySQL ROOT PASSWORD e REPEAT PASSWORD
devem ser idênticas.

Figura 3.1 – Criação de senha para o administrador root

Para criar outros usuários basta clicar em ADD USER e uma janela vai
aparecer permitindo a criação desse novo usuário e seu perfil de acesso,
conforme a figura 3.2.
Figura 3.2 – Tela de criação de novos usuários

Caso seja um usuário inexperiente, pode-se na instalação definir como


um serviço o MySQL., para que ele possa inicializar junto com o sistema
operacional. Lembrando que esta decisão acarretará, em mais um programa
consumindo memória e processamento do seu computador ou servidor.

Para marcar o MySQL como um serviço basta marcar a opção


CONFIGURE MySQL Server as Windows Service e a opção Start
the MySQL Server at System Startup conforme figura 3.3.

Figura 3.3 – Configurando o MySQL na inicialização do Windows e


como um serviço.

Finalmente, após o processo de instalação concluído, pode-se testar o


usuário root e a senha especificada, de modo a se certificar, se o servidor
está instalado e configurado adequadamente, conforme a figura 3.4.
Figura 3.4 – Teste de conexão para servidor bem-sucedido

Uso do MySQL

Uma vez instalado e configurado o MySQL, vamos agora passar utilizar


seus recursos. No escopo desse livro vamos trabalhar a manipulação de
dados, portanto não vamos entrar nos pormenores de modelagem de dados.

Vamos focar na Linguagem Estruturada de Consulta – SQL (sigla do


idioma inglês). Para acessar a área de acesso ao SQL e suas ferramentas,
vamos fazer o seguinte: Vamos buscar o cliente (software de acesso ao
servidor MySQL) chamado MySQL Workbench. Ele pode ser acessado no

menu iniciar conforme figura 3.5:

Figura 3.5 – Acesso ao MySQL Workbench

Uma observação importante, é que outros programas/ferramentas


clientes podem ser utilizados para conectar ao MySQL. Um excelente cliente
SQL recomendado éo HeidiSQL, que pode ser obtido aqui. Voltando ao
nosso cliente escolhido, por ora, o MySQL Workbench, Uma vez clicado o
ícone vamos para a tela seguinte na qual faremos conexão com o servidor
(Figura 3.6).

Figura 3.6 – Interface inicial do WORKBENCH


Agora, faz-se necessário abrir uma conexão (pois o MySQL trabalha


com clientes e servidors em rede), bastando clicar na conexão para o usuário
root (conexão padrão), ou clicar no ícone (+) para adicionar uma nova
conexão com nome de conexão (chamei de “conexao”). Você pode dar
qualquer nome a está conexão de usuário, definidos como visto na figura
3.7.

Figura 3.7 – Criação de conexão.


Importante lambra, que é necessário informar a senha do usuário usado


na conexão. Portanto, anote essa senha, para evitar problemas futuros. Feito
isto, a nova conexão está criada. Para toda conexão ao servidor agora, basta
informar a senha do usuário a ser conectado, e uma vez autenticado
(aprovado), a tela com acesso ao SQL será aberta (figura 3.8).
Figura 3.8 – Ambiente para programação SQL

A figura 3.8 tem alguns detalhes importantes: A tela em branco será o


local onde os scripts serão executados. À esquerda temos uma barra lateral
contendo dois itens: SCHEMAS (bancos de dados) e MANAGEMENT
(manutenção do servidor). Basta clicar em cada uma dessas palavras para
alternar os modos. Vamos concentrar nossos esforços nos bancos de dados
(SCHEMAS). Além disso, vamos entender a barra de ferramentas (figura
3.9).

Figura 3.9 – Barra de Ferramentas


Vamos nos concentrar nos ícones e suas funções: Tabela 3 - Ícones e funções no

MySQL Workbench

Existem outros ícones e funçõess que só os exploraremos no momento


devido, não cabendo os apresentar aqui.

Primeiros Comandos

Vamos agora aprender a usar os primeiros comandos básicos do SQL.


São simples mas importantes. O primeiro comando será o SHOW
DATABASES; que mostra todos os bancos de dados daquele servidor.

Figura 3.10 -Exibindo os bancos de dados daquele servidor

Para executar esse comando, lembrando que deve terminar com; temos
duas opções: usar o atalho Ctrl+ ENTER ou clicar no ícone do Flash
(trovão) com o cursor significando que só executará aquele conjunto de
comandos selecionado.

Pronto, agora você já sabe como exibir os bancos de um servidor (figura


3.10). Para selecionar um banco a ser usado na programação SQL, basta usar
o comando: use nomedobanco;

Isso significa que vou usar o banco de dados cujo nome é


“nomedobanco”. Se eu quisesse usar um banco hipotético "ESCOLA",
usaria o comando USE ESCOLA; Para ilustrar isto vamos mostrar um
exemplo:

Figura 3.11 – Usando o banco Sys

No comando acima (figura 3.11), após usar o comando adequadamente,


entramos no banco “sys” e lá podemos operar com seus dados.
Aprendemos também que comentários de uma linha em SQL basta usar o
simbolo - - . Podemos usar também comentários ao estilo do java.

-- isso é um comentário
/* isto também é um comentário */

Agora vamos saber quais são as tabelas do banco que estamos


conectados. O Comando SHOW TABLES
serve a esse propósito. Veja o
resultado na figura 3.12.

Figura 3.12 – Lista de tabelas do banco de dados SYS

Questões teóricas

1. Qual o nome (login) do super-usuário do MySQL? Qual sua


importância?
2. Qual o erro mais comum em relação ao Administrador (super-usuário)
do MySQL durante a instalação?
3. É possível criar outros usuários durante a instalação do MySql?
4. Quais as vantagens e desvantagens de instalar o MySQL como um
serviço, que inicializa juntamente com o sistema operacional (como por
exemplo, no Windows)?
5. Qual a porta padrão para conexões no servidor MySQL?
6. O que são Schemas e qual sua relação com Banco de Dados?
7. O que significa SQL?
8. Qual o comando básico para exibir os bancos de dados de um
servidor?
9. Para usar um banco de dados, qual comando (SQL) que usamos?
10. Uma vez, selecionado um Banco de Dados a ser usado, qual o
comando para exibir suas tabelas?

4. Explorando um banco de dados real

Aprendemos, recentemente, a conectar a um servidor de banco de


dados, a listar os bancos com o comando SHOW DATABASES; A usar um
banco daquele servidor, e listar todas as suas respectivas tabelas. Agora
vamos ampliar um pouco mais nosso conhecimento usando um banco real
chamado
bancotimes. O modelo de dados contendo tabelas do banco é
dado na figura 4.1.
Figura 4.1 – Modelo do banco de dados

Nosso modelo é constituído por duas tabelas (TIMES, JOGADORES)


e sabemos que cada time pode ter vários jogadores, por isto temos a chave
estrangeira idtimes na tabela JOGADORES, fazendo a associação dessas
tabelas.

Uma vez que conhecemos o banco e suas tabelas vamos agora instalar e
configurar o banco no servidor. Após o download do script [aqui] e o mesmo
salvo no seu sistema de arquivos (bancotimes.sql), vamos abrir e rodar o
script clicando na pastinha azul (ícone que representa o carregamento de
script em tela), como se pode ver na figura 4.2.

Figura 4.2 - Seleção do arquivo a ser carregado

Uma vez selecionado o arquivo e clicando no botão abrir teremos o


seguinte: A tela de script carregada (figura 4.3) com um banco a ser criado e
alimentado por dados diversos para que possamos operar os comandos
básicos que aprenderemos a seguir.

Figura 4.3 – Script de criação do banco com suas tabelas e dados

Para executar o script, basta clicar no botão com o símbolo do raio


(executar). Ele vai rodar o script, criar o banco, tabelas e preencher com
dados fictícios para práticas a seguir.

Vamos agora usar o banco. Use bancotimes;


Vamos ver quais são suas tabelas? Show tables;

Figura 4.4 – Após o comando show tables podemos ver as tabelas


para aquele banco.

Recapitulamos dois comandos (na figura 4.4) já apresentados antes,


agora vamos aprender um comando novo. Imagine que você não visse o
modelo (representação gráfica) com as tabelas, e quisesse saber os atributos
de uma tabela. Este comando é o DESCRIBE TABELA (figura 4.5).

Figura 4.5– Atributos da tabela Times

Como se vê que após a execução do comando DESCRIBE (figura 4.5)


são exibidos, exatamente, os atributos da tabela TIMES do modelo da figura
4.1 agora com algumas informações adicionais. Sabemos que o atributo
idtimes tem tamanho 10 e é positivo (unsigned). Além disso tem marcado
em KEY (chave) o valor PRI, ou seja, é a chave primária. A coluna NULL
pergunta se aquele atributo pode ficar sem preenchimento (YES) ou não
(NO). Essa informação será relevante mais adiante.

Agora tente fazer o mesmo comando para a tabela jogadores.

Describe jogadores;

Depois nos conte o que percebeu. A pergunta que nos vem agora é:
“onde estão os dados?”

Agora que temos um banco de dados preenchido com dados podemos


aprender a brincar com alguns comandos. O primeiro será selecionar dados.

O comando SELECT – Para selecionar dados

O primeiro comando a ser aprendido para selecionar dados é o SELECT.


Vamos aprender sua notação básica: Select * from times; --
seleciona todos os atributos e dados da tabela
times

Vamos ao resultado:

Figura 4.6 – Resultado da consulta executada

Na terminologia, usar o comando SELECT é chamado de “consultar” na


tabela. O uso do * (asterisco) não é recomendado para grandes quantidades
de dados, por questões de performance, processamento e tráfego de rede.
Portanto deve ser evitado.

Sendo assim, podemos selecionar apenas alguns atributos a serem


exibidos como a seguir:
Figura 4.7 – Selecionando alguns atributos apenas

Observe que o atributo idtimes


não é exibido nessa coleção, pois não o
colocamos na lista de atributos antes do FROM , conforme listagem da
figura 4.7.

Uma pergunta a seguir seria: "tem uma forma de filtrar os dados que
quero exibir?"

Por exemplo: Times que foram fundados depois de 1900. Nossa pergunta
poderia ser formulada assim: “Mostre todos os times onde ano de fundação
seja maior que 1900?”

Sendo assim precisamos aprender uma palavra nova: WHERE (no bom
português, significa “onde”). Alguns estudantes novatos gostam de associar
tal comando a um IF (SE) das tradicionais linguagens de programação.
Traduzindo para nosso SQL teríamos:

Figura 4.8 – Uso da cláusula WHERE (onde) como filtro

Observe que o time Flamengo saiu da lista exibida, uma vez que, sua
fundação é anterior a 1900, conforme resultados exibidos (figura 4.8). Uma
pergunta possível é se o Flamengo deixou de existir no banco de dados. A
resposta seria não. O comando SELECT serve somente para exibir dados
cadastrados. Ele não apaga dados.

Se minha questão fosse: “Mostre os times cuja fundação é entre 1900 e


1920”.

Agora temos um intervalo fechado para situações assim podemos usar


BETWEEN para intervalos. Uma tradução apropriada para BETWEEN
seria DENTRE.
Figura 4.9 -Intervalo fechado usando BETWEEN

Observe que para o comando BETWEEN precisamos de um conectivo


(operador lógico) AND. A figura 4.9 mostra o uso de intervalo fechado com
o uso do BETWEEN.

where anodefundacao between 1900 and 1920;

O comando acima numa tradução literal, significaria “onde ano de


fundação está entre 1900 e (AND) 1920.

O comando BETWEEN é ótimo para intervalos fechados.

A cláusula WHERE permite operadores lógicos diversos ( = , !=, <>, >,


<, AND, OR dentre outros).

Vamos agora selecionar alguns dados de jogadores. O resultado dessa


consulta pode ser visto, a seguir, na figura 4.10.
Figura 4.10 – Alguns dados selecionados de jogadores

Agora que vimos dados dos jogadores, vamos fazer algumas perguntas:
1. Mostre jogadores que ganham mais de 3000 ou menos de 2000.
Figura 4.11 – Uso do conectivo OU (OR) na cláusula WHERE

Observe (figura 4.11) que precisamos usar um conector “ou” (operador


lógico OR) para responder a essa questão. A Cláusula WHERE suporta
várias combinações de conectores, operadores e filtros.

2. Mostre os dados do jogador cujo nome seja “jorge”

Figura 4.12 – Cláusula WHERE com IGUALDADE


A consulta realizada (figura 4.12) foi uma busca exata pelo nome, por
isso usamos a igualdade. Lembrando do uso de aspas simples para tipos não
numéricos.

Agora, vamos prossseguir aprendendo uma coisa nova: Ordenação.


Vamos usar o comando ORDER BY para fazer isto. Imagine que quero a
lista de jogadores ordenada por nome s em ordem alfabética. Veremos o
resultado na figura 4.13:

Figura 4.13 – Lista de jogadores ordenadas por nome

Acabamos de aprender o comando ORDER BY, ou “ordernar por”,


usado para ordenações diversas. Caso queiramos a lista na ordem
decrescente (descendente) é só adicionar o sufixo DESC.

Para exemplificar essa variação, vamos mostrar a lista de jogadores do


maior para o menor salário (figura 4.14):

Figura 4.14 – Lista de Jogadores ordenados pelo maior salário

Também é possível fazer uma série de ordenações combinadas.

Muito bom! Agora podemos responder algumas perguntas básicas


usando o que chamamos de funções de agregação:

a) Contagem de jogadores (total de jogadores)


Figura 4.15 – Total de jogares (contagem)

Agora, como visto na figura 4.15, para contar os jogadores usamos a


função COUNT(ATRIBUTO). Essa função requer um atributo como
parâmetro, podendo ser qualquer um da tabela. Para melhorar a exibição de
dados usamos um rótulo ou apelido (alias) quando usamos o comando “as
total”. Em outras palavras dissemos “pegue esse resultado e dê um nome de
total”.

b) Maior salário de jogadores

Figura 4.16 – Maior salário de jogador


Observe, que neste caso (figura 4.16) , precisei especificar exatamente o


atributo que queria o maior valor ao usar MAX(salario). Para o menor
valor, usamos a função MIN(salario). Lembrando que podemos dar
qualquer rótulo ou apelido para esse resultado.

c) Salário médio dos jogadores


Figura 4.17– Salário médio dos jogadores com AVG (média em


inglês)

Para calcular a média de valores numéricos usamos a função


AVG(Atributo), conforme listado na figura 4.17.

Aprendemos até aqui algumas funções de agregação, e apresentaremo


outras, que resumiremos na tabela 4.1: tabela 4.1 - Funções de agragação
básicas

Vamos agora, somar os salários dos jogadores, usando a função


SUM(salario). O resultado disto pode ser visto na figura 4.18:

Figura 4.18 – Soma total dos salários dos jogadores

Finalmente, vamos explorar a função DISTINCT, que serve para


descartar valores repetidos. Vamos usar um exemplo simples:

Figura 4.19 - Lista com diferentes salários de jogadores

Esse exemplo listado (figura 4.19), pode parecer controverso, mas se


observarmos, temos 12 jogadores cadastrados com diferentes salários. Como
eu pedi para exibir diferentes salários DISTINCT SALARIO, o número de
resultados caiu, pois foram retirados os registros de dados com repetições.

Sendo assim, apresentamos as principais funções de agregações. Com


tais funções combinadas com com as cláusulas WHERE,
ORDER BY e
outros comandos apresentados podem trazer soluções a vários problemas e
questões.

Questões Teóricas

1. Qual o comando para selecionar um banco a ser usado num servidor?


2. Qual o comando para exibir as tabelas daquele banco?
3. Se eu quiser exibir a tabela com detalhamento de seus atributos, tipos
e restrições, qual o comando SQL que utilizo?
4. Qual o significado do termo UNSIGNED?
5. Qual o Significado do termo KEY? e do termo PRI? Ambos listados
através do comando de detalhamento da tabela.
6. Qual o objetivo do comando SELECT? Mostre dois exemplos,
exibindo alguns atributos da tabela JOGADORES.
7. Para que serve o Asterísco (*) no comando SELECT? Por que, na vida
real devemos evitá-lo?
8. O que significa WHERE? Para que serve esse comando? Ele tem
alguma relação, por exemplo com o comando IF de outras lingagens de
programação?
9. Para que serve o operador BETWEEN?
10. Quais são os operadores lógicos que podemos usar em consultas com
o comando WHERE?
11. Qual o objetivo de se usar o comando ORDER BY? Quais seus
tipos?
12. Qual o objetivo da função de agregação COUNT? Podemos usar essa
função em qualquer atributo?
13. Qual o objetio da função de agregação SUM?
14. Qual o objetio da função de agregação MAX?
15. Qual o objetio da função de agregação MIN?
16. Qual o objetio da função de agregação AVG?
17. Qual o objetivo do uso da função DISTINCT numa sentença
SELECT?

Questões Práticas

Parte 1 - Usando o modelo e banco de dados BANCOTIMES


responda a essas questões: 1. Mostre nome e ano de fundação dos times,
ordenados pelo nome

2. Mostre o valor médio dos times


3. Mostre o nome, salário e data de nascimento de jogadores do mais
velho para o mais novo 4. Mostre o nome e salário de jogadores que ganham
mais de 2000.

5. Mostre o valor total dos times


6. Mostre o nome dos jogadores ordenados por nome decrescente 7.
Mostre o valor mais baixo de um time
8. Mostre nome e data de nascimento para jogadores nascidos a partir do
ano 2000
9. Mostre o total de jogadores que ganham menos de 3000

10. Mostre o maior valor de times


Parte 2 - Usando o modelo e banco de dados CLINICA responda a


essas questões:

O primeiro passo para trabalhar com esse banco é executar seu script de
criação disponível Aqui.

Figura 4.20 – Modelo do banco CLINICA


1. Mostre nome e sexo dos pacientes, ordenados pelo nome 2. Mostre o


valor médio das idades de pacientes 3. Mostre dia e hora das consultas,
ordenadas por dia 4. Mostre o nome e salário de médicos que ganham mais
de 2000.
5. Mostre o valor total dos dos salários de médicos 6. Mostre o nome dos
pacientes ordenados por nome decrescente 7. Mostre o valor mais baixo de
um salário de médico 8. Mostre nome e idade e sexo de pacientes, que tem
mais de 30 anos 9. Mostre o total de médicos que ganham menos de 3000

10. Mostre a maior idade de pacientes


Esse capítulo foi só um aperitivo do comando SELECT e seu potencial,


adiante vamos apresentar mais recursos. Sigamos na leitura.
5. Como Modificar dados de um banco?

No capítulo anterior, aprendemos um pouco sobre acessar banco de


dados e recuperar e selecionar (consultar) dados. A pergunta que nos vem a
seguir é como podemos adicionar, modificar ou até excluir dados de uma
tabela?

Para dar continuidade a nosso processo de aprendizagem, vamos


conhecer 3 novos comandos: INSERT, DELETE, UPDATE.

O Comando INSERT

O comando INSERT (inserir em português) é o comando básico para


adicionar (ou cadastrar) um registro (conjunto de dados) numa tabela. Ele
tem duas sintaxes.

Vamos a sintaxe mais básica: Insert into TABELA (atributo1,


atributo2, atributoN) values (valor1,valor2,valor3);
No bom português o comando acima seria algo assim:

“insira na tabela cujo nome é TABELA nos atributos


(atributo1,atributo2, atributoN) os valores (valor1,valor2, valorN)”

Uma dica antes de inserir dados numa tabela, é verificar quais são seus
atributos e restrições de dados. Sendo Assim, precisamos revisitar o
comando DESCRIBE.

Cenário 1: Imagine que eu queria acrescentar um novo time, mas não


lembro bem os atributos da tabela. Podemos retomar isto com o comando
DESCRIBE TIMES;

Ao realizar este comando teremos o seguinte, conforme figura 5.1:

Figura 5.1 – Resultado do DESCRIBE TIMES

Um detalhe não tratado antes, que é importante mencionar aqui é o fato


do atributo idtimes ser AUTO_INCREMENT. Essa informação é relevante,
em especial pelo fato deste atributo ser uma chave primária. Logo a cada
novo time inserido, incrementa-se em 1 o valor do atributo idtimes (do
ultimo inserido).

Por que essa informação é importante? A resposta a essa questão é que


se o atributo for auto incremento não precisamos passar valor. Exemplo de
INSERT com auto_increment:

OPERAÇÃO 1 - insert into times (nome,valor,anodefundacao)


values (‘Santos’,4000000,1921);

Duas observações são importantes aqui: a) primeiro se observa que o


atributo-chave idtimes não passamos nem o atributo nem o valor a ser
preenchido. Isso aconteceu pela característica de autoincremento do atributo.
b) A segunda informação é que todo atributo não numérico deve ser
preenchido com aspas simples, como é o caso do nome do time.

Na tabela jogador, por exemplo, a data (tipo DATE) é também


preenchida entre aspas simples. Caso a chave não fosse auto_increment,
seria obrigatório passar o atributo e valor para idtimes.

A segunda notação para este comando permite a inserção de múltiplos


registros (linhas) num só comando: OPERACÃO 2 -insert into
times (nome,valor,anodefundacao) values
(‘Vasco’,5000000,1891),(‘Benfica’,400000,1910),
(‘Barcelona’, 100000,1899);

Observe que, agora passamos valores de vários atributos, na mesma


linha de comandos, para os times VASCO, BENFICA e BARCELONA.
Como posso ter certeza que meu comando funcionou? Primeiro, considere
que executei os comandos destacados corretamente. Segundo, vamos usar
um SELECT para ver o resultado:

Figura 5.2 - Lista de times obtidas pelo comando SELECT

Como se pode observar na listagem acima (figur 5.2), os 4 times foram


inseridos com sucesso em dois comandos diferentes. O primeiro (operação
1) apenas inserindo o SANTOS, e os três demais na segunda operação.

É importante notar que inseri valores para todos os atributos, mas


poderia evitar aqueles cujo o preenchimento não fosse obrigatório, como por
exemplo os atributos VALOR e ANODEFUNDACAO.

Mas como eu posso inserir dados para um jogador? A ideia é


basicamente a mesma, apenas com um detalhe: temos uma chave
estrangeira na tabela jogadores. A chave é idtimes, ela garante que eu não
possa ter um jogador não associado a um time. Chaves estrangeiras geram
uma relação de dependência.

Vimos que o maior idtimes existente é 8. Ou seja, se eu tentar passar um


valor não existente de idtimes na tabela TIMES, o MySQL. bloqueará o
INSERT dando mensagem de erro.
Vamos tentar provocar esse erro: insert into jogadores
(nome,salario,datanascimento,idtimes) values (‘Captu’,10000,’1999-
01-10’,18);

O último parâmetro desse comando é IDTIMES e estou passando um


valor 18. Já sabemos que não existe nenhum time com esse IDTIMEs. Logo
teremos um erro aqui.

Outra observação é o padrão de data no formato ‘AAAA-MM-DD’, ou


seja ano, mês, dia. Como por exemplo '2020-12-25' (vinte e cinco de
dezembro de 2020). A mensagem de erro fundamental aqui é: Error Code:
1452. Cannot add or update a child row: a foreign key constraint
fails (`bancotimes`.`jogadores`, CONSTRAINT `jogadores_ibfk_1`
FOREIGN KEY (`idtimes`) REFERENCES `times` (`idtimes`))

Em outras palavras, você está tentando inserir um jogador, cujo valor de


chave estrangeira se refere a um time que não existe. Não podemos inserir
um jogador, sem que ele pertença a algum time, já cadastrado. Sendo assim,
muito cuidado com tabelas que possuem chaves estrangeiras.

O Comando DELETE

O comando DELETE tem como objetivo excluir uma linha (registro,


dados de um registro) ou conjuntos de registro baseados em algum critério
(leia-se tudo que a cláusula WHERE permitir).

A experiência nos ensina, enquanto aprendizes que a melhor regra de


exclusão de dados, de um registro, é pela chave primária. Mas não é a única
forma.

Por exemplo, eu poderia apagar todos os jogadores que tem salário


abaixo de 2000, ou por um nome específico etc. Tais exclusões são
possíveis, mas é bom ser cuidadoso.

Vou explorar aqui os casos nos quais excluímos registros pela chave
primária. Sendo assim o comando DELETE ficaria assim: delete from
tabela where chaveprimaria=valor;
Por exemplo, quero excluir o time Barcelona, e já sei que o valor da
chave primária é 8, logo meu comando seria assim: delete from
times where idtimes = 8;

Essa exclusão ocorreria sem menor problema. Mas imagine excluir o


Bahia, teríamos um problema: delete from times where
nome=’bahia’; - - exclusão sem ser pela chave

Essa exclusão seria permitida, exceto pelo fato de termos 4 jogadores


associados ao bahia. Logo teríamos o seguinte erro: Error Code: 1451.
Cannot delete or update a parent row: a foreign key constraint fails
(`bancotimes`.`jogadores`, CONSTRAINT `jogadores_ibfk_1` FOREIGN KEY
(`idtimes`) REFERENCES `times` (`idtimes`))

Em outras palavras, você não pode excluir um time que ainda tem
jogadores associados a ele por chave estrangeira. Acredite, esse erro é
comum em novos programadores, muitas vezes por displicência do
programador SQL.

Portanto, comando DELETE deve observar as associações entre tabelas


e critérios para se evitar danos a base de dados.

O Comando UPDATE

O comando UPDATE serve para atualizar dados de uma linha ou


registro (ou conjunto deles) baseados num critério. Aqui valem todas as
considerações feitas em relação ao DELETE.

A sintaxe básica do update é:

update nometabela set atributo1 = novovalor1, atributo2 =


novovalor2, atributon = novovalorn where atributo = valor;

A melhor tradução aqui seria: Atualize a tabela “nometabela”


modificando o atributo1 pelo novovalor1, o atributo2 pelo novovalor2, o
atributon pelo novovalorn onde o atributo = valor.

Recomendo fortemente que o atributo da cláusula WHERE seja a chave


primária, repetindo o alerta relativo ao comando delete. Vamos para alguns
exemplos: update times set nome= 'Novo Bahia', valor =10000000

where idtimes = 1;

Esse comando vai alterar o nome do Bahia para Novo Bahia e seu valor
para 10000000. Observe que o update foi feito com o critério da chave
primária. O resultado após modificação pode ser visto na figura 5.3:

Figura 5.3 – Dados do Bahia atualizados

A despeito de tabelas com chaves estrangeiras, valem as mesmas


recomendações do comando DELETE. Lembrando que você não pode
atualizar uma chave estrangeira cujo valor não exista na tabela de origem
(time por exemplo) como chave primária.

Questões Teóricas

1. Qual o comando básico para inserir dados numa tabela de banco de


Dados? Quais suas variações possíveis?
2. Por que em tabelas com chave primária com autoincremento, devemos
evitar passar como parâmentro a chave e seu respectivo valor?
3. Podemos inserir mais de uma linha de registros num único comando?
Cite exemplos.
4. Qual o formato básico da datas no MySQL? Qual o formato básico de
hora ou tempo?
5. É possível inserir uma chave estrangeira numa tabela, sem que a
mesma exista na tabela original? justifique.
6. Qual o comando para excluir dados de uma tabela?
7. Qual o melhor critério de exclusão desses dados? É possível usar
vários critérios para exclusão? Quais as vantagens ou desvantagens dessa
segunda abordagem?
8. Podemos apagar dados de uma tabela, cuja sua chave primária, seja
uma chave estrangeira em uma outra tabela? Qual o efeito disto?
9. Qual o comando para atualizar dados (registros) de uma tabela?
Demonstre com um exemplo.
10. As regras de filtros (cláusula Where) também podem ser usadas nas
atualizações de registro?
11. Qual é o melhor atributo para se filtrar o registro a ser atualizado
numa tabela?

Exercícios de tradução

Traduza os comandos SQL a seguir:

1. delete from times where nome = ‘Vasco’


2.update jogadores set salario=10000 where
idjogadores =3
3. Insert into jogadores (nome, salario,idtimes)
values (‘Xuxa’, 4000,1)
4. Insert into times (nome, anodefundacao)
values (‘Olaria’, 40000)
5. select nome, salario from jogadores where
salario > 2000
6. select nome, valor from time where
anodefundacao < 1950
7. select nome,salario from jogadores where
salario < 400000
8. select distinct nome from jogadores
9. select anodefundacao,nome from times order by
nome
10. select max(salario) from jogadores
11. select count(nome) from times
12. select avg(salario) from jogadores where
datanascimento > ‘2000-01-10’

Questões Práticas

Parte 1 - Usando o BancoTimes:

1. Insira um novo time com dados a sua escolha


2. Insira um novo jogador no Flamengo 3. Insira um novo jogador no
Vasco

4. Atualize o valor do Vasco para 100000


5. Atualize o nome atual do Bahia para EC Bahia 6. Remova o time
inserido na questão 1
7. Remova o jogador inserido na questão 3

8. Remova o jogador KAKA


Parte 2 - Usando o banco Clube da Pizza

Figura 5.4 – Modelo de Dados Clube da Pizza


O script de Criação do banco acima, encontra-se aqui

1 – Insira um novo atendente 2 – Insira uma nova pizza 3 – Com a pizza


inserida na questão anterior altere a quantidade crítica para 5 e o preço para
50,00
4 – Mostre as pizzas ordenadas pelo preço 5 – Mostre os pedidos
ordenados por valor total do maior para o menor 6 – Apague a pizza inserida
na questão 2
7 – Mostre o valor médio das pizzas 8 – Mostre o menor valor total de
pedido 9 – Mostre o total de pedidos realizados 10 – Mostre as datas que
tiveram pedidos sem repetição 11 – Mostre a quantidade de pizzas com
preço acima de 50 reais 12 – Mostre as pizzas cuja quantidade crítica é 5
pizzas de diferença em relação a quantidade em estoque.
13 - Insira um novo pedido 14 - Insira itens para este pedido 15 -
Modifique o preço da pizza CALABRESA para 30 reais 16 - Modifique os
dados do atendente da questão 1 para seus dados

Parte 3- Para o banco CLINICA dado a seguir, resolva as seguintes


questões:

Figura 5.5 Modelo de Dados do Banco Clínica


O script do Banco CLINICA está disponível Aqui

1 – Adicione um novo paciente com seu nome


2 – Adicione uma nova doença
3 – Adicione um novo ambulatório
4 – Altere o nome que você colocou na questão um para seu nome
completo com idade de 30 anos 5 – Apague a doença inserida na questão 2
6 – Adicione um novo funcionário. Deu certo? Se não deu certo, o que
faltou?
7 – Insira uma nova especialidade
8 – Insira um novo médico
9 – De um aumento para 10.000 reais para o médico inserido na questão
8
10 – Altere a capacidade do ambulatório 2 para 50
11 – Insira um novo paciente
12 – Apague o paciente da questão anterior
13 – Insira uma consulta para pacientes e médicos válidos 14 –
Modifique o dia e hora da consulta inserida na questão anterior 15 – Altere
os dados do primeiro funcionário inserido no banco de dados

6. Criando nossos próprios bancos e tabelas

Aprendemos já a selecionar (consultar) dados, inserir, alterar e


modificar registros. A pergunta agora é como posso criar um banco de
dados, uma vez que um modelo me é apresentado para meus projetos?

Retomando o modelo dados na figura a seguir:

Figura 6.1 – Modelo do Banco VENDAS


O modelo (figura 6.1) vamos chamar de banco VENDAS é formado por
3 tabelas. Uma vez que temos um modelo em mãos, temos que definir a
ordem de criação de tabelas.

Essa ordem é sempre feita prioritariamente com tabelas sem chaves


estrangeiras. Alguns autores chamam essas tabelas de entidades fortes.
Depois delas criadas, vamos criar as tabelas, que precisam (dependem) de
menos chaves estrangeiras. No modelo acima, podemos criar a tabela
CLIENTES e VENDEDORES (não necessariamente nessa ordem) e depois
FATURAS, pois essa tem duas chaves estrangeiras que dependem dessas
tabelas.

Vamos aprender a criar um banco de dados. Para criar um banco de


dados usamos o comando:

CREATE DATABASE NOMEDOBANCO;

Nosso banco de dados agora está criado. Para usar o banco retomamos
ao famoso USE NOMEDOBANCO;

Apenas para relembrar, para mostrar as tabelas do banco usamos o


famoso SHOW TABLES;

Vamos agora para o modelo acima, criar o banco e tabelas respectivas, na


figura 6.2:

Figura 6.2 – Criação e uso de banco VENDAS, Exibição de tabelas


Esse conjunto de comandos apenas criou no espaço em disco (ou
armazenamento) locais e estruturas para receber futuras tabelas que serão
criadas. É um banco vazio sem tabelas.

CRIAÇÃO DE TABELAS

Para criar tabelas é necessário definir nome da tabela, atributos,


domínios e regras, chaves e informações adicionais. Vou proceder a criação
da tabela VENDEDORES.Toda tabela criada tem a seguinte estrutura:

Create table NOME(


atributo1 tipo nulo ou não, se é autoincremento ou primária,
atributo2 tipo nulo ou não,
atributo3 tipo outras características
chave primária,
chave estrangeira);

Vamos agora criar a tabela vendedores:

Figura 6.3 – Criação da tabela Vendedores

A figura 6.3 mostra a aplicação da estrutura básica de criação de tabelas,


no caso específico da tabela VENDEDORES. Observe que na linha 1,
criamos e demos nome à tabela, já na linha 2, criamos o atributo
idvendedores que é do tipo inteiro positivo (unsigned), sendo obrigatório
(NOT NULL), e finalmente, designamos ele como um auto incremento
(AUTO_INCREMENT), pois será definido como chave primária na linha 7.

Na linha 3, temos o atributo nome (texto) do tipo VARCHAR(50), o que


permite 50 caracteres, sendo obrigatório (NOT NULL). A Linha 4 tem o
atributo datacontratacao do tipo DATE não obrigatório. O formato do
atributo de tipo DATE é por padrão
'AAAA-MM-DD'. Ou seja: anomês-dia
O Atributo salario, do tipo float tem valor DEFAULT = 1000, isso
significa, que se nenhum valor for passado, esse valor padrão (Default, em
inglês) será assumido no atributo. O atributo Comissão também é float, mas
não obrigatório. Finalmente definimos a chave primária idvendedores.

Já a tabela CLIENTES segue o modelo da tabela VENDEDORES, com


todos os atributos. O script de criação desta tabela está dado na figura 6.4

Figura 6.4– Criação da tabela CLIENTES

Como dissemos anteriormente, a ordem de criação das tabelas leva em


consideração, de que tabelas com menos chaves estrangeiras devem ser
criadas primeiro. Por isso, criamos primeiramente, VENDEDORES e
CLIENTES, já que não possuíam chaves estrangeiras. Agora procederemos
a criação da tabela FATURAS.

A tabela FATURASpossui duas chaves estrangeiras idclientes e


idvendedores. Mesmo sendo chaves estrangeiras, precisam ser criadas como
atributos, antes de se fazer atribuição como chaves estrangeiras. Vamos ao
script, transcrito na figura 6.5:
Figura 6.5 – Criação da tabela Faturas

O que temos nesta tabela: chave primária idfaturas, o atributo data do


tipo date. Nas linhas 4 e 5 criamos os atributos idclientes e idvendedores
idênticos ao que temos nas tabelas originais, excetuando-se o
auto_increment. Essas linhas só criam os atributos, mas eles ainda não são
chaves.

A Linha 6 atribui idfaturas como chave primária desta tabela. As chaves


estrangeiras (FOREIGN KEY) são definidas nas linhas 7 e 8. A notação
básica é dizer o nome do atributo na tabela atual que será a chave
estrangeira.

No REFERENCES informar a tabela de origem e entre parênteses, o


nome do atributo na tabela de origem. Bons modelos geralmente, mantém os
noms das chaves estrangeiras idênticos aos da tabela de origem.
Finalmente,
se dermos um SHOW TABLES, teremos as 3 tabelas criadas (ver figura
6.6).
Figura 6.6 – Lista de tabelas criadas

MODIFICAÇÃO DE ESTRUTURA DE TABELAS

Uma vez criadas nossas tabelas do modelo, agora materializadas no


projeto lógico, é possível que se busque possíveis ajustes ou alterações nas
mesmas.

A primeira delas é apagar a tabela. O comando é simples:

drop table nomedatabela;

Para evitar confusão com o comando delete, assuma que DROP


significa apague a estrutura da tabela.

Caso a tabela tenha dados, e se queira limpar os dados usamos o


TRUNCATE:

Truncate table nomedatabela;

Finalmente, imaginemos que queremos alterar apenas parte da estrutura


de uma tabela. Essa alteração estrutural (ALTER) tem 4 possibilidades
básicas: 1) Adicionar atributo – ADD
2) Remover atributo – DROP
3) Modificar atributo – MODIFY
4) Mudar nome do atributo – CHANGE

Vamos tomar a tabela CLIENTES como exemplo. Observe que todos os


atributos estão como varchar. Vamos fazer alguns ajustes.

a) Ajuste 1: vamos adicionar o atributo telefone:


ALTER TABLE CLIENTES ADD TELEFONE Varchar(10);

Esse comando altera a estrutura da tabela cliente adicionando o atributo


TELEFONE que será do tipo varchar(10); b) Ajuste 2: vamos remover o
atributo CEP:

ALTER TABLE CLIENTES DROP CEP;


Esse comando altera a estrutura da tabela cliente removendo o atributo
CEP.

c) Ajuste 3: Vamos trocar o tipo do endereço pra TEXT


ALTER TABLE CLIENTES MODIFY ENDERECO TEXT;

O Modify basicamente altera o tipo de dados e domínio.

d) Ajuste 4: Vamos renomear o atributo cidade para municipio

ALTER TABLE CLIENTE CHANGE ENDERECO MUNICIPIO VARCHAR(100);

Aqui, além de modificar o nome do atributo ENDERECO para


MUNICIPIO, pudemos modificar o tipo para varchar(100). O CHANGE
muda o nome e o tipo do atributo.

Adicionalmente, gostaria de apresentar o tipo ENUM


(Enumeração), que
serve para predefinir uma lista de valores, à escolha do usuário para um
atributo. Vamos ao exemplo seguir:

sexo ENUM(‘m’,’f’); -- atributo sexo só pode ter os valores ‘m’


ou ‘f’

É importante mencionar que podemos criar atributos no momento de


criação de tabela com o CREATE TABLE ou através do ALTER TABLE
ADD

Então vamos agora adicionar um atributo sexo para clientes usando o


comando ENUM: alter table clientes add sexo enum(‘m’,’f’);

Com a execução dos comandos acima, a tabela CLIENTES fica da


seguinte forma (fugura 6.7):

Figura 6.7 -Tabela CLIENTES após a execução dos comandos ALTER


TABLE

Observe que as modificações nos atributos são bem diversas das listadas
na figura 6.7. Vale destacar que se a tabela estiver preenchida com dados,
pode haver perda de dados, problemas de conversão de tipos e outros erros.
Portanto, é preciso cautela ao usar ALTER TABLE e suas variantes com o
banco de dados em produção.

Questões teóricas

1. Qual o comando para criar um banco de dados?


2. Qual o comando para selecionar o banco a ser usado?
3. Qual o comando para apagar a estrutura de um banco de dados?
4. Explique a diferença de chave primária para chave estrangeira. Qual a
relação das tabelas originais?
5. Quais os principais tipos de dados para atributos de uma tabela?
6. Qual o significado de UNSIGNED?
7. Para que serve o NOT NULL? Qual seu significado?
8. O que é o AUTO_INCREMENT? Para que serve? É possível dois
atributos numa mesma tabela usar esse recurso?
9. Como eu defino uma chave primária na criação de uma tabela?
Demonstre com um exemplo.
10. Como eu defino chaves estrangeiras numa tabela? Precisamos criar
antes os atributos? Por quê?
11. Explique o comando de criação de chaves estrangeiras numa tabela.
12. Qual o comando para apagar a estrutura de uma tabela? Podemos
apagar uma tabela com dados?
13. Qual a diferença entre DELETE e DROP?
14. Para que serve o comando TRUNCATE?
15. Para que serve o comando ALTER TABLE? Quais são algumas das
possibilidades que esse comando nos dá em relação à tabelas?
16. Demonstre num exemplo para ALTER TABLE, a adição de um novo
atributo.
17. Demonstre num exemplo para ALTER TABLE, a remoção de um
atributo.
18. Demonstre num exemplo para ALTER TABLE, a modificação de
tipo de atributo.
19. Demonstre num exemplo para ALTER TABLE, a modificação de
nome de atributo.

Questões Práticas

Parte 1 - Exercícios de Fixação para o Banco Vendas

1. Liste as tabelas do banco VENDAS, exibido neste capítulo.


2. Descreva cada uma das tabelas
3. Adicione o atributo telefone para clientes
4. Modifique o atributo cep para varchar(10)
5.
Adicione o atributo sexo para vendedores do tipo ENUM com os
valores ‘F’ ou ‘M’
6. Adicione o atributo hora na tabela fatura. O formato de hora é
‘HH:mm’
7. Remova o atributo inserido na questão anterior
8. Adicione o atributo valor do tipo Double na tabela faturas
9. Renomeie o atributo nome (tabela vendedor) para “nomevendedor”
10. Modifique o endereço para varchar(200)
11. Adicione um atributo UF com dois caracteres na tabela clientes.
12.
Adicione um atributo valor tipo Double na tabela faturas
13. Adicione o atributo CPF na tabela Faturas
14. Remova o atributo CPF da tabela Faturas
15.Altere a comissão na tabela VENDEDORES para Double
16. Modifique o atributo cep para varchar(10)
Parte 2 - Exercícios para o Banco Vendas:
1. Insira 4 clientes 2. Insira 3 vendedores

3. Exclua o último cliente inserido


4. Insira uma nova fatura com o primeiro vendedor inserido, e o segundo
cliente

5. Modifique os dados do segundo vendedor


6. Dê um aumento de 20% a todos os vendedores 7. Insira uma nova
fatura com o segundo vendedor e o primeiro cliente

8. Mostre os vendedores do sexo feminino


9.Mostre os valores das faturas do mais alto para o mais baixo 10.
Mostre as cidades dos clientes em ordem alfabética 11. Mostre o valor total
em faturas

12. Mostre o menor salário de vendedor


13. Mostre as faturas emitidas entre o ano de 2000 e 2010.

Parte 3- Um novo banco (LOCADORA) para explorar e treinar:


Figura 6.8 - Banco Locadora de Carros


Para o modelo do banco LOCADORA dado acima (figura 6.8), execute
os comandos a seguir:

PARTE A - CRIAÇÃO DE TABELAS E ATRIBUTOS


a) Crie o banco (LOCADORA) conforme o modelo na ordem correta


das tabelas.
1. Altere o atributo placa (carro) para VARCHAR(12), obrigatório e
único.
2. Adicione o atributo modelo para carro.
3. Altere o atributo ano para YEAR.
4 . Remova o atributo adicionado na questão 2.
5 . Altere o atributo dataaluguel para DATE NOT NULL.
6. Adicione o atributo valor DOUBLE para o aluguel.
7 . Altere o atributo cpf para VARCHAR(11) UNIQUE.
8. Renomeie o nome do atributo datanascimento para datadenascimento
tipo DATE.
9 . Adicione o atributo cnh (carteira de habilitação) para o cliente.
10. Adicione o atributo ddd para telefone.

PARTE B - INSERÇÃO DE DADOS - (FAZER NA ORDEM


ESTABELECIDA)
1. Insira 10 carros com todos os atributos.
2. Insira 6 clientes.
3. Insira 2 telefones para cada cliente cadastrado.
4. Insira 10 aluguéis de carros por clientes (tabela aluguel).
5. Remova o último telefone informado.
6. Altere a data do penúltimo aluguel registrado para 30/06/2021.
7. Altere os dados do terceiro cliente para o nome de um dos seus avós.
8 . Insira um aluguel para o primeiro carro cadastrado e o último cliente
com a data de hoje.
9. Remova o primeiro telefone cadastrado.
10 Insira 2 novos clientes.

PARTE C - SELEÇÃO DE DADOS PARA O BANCO LOCADORA


1. Mostre os dados dos clientes ordenados pelo nome.
2. Mostre o total dos carros agrupados pela cor.
3. Mostre o total de alugueis por clientes.
4. Mostre os clientes que nunca alugaram carros.
5. Mostre os 3 clientes mais velhos.
6. Mostre os clientes cujo nome em alguma parte tenha a letra "o".
7. Mostre o valor total de aluguel por carro.
8. Mostre o valor total de aluguel por data do aluguel.

7. Ampliando nossos conhecimentos sobre o


Select, Delete, Insert e Update

Aprendemos já a selecionar (consultar) dados, inserir, alterar e


modificar registros. Aprendemos também a criar bancos e tabelas, verificar
sua estrutura e realizar consultas simples. Vamos agora, exercitar nossos
conhecimentos, revisitando os comandos ora aprendidos e expandí-los com
maior complexidade. Para ajudar em nossa tarefa, vamos trabalhar com o
banco de dados a seguir (CLINICA):

Figura 7.1 – Modelo do banco CLINICA

Nesse banco, temos dados de pacientes, médicos, funcionários doenças,


especialidades médicas, ambulatórios, consultas etc (ver figura 7.1). O
primeiro passo para trabalhar com esse banco é executar seu script de
criação disponível Aqui.

Figura 7.2 – Janela com o script a ser carregado e executado

Uma vez executado o script, o banco e tabelas serão criados com todos
os seus dados (conforme figura 7.2). Feito isso, vamos numa sequência de
comandos selecionar o banco (verifique o nome correto do banco no script) e
exibir as tabelas (figura 7.3):

Figura 7.3 – Usando o banco e exibindo suas tabelas

Feito isto, temos nosso banco criado e vamos examinar algumas tabelas.
Podemos dar um DESCRIBE em cada tabela ou usar um SELECT para
vermos os dados. Vou mostrar dois exemplos a seguir (figuras 7.4 e 7.5):

Figura 7.4 – Descrição da estrutura da tabela PACIENTES

Figura 7.5 - Selecionando todos os dados da tabela PACIENTES para


visualização dos dados.

Novamente faço o alerta que o SELECT * não é recomendável para


grandes conjuntos de dados.

Agora já sabemos como ver estrutura e dados de uma tabela, podemos


continuar nossa análise do banco CLINICA e aprender e ampliar nossos
conhecimentos através de exercícios e cenários novos, associando os
conceitos aprendidos anteriormente. Para isto, vamos fazer questionamentos
ao banco e apresentar soluções: PROBLEMA 1: Mostrar o nome, sexo e
idade dos pacientes com idade maior que 18 anos.
Figura 7.6 - Consulta e resultado

Observe, na listagem da figura 7.6, que aplicamos o filtro WHERE IDADE


> 18. Mas se quisermos apenas pacientes do sexo feminino? Basta adicionar
o operador lógico AND e uma nova condição sexo =’f’. Vejamos a seguir:

Figura 7.8 – Consulta modificada com a adição da condição do sexo


feminino
Podemos combinar numa cláusula WHERE várias condições e atributos
em consultas com os conectores AND, como vimos na figura 7.8.

PROBLEMA 2: Mostrar o total de pessoas por sexo.

Para resolver essa questão precisamos entender que poderíamos fazer


duas contagens (usando Count). Seria um para cada sexo:

select count(nome) from pacientes where sexo=


‘f’;

select count(nome) from pacientes where sexo=


‘m’;

O problema desta solução é que seriam consultas distintas com


resultados distintos. Mas imagine que fossem 3000 sexos diferentes
possíveis, você teria que fazer 3000 consultas para atingir esse resultado.
Sendo assim, deveria existir algum comando capaz de realizar
agrupamentos. Esse comando é o famoso GROUP BY. Vamos dar um
exemplo de uso simples a seguir:

Figura 7.9 – Uso do agrupamento por sexo

Observe que para fazer a contagem usamos o tradicional count(nome)


e demos o apelido de total (as total).
No Select também optamos a exibir o
atributo sexo para visualizarmos para que sexo, aquela quantidade (total)
está relacionada. Finalmente, fizemos o agrupamento com o comando
group by sexo. Deste modo, especificamos por qual atributo é esse
agrupamento de dados. Em consultas com a cláusula WHERE, o group by
é sempre depois o filtro da cláusula WHERE. Caso haja ordenações (order
by), o group by é sempre antes da ordenação. O resultado completo da
solução do problema foi dado na figura 7.9.

PROBLEMA 3: Mostrar a média salarial por sexo para os


funcionários que ganham acima de RS 1000.

Para resolver esse problema, vamos trabalhar, por similaridade, com a


forma de resolução anterior. A função AVG(atributo) nos fornece a média
de um conjunto de valores pra aquele atributo. Mas além disso, queremos
mostrar o sexo do funcionário (agrupamento), desde que seu salário seja
superior à R$ 1000,00 (filtro). Sendo assim, nossa resposta exige um
SELECT contendo função de agregação (AVG), filtro (WHERE) e
agrupamento (GROUP BY). Deste modo, teríamos a seguinte resposta
(figura 7.10):

Figura 7.10 – Seleção com uso de agrupamento e filtro


Poderíamos também, caso se fizesse necessário usar ordenação
(order
by)
para ordenar por algum atributo. Sendo assim, ampliamos nossos
conhecimentos do SELECT, com boa parte de suas nuanças, úteis em vários
tipos de problemas.

PROBLEMA 4: Mostrar o total de consultas de um paciente

Para resolver esse problema precisamos entender primeiro, que por uma
questão de modelagem, se prefere guardar o idpacientes na tabela
CONSULTAS. O motivo para isso é para que se evite o problema de
inconsistência nos dados, além de minimizar o uso recorrente do atributo
nome na tabela
CONSULTAS, evitando que o usuário em processos de
digitação para um mesmo nome, digite (de maneira errada ou despropositais)
nome errado para um paciente já cadastrado.

Idpacientes é uma chave, neste caso estrangeira, por ter origem na


tabela PACIENTES.

Com o conhecimento anterior adquirido poderíamos pensar então que a


resposta seria algo do tipo:

select idpacientes, count(dia) as total from


consultas group by idpacientes;

Figura 7.11 – Total de consultas por paciente

Embora a resposta esteja correta (figura 7.11), temos um problema novo.


Quem é o paciente cujo idpacientes tem valor 1 ou 3 ou 8?

Uma resposta simples seria fazer a boa e velha consulta básica: select
nome, sexo, idpacientes from pacientes where
idpacientes =1;

Agora temos uma reposta nova e um problema novo.

Como posso juntar a reposta para essas duas questões em uma única
consulta?

Veremos no capítulo a seguir. Aguardem.

PROBLEMA 5: Mostrar os pacientes que tiveram consultas

Para resolver essa questão, vamos voltar para a boa e velha teoria de
conjuntos. Já sabemos que o atributo idpacientes está em dois conjuntos ou
tabelas diferentes associadas. Nossa pergunta, dentro dessa perspectiva se
tornaria algo do tipo:

“Existe idpacientes da tabela PACIENTES que também esteja na tabela


CONSULTAS?” Para responder essa pergunta teríamos os seguintes
conjuntos: Conjunto A:

select nome,sexo, idpacientes from pacientes;

Conjunto B:

select idpacientes from consultas;

Então, agora, vamos fazer a pergunta se temos elementos do conjunto A


em B, usando o operador
IN
(está ou pertence). Podemos também usar o
operador de negação NOT para verificar, por exemplo se esse elemento de A
não está em B. Para finalmente responder a pergunta inicial temos o
seguinte:
Figura 7.12 – Operação de conjuntos (subconsultas)

Como se pode ver na figura 7.12, o filtro (cláusula WHERE) serviu para
selecionar e filtrar pelo idpacientes (elemento associativo) para verificar a
pertinência (não) de um elemento do CONJUNTO A (o primeiro select) no
SUB-CONJUNTO B (segunda consulta). Observe que a sub-consulta é
dada dentro de parênteses.

Caso quiséssemos perguntar quais os pacientes que não tem consulta,


bastaríamos incluir o prefixo NOT antes do IN. Ficando da seguinte forma.

Select nome,sexo, idpacientes from pacientes


where idpacientes not in (select idpacientes
from consultas);

PROBLEMA 6: Mostrar os funcionários cuja idade é maior que a


idade média dos pacientes.

Aqui agora temos dois conjuntos: o primeiro é o de funcionários e o


segundo a média de idade de pacientes (esse será um conjunto unitário).

Conjunto A: select nome, idade from funcionarios;

Conjunto B: select avg(idade) as media from


pacientes;

Para realizar essa sub-consulta, vamos usar o critério de que as idades do


conjunto A tem que ser maior que a média calculada do conjunto B.
Teríamos assim o seguinte (figura 7.13):

Figura 7.13 – Sub-consulta com comparador "maior que"

Por analogia, poderíamos usar os operadores menor que, igual ou maior


ou menor ou igual.

PROBLEMA 7: Mostrar os pacientes mais novos

Essa resposta pode parecer fácil, pois bastaríamos pegar a lista de


pacientes ordenadas por idade. Boa parte de nós pensaríamos assim: Select
nome, idade from pacientes order by idade;

O problema para esta abordagem é que se houver um empate de idades, a


consulta anterior traz uma lista ordenada apenas mostrando várias idades
sem dizer exatamente quem tem a menor idade. Usando sub-consultas
teríamos a seguinte solução:

select nome,idade from pacientes where idade = (select


min(idade) as menor from pacientes);

Agora, finalmente, temos uma listagem na qual somente teremos


pacientes, cuja idade seja exatamente a menor idade registrada. Ou seja,
os casos de empate de idade serão exibidos.

Por analogia poderíamos responder, usando os operadores lógicos


adequados, as seguintes questões:

(a) Pacientes cuja idade seja maior que a média de idades


(b) Pacientes que tenham que não tenham a maior idade
(c) Funcionários que tem salários menores que a média salarial de
médicos
(d) Dentre outras.

PROBLEMA 8: Mostrar as consultas que ocorreram entre janeiro e


maio de 2016.

Como trabalhamos pouco com datas e horas, vamos exercitar essa


habilidade. Vale relembrar que o tipo DATE é representado no padrão
‘aaaa-mm-dd’ e o tipo TIME é representado no padrão ‘HH:MM’.

Sendo assim, podemos representar o natal de um ano qualquer,


poderíamos assim representar ‘2010-12-25’, na ordem ANO, MÊS, DIA. Já
o horário de meio dia seria representado por ‘12:00’, hora e minuto. Vale
ressaltar que TIME pode representar também segundo, ficando da seguinte
forma ‘12:00:00’.

Uma vez detalhando esses tipos de dados a resposta a esta consulta seria
a representada na figura 7.14:
Figura 7.14 – Consulta com intervalo de datas

PROBLEMA 9: Mostrar as consultas que ocorreram entre janeiro e


maio de 2016 no turno vespertino.

Esse problema é uma ampliação do anterior, apenas acrescentando o filtro


para o turno vespertino. Vamos assumir que o turno vespertino é das 14 às
18 h. Assim, teremos uma nova configuração com a resposta dada na figura
7.15.

Figura 7.15 – Consulta com intervalo de datas e filtro de


horários
Questões teóricas

1. O que é o comando GROUP BY e qual sua vantagem de uso?


2. Por que devemos estar atentos aos agrupamentos para os casos de uso
de funções de agregação.
3. É possível fazer ordenações, após uso de funções de agregação? Cite
exemplos.
4. O que é um ALIAS (apelido) usado em atributos, e quais suas
vantagens?
5. O que são sub-consultas? Quais suas vantagens e limitações?
6. Qual a relação de sub-consultas e conjuntos?
7. Qual o siginificado do operador IN? E da sua negativa NOT IN?
8. É possível com sub-consultas, exibir dados do conjunto mais interno
(conjunto b - ou a própria sub-consulta)?
9. É possível realizar ordenações em sub-consultas? Demonstre com
exemplo.
10. Seria possível um resultado de sub-consulta retonar um valor a ser
usado num insert?

Escreva na língua portuguesa o que os comandos a seguir fazem:

1. select sabor, preco from pizzas where sabor like ‘%a’ order by preco
desc; 2. select idatendentes, idsocios, datapedido, valor_total from pedidos
where valor_total > 45 and datapedido between ‘2017-01-01’ and ‘2017-12-
31’; 3. select sabor, preco, quantidade from pizzas where preco < 45 and
quantidade < 100; 4. select count(idsocios), idtiposocio from socios group
by idtiposocio; 5. select idatendentes, idsocios, datapedido, valor_total from
pedidos where idatendentes = 1 order by datapedido; 6. select
sum(valor_total), idatendentes from pedidos group by idatendentes;

Questões Práticas

Parte 1 - Para o banco CLINICA dado a seguir, resolva as seguintes


questões:
1. Mostre todos os médicos que ganham mais que 4000
2. Mostre os médicos com idades entre 20 e 35 anos
3. Mostre o total de funcionários por sexo
4. Mostre o total de funcionários por cidade
5. Mostre todas as consultas realizadas no ano de 2016
6. Mostre a capacidade total de cada ambulatório
7. Mostre o total de médicos por especialidade
8. Mostre os funcionários do sexo feminino que ganham me nos de 3000
9. Mostre a média salarial por sexo
10.Mostre o nome das 5 pessoas mais novas
11. Mostre a média salarial por sexo
12.Mostre a idade média por sexo de cada cidade
13.Mostre o total de consultas por médico, realizadas no turno matutino
14. Mostre a lista de cidades e o total de pessoas de cada sexo
15.
Mostre os pacientes que não estão em nenhuma consulta
16. Mostre os nomes de médicos que tem consultas
17. Mostre o nome dos pacientes que tem idades acima da média das
idades
18. Mostre os dados dos médicos que ganham o menor salário
19. Usando o conceito de conjunto e o operador de pertinência IN
mostre as doenças que já tiveram atendimentos de consultas.
20. Usando sub-consulta e o operador IN mostre o nome dos médicos
que tenham consultas.
21. Mostre o ambulatórios sem médicos associados.
22. Mostre o nome dos funcionários que tenham salário acima da média
dos funcionários que moram em Salvador.
23. Mostre o nome dos médicos cujo salário é maior que todos os
salários de funcionários.
24. Mostre os médicos que tenham mais de 5 consultas realizadas.
25. Mostre as especialidades que não tem médicos.
26. Mostre os pacientes cuja idade é acima da média das idades de
todos os pacientes cadastrados.
27. Mostre os médicos que são mais jovens que todos os funcionários
cadastrados.
28.Mostre as funcionários do sexo feminino que ganham menos que o
menor salário de um médico.

Parte 2 - Usando o banco Clube da Pizza


Figura 7.16 – Modelo de Dados Clube da Pizza

Para o banco CLUBEDAPIZZA, resolva as seguintes questões:

1. Mostre o Valor médio das pizzas


2.Mostre o nome dos atendentes ordenados por nome

3. Mostre a soma total dos pedidos


4. Mostre o total de pedidos por data de pedido 5. Mostre as pizzas que
tem mais de 50 em quantidade de estoque 6. Mostre o todos os dados de
pedidos ordenados do maior valor para o menor

7. Mostre o menor valor de pizza


8 . Mostre o total de pedidos atendidos por atendente 9. Mostre os dados
dos pedidos realizados no ano de 2016
10. Mostre o total de pedidos cujo valor seja maior de 50 reais e foram
realizados em 2017
11. Mostre os dados das pizzas cujo sabor comece com a letra C
12. Mostre a soma de itens de pedido, por pedido
13. Mostre o total de Sócios por tipo
14 .Mostre a data dos pedidos sem repetição 15. Mostre o nome dos
sócios que terminam com a letra O
16. Mostre o sabor de pizza menos vendido em ITENS
17. Mostre os sabores de pizza, cujo preço seja maior que a média dos
preços de pizza 18. Mostre os sabores de pizza que terminam com a letra A e
quantidade em estoque maior que 50
19. Mostre os pedidos realizados entre janeiro e junho de 2016
20. Mostre o valor médio de pedidos por sócio 21. Mostre dados de
atendentes que atenderam pedidos acima de 50 reais 22. Mostre os sabores
de pizza que terminam com a letra A e quantidade em estoque maior que 50
8. Junções de tabelas

No MySQL temos três tipos básicos de junções de tabelas:


1. INNER JOIN
2. RIGHT JOIN

3. LEFT JOIN
Vamos começar pelo INNER JOIN, que equivale a uma interseção de
conjuntos. Isso significa que um elemento deverá estar nos dois conjuntos de
dados (tabelas ou resultados de consultas). Se observarmos o modelo, temos
o atributo idpacientes nas tabelas PACIENTES e CONSULTAS. Como
chave primária na primeira tabela (vamos chamar de tabela1) e chave
estrangeira na segunda tabela (vamos chamar de tabela2), esse atributo serve
como forma de associação entre esses conjuntos de dados. Deste modo,
precisamos para todo processo de junção de tabelas seguir os seguintes
passos:

Passos para junções de tabelas:


1. Identificar os atributos e as respectivas tabelas da junção (tabela1,
tabela2, atributo1, atributo2) 2. Juntar as tabelas com as chaves do
relacionamento. Exemplo: Tabela1.Chave1 = tabela2.chave1
3. Aplicar critérios e filtros pela cláusula WHERE, se solicitado 4.
Agrupamentos, se necessário (GROUP BY)
5. Ordenações, se necessário (ORDER BY)

É importante enfatizar que na junção de tabelas, faz-se necessário para


cada atributo utilizado no SELECT colocar como prefixo o nome da tabela
à qual pertence, por exemplo: (1) Pacientes.nome, Pacientes.sexo
(2) Medicos.nome, medicos.crm
(3) Doencas.iddoencas, doencas.descricao (4) Consultas.dia,
consultas.idmedico
(5) Dentre outros.

Vale ressaltar que o MySQL permite juntar até 16 tabelas numa mesma
instrução. É possível, que com a evolução do SGBD tais limites sejam
modificados. Vamos apresentar exemplos crescentes de junção de tabelas
com duas ou várias tabelas.

Exemplo 1: Mostrar o nome dos paciente e dia e hora de suas


consultas.

Para resolver essa questão, vamos para cada passo. Os atributos e tabelas
envolvidos são: pacientes.nome, consultas.dia, consultas.hora. Ressaltamos
que as tabelas envolvidas são CONSULTAS e PACIENTES.

A primeira parte dessa consulta seria: select pacientes.nome,


consultas.dia, consultas.hora from pacientes

Observem que a cláusula FROM TABELA é mantida, e estabelecemos


PACIENTES como a tabela1. Portanto a tabela2 da consulta será a tabela
CONSULTAS.
O passo dois é aplicar a junção [INNER, LEFT, RIGHT] para realizar
a junção. No nosso caso será o INNER JOIN. Como dito no passo 2, usando
as chaves do relacionamento e as regras de junção Tabela1.Chave1 =
tabela2.chave1. Sendo assim nossa consulta ampliada ficaria assim:
select pacientes.nome, consultas.dia,
consultas.hora from pacientes INNER JOIN consultas
ON pacientes.idpacientes =consultas.idpacientes;

Observe que a junção é sempre formada nos seguintes detalhes:


pacientes INNER JOIN consultas ON

E finalmente na associação das chaves primárias e estrangeiras das


tabelas envolvidas: PACIENTES.idpacientes =
CONSULTAS.idpacientes

Observe que a associação (ou relacionamento) das duas tabelas é feito


através da chave idpacientes. Vale destacar, que é posição em relação a
palavra JOIN, que determina que tabelas estão à esquerda (LEFT) ou a
direita (RIGHT) da igualdade, sendo determinantes nos casos de uso, para
utilização do LEFT JOIN ou RIGHT JOIN. Exemplos: 1. FROM TABELA
A LEFT JOIN B = A será a tabela da esquerda e B a tabela da direita. Os
dados da tabela A serão piorizados. Onde não houver correspondência, serão
retornados valores nulos.

2. FROM TABELA A RIGHT JOIN B = A será tabela da esquerda e


B, a tabela da direita. Os dados da tabela B serão piorizados. Onde não
houver correspondência, serão retornados valores nulos, agora da tabela A.

Figura 8.1 - Diferenças entre LEFT, INNER, RIGHT Joins


As diferenças (representadas na forma de conjuntos) demonstam as
diferenças nos respectivos usos de LEFT, INNER e RIGHT joins. Observe
que no caso do LEFT JOIN, todo conjunto da tabela 1 (conjunto A) é
priorizado, independentemente da tabela 2 (conjunto B). Espelhando, no
caso do RIGHT JOIN, o Conjunto B é priorizado. Finalmente, como já
dissemos antes, o INNER JOIN busca a intersecção dos conjuntos A e B.

Voltando a nossa questão do exemplo 1, temos a seguinte resposta para o


problema (figura 8.2):

Figura 8.2 – Junção de tabelas com INNER JOIN

Observem, que os passos 3, 4 e 5 não são usados, uma vez que não
tivemos filtros (WHERE), agrupamentos (GROUP BY), ou ordenações
(ORDER BY), passos que são opcionais e depende de cada questão
problema. Para ilustrar essa situação vamos ampliar a questão anterior.

Exemplo 2: Mostrar o nome dos pacientes e dia e hora de suas


consultas, desde que tenham acontecido pela manhã, ordenadas por
nome do paciente.

Agora para responder essa questão, basta executarmos os passos 3 e 5, já


que não precisamos por enquanto de agrupamento. Vale lembrar que, agora
os atributos devem ser representados sempre associados com sua tabela de
origem como prefixo. Por exemplo: consultas.hora e pacientes.nome.
Tendo em vista essas observações importantes, que evitam problemas e
erros, a resposta para o questionamento do exemplo 2 seria dada na figura
8.3:

Figura 8.3 – Junção de tabelas com cláusula where e order by

Até agora não combinamos, em nossas junções de tabelas, o uso de


agrupamento, e para isso, vamos trabalhar novos exemplos.

Exemplo 3: Mostrar o nome e crm do médico, bem como o total de


consultas que ele realizou.
Nessa junção de tabelas haverá um agrupamento para a contagem de
consultas para médicos (usando a função COUNT). As tabelas envolvidas
são MEDICOS e CONSULTAS. Sempre prefiro estabelecer como tabela do
FROM a tabela que tem a chave primária (MEDICOS - IdMedicos). Vamos
ao primeiro resultado, dado na figura 8.3:

Figura 8.4 – Junção de tabelas com função de agregação

Esse resultado acima pareceu um pouco estranho. Parece que temos


apenas um médico que concentrou todas as consultas. O que deu errado?
Justamente, esquecemos de realizar o agrupamento (objetivo do exemplo).
Para corrigirmos isto, vamos agrupar pelo atributo idmedicos. Com a devida
correção, a resposta correta para o exemplo 3 é a seguinte:

Figura 8.5 – Consulta com o agrupamento pelo idmedicos

Agora, na listagem apresentada na figura 8.5, temos a resposta correta


para a pergunta dada. Apenas temos um porém. Os médicos cadastrados sem
nenhuma consulta realizada não aparecerão nesta listagem. Isto ocorre pelo
fato de o INNER JOIN trazer sempre uma interseção de conjuntos. Para
contornar isto vamos usar o LEFT JOIN. Para isto vamos variar o exemplo
anterior.

Exemplo 4: Mostrar o nome e crm do médico, bem como o total de


consultas que ele realizou, ordenadas pelo total de consultas.

Como comentamos, para trazermos todos os médicos, inclusive aqueles


sem consultas, precisamos priorizar a tabela médicos. Isso é feito através do
LEFT ou RIGHT JOIN que definem que tabela terá todos os dados trazidos
nos resultados, para somente depois realizar a junção. Como quero priorizar
a tabela MEDICOS, que está à esquerda da igualdade usaremos o LEFT
JOIN. Sendo assim, como vemos na figura 8.6, teríamos o seguinte
resultado:

Figura 8.6 – Consulta usando LEFT JOIN ordenada pelo total de


consultas

Uma pergunta comum que os estudantes sempre fazem é: “o que


aconteceria se não houvesse consultas para um médico?" Para ilustrar isto
vamos fazer um exemplo simples.

Exemplo 5: Mostrar o nome e idmedicos dos médicos e caso tenham


consultas, dia e hora.

Figura 8.7 – Consulta usando LEFT JOIN com valores nulos (NULL)

Observe, que na figura 8.7, contendo os resultados da consulta planejada,


demos ênfase nos médicos Ana Smith e Marcus, que tem os valores NULL
(nulo) para dia e hora de consulta e para o atributo consultas.idmedicos.
Isso indica que eles não realizaram consultas.

Se fizéssemos o questionamento, perguntando quais os médicos que não


realizaram consultas, usando o conceito de Sub-consultas apresentados
anteriormente (veja o resultado na figura 8.8) teríamos o seguinte:

Figura 8.8 – Sub-consultas buscando médicos sem consultas


realizadas

Agora uma conclusão possível: O conjunto de dados de um LEFT ou


RIGHT JOIN é sempre maior ou igual ao conjunto de dados do INNER
JOIN. Isso Significa que o conjunto de dados de um INNER JOIN está
contido num LEFT ou INNER JOIN.

Apenas para ilustrar um exemplo usando RIGHT JOIN, vou repetir


a consulta do exemplo 5.

Figura 8.9 – Uso do RIGHT JOIN para o exemplo 5

Se você estiver fazendo esses exemplos no computador vai perceber que


o conjunto RIGHT JOIN e INNER JOIN são equivalentes. Isso ocorre,
pois, ao priorizar a tabela CONSULTAS (à direita), apenas vamos listar
consultas realizadas, as quais não existem sem médicos (veja figura 8.9).

Para ilustrar isto ( ver listagem da figura 8.10), vou apenas mostrar o
nome dos médicos nos três casos (sem repetição). Vou aplicar um limitador
para 5 registros, com o comando LIMIT 5;

Figura 8.10 – Uso do RIGHT JOIN priorizando consultas (tabela da


direita)

Agora com o uso do INNER JOIN :

Figura 8.11 – Uso do INNER JOIN para consultas


Observem que os resultados são idênticos para as consultas realizadas
tanto com INNER (figura 8.11) ou RIGHT JOIN, como já havíamos
explicado antes. Para ilustrar a diferença, mostramos a seguir a versão LEFT
JOIN, já discutida com o exemplo de sub-consultas. Observe que Ana Smith
estava na lista de médicos sem consulta realizada, como apresentado na
figura 8.12.

Figura 8.12– Uso do LEFT JOIN para consultas

Vamos agora juntar mais de 2 tabelas. Basta seguir os passos já


estabelecidos anteriormente.

Exemplo 6: Mostrar o nome do paciente e do médico, bem como dia


e hora das consultas realizadas.

Já havíamos realizado parte dessa consulta ao juntar a tabela


PACIENTES e CONSULTAS. Para dar resposta a este exemplo, precisamos
juntar a tabela MEDICOS.

Figura 8.13 – Junção de 3 tabelas com INNER JOIN


Observe no destaque da figura 8.13, que a junção adicional para a tabela


médicos é realizada através do comando inner join medicos on
consultas.idmedicos = medicos.idmedicos.

Sendo assim, caso desejarmos saber qual a especialidade do médico,


bastaria uma nova junção. Ou até mesmo o nome da doença atendida etc.
Vale destacar, que na exibição dos dados, aparece a coluna nome duas vezes.
Vamos usar um rótulo (aliás ou apelido) para tais colunas.

a) pacientes.nome as nomepaciente = apelide o atributo


nome da tabela pacientes como nomepaciente.

b) medicos.nome as nomepaciente = apelide o atributo nome


da tabela medicos como nomemedico.
Veja a seguir, a nova configuração (figura 8.14):

Figura 8.1 – Uso de Alias para as colunas NOME

Exemplo 6: Mostrar o nome do paciente e do médico, bem como dia


e hora das consultas realizadas. Mostre também a especialidade médica.

Figura 8.15 – Junção de 4 tabelas, exibindo a especialidade


médica

Observe que foi adicionada (ver na figura 8.15) a junção para a tabela
ESPECIALIDADES com o comando: inner join
especialidades on medicos.idespecialidades =
especialidades.idespecialidades
Usando o mesmo princípio, podemos juntar quantas tabelas forem
necessárias para responder a um questionamento a nossa base de dados.

Diante do que aprendemos sobre junções de tabelas vamos responder


mais quatro questões de exemplo, que possam misturar boa parte dos
conceitos ora aqui apresentados.

(Questão 1) Mostre os médicos com idade acima de 30 anos que


atenderam gripe

Para resolver essa questão, precisamos ter em mente que vamos exibir
dados de médico e o nome de doença atendida, que neste caso será gripe
(filtro), desde que o médico tenha mais de 30 anos (filtro). Apesar de
exibirmos dados de apenas duas tabelas, é obrigatório passar pela tabela
CONSULTAS, pois é por meio dela que se associam os dados de doença e
médico. Logo teremos três tabelas envolvidas (MEDICOS, CONSULTAS,
DOENCAS).

Vamos solucionar em duas fases essa questão: a) Junção das tabelas

Figura 8.16 – Junção de tabelas sem filtros (WHERE)

b) Aplicação de filtros de idade >30 e doenca = gripe

Observe que até a seleção de dados representada na figura 8.16, não foi
aplicado filtro (where), mas agora (na listagem da figura 8.17) foram
aplicados os fitros para idade e doença.

Figura 8.17 – Consulta completa com os filtros de doença e idade

(Questão 2) - Mostre a média salarial dos médicos por especialidade,


cuja idade seja maior que 30.

Para resolver essa questão, vamos envolver agrupamento por


especialidade médica (como listado na figura 8.18), o cálculo da média
salarial pela função AVG() e um filtro (WHERE) para a idade.

Figura 8.18 – Resposta para a questão 2


(Questão 3) - Mostre o nome das doenças que comecem Com a letra


"G" e para aquelas que têm consultas, exiba os dias de consultas
ordenados.

Neste cenário, precisamos considerar que até agora não trabalhamos com
busca textual parcial. Para isso, vamos precisar apresentar o operador LIKE
(em português “parecido”). Além disso, é possível que algumas doenças
cadastradas podem ainda não ter consultas realizadas para sua descrição.
Sendo assim, usar INNER JOIN é inadequado. Só usamos INNER JOIN
(considerando que é uma interseção de conjuntos) somente se sabemos que
há consulta para aquela doença. Vamos assim optar pelo uso do LEFT JOIN.

Vamos agora apresentar na forma de tabela alguns exemplos de LIKE e


do operador %: 1) Nome LIKE ‘A% : Nome comece com a letra A 2)
Nome LIKE ‘%A’: Nome termine com a letra A 3) Nome LIKE ‘%PA%’:
Nome o conjunto de caracteres PA Para exemplificar o uso do LIKE, vamos
para uma consulta simples. Exibir os nomes de médicos que começam com
M:

Figura 8.19 -Exemplo de uso do operador Like

Uma vez exemplificado o uso do operador LIKE (figura 8.19),


retomamos a nossa questão. Lembrando que vamos usar o LEFT JOIN
como forma de junção de tabelas. É bom deixar claro que embora em alguns
exemplos, junções com RIGHT e LEFT JOIN possam retornar valores
NULL, isto não é uma regra.
Sendo assim, a resposta para a questão é dada a seguir na listagem da
figura 8.20:

Figura 8.20 – Resultado da junção usando LEFT JOIN e operador


LIKE

(Questão 4) Mostre um ranking com as doenças com maior número


de atendimentos.

Solucionaremos esta questão, aproveitando a junção da questão anterior,


e, lembrando que temos, agora, que contar atendimentos em CONSULTAS
por doença, lembrando da possibilidade de algumas doenças sequer terem
tido atendimentos (evitamos o INNER JOIN).

Além disso, como ranking precisamos de ordenação, de modo geral, na


ordem decrescente pelo total de atendimentos.

Não custa relembrar que contagem (COUNT) é uma função de


agregação, de modo que será exigido agrupamento pelo nome (descrição) da
doença. Essa é a forma de agrupamento mais comum, mas sempre prefiro
agrupar pela chave primária, neste caso iddoencas.
Já usamos anteriormente o comando LIMIT 5, que limita o resultado da
consulta a 5 registros. Podemos especificar com esse comando N registros a
serem exibidos. Deste modo o resultado para a questão dada se encontra na
figura 8.21.

Figura 8.21 – Ranking de atendimento por doenças com um limite de


5.

Questões Teóricas

1. Por que é necessário juntar tabelas?

2. Quais os tipos possíveis de junção de tabelas?

3. Qual o tipo de junção de tabelas que equivale à intersecção de


conjuntos?

4. Por que, nas situações de junção de tabelas, devemos usar pré-fixos


(com os nomes de tabelas) ao usar os atributos?

5. Quais as regras ou passos para juntar tabelas?


6. É possivel juntar mais de duas ou mais tabelas?

7. É possível ou adequado juntar tabelas sem relacionamentos? Cite


exemplos, caso existam casos.

8. O que define se uma tabela está a ESQUEDA ou DIREITA, e como


isto afeta a prioridade na exibição de dados?

9. Por que, nos casos de junções sem INNER JOIN é comum termos
registros ou linhas de resultados com NULL?
10. Quando usamos funções de agregações, em consultas com uso de
junções de tabelas, é necessário realizar agrupamentos? Se sim, em que
casos?
11. Sub-consultas poderiam resolver problemas que normalmente
solucionaríamos com junções? Cite alguns exemplos.

12. É possível combinar os conceitos de sub-consultas e junções de


tabelas? Demonstre.

13. Qual a importância do comando LIMIT em resultados de consultas?

Questões Práticas

Parte 1 - Exercícios para resolução usando o Banco Clínica


1. Mostre as especialidades e para aquelas que tem médico mostre o
nome dos médicos.
2. Mostre o nome do paciente e para aqueles que têm consultas
realizadas, mostre as datas em ordem decrescente.
3. Mostre os dados dos médicos e consultas realizadas, mostre o dia e a
hora da consulta.
4. Mostre o nome das doenças que comece com a letra A, e para aquelas
que têm consultas ordenados as por data.
5. Mostre o total de funcionários do sexo masculino e para aqueles que
possuem salário maior que 2 mil, mostre seu ambulatório.
6. Mostre as doenças que não possuem consultas agendadas 7. Mostre o
nome dos pacientes e suas respectivas consultas, e para aquelas que foram
realizadas no turno da tarde, mostre o sexo do paciente.
8. Mostre o nome do médico, o número do ambulatório e o dia e hora de
uma consulta.
9. Mostre o número do ambulatório que não possuem consultas
realizadas.
10. Mostre as consultas realizadas e para aquelas realizadas no turno da
manhã, o nome do médico para médicos que ganham mais de 3mil reais.
11. Mostre o nome do médico e para aqueles que possuem consultas no
período da tarde a data da consulta.
12. Mostre o nome e o crm do médico e o ambulatório que ele pertence,
que não realizou atendimento em consultas.
13. Mostre todos os ambulatórios e, para aqueles ambulatórios onde
médicos realizam atendimento, exibir também os seus códigos e nomes.
14. Mostre todas as doenças e para aquelas possuem consultas realizadas,
exibir o nome dos pacientes do sexo masculino.
15. Mostre todos os médicos, para aqueles médicos com consultas
marcadas, exibir os crm e nomes dos seus pacientes e as datas das consultas.
16. Mostre os funcionários do sexo feminino e o número do seu
ambulatório 17. Mostre o nome das doenças e as datas de atendimentos 18.
Mostre o nome do paciente e dia e hora da consulta 19. Mostre as doenças
atendidas e os médicos envolvidos no atendimento 20. Mostre os médicos
com idade acima de 30 anos que atenderam gripe 21. Mostre a média de
idades dos medicos por especialidade 22. Mostre os ambulatórios e para
aqueles que tem atendimentos em consultas o total de consultas 23. Mostre
um ranking com o total de atendimentos por especialidade médica

Parte 2- Exercícios para o banco CLUBEDAPIZZA:


Figura 8.21 - Banco CLUBEDAPIZZA já apresentado anteriormente.

1. Mostre o nome dos sócios e seu respectivo tipo.


2. Mostre os dados dos atendentes e os dias que ele atendeu pedidos 3.
Mostre o nome do atendente, do sócio e pedidos que eles atenderam.
4. Mostre o total de pizzas já solicitadas por sabor 5. Mostre o valor
médio pago por sócio em seus pedidos 6. Mostre um ranking em valores de
pedidos feito por sócios. (considere o valor total pago em pedidos) 7. Mostre
o atendente que arrecadou a maior quantia em pedidos 8. Mostre o nome do
sócio e a soma total de itens que ele solicitou, ordenados pelo nome do sócio
9. Mostre o menor valor pago por sócio dentre todos os seus pedidos 10.
Mostre o nome do sócio e atendente com pedidos de valor total entre 40 e 70
reais 11. Mostre a pizza predileta de cada cliente.

Parte 3- Exercícios para o banco CINEMAS

O script deste banco pode ser obtido aqui.

Figura 8.22 - Modelo do Banco Cinemas


1. Mostre os dados dos estúdios e seus faturamentos


2. Mostre os dados dos filmes e suas categorias

3. Mostre o total de filmes por categorias


4. Mostre os dados do filme, seu respectivo estúdio e categoria 5. Mostre o
custo total dos filmes por estúdios
6 . Mostre os dados de atores e filmes que eles participaram
7. Mostre o total de atores que participaram de filmes por ano 8. Mostre as
categorias e para aquelas que tiveram atores participando de filmes, os dados
de autores 9. Mostre os dados dos atores e seus respectivos tipos de papeis

10. Mostre o cachê médio pago por filme

9. Visões (Views) ou visualização de dados de


tabelas

Nos capítulos anteriores discutimos consultas avançadas em banco de


dados. Trabalhamos sub-consultas e junção de tabelas, ajudando a ampliar a
solução de diversas questões complexas relativas às consultas e seleção de
dados de tabelas. Se observarmos os exemplos anteriores, podemos ver que
determinadas junções de tabelas soaram repetitivas e constantemente foram
executadas. Uma pergunta possível seria: “é possível reuso de consultas
realizadas anteriormente?”

Boa parte dos SGBDs modernos, como o MYSQL e MARIADB


(derivado do MYSQL), permitem a construção (e visualização) de dados por
meio de resultados de consultas já programadas. Este recurso é chamado de
visões (views).

Os dados são mantidos nas tabelas originais, mas podem ser


apresentados num objeto de banco de dados que agrega esses dados.
Alguns autores costumam associar views ao conceito de tabelas virtuais,
que são compostas por linhas e colunas de dados vindas de outras tabelas,.
Views (ou visões) são resultados de uma query (consulta) materializados
num objeto de banco de dados e armazenado no servidor. O objeto View é
um descritor para o resultado das consultas. Os dados se mantêm nas tabelas
originais. As views podem ser consultadas como tabelas, permitindo
comandos como SELECT, DESCRIBE, DROP, CREATE, ALTER,
dentre outros.

Um modelo de criação de view é dado a seguir: Create View


NomeDaView (lista de parâmetros) as
Comando SELECT

Vamos ao nosso primeiro exemplo de view, com uma visualização de


dados em uma única tabela.

Exemplo 1: Dados de um paciente numa visão contendo nome, sexo,


idade.

a) Passo 1: resolver a consulta: Para resolver tal questão, vamos executar a


consulta(select) que nos traz os dados e colunas da consulta (query) SQL
necessária para resolver o problema. Sendo assim teríamos o seguinte:

Figura 9.1 – Consulta básica para a view pedida.

Uma vez que temos certeza de que nossa consulta produziu o resultado
esperado (figura 9.1), vamos a construção da View. Vou chamá-la de
vPacientes. Neste livro vamos usar esse prefixo v (Letra V minúscula
antes do nome da View). É somente uma prática (estilo) pessoal. Não é uma
regra.

a) Passo 2 - Criar a Visão: Usando o comando CREATE VIEW vamos


criar a View usando a consulta já testada e validada anteriormente:

Figura 9.2 – Criação da view vPacientes

Observe que após realizar a execução do comando de criação da View,


nenhum resultado é exibido como resultado do comando, pois o objeto da
Visão ou View é construído no servidor, sem qualquer modificação de dados
das tabelas envolvidas no processo de construção (figura 9.2).

Além disso, é importante verificar que dentre os parênteses, dei novos


nomes aos atributos originais da tabela na view vPacientes. Chamos essa
visão (view) de View com parâmetros. Vamos ver a estrutura da view com
comandos já usados em tabelas. Primeiro vamos listar as tabelas (figura 9.3),
usando o comando SHOW TABLES:
Figura 9.3– Lista de tabelas e Views.

Observe que além das tabelas originais do banco, apareceu nossa view
vPacientes como se fosse uma tabela. Exato! Podemos operar com uma
view como se fosse uma tabela. Então vamos usar o comando DESCRIBE
para descrever nossa View?
Figura 9.4 – Descrição de uma View

Observe que ao descrever, na figura 9.4, a view vPacientes podemos


constatar que os nomes das colunas são exatamente os mesmos que
renomeei nos parênteses da figura 9.2. Ou seja: nomepaciente, sexo e idade.
Como se pode observar, eu apenas renomeei o atributo nome para
nomepaciente. Mantive os demais nomes de atributo originais da tabela
Pacientes. Vamos agora ao SELECT desses dados:

Figura 9.5 – Executando uma consulta numa View

Observe que o comando SELECT é executado da mesma forma que é


realizado em tabelas (figura 9.5). Para grandes conjuntos de dados o
resultado de uma consulta direta em View, retorna resultados mais
rapidamente (tempo de execução) que as consultas originais. Isso se dá pois
já houve um processo de análise sintática e verificação de erros na escrita da
consulta SQL, antes de criar a VIEW.

Assim como nas tabelas, podemos usar o comando DROP, permitindo


apagar a estrutura da view (ou objeto view). Teríamos algo assim:
Figura 9.6 - Comando para excluir uma view

Observe que comando DROP VIEW é seguido pelo nome da View a ser
apagada (figura 9.6). No nosso caso vPacientes.

Exemplo 2: Criar uma View com dados do paciente e dias de suas


consultas.

Para esta View, que vamos chamar vConsultasPacientes


precisaremos dos dados de tabelas diferentes (Pacientes, Consultas). Neste
caso, precisaremos juntar (usando joins) as duas tabelas. O resultado disto,
está demonstrado na figura 9.7.

Figura 9.7 – Junção das tabelas pacientes e medicos


Uma vez executada a consulta (seleções e junções de tabelas adequadas)
“alvo” com sucesso, vamos materializá-la numa view. Desta vez, vamos
omitir os parâmetros, de modo que materemos os nomes de atributos
originais das tabelas de origem (figura 9.8). Eis o resultado:

Figura 9.8 – Criação de View sem parâmetros

Uma vez criada nossa view vConsultaPacientes, vamos executar um


SELECT com todos os seus atributos. Desta vez vamos usar o coringa (*)
para este feito:

Figura 9.9 – Executando um comando SELECT na view e exibindo


todos os seus atributos.

Todos os atributos da view criada anteriormente (figura 9.9) foram


exibidos com o uso do coringa (*) .
Uma pergunta possível seria: “É possivel alterar uma view depois de
criada?” Sim, é possível através do comando ALTER VIEW. Vamos fazer
um exemplo: Exemplo 3: “Altere a view anterior para que exiba também
o CRM e Nome do Médico envolvido na consulta”.

Para dar conta do solicitado, primeiro precisamos rever nossa consulta e


juntar a tabela médico à consulta anterior. Faremos assim:

Figura 9.10 – Consulta modificada adicionando NOME e CRM dos


médicos

Observe que o resultado desta consulta (figura 9.10) trouxe dois atributos
nome (o primeiro para pacientes e o segundo para médico). Caso criássemos
uma View usando na íntegra tal comando teríamos uma “tabela virtual” ou
View com dois atributos de mesmo nome.

Isto provocaria um erro, pois em uma mesma tabela, não é possível ter
dois atributos com mesmo nome, o mesmo vale pra views. Para corrigir isto
vamos usar alias (ou apelido) nos nomes de médicos e pacientes (figura
9.11). Como exibido a seguir:
Figura 9.11 – Aplicando apelidos nas colunas nome de Pacientes e
Médicos

Resolvido o problema de não termos dois atributos de mesmo nome na


view vConsultaPacientes, vamos ALTERAR a View, conforme a figura
9.12.

Figura 9.12 – ALTER VIEW na visão vConsultaPacientes

Logo, nossa view alterada incorpora novos atributos do CRM e


NOMEMEDICO e o renomeado atributo NOMEPACIENTE. Uma
consulta básica a view teria o seguinte resultado:
Figura 9.13 – Executando um Select na view modificada

Na consulta (Seleção) expressa na figura 9.13, temos o resultado de uma


consulta na view vConsultaPacientes, agora, incorporando os novos
atributos adicionados na alteração da view.

Uma vez que aprendemos o básico sobre views (ou visões), uma
pergunta possível é: “Podemos juntar uma tabela com uma view?”
Veremos a seguir: Exemplo 4: “Aproveitando a visão VConsultasPaciente
exiba o nome da doença atendida.”

Observe que a visão vConsultaPacientes é limitada pelos atributos


predefinidos no momento da criação dela (figura 9.14). Com um
DESCRIBE temos os seguintes atributos:

Figura 9.14 – Atributos da visão


Observe ,que somente o atributo idPacientes é uma chave, vindo da


tabela PACIENTES, não temos quaisquer outros atributos chaves para
conexão (junção) com outras tabelas. A tabela CONSULTAS, por exemplo,
tinha os atributos idmedicos, iddoencas, idpacientes, idambulatorios. Tais
atributos permitiam junções em várias tabelas.

Para criar uma View reutilizável, precisamos ter chaves adicionais na


view, de modo a realizar junções em outraas tabelas e views. Chaves estas
que relacionam as duas tabelas ou views envolvidas.

Agora, vamos criar a View vConsultasGerais que terá os atributos da


view vConsultaPacientes com as chaves idmedicos, iddoencas,
idpacientes, idambulatorios. Isto vai nos permitir a juntar nossa visão com
as tabelas MEDICOS (Já juntada), DOENÇAS, AMBULATÓRIOS e
PACIENTES (já juntada).

Sendo assim, a View vConsultasGerais ficaria assim:


Figura 9.15 – View vConsultasGerais com chaves adicionais:
idmedicos,idambulatorios e iddoencas

Conforme vimos no sccript da view( figura 9.15), foram adicionadas as


chaves idmedicos, iddoencas, idambulatorios na nossa view original. Para
resolver o problema dado “exibir a doença atendida na consulta, podemos
juntar a tabela DOENCAS com a View VConsultasgerais.

Isso mesmo! podemos juntar uma View com uma tabela!

Basicamente, faremos uma junção de tabelas como aprendemos no


capítulo anterior. Tendo a seguinte junção:
Figura 9.16 – Junção de tabela com visão

Como vimos na figura 9.16, fizemos uma junção entre a tabela


DOENCAS e a visão vConsultasGerais usando o atributo iddoencas que
relacionam as ‘duas’ tabelas (tabela e visão).

Concluímos, então, que é possível realizar junção com visões desde que
tenhamos disponíveis chaves que relacionem as tabelas ou visões envolvidas
na consulta SQL a ser executada.

Exemplo 5: Mostrar a especialidade do médico das consultas


realizadas ordenadas pela especialidade médica.

Para resolver esta questão, vamos reusar a view vConsultasGerais.


Qual o atributo que relaciona médicos às suas especialidades? A resposta é
idespecialidades. Agora temos um novo problema, não temos este atributo
na view vConsultasGerais. Portanto, deveríamos ter este atributo na
visão criada anteriormente.
Foi proposital não incluir este atributo, pois, de modo geral,
programadores SQL esquecem que algumas tabelas envolvidas na criação de
visões podem ter conexõescom outras tabelas. Podemos corrigir a visão
anterior com um ALTER VIEW e adicionar o atributo idespecialidades. O
resultado dessa modificação pode ser visto na figura 9.17:

Figura 9.17 – Alter View na visão vConsultasGerais adicionando o


atributo idespecialidades.

Agora temos uma uma conexão para junção da tabela


ESPECIALIDADES com a visão vConsultasGerais.

Faremos essa junção pelo atributo recém adicionado idespecialidades.


Vou criar um apelido pra visão vConsultasGerais pra simplesmente V.
Isso vai facilitar a escrita da consulta. Toda vez que o interpretador de
comandos SQL vir o alias V, o mesmo vai ser referir a visãoo
vConsultasGerais. Vamos ao exemplo, já com a resolução do problema:
Figura 9.18 – Junção da tabela Especialidades com a visão
vConsultasGerais apelidada de V.

Para facilitar a visualização, usei comando


distinct para distinguir os
nomes dos médicos (figura 9.18), vindos da visão V (apelido da view
vConsultasGerais) para evitar repetições desnecessárias, pois um mesmo
médico atende várias consultas.

Também é possível usar junções, ordenações, agrupamentos, critérios


(cláusula WHERE ou HAVING) e vários outros recursos relativos à tabelas.
Vamos mostrar 3 exemplos:

Exemplo A: Mostrar os médicos que atenderam consultas, cujo


nome termina com a letra “a”, ordenados pelo nome.
Figura 9.19 – Consulta realizada numa visão usando where,
distinct e order by.

Observe que, embora a visão utilizada ficou restrita a dados da tabela


médicos (figura 9.19), temos uma condição ai: “médicos que atenderam
consultas”. De modo que precisava uma junção com a tabela consulta, mas
nossa visão vConsultasGerais já incorpora dados das consultas atendidas
por médicos. Portanto, nosso problema ficou mais simples. Usamos o
distinct aqui para evitar repetição no nome de médicos, ordenamos pelo
nome, e usamos o critério (o nome terminar com a letra a) com a cláusula
WHERE.

Exemplo B: Mostrar o total de consultas atendidas por médico no


ano de 2016.

Figura 9.20 – Resultado da consulta à view, com filtro no ano e


agrupamento pelo nome do médico

Agora, usamos uma função de data para simplificar nossa consulta,


conforme listado na figura 9.20. A Função YEAR(dia) pega a string relativa
ao ano de um atributo do tipo date. Isso evitaria o famoso “dia between
‘2016-01-01’ and ´2016-12-31’ “.

Exemplo C: Mostrar o nome do médico, especialidade, paciente


ordenados pela especialidade médica atendida.

Para solucionar a questão dada, usamos uma junção de views


vConsultasGerais (apelidada de V) com a tabela especialidades. A
listagem contida na figura 9.21 demonstra uma junção de view com tabela.
Figura 9.21 – Visão retornando especialidade atendida por médico
e paciente.

Questões Teóricas

1. O que são Views?


2. Qual a diferença de Views para Tabelas?
3. Quais comandos usados em TABELAS que também podem ser usados
em VIEWS?
4. Podemos criar VIEWS com Parâmetros ou não. Quais as vantagens ou
desvantagens de cada abordagem?
5. Quais os passos de construção de uma VIEW?
6. Quando eu apago uma VIEW, o que acontece com os dados? E por
quê?
7. Podemos realizar SELECTS em VIEWS?
8. Podemos juntar VIEWS com outras VIEWS ou TABELAS?
9. Como podemos tornar nossas VIEWS reutilizáveis para futuras
junções com outras VIEWS ou TABELAS?
10. Podemos usar ALIAS para VIEWS ou TABELAS? Se sim, dê
exemplos.

Exercícios práticos

PARTE 1 - Usando o conceito de criação, modificação ou exclusãode


views, responda as questões a seguir para o Banco Clínica.

1. Mostre os dados de um paciente e dias e horas de suas consultas

2. Mostre dados de um funcionário e o número do ambulatório que ele


pertence

3. Mostre o total de atendimentos por doença

4. Mostre o nome de um médico, crm, nome do paciente, idade e dia e hora


de atendimento em consulta

5. Mostrar o nome das especialidades e os respectivos médicos a elas


associadas

6. Mostre além dos dados na questão 4 a descrição da especialidade do


médico

7. Mostre um ranking de ambulatórios e o total de médicos de cada um deles

8. Mostre o nome do médico, do paciente, doença atendida, número do


ambulatório e dia e hora do atendimento

9 – Mostre todas as consultas realizadas no turno da manhã no ambulatório 1

10 – Mostre o salário médio dos funcionários por sexo e ambulatório

Figura 9.22 - Banco Clube da Pizza


PARTE 2 - Usando o conceito de criação, modificação ou exclusão de
views para o banco CLUBEDAPIZZA, responda as questões a seguir:

1. Mostre o nome, cpf e tipo do sócio ordenador por nome 2. Mostre o


nome do socio e o quantidade total de pedidos 3. Mostre o nome do sócio e a
quantidade total de pizzas que ele pediu 4. Mostre o o nome do atendente e a
soma total de pedidos atendidos 5. Mostre os sabores de pizza atendidos para
cada atendente 6. Mostre o total de pedidos atendidos por atendente 7.
Mostre o nome do cliente, data do pedido, valor total 8. mostre os sabores de
pizza contidos por cada pedido 9. Mostre o total de pedido por saber de
pizza 10. Faça um ranking com as 5 pizzas mais vendidas em pedidos,
ordenados pela mais pedida.

PARTE 3 - Usando o conceito de criação, modificação ou exclusão de


views para o banco CINEMAS, responda as questões a seguir:

O script deste banco pode ser obtido aqui.

Figura 9.23 - Modelo do Banco Cinemas


1. Mostre os dados dos estúdios e seus faturamentos 2. Mostre os dados dos


filmes e dados dos atores participantes
3. Mostre o total de filmes por categorias
4. Mostre os dados do filme, seu respectivo estúdio e categoria 5. Mostre o
custo total dos filmes por estúdios 6 . Mostre por quais estúdios um ator
participou de filmes 7. Mostre o total de atores que participaram de filmes
por ano 8. Mostre as categorias e para aquelas que tiveram atores
participando de filmes, os dados de autores 9. Mostre os dados dos atores e
seus respectivos tipos de papeis

10. Mostre o cachê médio pago por filme


11. Mostre o ranking de filme com maiores cachês pagos 12. Mostre a lista
de filmes mais caros por ano
10. Procedimentos Armazenados no servidor –
Stored Procedures

Quando trabalhamos em banco de dados, é muito provável que


queiramos otimizar processos relativos a modelos complexos de dados,
assim como aplicações que podem ter uma regra de negócio mais
sofisticada, que exige uma sinergia na equipe de trabalho.

Um bom projeto de Banco de Dados, respeitado o modelo de camadas de


desenvolvimento de software, pode ter também rotinas (mini programas)
armazenadas em servidor, usando comandos de uma linguagem de
programação específica, para além dos comandos básicos do SQL. Algumas
dessas rotinas (que chamamos métodos em outras linguagens de
programação) no MYSQL (e também MariaDB) são: a) Procedimentos
armazenados e b) Funções. Vamos dedicar este capítulo ao primeiro.
Procedimentos armazenados (Stored Procedures) são rotinas (blocos de
programas) definidas em banco de dados, que possuem uma assinatura (ou
nome) pelo qual são chamadas. Internamente, podem ser executados vários
comandos SQL: SELECT, INSERT, DELETE, UPDATE etc. buscando
atender um propósito pelo qual a rotina (ou aqui, procedimento armazenado)
foi criada. A depender da rotina projetada, se no lado cliente, a execução e
processamento da rotina, pode ter um custo computacional e de tráfego de
dados relativamente alto, como em alguns sistemas web.

Sendo assim, para evitar tal custo, além de permitir trabalho em


colaboração, podemos criar rotinas internas ao SGBD. Como de modo
geral, os servidores destinados à aplicações de Banco de Dados são mais
robustos, e algumas (ou todas) as rotinas relativas às regras de negócio de
uma aplicação podem ser incorporadas ao Projeto de Banco de Dados da
aplicação projetada. Procedimentos (ou procedures) são objetos também
armazenados em SGBD, assim como tabelas, visões e outros objetos de
banco de dados.

Uma Associação/paralelo conceitual com Classes e Objetos, poderiam


trazer a seguinte correlação: Tabelas seriam equivalentes às Classes/Objetos
e rotinas (procedimentos e funções) aos métodos, que neste caso, podem ser
específicos de tabelas ou não.

Assim como, os métodos das linguagens de programação, os


procedimentos (ou procedures) podem receber parâmetros, executar
instruções e retornar valores. Algumas outras vantagens no uso de
Procedures seriam:

1) Simplificação ou distribuição da execução de instruções SQL


centradas no servidor
2) Facilidade de manutenção, centradas no servidor.
3) Possibilidade de trabalho em equipe e reuso de rotinas programadas.
4) Processamento de boa parte do processamento para o servidor.
Algumas desvantagens relativas às procedures, são as seguintes:
1) As rotinas podem ficar acessíveis facilmente, caso políticas de
acesso ou segurança não sejam implementadas;
2) Maior necessidade de conhecimento de linguagens de programação
específicas daquele SGBD.

No MySQL e MariaDb são usadas uma PL/SQL específica, que será


demonstrada aos poucos por exemplos aqui.

O escopo básico de uma stored procedure no MySQL é da seguinte


forma:
Delimiter $$
CREATE PROCEDURE NomeDaProcedure (modo parametro1 tipo1, modo
parametro2 tipo2, modo parametroN tipo)
Begin
< BLOCO DE INSTRUÇÕES PL/SQL>
End;
$$

Um procedimento armazenado é definido (criado) como objeto do


SGBD, ou banco de dados, em um conjunto de comandos PL/SQL entre
DELIMITER $$ e $$ (que indica o fim do bloco de comandos do escopo da
procedure. O modo indica a forma como o parâmetro vai ser tratado no
procedimento. Pode assumir 3 valores:
a) IN
→ Indica que o parâmetro é de entrada (passado por valor) e não
pode ser usado como retorno.
b) OUT
→ Indica que o parâmetro é de saída. Não pode receber valor
direto e sim uma referência à uma variável.
c) INOUT→ Incorpora as características dos anteriores, mas com a
restrição de não receber valores diretos.

Por padrão no MYSQL, o modo é IN. Sendo assim, pode ser omitido no
momento da criação do procedimento.

Os blocos BEGIN/END delimitam o começo e fim das instruções


PL/SQL internas ao procedimento.

Agora, vamos a um exemplo concreto.

Exemplo 1: Criando uma procedure simples de cadastro de um


paciente
Figura 10.1 – Procedimento para cadastrar um Paciente

Após delimitar o escopo da procedure (linhas 1 e 8) pelos delimitadores


(conforme demonstrado na figura 10.1), criamos nossa procedure com o
comando
CREATE PROCEDURE dando o no spInserirPaciente
(sempre coloco um prefixo sp antes de minhas Stored Procedures). Isto não é
uma regra.

Além disso, temos os parâmetros pNome, pSexo, pIdade,


pDoenca_incial que servirão para receber valores que possam ser usados
na execução do comando INSERT ( linhas 5 e 6) para os atributos originais
da tabela (nome, sexo, idade, doença_inicial). O atributo autoincremento
IdPacientes é omitido aqui. Novamente aqui, uso um pré-fixo p antes do
nome de cada parâmetro. Não é uma regra, é apenas padrão pessoal de
nomenclatura de parâmetros.

Uma vez criado o procedimento


spInserirPaciente, como podemos
chamá-lo e executar comandos? A chamada de uma procedure é dada pelo
comando CALL ("chamar" em inglês), o nome do procedimento e os
parâmetros (ou valores) a serem trabalhados. Para nosso exemplo, temos o
seguinte:

Figura 10.2 – Exemplo de chamada da procedure spInserirPaciente

No exemplo da chamada acima (figura 10.2), chamamos a procedure


spInserirPaciente passando os valores acima, na ordem de apresentação
dos parâmetros (pNome, pSexo, pIdade, pDoenca_incial) com valores
adequados aos seus respectivos tipos (varchar,char,int,varchar). Neste
caso os valores foram respectivamente: João Alves Silva, sexo masculino,
idade de 40 anos e doença inicial a gripe.

Uma pergunta possível seria: "Se nas linguagens de programação


podemos ter métodos sem parâmetros, aqui também podemos?"

A resposta para esta pergunta virá com o exemplo a seguir: Exemplo 2:


Lista de pacientes cadastrados

Figura 10.3 – Exemplo de procedure sem parâmetros e sua


respectiva chamada

Observe que procedure listada (figura 10.3), temos na linha 2 o


comando:

DROP PROCEDURE if EXISTS spListarPacientes;


O qual tem como objetivo apagar a procedure spListarPacientes caso


ela exista (IF EXISTS), para posteriormente criar uma procedure de mesmo
nome, nas linhas a seguir. Na linha 3, temos a criação da procedure sem
parâmetros. E entre os comandos
BEGIN/END temos uma simples consulta
SELECT com dados de pacientes.

Observe que ao chamar a procedure spListarPacientess na linha 9,


com o comando CALL spListarPacientes(); temos um retorno da lista de
pacientes ordenadas por nome (figura 10.3). Portanto, podemos ter
procedures sem parâmetros.

Exemplo 3: Excluir um paciente pelo IDPACIENTE.

Figura 10.4 – Exclusão de paciente pelo parâmetro pIdpaciente

No trecho de código (listado na figura 10.4) criamos a procedure


spExcluirPaciente que recebe o parâmetro pIdpaciente, para buscar os
dados do paciente que tem o respectivo idpacientes (atributo da tabela), de
modo a excluir (comando DELETE) os dados do respectivo paciente. Na
chamada do procedimento, passamos o valor 37, IdPaciente relativo ao
paciente “coisinho da Silva” conforme figura 10.3.

Exemplo 4: Atualizar dados de um Paciente, passando novos valores.


Figura 10.4 – Procedimento de Atualização de dados.

Como vimos na figura 10.4, temos a criação da procedure


spEditarPaciente, que recebe os parâmetros de atualização, incluindo
aqui, também, a chave primária usada no critério de atualização da cláusula
WHERE. Na chamada do procedimento passamos novos valores para o
paciente cujo idpacientes=36 (originalmente: ‘Coisinho’), que agora
recebe os novos valores de nome, sexo, idade e doença inicial:

CALL spEditarPaciente('Coisinho
Silva','m',43,'espirros',36);

Após a execução da chamada do procedimento, a atualização de dados


foi realizada com sucesso, com os novos dados na figura 10.5 a seguir.

Figura 10.5 – Consulta com novos dados do paciente

Até agora, apresentamos exemplos simples de procedures usando apenas


o básico de SQL. Aprendemos a criar procedures (CREATE
PROCEDURE) e excluir (DROP PROCEDURE). Podemos listar
procedures ou rotinas do servidor com o comando a seguir:
Figura 10.6 – Lista de Procedures para o banco atual

Observe que filtramos os procedimentos com o critério WHERE


DB=’NOME-DO-BANCO’, deste modo, estamos exibindo somente
procedures para o banco CLINICA2020. Omitindo o critério, serão listadas
todas as procedures do servidor. São exibidos como resultado: nome do
banco, nome do procedimento, tipo (procedure), criador, dentre outras
informações (como demonstrado na figura 10.6).

Questões Teóricas

1. O que é um procedimento armazenado? Quais suas vantagens e


limitações?
2. Qual são as relações possíveis entre procedimentos e funções
armazenadas em servidor (para banco de dados e tabelas) e encapsulamento?
3. Qual o escopo básico de uma procedure?
4. Quais os tipos possíveis de parâmetros para uma STORED
PROCEDURE?
5. Como podemos apagar uma procedure?
6. Uma vez criada uma procedure, como podemos utilizá-la? Como ela é
chamada?
7. Como podemos listar as procedures de um banco de dados específico?

Exercícios Práticos:
Parte 1 - Crie Procedures para o banco CLINICA que:
1. Cadastre um paciente 2. Edite um paciente 3. Busque as consultas do
paciente pelo nome 4. Cadastre um médico

5. Exclua um funcionário pelo seu idFuncionarios


6. Busque todos os atendimentos de uma doença (parâmetro) 7. Que ao
receber o sexo como parâmetro, mostrar dos funcionários daquele sexo

8. Liste todos os funcionários de um ambulatório


9. Mostre todas as consultas marcadas para uma data específica
informando doença, médico e paciente 10. Mostre a ficha médica de um
paciente baseado no seu histórico de consultas, recebendo o nome do
paciente como parâmetro 11. Buscar uma doença pelo nome e listar a
quantidade de atendimentos dela 12. Mostrar uma listagem de médicos
baseados no parâmetro de especialidade

Parte 2- Para o banco Clube da Pizza, crie PROCEDURES que: 1.


Insiram um atendente
2. Apaguem um atendente pela chave primária
3. Atualize dados de um atendente

4. Busque um atendente pelo nome


5. Dado um id de sócio mostre a soma de seus pedidos

6. Cadastre um novo tipo de sócio


7. Insira os dados de um novo item de pedido

8. Atualize os dados de uma pizza


9. Busque todos os pedidos de um cliente num intervalo de duas datas,
exibindo seu nome e valor total

10. Remova um item de pedido


11. Ao receber um sabor de pizza, informar as datas na qual aquele sabor
foi solicitado.
12. Ao receber o tipo do sócio listar todos os nomes de sócios associados
à aquele tipo 13. Ao receber o nome do atendente, mostrar todos os sabores
de pizza que ele já atendeu.
14. Ao receber um IDPEDIDO mostrar todos os sabores contidos
naquele pedido.
15. Remover um atendente pelos dados passados por parâmetro.

Parte 3- Para o banco CINEMAS, crie PROCEDURES que:

1. Insira dados de um estúdio


2. Exclua um faturamento de estúdio, recebendo como parâmetros o
estúdio e o ano do faturamento

3. Modifique os dados de um ator


4. Adicione os tipos de papéis de um ator
5. Mostre o custo total dos filmes por estúdios, recebendo o nome do
estúdio como parâmetro 6;. Mostre por quais estúdios um ator participou de
filmes, lembrando que devemos passar o nome do ator e seu id 7. Mostre o
total de atores que participaram de filmes por ano, recebendo como
parâmetro o ano do filme 8. Recebendo o nome da categoria, mostre atores
que participaram de filmes e os dados dos filmes

9. Insira dados de um novo filme


10 - Modifique os dados da participação de um ator no elenco de um
filme, passando como parâmetro dados do ator e do filme
11. Programação estruturada em PL/SQL

Para incrementar e sofisticar nossas procedures (abordadas no capítulo


anterior) e Funções (que seria discutidas adiante), vamos introduzir alguns
conceitos de programação estruturada com PL/SQL do MySQL /MariaDB
através de exemplos simples: Exemplo 1: Vamos começar com um
exemplo simples de criação de variável local e retorno do valor.
Figura 11.1 – Exemplo de uso de variável interna.

No exemplo da figura 11.1, temos a criação de uma procedure que


internamente (linha 4) criamos uma variável local resultado que na linha 5,
vai receber o resultado da soma dos parâmetros X e Y. Observe que a
atribuição de valor aqui é dada pelo comando SET, à semelhança do que
ocorre nos updates. Na linha 6, decidimos exibir (por meio do comando
SELECT) o valor da variável resultado como uma mensagem (msg como
apelido). Observe que ao chamar o procedimento spExemplo1 temos o
retorno exato da soma proposta no escopo do procedimento.

Exemplo 2: Estrutura de Decisão


Figura 11.2 – Exemplo de Estrutura IF THEN ELSE

No bloco de comandos (figura 11.2), temos a criação de uma procedure


que internamente (linha 4) criamos uma variável local maior que na linha 5,
vai receber o resultado do teste da estrutura IF-THEN-ELSE comparando
X e Y. Na linha 9, temos uma estrutura de finalização do comando IF através
do END IF.

Decidimos exibir (linha 10) o valor da variável maior como uma


mensagem (msg como apelido). Desta vez usamos uma função para somar
strings (ou concatenar) chamada CONCAT(). Ela permite somar strings e
valores separados por vírgulas. O resultado exbido em msg é a soma do texto
‘o maior valor eh ‘ e o valor da variável maior.

Exemplo 3: Uso da Estrutura CASE


Figura 11.3 – Estrutura CASE – WHEN

O trecho transcrito da procedure(figura 11.3) mostra a procedure


spExemplo3 que receber um parâmetro (pSexo) do tipo char para o sexo e
internamente testa (das linhas 5 a 12) valores possíveis com uso da estrutura
WHEN (quando, na língua portuguesa) para masculino e feminino. Caso um
valor seja diferente de ‘m’ ou ‘f’, temos um ELSE (linha 10-11) para o bloco
de comandos CASE, atribuindo à variável interna resultado o valor
‘inválido’. O comando CASE é encerrado com END CASE;

Exemplo 4: Repetição condicional com While (simulando um FOR)


para imprimir soma dos 10 primeiros números.

Figura 11.4 – While usado em procedure

No exemplo de código da figura 11.4, temos um vislumbre da estrutra


While-DO. Observe, que nas linhas 4,5 foram declaradas as variáveis x e
soma e atribuído (inicializado) o valor padrão DEFAULT 0. Ou seja essas
variáveis começam com valor zero.

A repetição condicional (x<10) está na linha 6. Internamente temos um


somador (linha 7) e um incremento da variável x (linha 8), finalizando a
repetição na linha 9 com o comando END WHILE;

Novamente, temos um select para exibição do resultado da soma na linha


10. Ao ser chamada a procedure spExemplo4 temos o resultado da soma
na mensagem ‘a soma dos numeros eh 45’.

Apresentamos aqui, algumas estruturas úteis para programação de


procedimentos, funções, transações e triggers e outros objetos de banco.
Agora, vamos mesclar esses conceitos com o uso de instruções SQL.

Exemplo de Procedures que utilizam PL/SQL


Exemplo 1: Procedure que recebe um nome de paciente e busca sua
existência. Caso não exista retornar uma mensagem.
Figura 11.5 – Procedure testando a existência ou não de um
paciente, como resultado de uma busca.

Nesta procedure (figura 11.5) temos um primeiro SELECT que testa a


existência de algum paciente (busca pelo nome), na linha 6.Aqui temos,
também, a instrução idpacientes INTO id que serve para guardar o valor
do atributo idpacientes encontrado na variável local id.

Na linha 7, temos um bloco de teste IF-THEN-ELSE que testa se o valor


de id é diferente de zero. Isto significa que existe um ou mais pacientes que
atendem a consulta.

No caso de termos um id válido, imprimimos o resultado da consulta


SELECT da linha 8. Caso contrário, imprimimos uma mensagem de não
localização daquele paciente, nos trechos das linhas 9 a 11. O bloco do IF é
fechado com END IF;

Fizemos um segundo teste (figura 11.6) buscando o nome ‘xxxxx’, e o


retorno foi o seguinte:
Figura 11.6 – Retorno da procedure no caso de não encontrar um
paciente pelo nome passado por parâmetro.

Conforme implementamos na programação de nossa procedure, ao


passar um nome que não é encontrado dentre os pacientes, a mensagem
padrão programada foi exibida, informando que o paciente não foi
encontrado.

Exemplo 2: Procedure que busque as consultas de um médico pelo


seu nome e ano da consulta.

Agora, para este exemplo vamos testar se o usuário passou algum ano e
nome vazios ou nulos e vamos validar isto.

Uma observação importante é que é mais comum validações de dados,


serem realizadas nas telas de aplicação (aplicativo, programa cliente ou
página de internet) para evitar que o servidor faça tais validações.

Considere aqui este exemplo de validação como um exemplo didático.


Figura 11.7 – Validações de parâmetros interna à procedure.

No código transcrito da procedure spBuscarMedicoAno (figura


11.7). Podemos observar algumas validações realizadas. A primeira coisa a
se observar é a criação da variável local erros com valor default (padrão) ‘’.
Ou seja, string vazia na linha 5.

Temos duas validações para os parâmetros. A primeira nas linhas 6 a 8,


que testam se o parâmetro pNome recebeu um valor vazio ou nulo. Nas
linhas 9 a 11 fazemos uma validação semelhante para pAno. Observe que,
no caso de encontrar erros (pelos testes lógicos) é feita uma soma (ou
concatenação de mensagens de erro).

Finalmente, se não tivermos erros, com o teste lógico da linha 12,


podemos enfim, executar nossa consulta (usando joins) para atender ao
problema proposto (linhas 13 e 14). Caso tenhamos erros de validação
detectados, imprimimos a mensagem programada para o ELSE das linhas 16
a 18. Vamos mostrar 3 cenários de teste a seguir: Teste 1 – Nome inválido
Figura 11.8 – Teste do parâmetro pNome inválido

Ao chamarmos a procedure spBuscarMedicoAno (figura 11.8),


passamos um parâmetro de nome vazio, logo o erro programado foi exibido
como mensagem.

Teste 2 – Nome e ano inválidos

Figura 11.9 – Teste do parâmetro pNome e pAno inválidos

Nesse teste listado, provocamos como erros um nome vazio e um valor


nulo para o ano. Provocando uma mensagem concatenada com os dois erros
programados (figura 11.9).

Teste 3 – Nome e ano válidos


Figura 11.10 – Teste do parâmetro pNome e pAno Válidos

Finalmente, no terceiro teste (listado na figura 11.10), passamos valores


válidos para a procedure, trazendo os resultados devidos para o
procedimento programado.

Como se pôde observar nos três exemplos apresentados, testamos


validações possíveis para os parâmetros (figuras 11.8 e 11.9), com
mensagens de erro. Demonstramos também o resultado da procedure quando
encontra médicos e anos que atendam a consulta programada.

Para encerrar, por enquanto, o uso de comandos PL/SQL, nas nossas


procedures vamos encerrar com um procedimento que vai dar um aumento
de 10% para funcionários do sexo masculino e 20% para funcionárias do
sexo feminino.

Exemplo 3: Procedure que dê um aumento baseado no sexo do


funcionário.
Figura 11.12 – Procedure que recebe como parâmetro o sexo e dá
aumento relativo ao parâmetro recebido.

Nesta procedure criamos uma variável interna para controlar o valor


percentual do aumento vPercentual (linha 5) e decidimos que percentual
vamos aumentar baseado no valor do parâmetro recebido pSexo. Nas linhas
6 a 10, temos a estrutura IF-THEN-ELSE pra definição do aumento.

E finalmente, na linha 12, atualizamos a tabela Funcionários com base


no valor calculado para o aumento para o parâmetro pSexo recebido. A linha
15, tem a chamada do procedimento spDarAumento recebendo o valor ‘f’
para o sexo feminino.

Exemplo 4: Procedure que que busque os dados de um funcionário


pelo nome, mas o nome não pode ter menos de 3 caracteres. (BONÛS)
Figura 11.12 – Validação de parâmetro pelo tamanho em caracteres

Na figura 11.12, temos o procedimento spBuscarFuncionarioNome,


no qual introduzi duas coisas diferentes. A primeira é o uso da função
LENGTH() que retorna o tamanho de uma variável string (varchar, char
etc). Na linha 5, foi testado se o tamanho do nome recebido como parâmetro
(pNome) é inferior a 3 caracteres.

A segunda inovação é que a busca não é exata, usamos, portanto o


operador LIKE (parecido). Observe que na linha 9 temos o trecho WHERE
nome LIKE CONCAT(pNome, '%'); que busca um nome que comece
com aquelas iniciais, fornecidas no parâmetro. O CONCAT() aqui serve pra
juntar o parâmetro pNome com o coringa (%). Isto significa que estamos
buscando nomes parecidos (por isto usamos o operador LIKE) que
comecem com o valor do parâmetro fornecido.

Agora que nosso vocabulário da linguagem PL/SQL aumentou (embora


não exploramos tudo da linguagem que é disponível), vamos criar
procedures com algumas validações e testes.

Questões Teóricas

1. O MySQL e outros SGBD permitem programação estruturada. Cite


algumas dessas estrturas.
2. Como posso declarar uma variável interna em um procedimento
armazenado?
3. Como modifico um valor de variável dentro de um comando SQL?
4. Como funciona a estrutuda de decisão IF-ELSE? Como se encerra um
bloco IF?
5. Nos exemplos, deste capítulo, usamos a função nativa CONCAT.
Explique como ela funciona e qual sua vantagem.
6. Explique como funciona a estruta de decisão CASE. Demonstre com
um exemplo.
7. Podemos usar estruturas de repetição condicional. Explique o
funcionamento do WHILE-DO.
8. Como guardar um valor recebido de um atributo numa variável local
criada pelo usuário? Dê exemplos.
9. Para que serve a função nativa LENGTH()?

Exercícios práticos

Parte 1 - Crie procedures para o Banco CLINICA que:

1.
Receba o nome de um paciente e retorne os dias de suas consultas. O
nome não pode ter menos que 3 caracteres.
2. Cadastre um médico. Valide os dados obrigatórios da tabela.
3. Receba um sexo e mostre os pacientes daquele sexo. Valide os sexos
recebidos com a Estrutura CASE.
4. Busque os médicos de uma especialidade. Valide o nome da
especialidade, evitando nulos e dados vazios.
5. Insira uma consulta médica. Valide os dados obrigatórios da consulta
6. Busque uma doença pelo nome e listar a quantidade de atendimentos
dela. Informar ao usuário caso não a encontre. Use o operador LIKE
na busca
7. Busca todas as consultas realizadas, o nome do médico e do paciente.
Valide se os nomes são nulos ou não, nos parâmetros. Use busca
exata.
8. Exclua um funcionário baseado no seu IdFuncionário. Valide se o
valor passado é nulo ou não. Caso o usuário não exista, informe ao
usuário.
9.
Ao receber o número de um ambulatório, mostre os médicos ali
pertencentes. Valide testando se o número passado é positivo.
10. Mostre um ranking do maior para o menor, número de consultas por
médico, limitando a quantidade de registros ao limite passado por
parâmetro. Dica: Usar o comando LIMIT.

Parte 2 - Usando o banco Clube da Pizza, crie as seguintes


procedures:

1. Insiram um atendente.Valide os dados obrigatórios.

2. Apaguem um atendente pela chave primária


3. Atualize dados de um atendente

4. Busque um atendente pelo nome e exiba seus dados


5. Dado um id de sócio mostre a soma de seus pedidos
6. Mostre o total de pizzas já solicitadas por sabor (que é fornecido
como parâmetro)
7. Mostre o valor médio pago por sócio em seus pedidos. O nome do
sócio é fornecido como parâmetro
8. Mostre um ranking em valores de pedidos feito por sócios. O nome
do sócio é fornecido como parâmetro
9. Mostre o atendente que arrecadou a maior quantia em pedidos. Essa
procedure é sem parâmetros
10. Mostre o menor valor pago por sócio dentre todos os seus pedidos,
sendo que os parâmetros fornecidos são duas datas (inicial e final)
11. Mostre os dados de pedidos, dado que são passados como
parâmetros o nome do atendente e nome do sócio.
12. Mostre a pizza predileta de cada cliente. O parâmetro de entrada é o
ano do pedido.

PARTE 3 - Para o Banco CINEMAS, crie as seguinte procedures:


1. Mostre os dados dos estúdios e seus faturamentos, rebendo como


parâmetro o nome do estúdio 2. Mostre os dados dos filmes e dados dos
atores participantes, recebendo como parâmetro o nome do filme 3. Mostre o
total de filmes por ano. Receba o ano como parâmetro 4. Mostre os dados do
filme, seu respectivo estúdio e categoria. Receba o nome do filme como
parâmetro 5. Mostre o custo total dos filmes por estúdios. Receba o id do
estúdio como parâmetro.
6 . Mostre por quais estúdios um ator (atriz) participou de filmes. Neste caso,
informe o sexo do ator(atriz) como parâmetro.
7. Mostre o total de atores que participaram de filmes por ano. Informe o ano
como parâmetro.
8. Mostre o cachê pago por filme no qual um ator participou. Informe o
nome e sexo do ator como parâmetros.

12. Funções armazenadas ou Functions

Nos capítulos anteriores, aprendemos um pouco a respeito de


procedimentos armazenados, um pouco de programação SQL com PL/SQL.
Rotinas armazenadas em servidor são basicamente de dois tipos:
Procedimentos (já discutido antes) e Funções criadas por usuários. Vamos
nos dedicar agora ao segundo tipo de rotina.

Antes ao criar uma procedure invocávamos o seguinte comando:


Create procedure spNomeDaProcedure(
[ lista de parâmetros])

Nas funções armazenadas temos algumas pequenas diferenças: Create


procedure fNomeDaFunçao(

[ lista de parâmetros]) Returns <TIPO DO


RETORNO>
Por leve comparação, vimos que as Funções (ou functions) devem
retornar um valor de tipo específico.

Delimiter $$
CREATE FUNCTION NomeDaFunção (parametro1 tipo1,par ametro2 tipo2,
parametroN tipo)
RETURNS <TIPO>
Begin
< BLOCO DE INSTRUÇÕES PL/SQL>
End;
$$

Vamos dar continuidade através de alguns exemplos.

Exemplo 1: Função que retorna o nome do médico mais velho.

Figura 12.1 – Função fMedicoMaisVelho()

O importante a se notar no exemplo fMedicoMaisVelho()(figura 12.1)


é que temos especificado um retono para a função através do RETURNS
VARCHAR(50), informando ao servidor que aquele valor a ser retonado
através da variável local vnome (criada na linha 5), após execução do
comando SELECT das linhas 6 e 7, é retornado no final do corpo da função,
através do trecho RETURN vnome;
Diferentemente, das procedures chamadas por CALL, as funções
(functions) retornam valores que são exibidos por SELECT (como na linha
11). O próprio nome da função em si, é sua chamada.

Exemplo 2: Função que retorna o idDoencas de uma doença cuja


descrição é fornecida como parâmetro.

Figura 12.2 – Função fBuscarDoenca, com retorno Int.


Observe que diferentemente do exemplo anterior, após o RETURNS


INT, adicionei a palavra DETERMINISTIC. Por padrão, os retornos de
funções são deste tipo. Observe que temos uma variável local id , que
servirá de retorno, no final da função criada. Essa variável é do mesmo tipo
do retorno planejado no momento do CREATE FUNCTION. A exibição do
resultado da função, novamente, é dada por um SELECT, na linha 10 (figura
12.2).

Até o momento, neste texto, temos duas funções criadas. Podemos listar
as funções criadas pelo comando a seguir:
Figura 12.3 – Listando as funções armazenadas

Caso queiramos apagar uma função basta usar o comando: DROP


FUNCTION NomeDaFuncao;

Exemplo 3: Função que retorna o menor salário dentre os médicos e


funcionários.

Figura 12.4 - Função fMenorSalarioGeral()


A função fMenorSalarioGeral() foi criada sem parâmetros mas retorna
um tipo float (os salários são deste tipo). Internamente criamos em uma
única linha três variáveis internas (menor, menorSalarioMedico,
menorSalarioFuncionario) fundamentais para solucionar o problema.

Nas linhas 6 e 7 (da figura 12.4), armazenamos os resultados das duas


consultas que retornam os menores salários de médicos e funcionários,
respectivamente. Na linha 9, testamos quais dos dois menores salários é de
fato o menor de todos, com o teste lógico no IF-THEN-ELSE. A variável
menor é usada para o retorno da função (linha 14).

Uma observação importante nos exemplos acima, é que não permitimos


dentro da função comandos SELECT para exibir valores. Estávamos,
sempre, guardando valores numa variável local, através do comando INTO
VARIAVELLOCAL , que no final, serão os retornos da função. Em funções (por
enquanto, e também sensato) não é permitido retornar listas ou resultados de
consultas (como por exemplo, selects básicos de exibição de atributos).

Caso precise que uma função retorne uma lista ou um conjunto de dados,
programe sua rotina como um procedimento. Por enquanto, é este o
conhecimento que apresentamos até aqui.

Exemplo 4: Função que retorna um idDoencas e é usada dentro de


uma procedure de exclusão dos dados de uma doença.

Esse exemplo busca demonstrar como é possível chamar funções dentro


de procedimentos armazenados. Também é possível chamar procedimentos
dentro de procedimentos, e funções dentro de funções.

Para começar vamos nos lembrar que já criamos a função


fBuscarDoenca (figura 12.2) que retorna o IdDoencas. Vamos criar nossa
procedure que se utiliza desta função.
Figura 12.5 – função interna a uma procedure

Observe que a função spApagarDoenca recebe um nome de doença


como parâmetro (pDescricao). Internamente, temos uma variável local id
que vai receber o retorno da função fBuscarDoenca, que é um inteiro. Isto
ocorre na linha 6, quando a função é excutada e seu retorno é atribuido na
variável
id com o comando set
id=fBuscarDoencaDescricao(pDescricao). Após isto, é testado se o id
é válido (linha 7) , e no caso do valor id se referir a uma doença cadastrada,
a exclusão é feita com base nesse valor (linha 8). Caso contrário, nas linhas
10 a 12 é executada uma instrução SELECT para exibição da mensagem
‘doença não encontrada’, conforme listado na figura 12.5.

Exemplo 5: Calcular a idade média dos médicos. Desconsiderar que


existe a função AVG.

O valor médio de um atributo pode ser calculado com a função AVG.


Mas vamos imaginar (apenas um exercício didático aqui) que não exista essa
função. Deste modo uma proposta possível seria a seguir:

Figura 12.6 – Função média de idades criada pelo usuário

Para resolver esse problema, recorremos a duas funções conhecidas (e


não proíbidas nesta questão). Uma para contagem e uma para soma: Count
e Sum. Sendo assim fizemos a somatória das idades e a contagem de
registros. Deste modo obtivemos a média, que é retornada na linha 6 da
função criada fMediaIdadeMedico(), listada na figura 12.6.

Um recurso interessante a ser usado tanto em procedimentos e funções


armazenadas é o uso de variáveis de sessão. Tais variáveis são definidas com
o prefixo @nomevariavel. Vamos mostrar um exemplo de uso simples.

Exemplo 6: Pegar uma variável de sessão @ retornada por uma


função e usar na chamada de um procedimento.

Para este exemplo, vou retornar o idMedicos do médico mais velho e


buscar as consultas dele. Vamos mostrar a seguir essa solução (figura 12.7):
Figura 12.7 – Uso de variável de sessão com o @

Observe que na linha 4, temos o idmedico atribuido a uma variável de


sessão @retorno, que ficará disponível naquela conexão. Esse valor pode
ser modificado com novas atribuições de valores. Na linha 6, retornamos
este valor para a sessão, através do trecho RETURN @retono;.

Por fim, vamos executar o comando da linha 9 e teremos o seguinte:

Figura 12.8 – Retorno da função fRetornaIdVelho

Além de retornada no momento da execução da linha 9 (figura 12.8), o


valor da variável de sessão @retorno ficou disponível, para que na linha 10
possa ser utilizada pegando da “memória” o valor desta variável. Vejamos a
seguir:
Figura 12.9 – Instrução select pegando variável de sessão
@retorno.

Observe que na chamada do comando SELECT, transcrita na figura 12.9,


usamos como critério WHERE IDMEDICOS = @RETORNO. Portanto,
pegamos um resultado que estava disponivel como variável de sessão
@retorno para filtrar as consultas do médico mais velho, uma vez que esse
valor de @retorno nada mais é do que o resultado da função
fRetornaIdVelho criada anteriormente (figura 12.7).

Este recurso de usar variáveis de sessão pode ser bem interessante,


permitindo sua aplicação em vários contextos de rotinas e recursos diversos
de servidores MySQL/MariaDB. Para aprimorar nesses recursos, continue
treinando. Seguem alguns exercícios.

Questões Teóricas

1. Para implementar regras de negócio, por meio de linguagem


estruturada podemos usar duas formas básicas no MySQL. Procedimentos e
Funções. Qual a diferença delas?
2. O que é uma Função armazenada? Quais suas vantagens e limitações?
3. Como chamamos o resultado de uma função armazenada (programada
pelo usuário)?
4. É possível ter dados exibidos de um SELECT dentro do escopo de
uma função armazenada?
5. É possível usar o comando CALL dentro de uma função armazenada?
6. Qual o comando usado para excluir uma função armazenada, criada
por usuário?
7. Qual a importância dos delimitadores nas funções e procedimentos
armazenados?
8. Podemos criar funções armazenadas que não recebem parâmetros?
9. Podemos chamar funções dentro de funções ou procedimentos
armazenados? Dê exemplos.
10. O que são variáveis de sessão? Para que são usadas? Dê exemplos.

Questões Práticas
Parte 1 - Para o BANCO CLINICA e usando os conhecimentos de
Funções Armazenadas, RESOLVA AS QUESTÕES A SEGUIR:

1. Crie uma função que retorne o nome do paciente mais novo.


2. Crie uma função que retorne o idEspecialidades para uma
especialidade médica que o usuário informa a descrição da
especialidade.
3. Crie uma função que calcule a média salarial por cidade. O
parâmetro de entrada é o nome da cidade do funcionário.
4. Crie uma função que receba duas datas e mostre o total de consultas
realizadas naquele intervalo
5.Crie uma função que receba um sexo como parâmetro e determine a
idade média dos funcionários daquele sexo
6.Crie uma função que retorne um valor inteiro para a busca de um
funcionário pelo seu nome. Deverá retornar o idFuncionarios
quando encontrado, mas quando não encontrado, retornar -1.
7.
Crie uma função que retorne o dia com mais consultas realizadas
8. Crie uma função que some entre pacientes e funcionários o total de
pessoas do sexo masculino
9. Crie uma função que some o total de pessoas cadastradas no banco.
Isto é: médicos, funcionários e pacientes.
10.
Crie uma função que retorne a data com mais consultas realizadas.

Parte 2 - Para o BANCO CLUBE DA PIZZA e usando os


conhecimentos de Funções Armazenadas, RESOLVA AS QUESTÕES A
SEGUIR:
1. Cria uma função que receba o nome de uma atendente, e retorne
o valor total dos seus pedidos.
2. Crie uma função que ao receber o tipo de sócio, retorne a
quantidade de sócios para aquele tipo.
3. Crie uma função que ao receber duas datas retorne o valor total
recebido dos pedidos para aquela data.
4. Crie uma função que retorne o valor total das comissões de 10%
(do valor dos pedidos) recebidas por um Atendente. A Função deverá
receber o nome do atendente, um ano.
5. Crie uma função que retorne o nome do sócio com maior número
de pedidos. Receba como parâmetro um ano de referência.
6. Para a questão anterior, existe algum risco da mesma não
funcionar adequadamente? Se sim, por qual motivo?
7. Crie uma função que retorne o total de pedidos em que um sabor
de pizza (passsado como parâmetro) esteve.
8. Crie uma função que retorne o preço médio de pizzas que já
estiveram em pedidos.

Parte 3 - Para o banco CINEMAS e usando os conhecimentos de


Funções Armazenadas, RESOLVA AS QUESTÕES A SEGUIR:

1. Ao receber o nome (título de um filme), retonar o número total de


atores do elenco.
2. Ao receber o nome de um estúdio, retornar o faturamento total ao
longo dos anos.
3. Ao receber a nacionalidade de atores, informar em quantos filmes
ele atuou.
4. Ao receber um intervalo de dois anos e uma categoria, mostrar o
total de filmes produzidos para aqueles parâmetros.
5. Ao receber como parâmetro o sexo de atores, retonar o valor
pago em cachê de filmes para todos os atores daquele sexo.
6. Ao receber o nome de um filme, retornar o total pago em cachê
para o elenco do filme.
7. Ao receber um estúdio, e um intervalo de idades, retornar o total
de atores que participaram de filmes daquele estúdio, de acordo com os
parâmetros recebidos.
8. Ao receber um nome de ator, retornar os tipos de papéis
associados a ele.
9. Ao receber os dados de um Estúdio, retornar o tempo médio de
produção de seus filmes.
10. Ao receber uma categoria e ano, mostrar a quantidade de atores
que aturam em filmes daquela categoria naquele ano, recebido como
parâmetro.
13. Gatilhos ou Triggers

Gatilhos (ou Triggers) são objetos de banco de dados, que são


associados sempre à eventos de tabelas, que são disparados, como resposta a
um evento particular programado previamente. De modo geral, esses eventos
são INSERT, DELETE e UPDATE. Existem gatilhos para o evento
REPLACE. Nem toda tabela é obrigada a ter triggers (ou gatilhos)
associadas. Cada contexto (regra de negócio da aplicação) pode exigir ou
não o uso de gatilhos em tabelas.

Podemos ter várias triggers num banco de dados, mas apenas uma
trigger por evento. Por exemplo, a tabela T1 só poderá ter uma trigger para o
evento INSERT, outra para o DELETE e outra para UPDATE. Os eventos
geram dados em memória.

Toda trigger, no seu disparo, gera dados (novos ou velhos). Para o


evento INSERT, temos novos dados (NEW), em função do cadastro de
novos dados. Já o evento DELETE, temos dados antigos (OLD), que são
resultado da exclusão de dados. E finalmente, para os evento UPDATE
podemos ter dados antigos (que poderão ser modificados) e dados novos
(atualização).

Quando disparado um evento na tabela T1, para algum desses eventos


(INSERT, DELETE, UPDATE) podemos “enviar” dados (novos ou velhos)
para uma ou mais tabelas T2, T3, Tn.

Um cuidado aqui é de se evitar que uma trigger na tabela T1, provoque


efeitos na tabela T2, que também tem uma trigger que provoca efeitos na
tabela T1. Isto causaria um loop, e alguns SGBD como o MySQL oferecem
proteção para esse tipo de Loop infinito.

Já mencionamos os eventos possíveis para gatilhos ou triggers:


INSERT, DELETE, UPDATE. Os tipos de dados gerados NEW ou OLD
(novos ou velhos).

E agora finalmente devemos definir quando esses dados vão ser enviados
da tabela T1 para T2. Isto pode ocorrer ANTES (BEFORE) ou DEPOIS
(AFTER) do evento de tabela. De modo geral temos o seguinte:
a) Evento INSERT → Dados NEW. Momento AFTER
b) Evento DELETE→ Dados OLD. Momento BEFORE
c) Evento UPDATE → Podemos ter tanto dados OLD e NEW. E pode
ser disparada nos momentos antes (BEFORE) ou depois (AFTER)
do evento.

Um esquema do funcionamento de Triggers (gatilhos) é dado na figura


13.1.
Figura 13.1 – Esquema de funcionamento de gatilhos

A tabela 1
(T1) pode receber eventos (insert, delete, update) nos
momentos de disparo (antes ou depois), produzindo dados novos ou velhos
(NEW, OLD), que serão processados e utilizados nos efeitos produzidos na
tabela 2
(T2) .

Uma Trigger ou Gatilho é criada usando a seguinte estrutura SQL:


Delimiter $$
CREATE TRIGGER tgNomeDaTrigger [momento]
<EVENTO> on TABELA 1
For each row
Begin
<< SQL a ser executado na tabela 2 >>
end
$$

Para ilustrar melhor o uso de triggers, vamos trabalhar com alguns cenários e
exemplos.

Cenário 1 – Controle de operações em uma tabela para fins de registro


ou logs.
Para este exemplo, vamos continuar usando o banco Clínica e para cada
operação de cadastro, exclusão e atualização de dados de pacientes vamos
guardar numa segunda tabela, que sofrerá os efeitos da trigger,
chamada
REGISTROPACIENTES. Esta tabela terá a seguinte estrutura (figura
13.2):

Figura 13.2 – Tabela REGISTROPACIENTES

A tabela REGISTROPACIENTES receberá o nome do paciente, sexo,


idade, data e hora da operação na tabela PACIENTES, e uma descrição,
que informará a operação realizada.

Vamos ao exemplo de Triggers para os eventos INSERT, DELETE e


UPDATE.

Exemplo 1: Trigger para o evento INSERT na tabela Pacientes.

Figura 13.3 – Trigger para o evento INSERT


Temos agora, a trigger chamada tgInserirPaciente
associada a tabela
PACIENTES, que é disparada após o evento insert (AFTER) nesta tabela
(figura 13.3). O efeito acontece para cada linha modificada na tabela
PACIENTES (FOR EACH ROW) e executa o bloco de comandos entre o
BEGIN/END. Observe que o “efeito” na tabela
REGISTROPACIENTES
é
dado pelo comando INSERT (da linha 6 a 8). Observe que o evento INSERT
produziu novos dados (NEW.nome, NEW.sexo, NEW.idade), que foram,
originalmente, os dados inseridos na tabela PACIENTES. Esse prefixo
NEW (ou OLD) servem para pegar dados da tabela (T1, neste caso
PACIENTES) que dispara a TRIGGER.

Para exibir as triggers de um banco, podemos usar o comando a seguir:

Figura 13.4 – Comando para exibição das triggers


Conforme mostramos na lista de triggers (figura 13.4), já temos uma
trigger tgInserirPaciente (coloquei um prefixo tg antes do nome da
trigger). Novamente, esse prefixo é apenas um estilo pessoal de
nomenclatura.

Essa trigger foi programada para que ao se receber uma ação (evento) de
INSERT na tabela
PACIENTES, sejam registrados alguns de seus dados na
tabela REGISTROPACIENTES. Não há passagem de parâmetros em
gatilhos ou triggers, portanto, apenas operamos com os dados NEW ou OLD
disponíveis com o disparo da trigger.

Para prosseguir nesta aplicação, vamos dar um insert na tabela


PACIENTES. Mas antes disto, vamos demonstrar que a tabela que sofrerá o
efeito da trigger, está vazia (figura 13.5):
Figura 13.5 – Tabela REGISTROPACIENTES vazia

Como demonstrado acima, temos a tabela REGISTROPACIENTES


vazia. Vamos agora inserir um dado de novo paciente na tabela
PACIENTES

Figura 13.6 – Insert na tabela Pacientes com os respectivos dados


de Lula Molusco

A pergunta que pode surgir é: “E a trigger? Ela funcionou? Qual foi


seu efeito?”

Como dito anteriormente, gatilhos (ou triggers) apenas operam com


dados NEW ou OLD, resultantes do evento programado. No nosso exemplo,
apenas após o INSERT na tabela Pacientes. Esse processo de INSERT foi
ralizado e listado na figura 13.6. O efeito (resultado do disparo) foi
programado para acontecer na tabela REGISTROPACIENTES.

Vamos ver como está essa segunda tabela (REGISTROPACIENTES).


Lembre-se, que ela estava anteriormente vazia.
Figura 13.7 – Tabela RegistroPacientes com dados recebidos pela
execução da trigger tgInserirPaciente.

Conforme demonstrado (figura 13.7), os dados vindos do evento insert


na tabela Pacientes (por meio da trigger): nome,
sexo,
idade (dados do tipo
NEW) foram registrados na tabela REGISTROPACIENTES com a data e
hora do momento da execução da trigger (atributo datahora) e a operação
“evento INSERT na tabela Pacientes”.

Usando esta mesma lógica de registro de operação (como uma forma de


auditoria) vamos fazer um exemplo de trigger para o evento UPDATE.

Exemplo 2: Trigger para o evento UPDATE na tabela Pacientes.

Figura 13.8 – Trigger de Update na tabela Pacientes, com efeitos


na tabela RegistroPacientes.

Embora a ação programada (efeito) para esta trigger,


tgAtualizaPaciente, também seja um insert (para registro do log), fizemos
uma pequena modificação para o atributo operação, que receberá o valor
contendo o nome antigo , que foi modificado (OLD.nome) do paciente e
uma mensagem de que seu dado foi atualizado.

O evento que disparou a trigger foi o UPDATE. O momento do dispardo


da trigger foi depois (AFTER) do evento de disparo. O escopo completo da
Trigger está representdo na figura 13.8. Em boa parte dos exemplos que já
fiz com triggers em updates no MySQL, não houve diferença nos resultados
produzidos, para quem usou o BEFORE.

Novamente, relembrando que triggers não são chamadas explicitamente


como procedures (lá seriam com o comando CALL). Portanto, vamos dar
um update (o seja, evento de tabela) para disparar esta trigger. Esse
comando é executado na figura 13.9:

Figura 13.9 – Atualização de dados de paciente para disparar a


trigger tgAtualizaPaciente.

Vamos agora verificar o que aconteceu na tabela


REGISTROPACIENTES como consequencia da execução da trigger:

Figura 13.10 - Tabela RegistroPacientes com dados novos vindos da


trigger.

Observe em destaque (na figura 13.10), que na mensagem do atributo


operação temos o seguinte:

‘paciente Lula Molusco teve seus dados modificados’.


Observe que ‘Lula Molusco’ é o antigo nome


(OLD.nome) na tabela
original, PACIENTES, e no atributo nomepaciente temos o nome
modificado ‘Lula Molusco Novo’
(NEW.nome), na tabela
REGISTROPACIENTES. Como não modificamos o sexo e idade, os
mesmos se mantiveram como os valores originais da tabela PACIENTES.
Embora nos dois exemplos anteriores, a ação na segunda tabela tenha
sido um INSERT. Isto não é uma regra, é apenas o contexto para este
cenário. Vamos trabalhar outras situações.

Exemplo 3: Vamos excluir um paciente e registrar na tabela


RegistroPacientes (como efeito da Trigger).

Figura 13.11 – Trigger disparada para o evento DELETE

Na trigger tgApagarPaciente (figura 13.11), observe que o momento


de disparo do gatilho é antes (before) de uma operação delete na tabela
PACIENTES.

Outra observação importante, é que os dados recebidos (no escopo da


trigger) são dados antigos, afinal seriam excluídos da tabela original. Todos
eles, são do tipo OLD (linhas 7 e 8). Modificamos a string operação para
informar que os dados do paciente foram removidos.

Vamos, agora, proceder a exclusão de um paciente, para que haja o


disparo da trigger. Para isto vamos apagar o paciente Lula Molusco Novo.
Pela figura 13.6, sabemos que seu IdPacientes = 41, portanto vamos
apagar seu registro pela chave primária usando o seguinte:
Figura 13.12– Exclusão do paciente pelo Idpacientes, efeitos da
trigger tgApagarPaciente

Em destaque, temos mais um registro de operação na tabela pacientes,


que excluiu o paciente cujo idPacientes=41. Observe (figura 13.12), que
embora a exclusão foi realizada pela chave primária, os dados antigos do
registro do paciente (OLD.nome, OLD.sexo, OLD.idade) vieram ser
utilizados na execução da trigger programada para produzir efeitos na tabela
REGISTROPACIENTES.

Com os três exemplos anteriores, demonstramos o uso de triggers no


cenário de controle de operações em tabelas (registros de logs). Outras
possibilidades diferentes, também poderiam ser exploradas. Mas vamos ficar
por aqui neste exemplo. Vamos para o próximo cenário.

Cenário 2: CONTROLE DE ESTOQUE


Para este cenário vamos trabalhar com o Banco ClubePizza. Este


modelo trabalha com atendimento a pedidos de sócios por atendentes. Em
cada pedido, podemos ter vários itens de pizza distintos (sabores e
quantidades). O objetivo das triggers a serem desenvolvidas é controlar o
estoque de pizzas.

Figura 13.13 – Modelo de Dados Clube da Pizza.


Para trabalhar com o controle de estoque vamos nos concentrar
basicamente em 3 tabelas. PEDIDOS, ITENS, PIZZAS. A tabela ITENS
relaciona pizzas a pedidos por meio das chaves estrangeiras (IdPizzas,
IdPedidos). O atributo quantidade
serve para controlar a quantidade pedida,
com efeitos no estoque de pizzas. O estoque das pizzas é controlado pelo
atributo quantidade da tabela
PIZZAS.

O script de Criação do banco acima, encontra-se aqui

Exemplo 1: Comprar itens de pizza e descontar essa quantidade no


estoque.

Figura 13.14 – Trigger Para Debitar o estoque

Observe que a trigger


tgAdicionarItem (figura 13.14), está programada
para o evento insert na tabela ITENS.

Ou seja, ao se adicionar um item de pedido, para a quantidade solicitada


(NEW.QUANTIDADE) teremos que debitar esta quantidade do estoque de
pizzas [set quantidade = quantidade – NEW.quantidade]
(linhas 6 e 7). Ressalte-se, que, neste caso, nossa preocupação é apenas com
a chave estrangeira IdPizzas (que recebe o valor NEW.IdPizzas) que vem da
trigger disparada.

Vamos agora pedir uma pizza do sabor ‘Baiana’ cujo idPizzas=4 e tem
60 unidades em estoque (atributo quantidade, na figura 13.15). Vamos
adicionar esse sabor a um pedido já existente. Vamos optar pelo
Idpedidos=10;
Figura 13.15 – Dados das pizzas e suas quantidades

Agora vamos realizar uma adição de itens ao pedido 10.


Figura 13.16 – Efeito da execução da tgAdicionarItem.

Pela instrução acima, adicionamos ao pedido (10), o sabor (4) da pizza


baiana, na quantidade de 10 itens.

Essa operação de INSERT na tabela ITENS (figura 13.16), está listada


nas linhas 11 e 12. Como vimos anteriormente, esse sabor possuía 60 itens
de quantidade em estoque, mas após a execução da triger
tgAdicionarItem, como nós programamos para o evento INSERT da
tabela ITENS, o ajuste do estoque foi realizado adequadamente, neste caso
para o valor 50, na tabela PIZZAS, como resultado da consulta realizada na
linha 14.
Exemplo 2: Vamos cancelar todo o pedido do item anterior. Ou seja
excluir a adição do item adicionado anteriormente.

Para executar a operação acima vamos criar uma trigger associada ao


evento excluir da tabela ITENS. Apenas precisamos lembrar, que um
IDPIZZAS pode estar em vários pedidos. Logo ao realizar essa exclusão
vamos estar atentos ao IdPedidos.
A trigger ficaria assim:

Figura 13.17 – Trigger tgRemoverItem

Observe que a trigger programada (figura 13.17) para o evento


DELETE, antes de sua execução libera na memória da sessão os valores dos
atributos da tabela ITENS (idpedidos, idpizzas, quantidade) todos com
valores OLD.

Isso se dá, pois foram valores guardados antes (BEFORE) de serem


excluídos. Deste modo, a exclusão desse item devolverá, na íntegra, a
quantidade solicitada para a tabela PIZZAS.

O comando de exclusão do item do pedido seria o seguinte:


Figura 13.18– Excecução do comando delete na tabela ITENS e seus
efeitos na tabela Pizzas.

Observe (figura 13.18) que os 10 itens da pizza baiana (idpizzas=4) no


pedido (idpedidos=10) foram devolvidos na íntegra para o estoque da
tabela PIZZAS, voltando aos 60 itens originais em quantidade.

Exemplo 3: Devolução parcial de itens de um pedido.

Imaginemos que o cliente (sócio) queira ralizar uma devolução parcial


de itens de um pedido. Para resolver esta questão, vamos pegar um pedido
com uma quantidade solicitada e vamos modificar, a quantidade de um
determinado sabor de pizza.

Figura 13.19 – Trigger de devolução parcial de itens de um


pedido.

Observe que neste exemplo, representado na trigger listada (figura


13.19), é possível que o item de pedido possa ter acréscimo ou diminuição
na quantidade solicitada para aquele saber, naquele pedido. Por isto, na linha
6 , temos a operação [set quantidade = quantidade +
OLD.quantidade – NEW. Quantidade].

Essa operação que, aparentemente, é uma combinação das triggers


anteriores faz sentido. Imaginemos uma situação que determinada pizza tem
100 itens em estoque. E vamos a alguns cenários (tabela 13.1):

Tabela 13.1 - Situações de modificação de itens em pedidos

Observe que nas três situações simuladas a coluna Quantidade do Pedido


equivale a OLD.Quantidade. A coluna Nova Quantidade corresponde a
NEW.Quantidade. Nos três cenários tivemos o seguinte:

a) Quantidades idênticas = estoque identico


b) Quantidade nova maior que a antiga = diminuição no estoque
c) Quantidade nova menor que a antiga = devolução do saldo ao
estoque

Tendo a devida compreensão de como funcionam esses cenários, vamos


operar cada um deles a seguir.
Figura 13.20 – Lista de Itens

Vamos trabalhar com o idPedido=12 e idPizzas= 3, que solicitou a


quantidade de 3 itens.
A pizza de IdPizzas=3 é a pizza Quatro Queijos e tem
60 quantidades em estoque (figuras 13.20 e 13.21) :

Figura 13.21– Quatro queijos com 60 de quantidade

Vamos agora testar os cenários. Lembrem-se, que as triggers já foram


programadas anteriormente.

a) Nova quantidade solicitada = Antiga quantidade. Estoque igual


Figura 13.22– Resultado da atualização com quantidades


iguais.

Como era de se esperar (figura 13.22), o estoque se manteve intacto, pois a


nova quantidade era igual a anterior.

b)
Nova quantidade maior que a quantidade anterior. Diminuição do
estoque.

Neste cenário, o sócio em seus itens de pedido, solicita uma quantidade


maior de pizzas (daquele sabor), que o inicialmente planejado. Observe que
a quantidade atualizada (5) é superior a quantidade antiga (3) do pedido.
Como programado na trigger tgAtualizarItem temos um saldo negativo,
ou seja, diminuição do estoque, em dois itens (figura 13.23, em destaque).

Figura 13.23 – Resultado da execução da trigger com redução no


estoque
c) Quantidade Nova é menor que a anterior.

Neste cenário, o sócio em seu pedido, atualiza seus itens numa


quantidade menor que o solicitado anteriormente.

Considerando a execução do comando update (figura 13.24), tivemos a


seguinte modificação no item trabalhado: IdPedidos=12, IdPizzas=3,
Quantidade = 5. Com aquela operação o estoque (quantidade) de pizzas
diminuiu para 58 itens.

Figura 13.24 – Resultado da execução da trigger com devolução


(aumento) ao estoque
Agora, executando novamente o comando update para o mesmo pedido e
sabor de pizza, mas com a quantidade menor (quantidade=1) temos que
devolver ao estoque a diferença entre old.quantidade –
new.quantidade. Então teríamos a conta: 5 – 1 = 4. Logo esse saldo deve
ser adicionado ao estoque, totalizando 62 quantidades para a pizza ‘Quatro
Queijos’.

Como demonstrado, nos três cenários acima, pudemos cobrir as


possiblidades plausíveis de controle de estoque, demonstrando, assim, um
cenário interessante para o uso de triggers.
Até agora, nossos disparos de triggers sempre produziram efeitos e
apenas uma tabela, uma pergunta possível seria: “Uma trigger pode
disparar eventos para mais de uma tabela? A resposta para esta pergunta
é SIM. Vamos fazer um exemplo a seguir:

Para este exemplo vamos criar uma tabela extra chamada


LOGPEDIDOS. Esta tabela terá os seguintes atributos (figura 13.25):

Figura 13.25 – Tabela Logpedidos

Exemplo: Guardar os dados do sócio, sabor da pizza e quantidade.

Lembre-se que já existe uma trigger para o evento INSERT na tabela


ITENS. Para resolver este problema, vamos modificar a trigger
tgAdicionarItem. Novamente, apresentamos seu escopo original na figura
13.26:
Figura 13.26 – Trigger tgAdicionarItem original.

Agora vamos modificar esta trigger. Sua nova versão ficará assim:

Figura 13.27 – Trigger tgAdicionarItem modificada com ação nas


tabelas PIZZAS e LOGPEDIDOS.

Para esta trigger modificada (conforme apresentada na figura 13.27),


criamos duas variáveis locais nome, saborpizza (linhas 6 e 7), que
servirão para receber os valores das consultas realizadas nas linhas 12 a
14, para receber o nome do sócio para aquele IDPEDIDOS. E, na linha 16,
para receber o saborpizza da pizza que tem o IDPIZZAS passado como
valor durante a execução da trigger (no evento insert da tabela ITENS).

Triggers não permitem que SELECTS retornem valores, mas no nosso


caso, o resultado dos SELECTS mencionados retornam valores guardados
em variáveis locais, através do comando
INTO NomeDaVariavel.

Como o nome do sócio e o sabor da pizza não viriam por dados da


trigger, nós tivemos que fazer consultas internas aproveitando os dados da
trigger para recuperar valores para nome e saborpizza.

Observe, que a operação na segunda tabela LOGPEDIDOS, acontece


nas linhas 18 e 19, recebendo os valores diretos da trigger:
NEW.quantidade, NEW.idpedidos.

Além deles, temos um atributo de registro do momento da operação da


trigger (datahora) e as variáveis locais nome, saborpizza.

Então, resumindo temos algumas operações SQL ocorrendo nesta


trigger, a saber:

a) Operação de update na tabela PIZZAS (linhas 9 e 10) como o


primeiro efeito da trigger tgAdicionarItem;

b) Consulta SELECT com retorno na variável nomesocio (ver into


nomesocio), usando como critério de busca o NEW.IdPedidos para
aquele sócio (linhas 12 a 14)
c) Consulta SELECT com retorno na variável saborpizza (ver into
saborpizza), usando como critério de busca o NEW.Idpizzas para
encontrar o sabor da pizza para aquele IdPizzas (linha 16)

d) Operação de INSERT na tabela


LogPedidos usando as
variáveis locais (nome, saborpizza) e dados vindos da trigger
(NEW.Idpedidos,New.quantidade), como demonstrado nas linhas
18 e 19.

Feita tal explicação, vamos agora executar a trigger e verificar seus


efeitos.

Para este cenário vamos primeiramente criar um pedido. E depois


adicionar itens de pizza. Essa segunda ação, na tabela ITENS que vai
disparar nossa trigger modificada.

a) Criação do pedido:

Figura 13.28 – Criação de um pedido para o idSocios=6


(sabemos que é Yasmin)

Essa operação (de inserção ou cadastro do pedido, figura 13.28) não tem
efeito secundário em nenhuma tabela, pois não programamos nenhuma
trigger associada a um INSERT na tabela Pedidos.

B) Vamos agora adicionar itens a este pedido através do INSERT na


tabela ITENS.

Agora sim, nossa trigger será disparada com efeitos na tabela


PIZZAS e
na tabela
LOGPEDIDOS.

Desta vez, vamos adicionar o sabor de pizza “portuguesa” cujo


Idpizzas=5, na quantidade de 10 itens. Sabemos, que inicialmente no
estoque, temos 60 itens.

Figura 13.29 – Efeitos na tabela Pizzas após o insert de um ITEM


de pedido.

Como se pôde observar o comando insert para a tabela ITENS (linhas 8


e 9 da figura 13.29) produziu uma ação na tabela Pizzas, graças à trigger
programada. Como foi programado foi feito um débito (diminuição) na
quantidade de pizzas em estoque.
Agora vamos ver o efeito na segunda tabela:
LOGPEDIDOS

Figura 13.30 – Efeitos da trigger na tabela LogPedidos.

Como se pode observar (figura 13.30) atráves das consultas SELECT


internas a trigger e a operação (efeito) de inserir os dados na tabela
LogPedidos, temos os dados planejados registrados nesta segunda tabela.

Demonstramos por este exemplo que uma trigger pode gerar efeitos em
várias tabelas, desde que planejados adequadamente tais efeitos. Além disso,
pudemos demonstrar o uso de variáveis internas nas triggers por meio deste
exemplo adicional.

Questões Teóricas

1. O que são Gatilhos ou Triggers?


2. Para quais eventos de tabelas podemos associar gatilhos ou triggers?
3. Considerando uma única tabela (por exemplo) quantas triggers
podemos ter por evento? E por quê?
4. É possível uma trigger produzir resultados em múltiplas tabelas?
5. Triggers recebem parâmetros? Como elas são chamadas?
6. Em que momentos relativos aos eventos de tabelas, são executados os
comandos internos para a Trigger? Responda com os termos em inglês.
7. Qual é o significado do "For each row" da Trigger?
8. Que tipo de dados são produzidos para os eventos:
a) Insert
b) Delete
c) Update
9. É possível uma trigger para uma tabela T1 produzir efeitos numa
tabela T2, que dispara efeitos na tabela T1? O que aconteceria?
10. As triggers são chamadas explicitamente? Como então elas são
executadas?

Questões Práticas

Parte 1 - Usando o banco Clube da Pizza, crie as seguintes


TRIGGERS:

1. Crie (ou modifique) uma trigger que atualize o valor total de um


pedido para cada item adicionado na tabela ITENS.
2. Crie uma tabela chamada LOGSAtendentes que guarde data,
idpedidos e o valor do pedido, pra registrar os pedidos atendidos por um
Atendente.
a. Para o evento INSERT pra o pedido, crie uma trigger e informe
que foi realizado uma inclusão de pedidos
b. Para o evento DELETE pra o pedido, crie uma trigger que
registre os dados excluídos e também informe que foi realizado um
comando de exclusão
c. Para o evento UPDATE pra o pedido, crie uma trigger que
registre os novos dados atualizados, informando também que foi
realizada uma alteração de dados de um pedido.

3. Para uma nova tabela LOGSOCIOS com os dados


(idsocios,nomesocio, datahora), crie triggers que:
a. Para cada novo sócio cadastrado, guardar uma cópia dos seus
dados na tabela LOGSOCIOS.

b. Para cada sócio excluído, excluir sua cópia correspondente na


tabela LOGSOCIOS.

c. Para cada sócio com dados atualizados, inserir um novo registro


na tabela LOGSOCIOS com os novos dados atualizados, vindos da
tabela Socios.

Parte 2 - Usando o banco CINEMAS, crie as seguintes TRIGGERS:

1. Ao Inserir um novo ESTÚDIO, automaticamente, para o ano atual ,


insira um novo FATURAMENTO com o ano atual e o valor de 0.00 reais.

2. Ao inserir um novo ATOR ao ELENCO, adicionar o valor do seu


cachê ao custo total do Filme.

3. Ao modificar o cachê de um ator que participa de ELENCO de um


filme, ajuste o custo do filme na tabela Filme.

4. Ao remover novo ATOR do ELENCO, diminuir o valor do seu cachê


ao custo total do Filme.

5. Ao remover um ATOR, verificar antes, se o mesmo não está em algum


filme, e se não estiver, apagar todos os seus tipos de papéis associados.

6. Crie uma tabela TOTALTIPOPAPEL com os atributos básicos: nome


do ator e quantidade:
a) Para cada novo tipo de papel para um ator inserido, inserir nesta
nova tabela , TOTALTIPOPAPEL, o nome do ator e incrementar em
uma quantidade o número dos tipos de papéis cadastrados para aquele
ator.

b) Para cada tipo de papel removido para um ator, diminuir essa


quantidade na tabela TOTALTIPOPAPEL.
Sobre o autor Jorge Costa Leite Júnior

É Doutor em Educação e Contemporaneidade pela Universidade do Estado


da Bahia, possui bacharelado em Ciencias da Computacao pela Universidade
Federal da Bahia e mestrado em Mecatrônica pela Universidade Federal da
Bahia. Atualmente é professor do Instituto Federal da Bahia, onde também
foi membro do Conselho Superior e coordenador de curso, Diretor
Executivo de Pesquisa, Diretor de ensino. Atua com desenvolvimento de
sistemas WEB e Mobile, sistemas acadêmicos de gestão, EAD, TV Digital,
Banco de Dados, e no ensino, no nível superior e técnico, de linguagens de
programação, Banco de Dados, atuando, especialmente, no estudo das
questões que envolvem o aprendizado de novas tecnologias.

Você também pode gostar