[go: up one dir, main page]

0% acharam este documento útil (0 voto)
24 visualizações73 páginas

Curso SQL Mysql

O documento é um curso de SQL com MySQL que abrange desde a configuração do ambiente até conceitos fundamentais de bancos de dados relacionais e sintaxe básica de SQL. Ele inclui instruções detalhadas para a instalação do MySQL Server e MySQL Workbench em diferentes sistemas operacionais, além de explicar a estrutura de bancos de dados relacionais, como tabelas, colunas, chaves primárias e estrangeiras. O curso também introduz comandos DDL e DML essenciais para a manipulação de dados.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
24 visualizações73 páginas

Curso SQL Mysql

O documento é um curso de SQL com MySQL que abrange desde a configuração do ambiente até conceitos fundamentais de bancos de dados relacionais e sintaxe básica de SQL. Ele inclui instruções detalhadas para a instalação do MySQL Server e MySQL Workbench em diferentes sistemas operacionais, além de explicar a estrutura de bancos de dados relacionais, como tabelas, colunas, chaves primárias e estrangeiras. O curso também introduz comandos DDL e DML essenciais para a manipulação de dados.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 73

Curso de SQL com MySQL: Do Básico ao

Avançado
Módulo 1: Configuração do Ambiente e Conceitos
Fundamentais
1.1 Instalação do MySQL Server e MySQL Workbench
Para iniciar sua jornada no mundo do SQL com MySQL, o primeiro passo é configurar o
ambiente de desenvolvimento. Você precisará de duas ferramentas principais: o
MySQL Server, que é o sistema de gerenciamento de banco de dados em si, e o MySQL
Workbench, uma ferramenta gráfica que facilita a interação com o banco de dados.
1.1.1 Instalação do MySQL Server
O MySQL Server é o coração do seu banco de dados. Ele armazena e gerencia seus
dados. As instruções de instalação podem variar ligeiramente dependendo do seu
sistema operacional (Windows, macOS, Linux). Abaixo, apresentamos um guia geral
para os sistemas mais comuns.
Para Windows:
1. Download: Acesse o site oficial do MySQL e baixe o MySQL Installer para
Windows. Você pode encontrá-lo na seção de downloads, geralmente em "MySQL
Community Downloads" [1].
2. Execução do Instalador: Execute o arquivo .msi baixado. O instalador o guiará
através do processo.
3. Tipo de Configuração: Recomenda-se escolher a opção "Developer Default"
(Padrão do Desenvolvedor), que instala o MySQL Server, MySQL Workbench,
Shell e outros componentes úteis para desenvolvimento.
4. Configuração do Servidor: Durante a instalação, você será solicitado a
configurar o servidor. É crucial definir uma senha forte para o usuário root .
Lembre-se dessa senha, pois ela será necessária para acessar o banco de dados.
5. Porta: A porta padrão para o MySQL é 3306 . Geralmente, não é necessário
alterá-la, a menos que você tenha outro serviço usando essa porta.
6. Serviço do Windows: Certifique-se de que a opção para iniciar o MySQL Server
como um serviço do Windows esteja marcada, e que ele seja iniciado
automaticamente na inicialização do sistema.
7. Conclusão: Siga as instruções finais para completar a instalação.
Para macOS:
1. Download: Visite a página de downloads do MySQL e baixe o MySQL Community
Server para macOS (arquivo .dmg ) [1].

2. Instalação: Abra o arquivo .dmg e execute o instalador. Siga as etapas do


assistente de instalação.
3. Configuração: Durante a instalação, você será solicitado a definir uma senha
para o usuário root . Anote essa senha.
4. Preferências do Sistema: Após a instalação, você pode encontrar um painel de
preferências do MySQL nas Preferências do Sistema, onde pode iniciar ou parar o
servidor.
Para Linux (Ubuntu/Debian):
1. Atualizar Pacotes: Abra o terminal e atualize a lista de pacotes: bash sudo apt
update sudo apt upgrade

2. Instalar MySQL Server: Instale o servidor MySQL: bash sudo apt install
mysql-server

3. Configuração de Segurança: Após a instalação, execute o script de segurança


para remover configurações padrão inseguras e definir uma senha para o usuário
root : bash sudo mysql_secure_installation Siga as instruções, definindo
uma senha forte e respondendo Y (sim) para as perguntas de segurança.
4. Verificar Status: Verifique se o serviço MySQL está em execução: bash sudo
systemctl status mysql
1.1.2 Instalação do MySQL Workbench
O MySQL Workbench é uma ferramenta visual que permite que você projete, crie e
gerencie seus bancos de dados MySQL de forma intuitiva. Ele é essencial para
visualizar suas tabelas, executar consultas e administrar o servidor.
1. Download: Acesse o site oficial do MySQL e baixe o MySQL Workbench para o seu
sistema operacional [2].
2. Instalação: Execute o instalador baixado e siga as instruções. No Windows, se
você usou o MySQL Installer , o Workbench já pode ter sido incluído na
instalação "Developer Default".
3. Conexão com o Servidor: Após a instalação, abra o MySQL Workbench. Você
verá uma tela inicial. Clique no sinal de + ao lado de "MySQL Connections" para
criar uma nova conexão.
Connection Name: Dê um nome significativo para sua conexão (ex: Local
MySQL ).

Hostname: 127.0.0.1 (ou localhost )


Port: 3306
Username: root
Password: Clique em "Store in Keychain" (ou equivalente) e insira a senha
que você definiu para o usuário root durante a instalação do MySQL
Server.
Test Connection: Clique em "Test Connection" para verificar se a conexão
foi bem-sucedida. Se tudo estiver correto, você verá uma mensagem de
sucesso.
4. Abrir Conexão: Clique em "OK" para salvar a conexão e, em seguida, clique na
conexão recém-criada para abri-la. Você estará agora no ambiente do MySQL
Workbench, pronto para começar a trabalhar com bancos de dados.
Referências:
[1] MySQL Community Downloads: https://dev.mysql.com/downloads/ [2] MySQL
Workbench Download: https://dev.mysql.com/downloads/workbench/
1.2 Conceitos Fundamentais de Bancos de Dados Relacionais
Antes de mergulharmos na sintaxe do SQL, é fundamental entender os conceitos que
sustentam os bancos de dados relacionais. O modelo relacional, proposto por E.F.
Codd em 1970, é a base para a maioria dos sistemas de gerenciamento de banco de
dados (SGBDs) modernos, incluindo o MySQL. Ele organiza os dados em tabelas, que
se relacionam entre si.
1.2.1 O que é um Banco de Dados Relacional?
Um banco de dados relacional é uma coleção de dados organizados em tabelas, onde
cada tabela possui um conjunto de colunas e linhas. As tabelas são interligadas por
meio de relacionamentos, o que permite que os dados sejam combinados e
consultados de maneira eficiente. A força do modelo relacional reside na sua
capacidade de garantir a integridade e a consistência dos dados, evitando
redundâncias e anomalias.
1.2.2 Componentes Essenciais:
Tabela (Table): Uma tabela é a estrutura fundamental de um banco de dados
relacional. Ela é composta por colunas e linhas, e representa uma entidade
específica do mundo real (por exemplo, Clientes , Produtos , Pedidos ). Cada
tabela deve ter um nome único dentro do banco de dados.
Exemplo Visual de uma Tabela ( Clientes ):
id_cliente nome email telefone
1 João joao@email.com (11) 9876-5432
2 Maria maria@email.com (21) 9123-4567
3 Pedro pedro@email.com (31) 9988-7766
Coluna (Column) / Atributo (Attribute) / Campo (Field): Uma coluna
representa um atributo ou característica de uma entidade. Cada coluna em uma
tabela tem um nome único e um tipo de dado específico (por exemplo, texto,
número, data). No exemplo acima, id_cliente , nome , email e telefone são
colunas.
Linha (Row) / Tupla (Tuple) / Registro (Record): Uma linha representa uma
única ocorrência de uma entidade na tabela. Cada linha contém um conjunto de
valores para cada coluna da tabela. No exemplo acima, | 1 | João |
joao@email.com | (11) 9876-5432 | é uma linha.

Chave Primária (Primary Key - PK): É uma coluna (ou um conjunto de colunas)
que identifica unicamente cada linha em uma tabela. Os valores em uma chave
primária devem ser únicos e não podem ser nulos (NULL). Uma tabela pode ter
apenas uma chave primária. No exemplo da tabela Clientes , id_cliente seria
a chave primária.
Chave Estrangeira (Foreign Key - FK): É uma coluna (ou um conjunto de
colunas) em uma tabela que estabelece um vínculo com a chave primária de
outra tabela. Ela é usada para criar relacionamentos entre tabelas, garantindo a
integridade referencial. Por exemplo, em uma tabela Pedidos , poderia haver
uma chave estrangeira id_cliente que referencia a chave primária id_cliente
da tabela Clientes .
Exemplo Visual de Relacionamento ( Pedidos com Clientes ):
Tabela Clientes :
id_cliente (PK) nome
1 João
2 Maria
Tabela Pedidos :
id_pedido id_cliente (FK) data_pedido
101 1 2025-06-19
102 2 2025-06-19
103 1 2025-06-20
Neste exemplo, id_cliente na tabela Pedidos é uma chave estrangeira
que aponta para id_cliente na tabela Clientes , estabelecendo que um
pedido pertence a um cliente específico.
1.2.3 Integridade de Dados
O modelo relacional impõe regras para garantir a integridade dos dados:
Integridade da Entidade: Garante que cada linha em uma tabela seja única e
identificável, através da chave primária (PK não pode ser NULL e deve ser única).
Integridade Referencial: Garante que os relacionamentos entre tabelas sejam
válidos. Uma chave estrangeira (FK) deve sempre referenciar um valor existente
na chave primária da tabela relacionada, ou ser NULL (se permitido).
Compreender esses conceitos é o primeiro passo para projetar e interagir eficazmente
com bancos de dados relacionais usando SQL.
1.3 Sintaxe Básica do SQL: DDL e DML Introdutório
SQL (Structured Query Language) é a linguagem padrão para gerenciar e manipular
bancos de dados relacionais. Ela é dividida em várias categorias, sendo as mais
importantes para começar: DDL (Data Definition Language) e DML (Data Manipulation
Language).
1.3.1 DDL (Data Definition Language)
DDL é usada para definir, modificar e excluir a estrutura do banco de dados e seus
objetos (tabelas, índices, views, etc.). Os comandos DDL são responsáveis por criar o
"esqueleto" onde seus dados serão armazenados.
Comandos DDL Essenciais:
CREATE DATABASE : Usado para criar um novo banco de dados.

Sintaxe: sql CREATE DATABASE nome_do_banco_de_dados; Exemplo: sql


CREATE DATABASE minha_loja; Este comando cria um novo banco de dados
chamado minha_loja .
USE : Usado para selecionar um banco de dados específico para trabalhar. Após
selecionado, todos os comandos subsequentes serão executados dentro desse
banco de dados, a menos que outro seja explicitamente especificado.
Sintaxe: sql USE nome_do_banco_de_dados; Exemplo: sql USE minha_loja;
Este comando define minha_loja como o banco de dados ativo.
CREATE TABLE : Usado para criar uma nova tabela dentro do banco de dados
selecionado. Você deve especificar o nome da tabela e as colunas, juntamente
com seus tipos de dados e quaisquer restrições (como chave primária, não nulo,
etc.).
Sintaxe: sql CREATE TABLE nome_da_tabela ( nome_coluna1 TIPO_DADO
RESTRIÇÕES, nome_coluna2 TIPO_DADO RESTRIÇÕES, ... PRIMARY KEY
(nome_coluna_chave_primaria) ); Tipos de Dados Comuns no MySQL: * INT :
Números inteiros. * VARCHAR(tamanho) : Cadeia de caracteres de comprimento
variável (ex: VARCHAR(255) ). * TEXT : Cadeia de caracteres longas. * DATE : Data
(formato 'YYYY-MM-DD'). * DATETIME : Data e hora (formato 'YYYY-MM-DD
HH:MM:SS'). * DECIMAL(P, S) : Números decimais com precisão P (total de
dígitos) e escala S (dígitos após a vírgula). * BOOLEAN ou TINYINT(1) : Valores
booleanos (verdadeiro/falso).
Restrições Comuns: * PRIMARY KEY : Define a coluna como chave primária. *
NOT NULL : Garante que a coluna não pode ter valores nulos. * UNIQUE : Garante
que todos os valores na coluna são diferentes. * AUTO_INCREMENT : Gera um
número único automaticamente para cada nova linha (geralmente usado com
chaves primárias inteiras). * DEFAULT valor : Define um valor padrão para a
coluna se nenhum valor for especificado.
Exemplo: sql CREATE TABLE produtos ( id_produto INT AUTO_INCREMENT
PRIMARY KEY, nome_produto VARCHAR(100) NOT NULL, preco DECIMAL(10, 2)
NOT NULL, estoque INT DEFAULT 0 Este comando cria uma tabela
);
produtos com quatro colunas: id_produto (chave primária auto-
incrementável), nome_produto , preco e estoque .
ALTER TABLE : Usado para modificar a estrutura de uma tabela existente. Você
pode adicionar, excluir ou modificar colunas, adicionar ou remover restrições,
etc.
Sintaxe (exemplos): ```sql -- Adicionar uma nova coluna ALTER TABLE
nome_da_tabela ADD COLUMN nome_nova_coluna TIPO_DADO RESTRIÇÕES;
-- Modificar uma coluna existente ALTER TABLE nome_da_tabela MODIFY
COLUMN nome_coluna TIPO_DADO NOVAS_RESTRIÇÕES;
-- Excluir uma coluna ALTER TABLE nome_da_tabela DROP COLUMN
nome_da_coluna; **Exemplo:** sql ALTER TABLE produtos ADD COLUMN
descricao TEXT; `` Este comando adiciona uma coluna descricao do
tipo TEXT à tabela produtos`.

DROP TABLE : Usado para excluir uma tabela existente do banco de dados.
Cuidado: Este comando remove a tabela e todos os seus dados
permanentemente.
Sintaxe: sql DROP TABLE nome_da_tabela; Exemplo: sql DROP TABLE
produtos; Este comando exclui a tabela produtos .

DROP DATABASE : Usado para excluir um banco de dados inteiro. Cuidado: Este
comando remove o banco de dados e todas as suas tabelas e dados
permanentemente.
Sintaxe: sql DROP DATABASE nome_do_banco_de_dados; Exemplo: sql DROP
DATABASE minha_loja; Este comando exclui o banco de dados minha_loja .

1.3.2 DML (Data Manipulation Language)


DML é usada para manipular os dados dentro das tabelas do banco de dados. Estes
comandos permitem inserir, atualizar, excluir e recuperar dados.
Comandos DML Essenciais (Introdutório):
INSERT INTO : Usado para adicionar novas linhas (registros) a uma tabela.

