Entenda Banco de Dados Relacionais - Com exemplos práticos, vem comigo?
- #SQL
- #Banco de dados relacional
- #MySQL
Este artigo tem como finalidade trazer um overview de tudo que você precisa saber a respeito de banco de dados relacionais antes de começar a estuda-los.
Mas calma, quero deixar extremamente mastigado para você. Caso seja seu primeiro contato pode parecer muita informação, mas acredite em mim, a medida que você se aprofunda e os conceitos são assimilados, chegará o ponto que você terá um start e tudo ficará mais claro, preparado(a)?
Para um melhor aproveitamento, sugiro que você instale MySQL Workbench para acompanhar este conteúdo, caso tenha alguma dificuldade em instalar esse SGBD consulte a documentação.
Antes de mais nada, vamos falar de entidades, que são a abstração de algo do mundo real que queremos representar em forma de tabela em nosso BD.
Uma tabela nada mais é, do que nossa entidade compostas por propriedades/atributos e seus tipos. Temos:
Imagem representa sistema ER (Entidade e Relacionamento)
Com o Workbenk em funcionamento, abre uma nova query.
Click no SLQ File que se abrirá e cole o código abaixo e acompanhe os exemplos citados.
Para executar o script click no raio ⚡, sugiro que você coloque na ordem que esta disposto neste artigo (ou seja, copie e cole um abaixo do outro no mesmo script), sempre clicando no raio para executar, caso não tenha familiaridade.
DROP DATABASE IF EXISTS Hospital;
-- Criando DataBase
CREATE DATABASE Hospital;
USE Hospital;
-- Criando tabela Medico
CREATE TABLE Medico (
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
nome VARCHAR(45) NOT NULL,
crm VARCHAR(45) NOT NULL
);
-- Criando tabela Paciente
CREATE TABLE Paciente (
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
nome VARCHAR(45) NOT NULL,
cpf VARCHAR(11) NOT NULL
);
Nossas propriedades possuem tipos, que restringem os dados armazenados ao tipo passado para cada propriedade, ou seja, se você tentar adicionar um valor INT a um campo VARCHAR por exemplo, irá gerar um erro. (Não será abordado cada tipo de dado SQL neste artigo).
Antes de te mostrar como funciona os relacionamentos preciso que você entenda o que são Foreign Key e Primary Key.
-- Criando tabela Consulta
CREATE TABLE Consulta (
id INT AUTO_INCREMENT NOT NULL,
medico_id INT NOT NULL,
paciente_id INT NOT NULL,
data DATETIME NOT NULL,
CONSTRAINT `pk_consulta` PRIMARY KEY (id),
CONSTRAINT `fk_medico` FOREIGN KEY (medico_id) REFERENCES Medico(id),
CONSTRAINT `fk_paciente` FOREIGN KEY (paciente_id) REFERENCES Paciente(id)
);
-- Inserindo dados tabela Medico
INSERT INTO Medico(nome,crm) VALUES
("Gabriel","XXX.XXX.XXX"),
("Fabio","YYY.YYY.YYY");
-- Inserindo dados tabela Paciente
INSERT INTO Paciente(nome, cpf) VALUES
("Carlos","12345678912"),
("Hermes","14785236985");
-- Inserindo dado tabela Consulta
Insert INTO Consulta(medico_id,paciente_id,data) VALUES -- NOTE: NÃO FOI PASSADO id, como parâmetro em Consulta.
(1,1,now()),
(2,2,now());
Ao inserirmos dados na tabela Consulta, conforme no comando acima resultará no que chamo de evento. (Entenda evento como toda ocorrência de determinada entidade, representada por cada linha de um SELECT * <table> por exemplo).
SELECT * FROM Consulta;
Note que não adicionamos um campo para a propriedade id no bloco de código acima, porém ele foi preenchido automaticamente pelo AUTO_INCREMENT, como ela é uma Primary Key, ela é única, não haverá outra consulta com mesmo Id, da mesma maneira quando adicionamos um paciente ou médico ao sistema, este terá um Id único por serem pk.
Conclusão:
Foreign Key é uma referência que aponta para um evento de determinada tabela onde os dados estão realmente armazenados.
Enquanto Primary Key é o que garante que cada evento de uma tabela seja único.
Legal não é mesmo?
Você pode notar que cada informação fica presente em sua devida tabela, no entanto elas se relacionam de forma coerente de maneira que você consegue recupera-las posteriormente por meio de queries (pesquisas).
Agora que entendemos como funcionam fk e pk podemos partir para o entendimento dos relacionamentos.
Importante: Sempre que for identificado um relacionamento muitos para muitos (n:n), será gerado uma nova tabela.
Relacionamento 1:1 (lê-se 1 para 1)
Bom, vamos imaginar no contexto acima onde temos uma consulta, para seu entendimento imagine que nossa consulta possa gerar apenas uma receita no sistema, desta maneira criamos uma entidade receita que possui uma fk única que tem referência ao id da consulta. Isso implica que toda vez que uma receita for gerada será atrelada a uma consulta.
CREATE TABLE Receita (
consulta_id INT NOT NULL UNIQUE, -- É uma referência ao id da consulta
descricao VARCHAR(255) NOT NULL,
CONSTRAINT `fk_receita_consulta` fOREIGN KEY(consulta_id) REFERENCES Consulta(id)
);
Note: foi dispensado o uso de id na tabela receita, pois ao criarmos está relação de dependência com a tabela consulta, não haveria necessidade do mesmo.
ER - Com ênfase no relacionamento 1:1 descrito acima.
Relacionamento 1:n (lê-se 1 para muitos)
Observe o relacionamento entre paciente e consulta, há uma fk de Paciente em Consulta (quando digo isso, estou dizendo que em consulta há uma chave estrangeira com referência a um paciente na tabela Paciente, contendo todos seus dados), isso implica que um cliente pode ter uma ou mais consultas distintas.
Mas, Danilo, e se nossa fk estivesse na tabela paciente?
Bom, desta maneira você teria um paciente podendo ter apenas uma consulta, lembra-se da Primary Key? Ao tentarmos adicionar um mesmo paciente ao sistema, ocorreria um erro, pois o mesmo já existe. Não é isso que queremos com a abstração deste sistema não é mesmo? Caso um novo cliente for adicionado com o mesmo id, irá gerar um erro.
Note que passamos id como parâmetro para Paciente, no entanto já existe uma pk com este valor, causando o erro acima.
ER - 1:n entre Paciente e Consulta
É muito importante se atentar ao que nossas tabelas estão nos falando.
Relacionamento n:n (lê-se muitos para muitos)
Como dito anteriormente sempre que for identificado este relacionamento é necessário criar uma nova tabela.
No mesmo contexto de hospital, vamos criar uma tabela de endereços.
Temos:
CREATE TABLE Endereco (
id INT AUTO_INCREMENT NOT NULL,
cidade VARCHAR(45) NOT NULL,
estado CHAR(2) NOT NULL,
logradouro VARCHAR(45) NOT NULL,
numero VARCHAR(45) NOT NULL,
cep VARCHAR(45) NOT NULL,
CONSTRAINT `pk_endereco` PRIMARY KEY(id)
);
Você concorda comigo que um paciente pode ter um ou mais endereços? Da mesma forma um endereço pode pertencer a mais de uma pessoa? E essa analise que deve ser feita ao procurar o entendimento de seus relacionamentos, acabamos de evidenciar um relacionamento n:n. Segue o comando para cria este relacionamento por meio de uma nova tabela.
CREATE TABLE Endereco_Paciente (
id INT AUTO_INCREMENT NOT NULL,
endereco_id INT NOT NULL,
paciente_id INT NOT NULL,
CONSTRAINT `fk_endereco_cliente` FOREIGN KEY(endereco_id) REFERENCES Endereco(id),
CONSTRAINT `fk_cliente_endereco` FOREIGN KEY(paciente_id) REFERENCES Paciente(id),
CONSTRAINT `pk_endereco_paciente` PRIMARY KEY(id)
);
Ao inserirmos dados nesta tabela, estaremos fazendo referência ao id tanto de Paciente quanto de "Endereco", possibilitando que ambos possam ter mais de uma ocorrência do mesmo evento atrelados a um endereço ou paciente.
ER - relacionamento n:n entre as tabelas Paciente e Endereco (gerando uma nova tabela)
Entendido os tipos de relacionamentos, temos de manipular os dados.
Linguagem SQL
Caso não conheça a linguagem, os blocos de código acima são Stundard Query Language, utilizada para se manipular banco de dados. Ela é bastante intuitiva.
Dentre os comando mais usados estão.
SELECT - Seleciona
INSERT - Insere
UPDATE - Atualiza
DELETE - Deleta
"Há uma observação a ser feita sobre o DELETE. Nunca o execute sem o WHERE pois ele irá deletar seu montante de dados, caso não haja um backup feito, os mesmos serão perdidos, por isso muito cuidado ao utiliza-lo."
Como dito antes, é bastante intuitiva, não irei aborda-los pois não é o intuito deste material. No entanto quero você possa ter um norte legal a seguir em seus estudos, ao executar todos os comando acima, você terá um banco de dados simples onde poderá praticar e aprimorá-lo a medida que seus estudos avançam.
Recuperando dados
Note que nossas tabelas possuem dados concretos e em algumas possuem referência a eventos de outras tabelas. Queries são bastantes legais, eu particularmente gosto, é necessário juntar estas tabelas afim de receber dados que a primeira vista estão separados.
Para isso vamos inserir alguns dados.
-- Inserindo dados tabela Endereco
INSERT INTO Endereco(cidade, estado, logradouro, numero, cep) VALUES
("Cidade A",'AA',"Rua A", "1234","12345258"),
("Cidade B",'BB',"Rua B", "1235","12345364"),
("Cidade C",'CC',"Rua C", "1236","12345145"),
("Cidade D",'DD',"Rua D", "1237","12345245");
-- Inserindo dados tabela Endereco_Paciente
INSERT INTO Endereco_Paciente (endereco_id, paciente_id) VALUES
(4,1),(1,2),(1,1),(2,1),(3,2),(4,2);
O comando INNER JOIN é utilizado para juntar as informações que queremos buscar por nossas queries. Por meio do SELECT nos selecionamos os dados que queremos de determinadas tabelas onde SELECT * recupera todos os dados e ao se passar paramentos específicos a busca se torna mais objetiva como nos exemplos abaixo:
- Será buscado dados do médico e paciente atrelados as suas consultas. Meu intuito é mostrar que os dados armazenados podem ser recuperados dentro da coerência de seus contextos, porém para isso é necessário que seus relacionamentos estejam feitos de forma correta.
SELECT m.nome as `Nome do médico`,m.crm as `CRM MEDICO`, p.nome as `Nome do Paciente`, p.cpf as `CPF PACIENTE`, c.data as `Data da Consulta`
FROM Consulta as c INNER JOIN Paciente as p ON c.paciente_id = p.id
INNER JOIN Medico as m ON c.medico_id = m.id;
- Podemos ver os endereços de um determinado paciente, no caso o paciente de id = 1, com o uso do WHERE.
SELECT p.nome as `Nome`,e.cidade as `Cidade`, e.estado as `Estado`, e.logradouro as `Logradouro`,e.numero `numero`, e.cep as `CEP`
FROM Paciente as p INNER JOIN Endereco_Paciente as ep ON p.id = ep.paciente_id
INNER JOIN Endereco as e ON e.id = ep.endereco_id
WHERE p.id = 1
GROUP BY p.nome
ORDER BY e.cidade;
Comandos utilizados para filtrar ainda mais nossas queries.
WHERE - Filtra por determinado parâmetro
ORDER BY - Organiza pela ordem baseado no parâmetro que será passado
GROUP BY - Agrupa por determinado parâmetro
Conceitos Bônus 🎁✨
Trigger, "gatilhos". São comandos SQL que são executados quando uma determinada ação acontece dentro do banco de dados. Por exemplo, ao se inserir um determinado dado em uma tabela, um código SQL é disparado e preenche um campo automaticamente em outra.
Procedures, são "processo" que são realizados comumente dentro do banco, onde um script que executa uma determinada ação recorrente no BD é "salva" para ser chamada posteriormente, evitando que se escreva todo processo novamente.
Já as functions é necessário especificar seu retorno na construção das mesmas. A principal diferença entre elas e as procedures é que as functions retornam um valor podendo ser usadas em queries por exemplo.
Os exemplos acima foram feitos utilizando de MySQL WorkBench.
Um site bem legal que trás exemplos é o w3schools, lá além de SQL você encontra diversos outros tópicos para estudos.
Aprendemos sobre entidades e seus relacionamentos, acompanhamos exemplos práticos de criação, inserção e manipulação de dados, espero que gostem.
Abraços. Danilo.