Sintaxe: ```sql INSERT INTO nome_da_tabela (coluna1, coluna2, ...) VALUES


(valor1, valor2, ...);
-- Ou, se você estiver inserindo valores para todas as colunas na ordem correta:
INSERT INTO nome_da_tabela VALUES (valor1, valor2, ...); **Exemplo:** sql
INSERT INTO produtos (nome_produto, preco, estoque) VALUES ('Laptop',
1200.00, 50);
INSERT INTO produtos (nome_produto, preco, estoque) VALUES ('Mouse', 25.50,
200); `` Estes comandos inserem dois novos produtos na
tabela produtos`.
SELECT : Usado para recuperar dados de uma ou mais tabelas. É o comando mais
frequentemente usado em SQL e será explorado em muito mais detalhes nos
próximos módulos.
Sintaxe (básica): ```sql SELECT coluna1, coluna2, ... FROM nome_da_tabela;
-- Para selecionar todas as colunas: SELECT * FROM nome_da_tabela;
**Exemplo:** sql SELECT nome_produto, preco FROM produtos;

SELECT * FROM produtos; ``` O primeiro comando recupera os nomes e preços


de todos os produtos. O segundo recupera todas as colunas de todos os
produtos.
UPDATE : Usado para modificar dados existentes em uma ou mais linhas de uma
tabela.
Sintaxe: sql UPDATE nome_da_tabela SET coluna1 = novo_valor1, coluna2
= novo_valor2, ... WHERE condicao; Cuidado: Sempre use a cláusula WHERE
com UPDATE para especificar quais linhas devem ser atualizadas. Se você omitir
WHERE , todas as linhas da tabela serão atualizadas!

Exemplo: sql UPDATE produtos SET preco = 1250.00 WHERE nome_produto =


'Laptop'; Este comando atualiza o preço do produto 'Laptop' para 1250.00.

DELETE FROM : Usado para excluir linhas existentes de uma tabela.

Sintaxe: sql DELETE FROM nome_da_tabela WHERE condicao; Cuidado: Assim


como no UPDATE , sempre use a cláusula WHERE com DELETE para especificar
quais linhas devem ser excluídas. Se você omitir WHERE , todas as linhas da tabela
serão excluídas permanentemente!
Exemplo: sql DELETE FROM produtos WHERE estoque = 0; Este comando
exclui todos os produtos que estão com estoque zero.
Com esta introdução aos comandos DDL e DML, você já tem uma base sólida para
começar a interagir com o MySQL. Nos próximos módulos, aprofundaremos em cada
um desses comandos e exploraremos funcionalidades mais avançadas do SQL.
Módulo 2: Comandos DDL, DML e Consultas SELECT
Básicas
Neste módulo, aprofundaremos nos comandos DDL (Data Definition Language) e DML
(Data Manipulation Language) que você já teve uma introdução, e exploraremos as
consultas SELECT de forma mais detalhada, que são a espinha dorsal da recuperação
de dados em SQL.
2.1 Detalhando Comandos DDL
Os comandos DDL são cruciais para a criação e gerenciamento da estrutura do seu
banco de dados. Vamos revisitar e expandir o conhecimento sobre CREATE DATABASE ,
CREATE TABLE , ALTER TABLE e DROP TABLE .

2.1.1 CREATE DATABASE e USE


Como vimos, CREATE DATABASE é o ponto de partida para qualquer projeto de banco
de dados. Ele cria um novo espaço isolado onde suas tabelas e dados residirão.
Sintaxe e Considerações:
CREATE DATABASE [IF NOT EXISTS] nome_do_banco_de_dados
[CHARACTER SET charset_name]
[COLLATE collation_name];

IF NOT EXISTS : Esta cláusula opcional é altamente recomendada. Ela evita um


erro se você tentar criar um banco de dados que já existe. Se o banco de dados já
existir, o comando será ignorado sem gerar um erro.
CHARACTER SET : Define o conjunto de caracteres padrão para o banco de dados.
O utf8mb4 é o mais recomendado atualmente, pois suporta uma ampla gama de
caracteres, incluindo emojis, e é compatível com a maioria dos idiomas. Se não
especificado, o MySQL usará o conjunto de caracteres padrão do servidor.
COLLATE : Define a regra de ordenação (collation) para o conjunto de caracteres.
Por exemplo, utf8mb4_unicode_ci é uma collation comum que oferece
ordenação case-insensitive (ignora maiúsculas/minúsculas) e acentuação para
muitos idiomas.
Exemplo Prático:
Vamos criar um banco de dados para uma livraria, garantindo que ele suporte uma
ampla gama de caracteres para títulos de livros e nomes de autores.
CREATE DATABASE IF NOT EXISTS livraria
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;

USE livraria;

Após criar o banco de dados, o comando USE livraria; o seleciona como o banco de
dados ativo para as operações subsequentes. No MySQL Workbench, você pode
simplesmente dar um duplo clique no nome do banco de dados no painel
Navigator para ativá-lo.
2.1.2 CREATE TABLE
CREATE TABLE é um dos comandos DDL mais importantes, pois é onde você define a
estrutura das suas tabelas, especificando as colunas, seus tipos de dados e as
restrições que garantem a integridade dos dados.
Sintaxe e Considerações:
CREATE TABLE [IF NOT EXISTS] nome_da_tabela (
nome_coluna1 TIPO_DADO [NOT NULL | NULL] [DEFAULT valor] [AUTO_INCREMENT]
[UNIQUE] [PRIMARY KEY],
nome_coluna2 TIPO_DADO ...,
...
[CONSTRAINT nome_restricao] PRIMARY KEY (coluna1, ...),
[CONSTRAINT nome_restricao] FOREIGN KEY (coluna_fk) REFERENCES
tabela_referenciada(coluna_pk) [ON DELETE acao] [ON UPDATE acao],
[CONSTRAINT nome_restricao] UNIQUE (coluna1, ...),
[CONSTRAINT nome_restricao] CHECK (condicao)
);

IF NOT EXISTS : Similar ao CREATE DATABASE , evita erros se a tabela já existir.


Tipos de Dados (Revisão e Expansão):
Numéricos:
TINYINT , SMALLINT , MEDIUMINT , INT , BIGINT : Para números
inteiros de diferentes tamanhos. INT é o mais comum.
FLOAT , DOUBLE : Para números de ponto flutuante (com casas
decimais). DOUBLE tem maior precisão.
DECIMAL(P, S) : Para números decimais com precisão exata, ideal
para valores monetários. P é o número total de dígitos e S é o
número de dígitos após o ponto decimal.
Strings (Cadeias de Caracteres):
CHAR(tamanho) : Cadeia de caracteres de tamanho fixo. Ocupa sempre
o tamanho especificado, mesmo que o conteúdo seja menor.
VARCHAR(tamanho) : Cadeia de caracteres de tamanho variável. Ocupa
apenas o espaço necessário para o conteúdo, até o tamanho máximo
especificado. Mais comum para textos curtos a médios.
TEXT , MEDIUMTEXT , LONGTEXT : Para textos longos, como descrições
ou artigos.
ENUM('valor1', 'valor2', ...) : Permite que uma coluna contenha
apenas um valor de uma lista predefinida.
SET('valor1', 'valor2', ...) : Permite que uma coluna contenha
zero ou mais valores de uma lista predefinida.
Data e Hora:
DATE : Armazena apenas a data (YYYY-MM-DD).

TIME : Armazena apenas a hora (HH:MM:SS).

DATETIME : Armazena data e hora (YYYY-MM-DD HH:MM:SS).

TIMESTAMP : Armazena data e hora, mas é automaticamente


atualizado em algumas operações e é influenciado pelo fuso horário.
YEAR : Armazena o ano (YYYY).

Binários:
BLOB , TINYBLOB , MEDIUMBLOB , LONGBLOB : Para armazenar dados
binários, como imagens, vídeos ou arquivos.
Restrições (Revisão e Expansão):
NOT NULL : Garante que a coluna não pode conter valores NULL (ausência
de valor).
NULL : Permite que a coluna contenha valores NULL (é o padrão se NOT
NULL não for especificado).
DEFAULT valor : Define um valor padrão para a coluna se nenhum valor for
explicitamente fornecido durante a inserção.
AUTO_INCREMENT : Usado com tipos inteiros, gera automaticamente um
número sequencial único para cada nova linha. Ideal para chaves primárias.
UNIQUE : Garante que todos os valores em uma coluna (ou conjunto de
colunas) sejam únicos. Diferente da PRIMARY KEY , uma tabela pode ter
múltiplas restrições UNIQUE , e colunas UNIQUE podem aceitar NULL (mas
apenas uma vez).
PRIMARY KEY : Define a coluna(s) como a chave primária da tabela. Garante
unicidade e NOT NULL implicitamente.
FOREIGN KEY : Define uma chave estrangeira, estabelecendo um
relacionamento entre tabelas. A cláusula REFERENCES especifica a tabela e
a coluna que está sendo referenciada.
ON DELETE CASCADE : Se uma linha na tabela pai for excluída, as linhas
correspondentes na tabela filha também serão excluídas.
ON DELETE SET NULL : Se uma linha na tabela pai for excluída, a chave
estrangeira na tabela filha será definida como NULL .
ON DELETE RESTRICT (padrão): Impede a exclusão de uma linha na
tabela pai se houver linhas correspondentes na tabela filha.
ON DELETE NO ACTION : Similar a RESTRICT , mas pode ser adiado em
alguns SGBDs.
ON UPDATE CASCADE , ON UPDATE SET NULL , ON UPDATE RESTRICT ,
ON UPDATE NO ACTION : Comportamento similar para atualizações na
tabela pai.
CHECK (condicao) : Permite definir uma condição que deve ser verdadeira
para que os dados sejam inseridos ou atualizados na coluna. No MySQL, a
restrição CHECK é analisada, mas não é imposta em versões anteriores ao
MySQL 8.0.16. Em versões mais recentes, ela funciona como esperado.
Exemplo Prático:
Vamos criar algumas tabelas para a nossa livraria :
USE livraria;

CREATE TABLE IF NOT EXISTS autores (


id_autor INT AUTO_INCREMENT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
sobrenome VARCHAR(100) NOT NULL,
data_nascimento DATE,
nacionalidade VARCHAR(50)
);

CREATE TABLE IF NOT EXISTS livros (


id_livro INT AUTO_INCREMENT PRIMARY KEY,
titulo VARCHAR(255) NOT NULL,
id_autor INT NOT NULL,
ano_publicacao YEAR,
isbn VARCHAR(13) UNIQUE,
genero VARCHAR(50),
preco DECIMAL(10, 2) NOT NULL,
estoque INT DEFAULT 0,
FOREIGN KEY (id_autor) REFERENCES autores(id_autor)
ON DELETE RESTRICT
ON UPDATE CASCADE
);

CREATE TABLE IF NOT EXISTS clientes (


id_cliente INT AUTO_INCREMENT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
sobrenome VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
telefone VARCHAR(20)
);

CREATE TABLE IF NOT EXISTS vendas (


id_venda INT AUTO_INCREMENT PRIMARY KEY,
id_cliente INT NOT NULL,
data_venda DATETIME DEFAULT CURRENT_TIMESTAMP,
valor_total DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (id_cliente) REFERENCES clientes(id_cliente)
ON DELETE RESTRICT
ON UPDATE CASCADE
);

CREATE TABLE IF NOT EXISTS itens_venda (


id_item_venda INT AUTO_INCREMENT PRIMARY KEY,
id_venda INT NOT NULL,
id_livro INT NOT NULL,
quantidade INT NOT NULL CHECK (quantidade > 0),
preco_unitario DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (id_venda) REFERENCES vendas(id_venda)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (id_livro) REFERENCES livros(id_livro)
ON DELETE RESTRICT
ON UPDATE CASCADE
);

Observe como as chaves estrangeiras ( FOREIGN KEY ) conectam as tabelas,


estabelecendo os relacionamentos. Por exemplo, a tabela livros tem uma chave
estrangeira id_autor que referencia a tabela autores . As cláusulas ON DELETE e ON
UPDATE definem o comportamento do banco de dados quando uma linha referenciada
é excluída ou atualizada. RESTRICT impede a operação se houver dependências,
enquanto CASCADE propaga a alteração.
2.1.3 ALTER TABLE
ALTER TABLE é usado para modificar a estrutura de uma tabela existente sem precisar
recriá-la. Isso é extremamente útil para fazer ajustes no esquema do banco de dados à
medida que seus requisitos evoluem.
Sintaxe e Operações Comuns:
Adicionar uma Coluna: sql ALTER TABLE nome_da_tabela ADD COLUMN
nome_nova_coluna TIPO_DADO [RESTRIÇÕES] [AFTER coluna_existente |
FIRST];

AFTER coluna_existente : Adiciona a nova coluna após uma coluna


específica.
FIRST : Adiciona a nova coluna como a primeira coluna da tabela.

Exemplo: Adicionar uma coluna numero_paginas à tabela livros . sql ALTER


TABLE livros ADD COLUMN numero_paginas INT AFTER genero;

Modificar uma Coluna: sql ALTER TABLE nome_da_tabela MODIFY COLUMN


nome_coluna TIPO_DADO [NOVAS_RESTRIÇÕES]; Exemplo: Aumentar o tamanho
da coluna titulo na tabela livros . sql ALTER TABLE livros MODIFY COLUMN
titulo VARCHAR(300) NOT NULL;

Renomear uma Coluna: sql ALTER TABLE nome_da_tabela RENAME COLUMN


nome_antigo TO nome_novo; Exemplo: Renomear nome para primeiro_nome
na tabela autores . sql ALTER TABLE autores RENAME COLUMN nome TO
primeiro_nome;

Excluir uma Coluna: sql ALTER TABLE nome_da_tabela DROP COLUMN


nome_da_coluna; Exemplo: Excluir a coluna telefone da tabela clientes . sql
ALTER TABLE clientes DROP COLUMN telefone;
Adicionar uma Chave Primária: sql ALTER TABLE nome_da_tabela ADD
PRIMARY KEY (coluna1, ...); Exemplo: Adicionar uma chave primária
composta à tabela itens_venda (se não tivesse sido definida antes). sql --
Supondo que id_item_venda não fosse PK -- ALTER TABLE itens_venda --
ADD PRIMARY KEY (id_venda, id_livro);

Adicionar uma Chave Estrangeira: sql ALTER TABLE nome_da_tabela ADD


CONSTRAINT nome_restricao_fk FOREIGN KEY (coluna_fk) REFERENCES
tabela_referenciada(coluna_pk); Exemplo: Adicionar uma chave estrangeira
para id_cliente na tabela vendas (se não tivesse sido definida antes). sql --
ALTER TABLE vendas -- ADD CONSTRAINT fk_vendas_clientes FOREIGN KEY
(id_cliente) REFERENCES clientes(id_cliente);

Remover uma Chave Primária ou Estrangeira: Para remover uma chave


primária, você precisa saber o nome da restrição. No MySQL, a chave primária
geralmente tem o nome PRIMARY . sql ALTER TABLE nome_da_tabela DROP
PRIMARY KEY; Para remover uma chave estrangeira, você precisa saber o nome
da restrição (que você pode ter definido com CONSTRAINT nome_restricao_fk
ou que o MySQL gerou automaticamente). sql ALTER TABLE nome_da_tabela
DROP FOREIGN KEY nome_da_restricao_fk; Você pode encontrar o nome da
restrição de chave estrangeira usando SHOW CREATE TABLE nome_da_tabela; .
2.1.4 DROP TABLE
DROP TABLE é o comando para remover uma tabela inteira do banco de dados. É um
comando poderoso e deve ser usado com cautela, pois ele apaga a tabela e todos os
seus dados permanentemente.
Sintaxe e Considerações:
DROP TABLE [IF EXISTS] nome_da_tabela;

IF EXISTS : Evita um erro se você tentar excluir uma tabela que não existe.
Exemplo:
DROP TABLE IF EXISTS itens_venda;
DROP TABLE IF EXISTS vendas;
DROP TABLE IF EXISTS clientes;
DROP TABLE IF EXISTS livros;
DROP TABLE IF EXISTS autores;

É uma boa prática excluir tabelas em ordem inversa à sua criação, especialmente se
houver chaves estrangeiras, para evitar erros de dependência. Por exemplo,
itens_venda depende de vendas e livros , então itens_venda deve ser excluída
primeiro.
Compreender e dominar os comandos DDL é essencial para projetar e manter a
estrutura do seu banco de dados de forma eficaz. Eles são a base sobre a qual todos os
seus dados serão organizados.
2.2 Detalhando Comandos DML
Os comandos DML (Data Manipulation Language) são usados para interagir com os
dados armazenados nas tabelas. Eles permitem que você insira novos registros,
atualize informações existentes, exclua dados e, o mais importante, recupere
informações do banco de dados.
2.2.1 INSERT INTO
O comando INSERT INTO é utilizado para adicionar uma ou mais novas linhas
(registros) a uma tabela. Cada linha representa uma nova entrada de dados.
Sintaxe e Considerações:
Existem duas formas principais de usar o INSERT INTO :
1. Especificando Colunas e Valores: Esta é a forma mais segura e recomendada,
pois você especifica explicitamente quais colunas receberão os valores. Isso
torna seu código mais legível e menos propenso a erros se a ordem das colunas
na tabela mudar no futuro.
sql INSERT INTO nome_da_tabela (coluna1, coluna2, coluna3, ...)
VALUES (valor1, valor2, valor3, ...);

Os valores devem corresponder aos tipos de dados das colunas e estar na


mesma ordem em que as colunas foram listadas.
Colunas com AUTO_INCREMENT não precisam ser incluídas na lista de
colunas, pois o valor será gerado automaticamente.
Colunas com DEFAULT podem ser omitidas se você quiser usar o valor
padrão.
2. Inserindo Valores para Todas as Colunas (na Ordem da Tabela): Esta forma é
mais concisa, mas exige que você forneça valores para todas as colunas da
tabela, na ordem exata em que foram definidas na CREATE TABLE . Se a estrutura
da tabela mudar, seu comando INSERT pode falhar.
sql INSERT INTO nome_da_tabela VALUES (valor1, valor2, valor3, ...);

Exemplos Práticos:
Vamos inserir alguns dados nas tabelas que criamos para a livraria .
USE livraria;

-- Inserindo autores
INSERT INTO autores (nome, sobrenome, data_nascimento, nacionalidade)
VALUES ('Machado', 'de Assis', '1839-06-21', 'Brasileira');

INSERT INTO autores (nome, sobrenome, data_nascimento, nacionalidade)


VALUES ('Clarice', 'Lispector', '1920-12-10', 'Brasileira');

INSERT INTO autores (nome, sobrenome, data_nascimento, nacionalidade)


VALUES ('Gabriel', 'García Márquez', '1927-03-06', 'Colombiana');

-- Inserindo livros
-- id_autor 1 = Machado de Assis
-- id_autor 2 = Clarice Lispector
-- id_autor 3 = Gabriel García Márquez
INSERT INTO livros (titulo, id_autor, ano_publicacao, isbn, genero, preco,
estoque)
VALUES ('Dom Casmurro', 1, 1899, '9788508127110', 'Romance', 35.90, 100);

INSERT INTO livros (titulo, id_autor, ano_publicacao, isbn, genero, preco,


estoque)
VALUES ('Memórias Póstumas de Brás Cubas', 1, 1881, '9788572328206', 'Romance',
42.50, 80);

INSERT INTO livros (titulo, id_autor, ano_publicacao, isbn, genero, preco,


estoque)
VALUES ('A Hora da Estrela', 2, 1977, '9788532507822', 'Romance', 29.90, 120);

INSERT INTO livros (titulo, id_autor, ano_publicacao, isbn, genero, preco,


estoque)
VALUES ('Cem Anos de Solidão', 3, 1967, '9788501012502', 'Realismo Mágico',
59.90, 70);

-- Inserindo clientes
INSERT INTO clientes (nome, sobrenome, email, telefone)
VALUES ('Ana', 'Silva', 'ana.silva@email.com', '11987654321');

INSERT INTO clientes (nome, sobrenome, email, telefone)


VALUES ('Bruno', 'Souza', 'bruno.souza@email.com', '21912345678');

INSERT INTO clientes (nome, sobrenome, email, telefone)


VALUES ('Carla', 'Oliveira', 'carla.oliveira@email.com', '31998877665');

-- Inserindo vendas (assumindo que id_cliente 1 = Ana Silva, 2 = Bruno Souza)


INSERT INTO vendas (id_cliente, valor_total)
VALUES (1, 65.80); -- Ana comprou Dom Casmurro (35.90) + A Hora da Estrela
(29.90)

INSERT INTO vendas (id_cliente, valor_total)


VALUES (2, 59.90); -- Bruno comprou Cem Anos de Solidão

-- Inserindo itens de venda


-- id_venda 1 = Venda da Ana
-- id_venda 2 = Venda do Bruno
-- id_livro 1 = Dom Casmurro
-- id_livro 3 = A Hora da Estrela
-- id_livro 4 = Cem Anos de Solidão
INSERT INTO itens_venda (id_venda, id_livro, quantidade, preco_unitario)
VALUES (1, 1, 1, 35.90);
INSERT INTO itens_venda (id_venda, id_livro, quantidade, preco_unitario)
VALUES (1, 3, 1, 29.90);

INSERT INTO itens_venda (id_venda, id_livro, quantidade, preco_unitario)


VALUES (2, 4, 1, 59.90);

Você pode inserir múltiplas linhas em um único comando INSERT separando os


conjuntos de valores por vírgulas:
INSERT INTO autores (nome, sobrenome, data_nascimento, nacionalidade)
VALUES
('Cecília', 'Meireles', '1901-11-07', 'Brasileira'),
('Jorge', 'Amado', '1912-08-10', 'Brasileira');

2.2.2 UPDATE
O comando UPDATE é usado para modificar dados existentes em uma ou mais linhas
de uma tabela. É fundamental usar a cláusula WHERE para especificar quais linhas
devem ser atualizadas, caso contrário, todas as linhas da tabela serão afetadas.
Sintaxe e Considerações:
UPDATE nome_da_tabela
SET
coluna1 = novo_valor1,
coluna2 = novo_valor2,
...
WHERE condicao;

: Define os novos valores para as colunas especificadas.


SET

WHERE : Filtra as linhas que serão atualizadas. Se omitida, todas as linhas da


tabela serão atualizadas.
Exemplos Práticos:
USE livraria;

-- Atualizar o estoque de um livro específico


UPDATE livros
SET estoque = 95
WHERE titulo = 'Dom Casmurro';

-- Atualizar o preço de todos os livros de um determinado autor


-- Primeiro, precisamos saber o id_autor de Machado de Assis. Em um cenário
real, você faria uma consulta SELECT para isso.
-- Supondo que id_autor de Machado de Assis seja 1
UPDATE livros
SET preco = preco * 1.10 -- Aumenta o preço em 10%
WHERE id_autor = 1;

-- Corrigir o telefone de um cliente


UPDATE clientes
SET telefone = '11998877665'
WHERE email = 'ana.silva@email.com';

-- Atualizar a data de nascimento de um autor


UPDATE autores
SET data_nascimento = '1920-12-10'
WHERE nome = 'Clarice' AND sobrenome = 'Lispector';

2.2.3 DELETE FROM


O comando DELETE FROM é usado para remover uma ou mais linhas de uma tabela.
Assim como o UPDATE , é crucial usar a cláusula WHERE para especificar quais linhas
devem ser excluídas, caso contrário, todos os dados da tabela serão apagados.
Sintaxe e Considerações:
DELETE FROM nome_da_tabela
WHERE condicao;

WHERE: Filtra as linhas que serão excluídas. Se omitida, todas as linhas da tabela
serão excluídas permanentemente.
Exemplos Práticos:
USE livraria;

-- Excluir um livro específico


DELETE FROM livros
WHERE titulo = 'Memórias Póstumas de Brás Cubas';

-- Excluir clientes que não fizeram nenhuma compra (neste exemplo, vamos
simular um cliente sem vendas)
-- Primeiro, vamos inserir um cliente que não fará compras para o exemplo
INSERT INTO clientes (nome, sobrenome, email, telefone)
VALUES ('Daniel', 'Ferreira', 'daniel.ferreira@email.com', '41911223344');

DELETE FROM clientes


WHERE email = 'daniel.ferreira@email.com';

-- Excluir todas as vendas de um cliente específico (id_cliente 2 = Bruno


Souza)
-- ATENÇÃO: Se a tabela 'itens_venda' tiver ON DELETE CASCADE configurado para
'id_venda', os itens de venda também serão excluídos.
-- Se for ON DELETE RESTRICT, você precisará excluir os itens de venda
primeiro.
DELETE FROM vendas
WHERE id_cliente = 2;

Cuidado Extremo: DELETE FROM sem WHERE é equivalente a TRUNCATE TABLE em


termos de apagar todos os dados, mas TRUNCATE TABLE é geralmente mais rápido
para grandes volumes de dados e reinicia o AUTO_INCREMENT . No entanto, TRUNCATE
TABLE é um comando DDL (não DML) e não pode ser revertido com ROLLBACK em
transações, ao contrário do DELETE FROM .
Com os comandos DML, você tem o poder de gerenciar o ciclo de vida dos dados
dentro do seu banco de dados, desde a inserção inicial até a atualização e exclusão. O
próximo passo é aprender a recuperar esses dados de forma eficiente com o comando
SELECT .

2.3 Consultas SELECT Básicas


O comando SELECT é, sem dúvida, o mais utilizado em SQL. Ele permite que você
recupere dados de uma ou mais tabelas, filtrando, ordenando e limitando os
resultados de acordo com suas necessidades. Dominar o SELECT é fundamental para
qualquer pessoa que trabalhe com bancos de dados.
2.3.1 Selecionando Todas as Colunas ( SELECT * )
A forma mais simples de uma consulta SELECT é recuperar todas as colunas de uma
tabela. Isso é útil para uma visão geral rápida dos dados.
Sintaxe:
SELECT *
FROM nome_da_tabela;

Exemplo:
USE livraria;

SELECT *
FROM autores;

SELECT *
FROM livros;

Este comando retornará todas as colunas e todas as linhas das tabelas autores e
livros , respectivamente.

2.3.2 Selecionando Colunas Específicas


Na maioria das vezes, você não precisará de todas as colunas de uma tabela.
Selecionar apenas as colunas necessárias é uma boa prática, pois melhora a
performance da consulta e torna o resultado mais legível.
Sintaxe:
SELECT coluna1, coluna2, coluna3, ...
FROM nome_da_tabela;

Exemplo:
USE livraria;

-- Selecionar apenas o nome e sobrenome dos autores


SELECT nome, sobrenome
FROM autores;

-- Selecionar o título e o preço dos livros


SELECT titulo, preco
FROM livros;

2.3.3 Renomeando Colunas ( AS )


Você pode renomear as colunas no resultado da sua consulta usando a palavra-chave
AS . Isso é útil para tornar os nomes das colunas mais descritivos ou para evitar
conflitos de nomes quando você estiver combinando dados de várias tabelas.
Sintaxe:
SELECT coluna1 AS novo_nome1, coluna2 AS novo_nome2, ...
FROM nome_da_tabela;

Exemplo:
USE livraria;

-- Renomear as colunas para um resultado mais amigável


SELECT
nome AS PrimeiroNome,
sobrenome AS UltimoNome,
nacionalidade AS PaisDeOrigem
FROM autores;

-- Renomear o título do livro para 'Nome do Livro' e o preço para 'Preço


Unitário'
SELECT
titulo AS 'Nome do Livro',
preco AS 'Preço Unitário'
FROM livros;

Note que, se o novo nome da coluna contiver espaços ou caracteres especiais, ele deve
ser colocado entre aspas simples ( ' ) ou crases ( ` ) no MySQL. É uma boa prática usar
crases para nomes de colunas e tabelas no MySQL, especialmente se eles contiverem
caracteres especiais ou palavras reservadas, mas aspas simples funcionam para
aliases.
2.3.4 Filtrando Resultados ( WHERE )
A cláusula WHERE é usada para filtrar as linhas retornadas por uma consulta SELECT ,
com base em uma ou mais condições. Apenas as linhas que satisfazem a condição
serão incluídas no conjunto de resultados.
Sintaxe:
SELECT coluna1, coluna2, ...
FROM nome_da_tabela
WHERE condicao;

Operadores Comuns na Cláusula WHERE :


Operadores de Comparação:
= (Igual a)
!= ou <> (Diferente de)

> (Maior que)

< (Menor que)

>= (Maior ou igual a)

<= (Menor ou igual a)

Operadores Lógicos:
AND : Combina duas ou mais condições. Todas as condições devem ser
verdadeiras.
OR : Combina duas ou mais condições. Pelo menos uma das condições deve
ser verdadeira.
NOT : Nega uma condição.

Outros Operadores:
BETWEEN valor1 AND valor2 : Verifica se um valor está dentro de um
determinado intervalo (inclusive).
LIKE padrao : Usado para pesquisa de padrões em strings. % representa
zero ou mais caracteres, _ representa um único caractere.
IN (valor1, valor2, ...) : Verifica se um valor corresponde a qualquer
valor em uma lista.
IS NULL : Verifica se um valor é NULL.

IS NOT NULL : Verifica se um valor não é NULL.

Exemplos Práticos:
USE livraria;

-- Livros com preço maior que 40.00


SELECT titulo, preco
FROM livros
WHERE preco > 40.00;

-- Autores brasileiros
SELECT nome, sobrenome
FROM autores
WHERE nacionalidade = 'Brasileira';

-- Livros publicados após 1900 e com estoque maior que 50


SELECT titulo, ano_publicacao, estoque
FROM livros
WHERE ano_publicacao > 1900 AND estoque > 50;

-- Clientes com email que termina com '@email.com'


SELECT nome, sobrenome, email
FROM clientes
WHERE email LIKE '%@email.com';

-- Livros de Romance ou Realismo Mágico


SELECT titulo, genero
FROM livros
WHERE genero IN ('Romance', 'Realismo Mágico');

-- Autores que não têm data de nascimento registrada


SELECT nome, sobrenome
FROM autores
WHERE data_nascimento IS NULL;

-- Livros com preço entre 30.00 e 50.00 (inclusive)


SELECT titulo, preco
FROM livros
WHERE preco BETWEEN 30.00 AND 50.00;

2.3.5 Ordenando Resultados ( ORDER BY )


A cláusula ORDER BY é usada para classificar o conjunto de resultados de uma
consulta em ordem crescente ( ASC , padrão) ou decrescente ( DESC ) com base em uma
ou mais colunas.
Sintaxe:
SELECT coluna1, coluna2, ...
FROM nome_da_tabela
WHERE condicao
ORDER BY coluna_ordenacao1 [ASC|DESC], coluna_ordenacao2 [ASC|DESC], ...;

Exemplos Práticos:
USE livraria;

-- Livros ordenados por título em ordem alfabética crescente


SELECT titulo, preco
FROM livros
ORDER BY titulo ASC;

-- Livros ordenados por preço em ordem decrescente


SELECT titulo, preco
FROM livros
ORDER BY preco DESC;

-- Autores ordenados por sobrenome (crescente) e depois por nome (crescente)


SELECT nome, sobrenome
FROM autores
ORDER BY sobrenome ASC, nome ASC;

-- Livros de Romance, ordenados por ano de publicação (mais recente primeiro)


SELECT titulo, ano_publicacao, genero
FROM livros
WHERE genero = 'Romance'
ORDER BY ano_publicacao DESC;

2.3.6 Limitando Resultados ( LIMIT )


A cláusula LIMIT é usada para restringir o número de linhas retornadas por uma
consulta. Isso é particularmente útil para paginação ou para obter apenas os
primeiros N resultados.
Sintaxe:
SELECT coluna1, coluna2, ...
FROM nome_da_tabela
WHERE condicao
ORDER BY coluna_ordenacao
LIMIT numero_de_linhas;

-- Ou, para pular um número de linhas e depois limitar:


LIMIT offset, numero_de_linhas;

numero_de_linhas : O número máximo de linhas a serem retornadas.


offset : O número de linhas a serem puladas antes de começar a retornar os
resultados. O offset é opcional e, se omitido, assume o valor 0.
Exemplos Práticos:
USE livraria;

-- Obter os 3 livros mais caros


SELECT titulo, preco
FROM livros
ORDER BY preco DESC
LIMIT 3;

-- Obter os 2 autores mais antigos (baseado na data de nascimento)


SELECT nome, sobrenome, data_nascimento
FROM autores
ORDER BY data_nascimento ASC
LIMIT 2;

-- Paginação: Obter os próximos 3 livros após os primeiros 3 (pular 3, pegar 3)


-- Útil para exibir resultados em páginas (ex: página 1: LIMIT 0, 3; página 2:
LIMIT 3, 3; página 3: LIMIT 6, 3)
SELECT titulo, preco
FROM livros
ORDER BY titulo ASC
LIMIT 3, 3;

Com esses comandos SELECT básicos, você já pode realizar uma variedade de
consultas para extrair informações valiosas do seu banco de dados. No próximo
módulo, exploraremos funcionalidades mais avançadas do SELECT , como funções de
agregação, agrupamento e junções de tabelas.

Módulo 3: Consultas Intermediárias: JOINs, Funções e


Subconsultas
Neste módulo, vamos explorar técnicas mais avançadas de consulta que permitem
combinar dados de múltiplas tabelas, realizar cálculos e filtrar resultados de maneiras
mais complexas. Dominar esses conceitos é crucial para extrair informações
significativas de bancos de dados relacionais.
3.1 Abordando Diferentes Tipos de JOINs
Em um banco de dados relacional, os dados são frequentemente distribuídos em
várias tabelas para evitar redundância e garantir a integridade. As operações JOIN são
usadas para combinar linhas de duas ou mais tabelas com base em uma coluna
relacionada entre elas. Existem vários tipos de JOIN , cada um com um propósito
específico.
3.1.1 INNER JOIN (Junção Interna)
O INNER JOIN retorna apenas as linhas que têm correspondência em ambas as
tabelas. É o tipo de JOIN mais comum e, se você não especificar um tipo de JOIN , o
INNER JOIN é geralmente o padrão.

Sintaxe:
SELECT colunas
FROM tabela1
INNER JOIN tabela2
ON tabela1.coluna_comum = tabela2.coluna_comum;

ON : Especifica a condição de junção, ou seja, qual coluna é usada para relacionar


as tabelas.
Exemplo Prático:
Vamos encontrar todos os livros e seus respectivos autores na nossa livraria.
USE livraria;

SELECT
l.titulo AS TituloLivro,
a.nome AS NomeAutor,
a.sobrenome AS SobrenomeAutor
FROM livros l
INNER JOIN autores a
ON l.id_autor = a.id_autor;

l e a são aliases (apelidos) para as tabelas livros e autores ,


respectivamente. Isso torna a consulta mais concisa e legível, especialmente
quando você tem nomes de tabelas longos ou quando precisa referenciar
colunas de tabelas diferentes que têm o mesmo nome.
O resultado incluirá apenas os livros que têm um autor correspondente na tabela
autores .

3.1.2 LEFT JOIN (Junção Esquerda) / LEFT OUTER JOIN


O LEFT JOIN retorna todas as linhas da tabela da esquerda (a primeira tabela listada
no FROM ) e as linhas correspondentes da tabela da direita. Se não houver
correspondência na tabela da direita, as colunas da tabela da direita terão valores
NULL .
Sintaxe:
SELECT colunas
FROM tabela1
LEFT JOIN tabela2
ON tabela1.coluna_comum = tabela2.coluna_comum;

Exemplo Prático:
Vamos listar todos os autores e, se eles tiverem livros, listar os títulos dos livros. Se um
autor não tiver livros, ele ainda aparecerá na lista, mas o título do livro será NULL .
USE livraria;

SELECT
a.nome AS NomeAutor,
a.sobrenome AS SobrenomeAutor,
l.titulo AS TituloLivro
FROM autores a
LEFT JOIN livros l
ON a.id_autor = l.id_autor;

Este resultado é útil para identificar autores que ainda não publicaram livros em nosso
sistema.
3.1.3 RIGHT JOIN (Junção Direita) / RIGHT OUTER JOIN
O RIGHT JOIN é o oposto do LEFT JOIN . Ele retorna todas as linhas da tabela da
direita (a segunda tabela listada no FROM ) e as linhas correspondentes da tabela da
esquerda. Se não houver correspondência na tabela da esquerda, as colunas da tabela
da esquerda terão valores NULL .
Sintaxe:
SELECT colunas
FROM tabela1
RIGHT JOIN tabela2
ON tabela1.coluna_comum = tabela2.coluna_comum;

Exemplo Prático:
Vamos listar todos os livros e, se eles tiverem um autor correspondente, listar o nome
do autor. Se um livro não tiver um autor (o que não deveria acontecer com nossa
restrição NOT NULL na FK, mas serve para ilustração), ele ainda apareceria, e o nome
do autor seria NULL .
USE livraria;

SELECT
l.titulo AS TituloLivro,
a.nome AS NomeAutor,
a.sobrenome AS SobrenomeAutor
FROM autores a
RIGHT JOIN livros l
ON a.id_autor = l.id_autor;

Na prática, um RIGHT JOIN pode ser reescrito como um LEFT JOIN trocando a ordem
das tabelas. Por exemplo, o exemplo acima é equivalente a:
SELECT
l.titulo AS TituloLivro,
a.nome AS NomeAutor,
a.sobrenome AS SobrenomeAutor
FROM livros l
LEFT JOIN autores a
ON l.id_autor = a.id_autor;

Por essa razão, muitos desenvolvedores preferem usar LEFT JOIN consistentemente e
ajustar a ordem das tabelas.
3.1.4 FULL JOIN (Junção Completa) / FULL OUTER JOIN
O FULL JOIN retorna todas as linhas quando há uma correspondência em uma das
tabelas. Ele combina os resultados de LEFT JOIN e RIGHT JOIN . Se não houver
correspondência, as colunas da tabela sem correspondência terão valores NULL .
Sintaxe (MySQL não suporta FULL JOIN diretamente, mas pode ser simulado):
O MySQL não possui um comando FULL OUTER JOIN nativo. No entanto, você pode
simular seu comportamento combinando um LEFT JOIN e um RIGHT JOIN (ou dois
LEFT JOIN s) com um UNION .

SELECT colunas
FROM tabela1
LEFT JOIN tabela2
ON tabela1.coluna_comum = tabela2.coluna_comum

UNION

SELECT colunas
FROM tabela1
RIGHT JOIN tabela2
ON tabela1.coluna_comum = tabela2.coluna_comum;
UNION : Combina os conjuntos de resultados de duas ou mais instruções SELECT .
Ele remove linhas duplicadas por padrão.
UNION ALL : Combina os conjuntos de resultados, mas inclui todas as linhas,
mesmo as duplicadas.
Exemplo Prático (Simulando FULL JOIN ):
Vamos simular um FULL JOIN entre autores e livros para ver todos os autores
(mesmo sem livros) e todos os livros (mesmo sem autores, o que não deveria
acontecer devido à FK, mas para fins de demonstração).
USE livraria;

SELECT
a.nome AS NomeAutor,
a.sobrenome AS SobrenomeAutor,
l.titulo AS TituloLivro
FROM autores a
LEFT JOIN livros l
ON a.id_autor = l.id_autor

UNION

SELECT
a.nome AS NomeAutor,
a.sobrenome AS SobrenomeAutor,
l.titulo AS TituloLivro
FROM autores a
RIGHT JOIN livros l
ON a.id_autor = l.id_autor;

Este comando retornará todos os autores (com seus livros, se houver) e todos os livros
(com seus autores, se houver). Se um autor não tiver livros, o TituloLivro será NULL .
Se um livro não tiver autor (o que, novamente, não deve acontecer com a FK), o
NomeAutor e SobrenomeAutor serão NULL .

3.1.5 CROSS JOIN (Produto Cartesiano)


O CROSS JOIN retorna o produto cartesiano das duas tabelas, ou seja, cada linha da
primeira tabela é combinada com cada linha da segunda tabela. Isso resulta em um
número de linhas igual ao número de linhas da tabela1 multiplicado pelo número de
linhas da tabela2. Raramente é usado diretamente, mas é importante entender seu
conceito.
Sintaxe:
SELECT colunas
FROM tabela1
CROSS JOIN tabela2;

-- Ou, implicitamente, sem a palavra-chave JOIN:


SELECT colunas
FROM tabela1, tabela2;

Exemplo Prático:
Se você tiver 3 autores e 4 livros, um CROSS JOIN retornaria 12 combinações (3 * 4).
USE livraria;

SELECT
a.nome AS NomeAutor,
l.titulo AS TituloLivro
FROM autores a
CROSS JOIN livros l;

Este tipo de junção é útil em cenários muito específicos, como gerar todas as
combinações possíveis de itens para um relatório, mas deve ser usado com cautela
devido ao grande volume de dados que pode gerar.
3.1.6 SELF JOIN (Auto Junção)
Um SELF JOIN é uma junção de uma tabela consigo mesma. Isso é útil quando você
precisa comparar linhas dentro da mesma tabela. Para realizar um SELF JOIN , você
deve usar aliases de tabela para diferenciar as duas instâncias da mesma tabela.
Sintaxe:
SELECT colunas
FROM tabela t1
JOIN tabela t2
ON t1.coluna_comum = t2.coluna_comum
WHERE condicao;

Exemplo Prático:
Imagine que temos uma tabela de funcionarios com uma coluna gerente_id que
referencia o id_funcionario do gerente. Queremos listar os funcionários e seus
respectivos gerentes.
-- Primeiro, vamos criar uma tabela de exemplo para ilustrar o SELF JOIN
CREATE TABLE IF NOT EXISTS funcionarios (
id_funcionario INT AUTO_INCREMENT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
cargo VARCHAR(100),
gerente_id INT,
FOREIGN KEY (gerente_id) REFERENCES funcionarios(id_funcionario)
);

INSERT INTO funcionarios (nome, cargo, gerente_id)


VALUES
("Alice", "CEO", NULL),
("Bob", "Gerente de Vendas", 1),
("Charlie", "Vendedor", 2),
("David", "Gerente de Marketing", 1),
("Eve", "Marketing Analyst", 4);

SELECT
f.nome AS Funcionario,
f.cargo AS CargoFuncionario,
g.nome AS Gerente,
g.cargo AS CargoGerente
FROM funcionarios f
LEFT JOIN funcionarios g
ON f.gerente_id = g.id_funcionario;

Neste exemplo, f representa a instância do funcionário e g representa a instância do


gerente. O LEFT JOIN garante que todos os funcionários sejam listados, mesmo
aqueles que não têm um gerente (como o CEO).
Dominar os diferentes tipos de JOIN é fundamental para construir consultas
complexas e eficientes que extraem dados de múltiplas tabelas em um banco de
dados relacional. A escolha do JOIN correto depende da relação que você deseja
estabelecer entre as tabelas e dos dados que você espera no resultado.
3.2 Funções de Agregação, GROUP BY e HAVING
As funções de agregação permitem realizar cálculos em um conjunto de linhas e
retornar um único valor. Elas são frequentemente usadas em conjunto com a cláusula
GROUP BY para agrupar linhas que têm os mesmos valores em colunas especificadas,
e com a cláusula HAVING para filtrar esses grupos.
3.2.1 Funções de Agregação Comuns
COUNT() : Retorna o número de linhas que correspondem a um critério
especificado.
COUNT(*) : Conta todas as linhas, incluindo NULL s.
COUNT(coluna) : Conta o número de valores não NULL em uma coluna.

COUNT(DISTINCT coluna) : Conta o número de valores distintos não NULL


em uma coluna.
Exemplos: ```sql USE livraria;
-- Contar o número total de livros SELECT COUNT(*) AS TotalLivros FROM livros;
-- Contar o número de autores com nacionalidade registrada SELECT
COUNT(nacionalidade) AS AutoresComNacionalidade FROM autores;
-- Contar o número de nacionalidades distintas de autores SELECT
COUNT(DISTINCT nacionalidade) AS NacionalidadesDistintas FROM autores; ```
SUM() : Retorna a soma total de uma coluna numérica.

Exemplo: ```sql USE livraria;


-- Calcular o valor total de todos os livros em estoque SELECT SUM(preco *
estoque) AS ValorTotalEstoque FROM livros;
-- Calcular o valor total de todas as vendas SELECT SUM(valor_total) AS
TotalVendas FROM vendas; ```
AVG() : Retorna o valor médio de uma coluna numérica.

Exemplo: ```sql USE livraria;


-- Calcular o preço médio dos livros SELECT AVG(preco) AS PrecoMedioLivros
FROM livros; ```
MIN() : Retorna o menor valor em uma coluna.

Exemplo: ```sql USE livraria;


-- Encontrar o livro mais barato SELECT MIN(preco) AS LivroMaisBarato FROM
livros;
-- Encontrar a data de publicação mais antiga SELECT MIN(ano_publicacao) AS
AnoPublicacaoMaisAntigo FROM livros; ```
MAX() : Retorna o maior valor em uma coluna.
Exemplo: ```sql USE livraria;
-- Encontrar o livro mais caro SELECT MAX(preco) AS LivroMaisCaro FROM livros;
-- Encontrar a data de publicação mais recente SELECT MAX(ano_publicacao) AS
AnoPublicacaoMaisRecente FROM livros; ```
3.2.2 A Cláusula GROUP BY
A cláusula GROUP BY é usada para agrupar linhas que têm os mesmos valores em uma
ou mais colunas. Isso é frequentemente usado em conjunto com funções de agregação
para realizar cálculos para cada grupo, em vez de para o conjunto inteiro de dados.
Sintaxe:
SELECT coluna1, funcao_agregacao(coluna2)
FROM nome_da_tabela
WHERE condicao
GROUP BY coluna1, coluna3, ...
ORDER BY coluna_ordenacao;

Todas as colunas no SELECT que não são funções de agregação devem estar na
cláusula GROUP BY .
Exemplos Práticos:
USE livraria;

-- Contar quantos livros cada autor tem


SELECT
a.nome AS NomeAutor,
a.sobrenome AS SobrenomeAutor,
COUNT(l.id_livro) AS QuantidadeLivros
FROM autores a
INNER JOIN livros l ON a.id_autor = l.id_autor
GROUP BY a.id_autor, a.nome, a.sobrenome -- Agrupar por ID para garantir
unicidade, e por nome/sobrenome para exibição
ORDER BY QuantidadeLivros DESC;

-- Calcular o preço médio dos livros por gênero


SELECT
genero,
AVG(preco) AS PrecoMedio
FROM livros
GROUP BY genero;

-- Contar o número de vendas por cliente


SELECT
c.nome AS NomeCliente,
c.sobrenome AS SobrenomeCliente,
COUNT(v.id_venda) AS TotalVendas
FROM clientes c
INNER JOIN vendas v ON c.id_cliente = v.id_cliente
GROUP BY c.id_cliente, c.nome, c.sobrenome
ORDER BY TotalVendas DESC;

3.2.3 A Cláusula HAVING


A cláusula HAVING é usada para filtrar grupos criados pela cláusula GROUP BY .
Diferente da cláusula WHERE , que filtra linhas individuais antes do agrupamento,
HAVING filtra os grupos depois que as funções de agregação foram aplicadas.

Sintaxe:
SELECT coluna1, funcao_agregacao(coluna2)
FROM nome_da_tabela
WHERE condicao_linha
GROUP BY coluna1
HAVING condicao_grupo
ORDER BY coluna_ordenacao;

Exemplos Práticos:
USE livraria;

-- Encontrar autores que escreveram mais de 1 livro


SELECT
a.nome AS NomeAutor,
a.sobrenome AS SobrenomeAutor,
COUNT(l.id_livro) AS QuantidadeLivros
FROM autores a
INNER JOIN livros l ON a.id_autor = l.id_autor
GROUP BY a.id_autor, a.nome, a.sobrenome
HAVING COUNT(l.id_livro) > 1;

-- Gêneros com preço médio de livro acima de 40.00


SELECT
genero,
AVG(preco) AS PrecoMedio
FROM livros
GROUP BY genero
HAVING AVG(preco) > 40.00;

-- Clientes que fizeram mais de 1 venda e cujo valor total de vendas é superior
a 100.00
SELECT
c.nome AS NomeCliente,
c.sobrenome AS SobrenomeCliente,
COUNT(v.id_venda) AS TotalVendas,
SUM(v.valor_total) AS ValorTotalGasto
FROM clientes c
INNER JOIN vendas v ON c.id_cliente = v.id_cliente
GROUP BY c.id_cliente, c.nome, c.sobrenome
HAVING COUNT(v.id_venda) > 1 AND SUM(v.valor_total) > 100.00;

Em resumo, WHERE filtra linhas antes do agrupamento, e HAVING filtra grupos após o
agrupamento e a aplicação das funções de agregação. Essa distinção é crucial para
escrever consultas eficientes e corretas.
3.3 Subconsultas e Consultas Aninhadas
Subconsultas (também conhecidas como consultas aninhadas ou inner queries) são
consultas SELECT que estão embutidas dentro de outra instrução SQL. Elas podem ser
usadas em várias partes de uma consulta principal, como na cláusula WHERE , FROM ,
ou SELECT , para filtrar dados, fornecer valores para comparações ou criar tabelas
temporárias.
3.3.1 Subconsultas na Cláusula WHERE
Subconsultas na cláusula WHERE são usadas para filtrar os resultados da consulta
externa com base nos resultados da subconsulta. Elas são frequentemente usadas
com operadores como IN , NOT IN , = , != , > , < , >= , <= , EXISTS , NOT EXISTS ,
ANY , ALL .

Exemplo com IN :
Vamos encontrar os títulos dos livros escritos por autores brasileiros.
USE livraria;

SELECT titulo
FROM livros
WHERE id_autor IN (
SELECT id_autor
FROM autores
WHERE nacionalidade = 'Brasileira'
);

Neste exemplo, a subconsulta SELECT id_autor FROM autores WHERE nacionalidade


= 'Brasileira' retorna uma lista de id_autor s. A consulta externa então seleciona
os livros cujo id_autor está nessa lista.
Exemplo com NOT IN :
Encontrar os títulos dos livros que não foram escritos por autores brasileiros.
USE livraria;

SELECT titulo
FROM livros
WHERE id_autor NOT IN (
SELECT id_autor
FROM autores
WHERE nacionalidade = 'Brasileira'
);

Exemplo com Operadores de Comparação ( = ):


Encontrar o livro mais caro (usando uma subconsulta para determinar o preço
máximo).
USE livraria;

SELECT titulo, preco


FROM livros
WHERE preco = (
SELECT MAX(preco)
FROM livros
);
Exemplo com EXISTS :
EXISTS é usado para testar a existência de linhas retornadas por uma subconsulta. Ele
retorna TRUE se a subconsulta retornar uma ou mais linhas, e FALSE caso contrário. É
eficiente porque para de procurar assim que encontra a primeira linha.
Listar clientes que fizeram pelo menos uma venda.
USE livraria;

SELECT nome, sobrenome


FROM clientes c
WHERE EXISTS (
SELECT 1
FROM vendas v
WHERE v.id_cliente = c.id_cliente
);

Exemplo com NOT EXISTS :


Listar clientes que não fizeram nenhuma venda.
USE livraria;

SELECT nome, sobrenome


FROM clientes c
WHERE NOT EXISTS (
SELECT 1
FROM vendas v
WHERE v.id_cliente = c.id_cliente
);

Exemplo com ANY / SOME :


ANY (ou SOME ) compara um valor com qualquer valor em um conjunto de resultados
de uma subconsulta. Retorna TRUE se a comparação for verdadeira para qualquer
valor no conjunto.
Encontrar livros cujo preço é maior que o preço de qualquer livro de Romance.
USE livraria;

SELECT titulo, preco


FROM livros
WHERE preco > ANY (
SELECT preco
FROM livros
WHERE genero = 'Romance'
);

Exemplo com ALL :


ALL compara um valor com todos os valores em um conjunto de resultados de uma
subconsulta. Retorna TRUE se a comparação for verdadeira para todos os valores no
conjunto.
Encontrar livros cujo preço é maior que o preço de todos os livros de Romance (ou
seja, mais caro que o livro de Romance mais caro).
USE livraria;

SELECT titulo, preco


FROM livros
WHERE preco > ALL (
SELECT preco
FROM livros
WHERE genero = 'Romance'
);

3.3.2 Subconsultas na Cláusula FROM (Tabelas Derivadas)


Uma subconsulta na cláusula FROM atua como uma tabela temporária (também
chamada de tabela derivada ou inline view) que pode ser consultada como qualquer
outra tabela. É obrigatório dar um alias para essa tabela derivada.
Exemplo:
Encontrar o nome dos autores e a quantidade de livros que cada um escreveu, mas
apenas para autores que escreveram mais de um livro. (Este exemplo pode ser feito
com GROUP BY e HAVING , mas serve para ilustrar a subconsulta no FROM ).
USE livraria;

SELECT
a.nome, a.sobrenome, sub.QuantidadeLivros
FROM autores a
INNER JOIN (
SELECT id_autor, COUNT(id_livro) AS QuantidadeLivros
FROM livros
GROUP BY id_autor
HAVING COUNT(id_livro) > 1
) AS sub ON a.id_autor = sub.id_autor;

Neste caso, a subconsulta cria uma tabela temporária sub que contém id_autor e
QuantidadeLivros para autores com mais de um livro. A consulta externa então une
essa tabela temporária com a tabela autores .
3.3.3 Subconsultas na Cláusula SELECT (Subconsultas Escalares)
Uma subconsulta escalar retorna um único valor (uma única coluna e uma única
linha). Se a subconsulta retornar mais de um valor, ocorrerá um erro. Elas são úteis
para adicionar informações calculadas a cada linha do resultado da consulta principal.
Exemplo:
Listar cada livro e o nome do seu autor.
USE livraria;

SELECT
titulo,
(SELECT CONCAT(nome, ' ', sobrenome) FROM autores WHERE autores.id_autor =
livros.id_autor) AS NomeAutor
FROM livros;

Neste exemplo, para cada linha da tabela livros , a subconsulta é executada para
buscar o nome completo do autor correspondente. Note que esta subconsulta é
correlacionada, pois depende de um valor da consulta externa ( livros.id_autor ).
3.3.4 Subconsultas Correlacionadas vs. Não Correlacionadas
Subconsulta Não Correlacionada: A subconsulta pode ser executada
independentemente da consulta externa. Ela é executada apenas uma vez e seus
resultados são usados pela consulta externa (ex: SELECT titulo FROM livros
WHERE id_autor IN (SELECT id_autor FROM autores WHERE nacionalidade =
'Brasileira'); ).
Subconsulta Correlacionada: A subconsulta depende da consulta externa para
seus valores. Ela é executada uma vez para cada linha processada pela consulta
externa (ex: o exemplo de subconsulta escalar acima). Subconsultas
correlacionadas podem ser menos eficientes para grandes conjuntos de dados, e
muitas vezes podem ser reescritas usando JOIN s para melhor performance.
Exemplo de Subconsulta Correlacionada (para ilustrar a diferença):
Encontrar os livros cujo preço é maior que o preço médio dos livros do mesmo gênero.
USE livraria;

SELECT titulo, genero, preco


FROM livros l1
WHERE preco > (
SELECT AVG(preco)
FROM livros l2
WHERE l2.genero = l1.genero
);

Aqui, l2.genero = l1.genero mostra a correlação: a subconsulta para calcular a


média depende do gênero do livro da consulta externa ( l1 ).
Dominar subconsultas é uma habilidade poderosa em SQL, permitindo que você
resolva problemas complexos de consulta de dados de forma concisa. No entanto, é
importante considerar a performance, e em muitos casos, um JOIN pode ser uma
alternativa mais eficiente para subconsultas correlacionadas.

Módulo 4: Recursos Avançados e Otimização


Neste módulo, exploraremos recursos mais avançados do MySQL que permitem criar
lógica de negócios complexa diretamente no banco de dados, automatizar tarefas e
otimizar o desempenho das suas consultas. Abordaremos Stored Procedures,
Functions, Triggers, Views e técnicas de otimização.
4.1 Ensinando a Criação e Uso de Stored Procedures e Functions
Stored Procedures (Procedimentos Armazenados) e Functions (Funções) são blocos de
código SQL que são armazenados no banco de dados e podem ser executados
repetidamente. Eles oferecem benefícios como modularidade, segurança,
desempenho e redução do tráfego de rede.
4.1.1 Stored Procedures (Procedimentos Armazenados)
Uma Stored Procedure é um conjunto de instruções SQL que executa uma tarefa
específica. Ela pode aceitar parâmetros de entrada, retornar parâmetros de saída e
não necessariamente retorna um valor único, podendo executar várias operações
(INSERT, UPDATE, DELETE, SELECT).
Vantagens: * Reusabilidade: O código é escrito uma vez e pode ser chamado de
qualquer aplicação ou outra procedure. * Segurança: Permite conceder permissões
aos usuários para executar a procedure sem dar acesso direto às tabelas subjacentes. *
Desempenho: O código é compilado e armazenado no banco de dados, o que pode
levar a uma execução mais rápida. * Redução de Tráfego de Rede: Em vez de enviar
várias instruções SQL, apenas uma chamada de procedure é enviada.
Sintaxe Básica:
DELIMITER //

CREATE PROCEDURE nome_da_procedure (


[IN parametro_entrada TIPO_DADO,
OUT parametro_saida TIPO_DADO,
INOUT parametro_entrada_saida TIPO_DADO]
)
BEGIN
-- Declaração de variáveis (opcional)
DECLARE variavel TIPO_DADO DEFAULT valor_inicial;

-- Lógica SQL
-- Ex: SELECT, INSERT, UPDATE, DELETE

-- Estruturas de controle (IF, CASE, LOOP, WHILE, REPEAT)


IF condicao THEN
-- instrucoes
ELSE
-- instrucoes
END IF;

-- Cursor (para iterar sobre resultados de SELECT)


-- Manipulação de erros (Handlers)

END //

DELIMITER ;

DELIMITER // e DELIMITER ; : O MySQL usa o ponto e vírgula ( ; ) como


delimitador padrão para o final das instruções SQL. Dentro de uma procedure,
você terá várias instruções SQL, cada uma terminando com ; . Para que o MySQL
não interprete cada ; dentro da procedure como o fim da CREATE PROCEDURE ,
precisamos mudar o delimitador temporariamente para outro caractere (como
// ) e depois restaurá-lo.

IN : Parâmetro de entrada. O valor é passado para a procedure.

OUT : Parâmetro de saída. A procedure pode retornar um valor através deste


parâmetro.
INOUT : Parâmetro de entrada e saída. O valor é passado para a procedure e pode
ser modificado e retornado.
BEGIN ... END : Bloco que contém as instruções SQL da procedure.

Exemplos Práticos:
1. Procedure Simples (sem parâmetros):
Vamos criar uma procedure para listar todos os livros.
USE livraria;

DELIMITER //

CREATE PROCEDURE ListarTodosLivros()


BEGIN
SELECT * FROM livros;
END //

DELIMITER ;

-- Para executar a procedure:


CALL ListarTodosLivros();

2. Procedure com Parâmetro IN :


Vamos criar uma procedure para encontrar livros por gênero.
USE livraria;

DELIMITER //

CREATE PROCEDURE BuscarLivrosPorGenero(IN genero_procurado VARCHAR(50))


BEGIN
SELECT titulo, preco, estoque
FROM livros
WHERE genero = genero_procurado;
END //

DELIMITER ;

-- Para executar a procedure:


CALL BuscarLivrosPorGenero("Romance");
CALL BuscarLivrosPorGenero("Realismo Mágico");

3. Procedure com Parâmetro OUT :


Vamos criar uma procedure para obter o número total de livros em estoque.
USE livraria;

DELIMITER //

CREATE PROCEDURE ObterTotalEstoque(OUT total_estoque INT)


BEGIN
SELECT SUM(estoque) INTO total_estoque
FROM livros;
END //

DELIMITER ;

-- Para executar a procedure e ver o resultado:


CALL ObterTotalEstoque(@estoque_geral);
SELECT @estoque_geral AS TotalEstoqueGeral;

@estoque_geral é uma variável de sessão no MySQL. Variáveis de sessão


começam com @ .
4. Procedure com Lógica Condicional ( IF ):
Vamos criar uma procedure para atualizar o estoque de um livro, verificando se a
quantidade é válida.
USE livraria;

DELIMITER //

CREATE PROCEDURE AtualizarEstoqueLivro(


IN livro_id INT,
IN quantidade_adicionar INT
)
BEGIN
IF quantidade_adicionar > 0 THEN
UPDATE livros
SET estoque = estoque + quantidade_adicionar
WHERE id_livro = livro_id;
SELECT CONCAT("Estoque do livro ", livro_id, " atualizado com
sucesso.") AS Mensagem;
ELSE
SELECT "Quantidade para adicionar deve ser maior que zero." AS
Mensagem;
END IF;
END //

DELIMITER ;

-- Para executar:
CALL AtualizarEstoqueLivro(1, 10); -- Adiciona 10 unidades ao livro com ID 1
CALL AtualizarEstoqueLivro(2, -5); -- Tenta adicionar -5 (mensagem de erro)

Excluindo uma Procedure:


DROP PROCEDURE IF EXISTS nome_da_procedure;

4.1.2 Functions (Funções)


Uma Function (Função) é similar a uma Stored Procedure, mas ela sempre retorna um
único valor escalar (como um número, string ou data). Funções podem ser usadas em
expressões SQL, como na cláusula SELECT , WHERE ou HAVING .
Vantagens: * Uso em Expressões: Podem ser usadas diretamente em consultas SQL, o
que as torna muito flexíveis. * Modularidade: Encapsulam lógica complexa em um
único bloco reutilizável.
Sintaxe Básica:
DELIMITER //

CREATE FUNCTION nome_da_funcao (


[parametro1 TIPO_DADO,
parametro2 TIPO_DADO]
)
RETURNS TIPO_RETORNO
[DETERMINISTIC | NOT DETERMINISTIC]
[READS SQL DATA | NO SQL | MODIFIES SQL DATA]
BEGIN
-- Declaração de variáveis
DECLARE variavel TIPO_DADO;

-- Lógica SQL

RETURN valor_a_retornar;
END //

DELIMITER ;

RETURNS TIPO_RETORNO : Define o tipo de dado que a função irá retornar.


DETERMINISTIC | NOT DETERMINISTIC : Indica se a função sempre retorna o
mesmo resultado para os mesmos parâmetros de entrada ( DETERMINISTIC ) ou
não ( NOT DETERMINISTIC ). Isso afeta a otimização do MySQL.
READS SQL DATA | NO SQL | MODIFIES SQL DATA : Indica o tipo de operação
SQL que a função realiza. Funções usadas em SELECT geralmente devem ser
READS SQL DATA ou NO SQL .

Exemplos Práticos:
1. Função Simples:
Vamos criar uma função para calcular o valor total de um item de venda (quantidade *
preço unitário).
USE livraria;

DELIMITER //

CREATE FUNCTION CalcularValorItem(quantidade INT, preco_unitario DECIMAL(10,


2))
RETURNS DECIMAL(10, 2)
DETERMINISTIC
BEGIN
RETURN quantidade * preco_unitario;
END //

DELIMITER ;

-- Para usar a função:


SELECT CalcularValorItem(5, 10.50) AS ValorCalculado;

-- Usando em uma consulta:


SELECT
id_item_venda,
quantidade,
preco_unitario,
CalcularValorItem(quantidade, preco_unitario) AS ValorTotalItem
FROM itens_venda;

2. Função para Obter Nome Completo do Autor:


USE livraria;

DELIMITER //

CREATE FUNCTION ObterNomeCompletoAutor(autor_id INT)


RETURNS VARCHAR(200)
READS SQL DATA
BEGIN
DECLARE nome_completo VARCHAR(200);
SELECT CONCAT(nome, ' ', sobrenome) INTO nome_completo
FROM autores
WHERE id_autor = autor_id;
RETURN nome_completo;
END //

DELIMITER ;

-- Para usar a função:


SELECT
titulo,
ObterNomeCompletoAutor(id_autor) AS AutorDoLivro
FROM livros;

Excluindo uma Function:


DROP FUNCTION IF EXISTS nome_da_funcao;

Diferenças Chave entre Procedures e Functions:


Característica Stored Procedure Function
Pode retornar 0 ou N valores (via Sempre retorna um único valor
Retorno OUT/INOUT parâmetros ou escalar
SELECT)
Uso em SQL Usada com CALL Usada em expressões SQL ( SELECT ,
WHERE , etc.)

Modificação de Pode modificar dados ( INSERT , Geralmente não modifica dados


Dados UPDATE , DELETE )
(MySQL permite, mas não é boa
prática)
Transações Pode iniciar e gerenciar Não pode iniciar ou gerenciar
transações transações
Stored Procedures e Functions são ferramentas poderosas para encapsular lógica de
negócios e melhorar a eficiência do seu banco de dados. A escolha entre uma e outra
depende do que você precisa que o bloco de código faça e como você pretende usá-lo.
4.2 Explicando Triggers e Views
Triggers e Views são outros recursos avançados do MySQL que oferecem
funcionalidades poderosas para automatizar ações e simplificar a visualização de
dados, respectivamente.
4.2.1 Triggers (Gatilhos)
Um Trigger é um bloco de código SQL que é executado automaticamente em resposta
a um evento específico (INSERT, UPDATE ou DELETE) em uma tabela. Eles são usados
para impor regras de negócios complexas, auditar dados, manter a integridade
referencial ou automatizar tarefas.
Vantagens: * Automação: Executam ações automaticamente sem a necessidade de
intervenção manual ou de aplicação. * Integridade de Dados: Podem ser usados para
impor regras de negócios que não podem ser facilmente implementadas com
restrições de integridade padrão (PRIMARY KEY, FOREIGN KEY, UNIQUE, CHECK). *
Auditoria: Registram alterações em tabelas para fins de auditoria.
Sintaxe Básica:
DELIMITER //

CREATE TRIGGER nome_do_trigger


[BEFORE | AFTER] [INSERT | UPDATE | DELETE]
ON nome_da_tabela
FOR EACH ROW
BEGIN
-- Lógica SQL a ser executada
-- NEW.coluna (para INSERT e UPDATE): refere-se ao valor da coluna após a
operação
-- OLD.coluna (para UPDATE e DELETE): refere-se ao valor da coluna antes da
operação
END //

DELIMITER ;

BEFORE | AFTER : Define quando o trigger será acionado: antes ou depois da


operação que o disparou.
INSERT | UPDATE | DELETE : O tipo de evento que acionará o trigger.

ON nome_da_tabela : A tabela na qual o trigger será definido.

FOR EACH ROW : Indica que o trigger será executado para cada linha afetada pela
operação.
NEW e OLD : São palavras-chave especiais que permitem acessar os valores das
colunas antes ( OLD ) e depois ( NEW ) da operação. NEW é válido para INSERT e
UPDATE . OLD é válido para UPDATE e DELETE .

Exemplos Práticos:
1. Trigger AFTER INSERT para Atualizar Estoque:
Vamos criar um trigger que, após uma inserção na tabela itens_venda , atualiza o
estoque do livro correspondente na tabela livros .
USE livraria;

DELIMITER //

CREATE TRIGGER trg_after_insert_itens_venda


AFTER INSERT ON itens_venda
FOR EACH ROW
BEGIN
UPDATE livros
SET estoque = estoque - NEW.quantidade
WHERE id_livro = NEW.id_livro;
END //

DELIMITER ;

-- Testando o trigger:
-- Primeiro, vamos verificar o estoque atual de um livro (ex: Dom Casmurro,
id_livro = 1)
SELECT titulo, estoque FROM livros WHERE id_livro = 1;

-- Agora, vamos simular uma venda deste livro


-- Assumindo que id_venda 3 é uma nova venda
INSERT INTO itens_venda (id_venda, id_livro, quantidade, preco_unitario)
VALUES (3, 1, 2, 35.90); -- Vende 2 unidades de Dom Casmurro

-- Verifique o estoque novamente. Ele deve ter diminuído em 2.


SELECT titulo, estoque FROM livros WHERE id_livro = 1;

2. Trigger BEFORE INSERT para Validar Preço:


Vamos criar um trigger que, antes de inserir um novo livro, verifica se o preço é
positivo. Se não for, ele pode definir o preço como 0 ou gerar um erro.
USE livraria;

DELIMITER //

CREATE TRIGGER trg_before_insert_livros_preco


BEFORE INSERT ON livros
FOR EACH ROW
BEGIN
IF NEW.preco < 0 THEN
SET NEW.preco = 0; -- Define o preço como 0 se for negativo
-- Ou, para gerar um erro e impedir a inserção:
-- SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'O preço do livro não
pode ser negativo.';
END IF;
END //

DELIMITER ;

-- Testando o trigger:
INSERT INTO livros (titulo, id_autor, ano_publicacao, isbn, genero, preco,
estoque)
VALUES (
'Livro com Preço Negativo',
1, -- id_autor de Machado de Assis
2020,
'9781234567890',
'Ficção',
-10.00, -- Preço negativo
50
);

SELECT titulo, preco FROM livros WHERE titulo = 'Livro com Preço Negativo';
-- O preço deve ser 0.00

3. Trigger AFTER DELETE para Auditoria:


Vamos criar uma tabela de auditoria e um trigger que registra quando um livro é
excluído.
USE livraria;

CREATE TABLE IF NOT EXISTS auditoria_livros (


id_auditoria INT AUTO_INCREMENT PRIMARY KEY,
id_livro_excluido INT,
titulo_excluido VARCHAR(255),
data_exclusao DATETIME DEFAULT CURRENT_TIMESTAMP,
usuario_exclusao VARCHAR(100) DEFAULT USER()
);

DELIMITER //

CREATE TRIGGER trg_after_delete_livros


AFTER DELETE ON livros
FOR EACH ROW
BEGIN
INSERT INTO auditoria_livros (id_livro_excluido, titulo_excluido)
VALUES (OLD.id_livro, OLD.titulo);
END //

DELIMITER ;

-- Testando o trigger:
-- Primeiro, insira um livro para ser excluído
INSERT INTO livros (titulo, id_autor, ano_publicacao, isbn, genero, preco,
estoque)
VALUES (
'Livro para Excluir',
1, -- id_autor de Machado de Assis
2023,
'9780987654321',
'Teste',
20.00,
10
);

-- Verifique se o livro foi inserido (anote o id_livro)


SELECT * FROM livros WHERE titulo = 'Livro para Excluir';

-- Exclua o livro (substitua o ID pelo ID real do livro inserido)


DELETE FROM livros WHERE id_livro = (SELECT id_livro FROM livros WHERE titulo =
'Livro para Excluir');

-- Verifique a tabela de auditoria


SELECT * FROM auditoria_livros;

Excluindo um Trigger:
DROP TRIGGER IF EXISTS nome_do_trigger;

4.2.2 Views (Visões)


Uma View é uma tabela virtual baseada no conjunto de resultados de uma consulta
SQL. Uma View contém linhas e colunas, assim como uma tabela real. Os campos em
uma View são campos de uma ou mais tabelas reais no banco de dados. Quando você
consulta uma View, o banco de dados executa a consulta subjacente e apresenta os
resultados como se fossem de uma tabela.
Vantagens: * Simplificação de Consultas: Complexas junções e condições podem ser
encapsuladas em uma View, tornando as consultas subsequentes mais simples. *
Segurança: Permite que os usuários acessem apenas um subconjunto de dados de
uma tabela, ou apenas certas colunas, sem dar acesso total à tabela subjacente. *
Consistência: Garante que todos os usuários vejam os dados da mesma forma. *
Compatibilidade: Pode ser usada para compatibilidade com sistemas legados ou para
apresentar dados de forma diferente sem alterar a estrutura da tabela real.
Sintaxe Básica:
CREATE VIEW nome_da_view AS
SELECT coluna1, coluna2, ...
FROM tabela1
JOIN tabela2 ON condicao
WHERE condicao;

Exemplos Práticos:
1. View Simples para Livros em Estoque:
Vamos criar uma view que mostra apenas os livros que estão em estoque.
USE livraria;

CREATE VIEW livros_em_estoque AS


SELECT id_livro, titulo, preco, estoque
FROM livros
WHERE estoque > 0;

-- Para consultar a view:


SELECT * FROM livros_em_estoque;

2. View para Detalhes de Vendas:


Vamos criar uma view que combine informações de vendas, clientes e livros para ter
uma visão completa de cada item vendido.
USE livraria;

CREATE VIEW detalhes_vendas AS


SELECT
v.id_venda,
v.data_venda,
c.nome AS NomeCliente,
c.sobrenome AS SobrenomeCliente,
l.titulo AS TituloLivro,
iv.quantidade,
iv.preco_unitario,
(iv.quantidade * iv.preco_unitario) AS SubtotalItem
FROM vendas v
INNER JOIN clientes c ON v.id_cliente = c.id_cliente
INNER JOIN itens_venda iv ON v.id_venda = iv.id_venda
INNER JOIN livros l ON iv.id_livro = l.id_livro;

-- Para consultar a view:


SELECT * FROM detalhes_vendas;

-- Você pode até filtrar a view:


SELECT * FROM detalhes_vendas
WHERE NomeCliente = 'Ana';

3. View para Autores e Quantidade de Livros:


USE livraria;

CREATE VIEW autores_com_quantidade_livros AS


SELECT
a.nome AS NomeAutor,
a.sobrenome AS SobrenomeAutor,
COUNT(l.id_livro) AS QuantidadeLivros
FROM autores a
LEFT JOIN livros l ON a.id_autor = l.id_autor
GROUP BY a.id_autor, a.nome, a.sobrenome;

-- Para consultar a view:


SELECT * FROM autores_com_quantidade_livros
WHERE QuantidadeLivros > 1;

Atualizando Dados através de Views:


Em alguns casos, é possível usar INSERT , UPDATE e DELETE em Views, mas há
restrições: * A View deve ser baseada em uma única tabela. * Não pode conter funções
de agregação ( SUM , COUNT , etc.), GROUP BY , HAVING , UNION , DISTINCT . * Não pode
conter subconsultas na cláusula FROM . * Todas as colunas NOT NULL da tabela base
devem estar presentes na View.
Se a View for complexa ou envolver múltiplas tabelas, as operações DML geralmente
não são permitidas ou podem ter comportamentos inesperados. Nesses casos, é
melhor manipular os dados diretamente nas tabelas base.
Excluindo uma View:
DROP VIEW IF EXISTS nome_da_view;

Triggers e Views são ferramentas poderosas para estender a funcionalidade do seu


banco de dados e melhorar a forma como os dados são gerenciados e acessados. Eles
são amplamente utilizados em aplicações do mundo real para otimizar processos e
garantir a integridade e segurança dos dados.
4.3 Abordando Índices e Otimização de Consultas
A otimização de consultas é um aspecto crucial no desenvolvimento de bancos de
dados, especialmente à medida que o volume de dados cresce. Consultas lentas
podem impactar significativamente o desempenho de uma aplicação. Índices são uma
das ferramentas mais eficazes para acelerar a recuperação de dados, e entender como
otimizar suas consultas é uma habilidade valiosa.
4.3.1 O que são Índices?
Um índice é uma estrutura de dados especial que melhora a velocidade das operações
de recuperação de dados em uma tabela. Pense em um índice de banco de dados
como o índice de um livro: em vez de ler o livro inteiro para encontrar uma informação,
você consulta o índice para encontrar rapidamente a página onde a informação está
localizada. Da mesma forma, um índice em um banco de dados permite que o SGBD
localize rapidamente as linhas de dados sem ter que escanear a tabela inteira.
Como Funcionam os Índices:
Quando você cria um índice em uma ou mais colunas de uma tabela, o MySQL cria
uma estrutura de dados (geralmente uma árvore B-Tree) que armazena os valores
dessas colunas em uma ordem classificada, juntamente com ponteiros para as linhas
correspondentes na tabela. Quando uma consulta é executada e envolve as colunas
indexadas, o MySQL pode usar o índice para encontrar os dados de forma muito mais
eficiente.
Tipos de Índices no MySQL:
Índice Primário ( PRIMARY KEY ): Automaticamente criado quando você define
uma PRIMARY KEY em uma tabela. Garante que os valores na coluna sejam
únicos e não nulos. Uma tabela pode ter apenas um índice primário.
Índice Único ( UNIQUE ): Garante que todos os valores na coluna (ou conjunto de
colunas) sejam únicos. Permite valores NULL (mas apenas uma vez). É criado
automaticamente quando você define uma restrição UNIQUE .
Índice Simples ( INDEX ): O tipo mais comum de índice. Não impõe unicidade ou
não nulidade. Usado para acelerar consultas em colunas frequentemente usadas
em cláusulas WHERE , JOIN , ORDER BY ou GROUP BY .
Índice de Texto Completo ( FULLTEXT ): Usado para pesquisa de texto em
colunas de texto ( TEXT , VARCHAR , CHAR ). Permite pesquisas de palavras e frases
dentro de grandes blocos de texto.
Índice Espacial ( SPATIAL ): Usado para dados geográficos (tipos GEOMETRY ).
Quando Usar Índices:
Em colunas usadas frequentemente na cláusula WHERE para filtrar dados.
Em colunas usadas em JOIN s para conectar tabelas.
Em colunas usadas em ORDER BY para ordenar resultados.
Em colunas usadas em GROUP BY para agrupar resultados.
Em colunas com alta cardinalidade (muitos valores distintos).
Quando Evitar Índices (ou Usar com Cautela):
Em tabelas pequenas, onde o benefício de desempenho é mínimo e o custo de
manutenção do índice pode ser maior.
Em colunas com baixa cardinalidade (poucos valores distintos), como uma
coluna sexo ( M/F ).
Em tabelas com muitas operações de INSERT , UPDATE e DELETE , pois cada
modificação de dados exige que o índice seja atualizado, o que pode diminuir o
desempenho dessas operações.
Em colunas que são raramente consultadas.
Sintaxe para Criar Índices:
-- Criar um índice simples
CREATE INDEX idx_nome_coluna ON nome_da_tabela (nome_da_coluna);

-- Criar um índice único


CREATE UNIQUE INDEX idx_nome_coluna_unico ON nome_da_tabela (nome_da_coluna);

-- Criar um índice em múltiplas colunas (índice composto)


CREATE INDEX idx_coluna1_coluna2 ON nome_da_tabela (coluna1, coluna2);

Exemplo Prático:
Vamos criar um índice na coluna genero da tabela livros , pois é provável que
consultemos livros por gênero frequentemente.
USE livraria;

CREATE INDEX idx_livros_genero ON livros (genero);

Excluindo um Índice:
DROP INDEX idx_nome_coluna ON nome_da_tabela;

4.3.2 Otimização de Consultas


A otimização de consultas é o processo de melhorar o desempenho das suas
instruções SQL. Além de usar índices, existem várias outras práticas e ferramentas que
podem ajudar.
1. Use EXPLAIN para Analisar Consultas:
O comando EXPLAIN é uma ferramenta poderosa no MySQL que mostra como o
servidor de banco de dados executa uma consulta SELECT . Ele fornece informações
sobre a ordem das junções, quais índices são usados, como as tabelas são acessadas e
muito mais. Analisar a saída do EXPLAIN é o primeiro passo para identificar gargalos
de desempenho.
Sintaxe:
EXPLAIN SELECT ... FROM ... WHERE ...;

Exemplo:
USE livraria;

EXPLAIN SELECT titulo, preco FROM livros WHERE genero = 'Romance';

Saída Típica do EXPLAIN (colunas importantes):


id : Identificador da consulta.

select_type : Tipo de SELECT (SIMPLE, PRIMARY, SUBQUERY, DERIVED, etc.).

table : A tabela à qual a linha de saída se refere.

type : O tipo de junção. Indica como o MySQL procura as linhas na tabela. Os


tipos mais eficientes são system , const , eq_ref , ref , range . ALL (full table
scan) é o pior.
possible_keys : Índices que o MySQL poderia usar.

key : O índice que o MySQL realmente escolheu usar.

key_len : O comprimento da chave usada.

ref : Quais colunas ou constantes são usadas com a key para selecionar linhas.

rows : O número estimado de linhas que o MySQL precisa examinar para


executar a consulta. Quanto menor, melhor.
Extra : Informações adicionais sobre como o MySQL resolve a consulta (e.g.,
Using where , Using index , Using filesort , Using temporary ).

Interpretando EXPLAIN :
Se type for ALL , significa que o MySQL está fazendo um full table scan, o que é
lento para tabelas grandes. Considere adicionar um índice.
Se key for NULL , nenhum índice foi usado. Verifique se há índices apropriados
ou se a consulta pode ser reescrita para usá-los.
Using filesort em Extra indica que o MySQL precisa ordenar os resultados
no disco, o que é lento. Um índice na coluna ORDER BY pode ajudar.
Using temporary em Extra indica que o MySQL está usando uma tabela
temporária, o que também é lento. Isso pode ocorrer com GROUP BY ou
DISTINCT em colunas não indexadas.

2. Escreva Consultas Eficientes:


Selecione Apenas o Necessário: Evite SELECT * . Selecione apenas as colunas
que você realmente precisa. Isso reduz o tráfego de rede e o uso de memória.
Use WHERE para Filtrar Cedo: Filtre os dados o mais cedo possível na consulta
para reduzir o número de linhas a serem processadas.
Evite Funções em Colunas Indexadas na Cláusula WHERE : Se você aplicar uma
função a uma coluna indexada na cláusula WHERE (ex: WHERE YEAR(data) =
2023 ), o MySQL pode não conseguir usar o índice. Em vez disso, reescreva a
condição para que o índice possa ser usado (ex: WHERE data BETWEEN '2023-01-
01' AND '2023-12-31' ).

Cuidado com LIKE com % no Início: LIKE '%termo' não pode usar um índice,
pois o padrão começa com um curinga. LIKE 'termo%' pode usar um índice.
Otimize JOIN s: Certifique-se de que as colunas usadas na cláusula ON dos
JOIN s estejam indexadas.

Evite Subconsultas Correlacionadas Complexas: Embora úteis, subconsultas


correlacionadas podem ser lentas. Considere reescrevê-las como JOIN s quando
possível.
Use LIMIT para Paginação: Para consultas que retornam muitos resultados, use
LIMIT para paginar os dados e evitar carregar tudo de uma vez.

Normalização e Desnormalização: Um esquema de banco de dados bem


normalizado (evitando redundância) é geralmente bom para integridade de
dados. No entanto, para consultas de leitura intensiva, a desnormalização
controlada (adicionar dados redundantes ou combinar tabelas) pode melhorar o
desempenho, mas deve ser feita com cautela para evitar problemas de
integridade.
3. Configuração do Servidor MySQL:
Além da otimização de consultas e índices, a configuração do próprio servidor MySQL
desempenha um papel vital no desempenho. Parâmetros como
innodb_buffer_pool_size , query_cache_size (obsoleto em versões mais recentes),
max_connections , entre outros, podem ser ajustados para otimizar o uso de
memória, CPU e disco.
4. Hardware:
Por fim, o hardware subjacente (CPU, RAM, tipo de disco - SSDs são muito mais rápidos
para I/O de banco de dados) tem um impacto direto no desempenho do banco de
dados. Um servidor bem configurado em hardware adequado é essencial para
aplicações de alto desempenho.
A otimização é um processo contínuo de monitoramento, análise e ajuste. Ao
combinar o uso inteligente de índices com a escrita de consultas eficientes e a
configuração adequada do servidor, você pode garantir que seu banco de dados
MySQL opere com o melhor desempenho possível.
5.2 Exercícios Práticos
Execute o script livraria_setup.sql no seu MySQL Workbench ou terminal para
criar e popular o banco de dados livraria antes de iniciar os exercícios. Isso
garantirá que você tenha os dados necessários para praticar.
Exercícios do Módulo 1: Conceitos Fundamentais e DDL/DML Introdutório
1. Criação de Banco de Dados e Tabela:
Crie um novo banco de dados chamado escola .
Dentro do banco de dados escola , crie uma tabela chamada alunos com
as seguintes colunas:
id_aluno (inteiro, chave primária, auto-incremento)

nome (texto, não nulo)

sobrenome (texto, não nulo)

data_nascimento (data)

email (texto, único, não nulo)

2. Inserção de Dados:
Insira 3 alunos na tabela alunos com dados de sua escolha.
3. Atualização de Dados:
Atualize o email de um dos alunos que você inseriu.
4. Exclusão de Dados:
Exclua um aluno da tabela alunos .
5. Modificação de Tabela:
Adicione uma nova coluna chamada telefone (VARCHAR(20)) à tabela
alunos .

Modifique a coluna nome para ter um tamanho máximo de 150 caracteres.


6. Exclusão de Tabela e Banco de Dados:
Exclua a tabela alunos .
Exclua o banco de dados escola .
Exercícios do Módulo 2: Consultas SELECT Básicas
Use o banco de dados livraria para os exercícios a seguir.
1. Seleção Básica:
Selecione todas as colunas de todos os autores.
Selecione o título e o preço de todos os livros.
2. Renomeando Colunas:
Selecione o nome e sobrenome dos clientes, renomeando as colunas para
PrimeiroNome e UltimoNome .

3. Filtrando Resultados ( WHERE ):


Encontre todos os livros com estoque menor que 100 unidades.
Liste os autores nascidos antes de 1900.
Selecione os livros cujo gênero é 'Romance' e o preço é maior que 30.00.
Encontre clientes cujo email contém 'email.com'.
Liste os livros que não são do gênero 'Distopia'.
4. Ordenando Resultados ( ORDER BY ):
Liste todos os livros ordenados pelo título em ordem alfabética crescente.
Liste os autores ordenados pela nacionalidade (crescente) e depois pelo
sobrenome (crescente).
Encontre os 5 livros mais caros.
5. Limitando Resultados ( LIMIT ):
Selecione os 3 livros mais recentes (pelo ano de publicação).
Simule a paginação: selecione os livros da
segunda página, considerando 3 livros por página (ou seja, pule os primeiros 3 e pegue
os próximos 3).
Exercícios do Módulo 3: Consultas Intermediárias (JOINs, Funções e Subconsultas)
Use o banco de dados livraria para os exercícios a seguir.
1. INNER JOIN :
Liste o título de cada livro e o nome completo do autor correspondente.
Mostre o nome do cliente e o título dos livros que ele comprou.
2. LEFT JOIN :
Liste todos os autores e, para cada um, o título dos livros que escreveu.
Inclua autores que não escreveram nenhum livro em nosso registro.
Liste todos os clientes e, para cada um, o ID da venda que ele realizou.
Inclua clientes que não fizeram nenhuma compra.
3. Funções de Agregação e GROUP BY :
Calcule o número total de livros por gênero.
Encontre o preço médio dos livros para cada nacionalidade de autor.
Determine o valor total de vendas para cada cliente.
Conte quantos livros cada autor escreveu.
4. HAVING :
Liste os gêneros que têm mais de 2 livros cadastrados.
Encontre os autores que escreveram livros com um preço médio superior a
30.00.
Liste os clientes que realizaram mais de uma compra.
5. Subconsultas na Cláusula WHERE :
Encontre o título dos livros que foram escritos por autores britânicos.
Liste os clientes que compraram o livro "Dom Casmurro".
Selecione os livros cujo preço é maior que o preço médio de todos os livros.
Encontre os autores que não têm nenhum livro registrado na livraria.
6. Subconsultas na Cláusula FROM (Tabelas Derivadas):
Liste o nome dos autores e a quantidade de livros que cada um escreveu,
mas apenas para autores que escreveram 2 ou mais livros. (Use uma
subconsulta no FROM).
7. Subconsultas na Cláusula SELECT (Escalares):
Para cada livro, mostre o título e o nome completo do autor ao lado.
Para cada venda, mostre o ID da venda, a data e o nome completo do
cliente que a realizou.
Exercícios do Módulo 4: Recursos Avançados e Otimização
Use o banco de dados livraria para os exercícios a seguir.
1. Stored Procedures:
Crie uma Stored Procedure chamada ObterLivrosPorAutor que receba o
id_autor como parâmetro de entrada e retorne todos os livros daquele
autor.
Crie uma Stored Procedure chamada RegistrarNovaVenda que receba o
id_cliente e o valor_total como parâmetros e insira uma nova venda
na tabela vendas . A procedure deve retornar o id_venda gerado.
Crie uma Stored Procedure que receba o id_livro e uma
nova_quantidade e atualize o estoque do livro. Se a nova_quantidade for
negativa, a procedure deve exibir uma mensagem de erro.
2. Functions:
Crie uma Function chamada CalcularDesconto que receba um valor e
uma porcentagem_desconto e retorne o valor com o desconto aplicado.
Crie uma Function que receba o id_cliente e retorne o número total de
compras que o cliente fez.
3. Triggers:
Crie um trigger BEFORE INSERT na tabela livros que, se o estoque for
inserido como um valor negativo, ele seja automaticamente ajustado para
0.
Crie um trigger AFTER UPDATE na tabela livros que, se o preco de um
livro for alterado, registre a alteração (id do livro, preço antigo, preço novo,
data da alteração) em uma nova tabela de auditoria de preços
( auditoria_precos_livros ).
4. Views:
Crie uma View chamada LivrosPorAutor que mostre o título do livro, o
nome do autor e a nacionalidade do autor.
Crie uma View chamada VendasPorCliente que liste o nome completo do
cliente, o número total de vendas que ele fez e o valor total gasto por ele.
Crie uma View que mostre os funcionários e seus respectivos gerentes,
incluindo o cargo de ambos.
5. Otimização ( EXPLAIN ):
Execute EXPLAIN em uma consulta que você acha que pode ser lenta (por
exemplo, uma consulta sem WHERE em uma tabela grande, ou uma
consulta com `LIKE
Analise a saída do EXPLAIN e identifique possíveis gargalos. Se possível,
crie um índice para otimizar a consulta e execute EXPLAIN novamente para
ver a diferença.
5.3 Soluções dos Exercícios Práticos
Soluções dos Exercícios do Módulo 1: Conceitos Fundamentais e DDL/DML
Introdutório
1. Criação de Banco de Dados e Tabela: sql CREATE DATABASE escola; USE
escola; CREATE TABLE alunos ( id_aluno INT AUTO_INCREMENT PRIMARY
KEY, nome VARCHAR(100) NOT NULL, sobrenome VARCHAR(100) NOT NULL,
data_nascimento DATE, email VARCHAR(255) UNIQUE NOT NULL );

2. Inserção de Dados: sql USE escola; INSERT INTO alunos (nome,


sobrenome, data_nascimento, email) VALUES ("João", "Silva", "2005-03-
15", "joao.silva@email.com"), ("Maria", "Souza", "2004-11-22",
"maria.souza@email.com"), ("Pedro", "Santos", "2006-07-01",
"pedro.santos@email.com");

3. Atualização de Dados: sql USE escola; UPDATE alunos SET email =


"joao.silva.novo@email.com" WHERE nome = "João" AND sobrenome =
"Silva";

4. Exclusão de Dados: sql USE escola; DELETE FROM alunos WHERE nome =
"Pedro" AND sobrenome = "Santos";

5. Modificação de Tabela: ```sql USE escola; ALTER TABLE alunos ADD COLUMN
telefone VARCHAR(20);
ALTER TABLE alunos MODIFY COLUMN nome VARCHAR(150) NOT NULL; ```
6. Exclusão de Tabela e Banco de Dados: ```sql USE escola; DROP TABLE alunos;
DROP DATABASE escola; ```
Soluções dos Exercícios do Módulo 2: Consultas SELECT Básicas
Use o banco de dados livraria .
1. Seleção Básica: sql USE livraria; SELECT * FROM autores; SELECT titulo,
preco FROM livros;
2. Renomeando Colunas: sql USE livraria; SELECT nome AS PrimeiroNome,
sobrenome AS UltimoNome FROM clientes;

3. Filtrando Resultados ( WHERE ): sql USE livraria; SELECT titulo, estoque


FROM livros WHERE estoque < 100; SELECT nome, sobrenome,
data_nascimento FROM autores WHERE YEAR(data_nascimento) < 1900;
SELECT titulo, genero, preco FROM livros WHERE genero = 'Romance' AND
preco > 30.00; SELECT nome, sobrenome, email FROM clientes WHERE
email LIKE '%email.com%'; SELECT titulo, genero FROM livros WHERE
genero != 'Distopia';

4. Ordenando Resultados ( ORDER BY ): sql USE livraria; SELECT titulo FROM


livros ORDER BY titulo ASC; SELECT nacionalidade, sobrenome, nome
FROM autores ORDER BY nacionalidade ASC, sobrenome ASC; SELECT
titulo, preco FROM livros ORDER BY preco DESC LIMIT 5;

5. Limitando Resultados ( LIMIT ): sql USE livraria; SELECT titulo,


ano_publicacao FROM livros ORDER BY ano_publicacao DESC LIMIT 3;
SELECT titulo, preco FROM livros ORDER BY titulo ASC LIMIT 3, 3;

Soluções dos Exercícios do Módulo 3: Consultas Intermediárias (JOINs, Funções e


Subconsultas)
Use o banco de dados livraria .
1. INNER JOIN : ```sql USE livraria; SELECT l.titulo, a.nome, a.sobrenome FROM
livros l INNER JOIN autores a ON l.id_autor = a.id_autor;
SELECT c.nome AS NomeCliente, c.sobrenome AS SobrenomeCliente, l.titulo AS
TituloLivro FROM clientes c INNER JOIN vendas v ON c.id_cliente = v.id_cliente
INNER JOIN itens_venda iv ON v.id_venda = iv.id_venda INNER JOIN livros l ON
iv.id_livro = l.id_livro; ```
2. LEFT JOIN : ```sql USE livraria; SELECT a.nome, a.sobrenome, l.titulo FROM
autores a LEFT JOIN livros l ON a.id_autor = l.id_autor;
SELECT c.nome, c.sobrenome, v.id_venda FROM clientes c LEFT JOIN vendas v
ON c.id_cliente = v.id_cliente; ```
3. Funções de Agregação e GROUP BY : ```sql USE livraria; SELECT genero,
COUNT(*) AS TotalLivros FROM livros GROUP BY genero;
SELECT a.nacionalidade, AVG(l.preco) AS PrecoMedioLivros FROM autores a
INNER JOIN livros l ON a.id_autor = l.id_autor GROUP BY a.nacionalidade;
SELECT c.nome, c.sobrenome, SUM(v.valor_total) AS ValorTotalVendas FROM
clientes c INNER JOIN vendas v ON c.id_cliente = v.id_cliente GROUP BY
c.id_cliente, c.nome, c.sobrenome;
SELECT a.nome, a.sobrenome, COUNT(l.id_livro) AS QuantidadeLivros FROM
autores a LEFT JOIN livros l ON a.id_autor = l.id_autor GROUP BY a.id_autor,
a.nome, a.sobrenome; ```
4. HAVING : ```sql USE livraria; SELECT genero, COUNT() AS TotalLivros FROM livros
GROUP BY genero HAVING COUNT() > 2;
SELECT a.nome, a.sobrenome, AVG(l.preco) AS PrecoMedioLivros FROM autores a
INNER JOIN livros l ON a.id_autor = l.id_autor GROUP BY a.id_autor, a.nome,
a.sobrenome HAVING AVG(l.preco) > 30.00;
SELECT c.nome, c.sobrenome, COUNT(v.id_venda) AS TotalCompras FROM
clientes c INNER JOIN vendas v ON c.id_cliente = v.id_cliente GROUP BY
c.id_cliente, c.nome, c.sobrenome HAVING COUNT(v.id_venda) > 1; ```
5. Subconsultas na Cláusula WHERE : ```sql USE livraria; SELECT titulo FROM
livros WHERE id_autor IN ( SELECT id_autor FROM autores WHERE nacionalidade
= 'Britânica' );
SELECT c.nome, c.sobrenome FROM clientes c WHERE c.id_cliente IN ( SELECT
v.id_cliente FROM vendas v INNER JOIN itens_venda iv ON v.id_venda =
iv.id_venda INNER JOIN livros l ON iv.id_livro = l.id_livro WHERE l.titulo = 'Dom
Casmurro' );
SELECT titulo, preco FROM livros WHERE preco > ( SELECT AVG(preco) FROM
livros );
SELECT nome, sobrenome FROM autores WHERE id_autor NOT IN ( SELECT
DISTINCT id_autor FROM livros ); ```
6. Subconsultas na Cláusula FROM (Tabelas Derivadas): sql USE livraria;
SELECT a.nome, a.sobrenome, sub.QuantidadeLivros FROM autores a INNER
JOIN ( SELECT id_autor, COUNT(id_livro) AS QuantidadeLivros FROM
livros GROUP BY id_autor HAVING COUNT(id_livro) >= 2 ) AS sub ON
a.id_autor = sub.id_autor;

7. Subconsultas na Cláusula SELECT (Escalares): ```sql USE livraria; SELECT


titulo, (SELECT CONCAT(nome, ' ', sobrenome) FROM autores WHERE
autores.id_autor = livros.id_autor) AS AutorDoLivro FROM livros;
SELECT id_venda, data_venda, (SELECT CONCAT(nome, ' ', sobrenome) FROM
clientes WHERE clientes.id_cliente = vendas.id_cliente) AS NomeCliente FROM
vendas; ```
Soluções dos Exercícios do Módulo 4: Recursos Avançados e Otimização
Use o banco de dados livraria .
1. Stored Procedures:
ObterLivrosPorAutor : ```sql USE livraria; DELIMITER // CREATE
PROCEDURE ObterLivrosPorAutor(IN autor_id INT) BEGIN SELECT titulo,
genero, preco, estoque FROM livros WHERE id_autor = autor_id; END //
DELIMITER ;
-- Teste: CALL ObterLivrosPorAutor(1); * `RegistrarNovaVenda`: sql USE
livraria; DELIMITER // CREATE PROCEDURE RegistrarNovaVenda( IN
cliente_id INT, IN valor_total_venda DECIMAL(10, 2), OUT nova_venda_id
INT ) BEGIN INSERT INTO vendas (id_cliente, valor_total) VALUES
(cliente_id, valor_total_venda); SET nova_venda_id = LAST_INSERT_ID();
END // DELIMITER ;
-- Teste: CALL RegistrarNovaVenda(4, 50.00, @venda_id); SELECT
@venda_id AS NovaVendaID; SELECT * FROM vendas WHERE id_venda =
@venda_id; * Procedure para atualizar estoque com validação: sql
USE livraria; DELIMITER // CREATE PROCEDURE
AtualizarEstoqueLivroValidado( IN livro_id INT, IN quantidade_alterar INT )
BEGIN IF (SELECT estoque FROM livros WHERE id_livro = livro_id) +
quantidade_alterar < 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT
= 'Estoque insuficiente para esta operação.'; ELSE UPDATE livros SET
estoque = estoque + quantidade_alterar WHERE id_livro = livro_id; SELECT
CONCAT('Estoque do livro ', livro_id, ' atualizado com sucesso.') AS
Mensagem; END IF; END // DELIMITER ;
-- Teste: SELECT titulo, estoque FROM livros WHERE id_livro = 1; CALL
AtualizarEstoqueLivroValidado(1, -5); -- Diminui 5 SELECT titulo, estoque
FROM livros WHERE id_livro = 1; -- Tente um valor que deixaria o estoque
negativo (pode precisar ajustar o valor para testar o erro) -- CALL
AtualizarEstoqueLivroValidado(1, -1000); ```
2. Functions:
CalcularDesconto : ```sql USE livraria; DELIMITER // CREATE FUNCTION
CalcularDesconto(valor DECIMAL(10, 2), porcentagem_desconto
DECIMAL(5, 2)) RETURNS DECIMAL(10, 2) DETERMINISTIC BEGIN RETURN
valor - (valor * porcentagem_desconto / 100); END // DELIMITER ;
-- Teste: SELECT CalcularDesconto(100.00, 10) AS ValorComDesconto; *
Função para total de compras do cliente: sql USE livraria; DELIMITER
// CREATE FUNCTION TotalComprasCliente(cliente_id INT) RETURNS INT
READS SQL DATA BEGIN DECLARE total_compras INT; SELECT
COUNT(id_venda) INTO total_compras FROM vendas WHERE id_cliente =
cliente_id; RETURN total_compras; END // DELIMITER ;
-- Teste: SELECT nome, sobrenome, TotalComprasCliente(id_cliente) AS
NumeroDeCompras FROM clientes; ```
3. Triggers:
Trigger BEFORE INSERT para livros (estoque negativo para 0): ```sql USE
livraria; DELIMITER // CREATE TRIGGER trg_before_insert_livros_estoque
BEFORE INSERT ON livros FOR EACH ROW BEGIN IF NEW.estoque < 0 THEN
SET NEW.estoque = 0; END IF; END // DELIMITER ;
-- Teste: INSERT INTO livros (titulo, id_autor, ano_publicacao, isbn, genero,
preco, estoque) VALUES ('Livro Teste Estoque Negativo', 1, 2024,
'9999999999999', 'Teste', 10.00, -5); SELECT titulo, estoque FROM livros
WHERE titulo = 'Livro Teste Estoque Negativo'; * Trigger `AFTER UPDATE`
para auditoria de preços: sql USE livraria; CREATE TABLE IF NOT EXISTS
auditoria_precos_livros ( id_auditoria INT AUTO_INCREMENT PRIMARY KEY,
id_livro INT, preco_antigo DECIMAL(10, 2), preco_novo DECIMAL(10, 2),
data_alteracao DATETIME DEFAULT CURRENT_TIMESTAMP,
usuario_alteracao VARCHAR(100) DEFAULT USER() );
DELIMITER // CREATE TRIGGER trg_after_update_livros_preco AFTER
UPDATE ON livros FOR EACH ROW BEGIN IF OLD.preco <> NEW.preco THEN
INSERT INTO auditoria_precos_livros (id_livro, preco_antigo, preco_novo)
VALUES (OLD.id_livro, OLD.preco, NEW.preco); END IF; END // DELIMITER ;
-- Teste: SELECT * FROM livros WHERE id_livro = 1; UPDATE livros SET preco
= 36.50 WHERE id_livro = 1; SELECT * FROM auditoria_precos_livros; ```
4. Views:
LivrosPorAutor : ```sql USE livraria; CREATE VIEW LivrosPorAutor AS
SELECT l.titulo AS TituloLivro, a.nome AS NomeAutor, a.sobrenome AS
SobrenomeAutor, a.nacionalidade AS NacionalidadeAutor FROM livros l
INNER JOIN autores a ON l.id_autor = a.id_autor;
-- Teste: SELECT * FROM LivrosPorAutor; * `VendasPorCliente`: sql USE
livraria; CREATE VIEW VendasPorCliente AS SELECT c.nome AS
NomeCliente, c.sobrenome AS SobrenomeCliente, COUNT(v.id_venda) AS
TotalVendas, SUM(v.valor_total) AS ValorTotalGasto FROM clientes c INNER
JOIN vendas v ON c.id_cliente = v.id_cliente GROUP BY c.id_cliente, c.nome,
c.sobrenome;
-- Teste: SELECT * FROM VendasPorCliente; * View para funcionários e
gerentes: sql USE livraria; CREATE VIEW FuncionariosGerentes AS SELECT
f.nome AS Funcionario, f.cargo AS CargoFuncionario, g.nome AS Gerente,
g.cargo AS CargoGerente FROM funcionarios f LEFT JOIN funcionarios g ON
f.gerente_id = g.id_funcionario;
-- Teste: SELECT * FROM FuncionariosGerentes; ```
5. Otimização ( EXPLAIN ):
Exemplo de EXPLAIN e otimização: ```sql USE livraria;
-- Consulta original (pode ser lenta sem índice em 'genero') EXPLAIN SELECT
titulo, preco FROM livros WHERE genero = 'Romance';
-- Se o 'type' for 'ALL' e 'key' for NULL, um índice pode ajudar. -- Criar índice
(se ainda não existir do script de setup): -- CREATE INDEX idx_livros_genero
ON livros (genero);
-- Executar EXPLAIN novamente após criar o índice para ver a diferença
EXPLAIN SELECT titulo, preco FROM livros WHERE genero = 'Romance'; --
Agora, 'type' deve ser 'ref' ou 'range' e 'key' deve mostrar
'idx_livros_genero'. ```
Com a conclusão dos exercícios e suas soluções, você tem um material completo para
praticar e aprofundar seus conhecimentos em SQL com MySQL. Lembre-se que a
prática constante é a chave para a maestria!

Você também pode gostar