O principal objetivo é:
- Redução da redundância: Menos dados repetidos, economizando espaço.
- Melhora da integridade dos dados: Menos chances de informações inconsistentes.
- Facilidade de atualização: Alterar uma informação em um só lugar.
- Maior flexibilidade: Estrutura mais adaptável a mudanças.
🛠️ Testando no Oracle Live SQL
🧱 Cenário Inicial: Um modelo não normalizado
Imagine que recebemos a seguinte tabela, contendo dados de notas de alunos em um curso:
Comando SQL:
--CRIAÇÃO DA TABELA CREATE TABLE notas_brutas ( AlunoID NUMBER, NomeAluno VARCHAR2(100), DisciplinaID NUMBER, NomeDisciplina VARCHAR2(100), ProfessorID NUMBER, NomeProfessor VARCHAR2(100), Nota NUMBER ); -- INSERÇÃO DOS DADOS INSERT INTO notas_brutas VALUES (1, 'João', 101, 'Matemática', 201, 'Silva', 8.5); INSERT INTO notas_brutas VALUES (2, 'Maria', 102, 'História', 202, 'Santos', 7.0); INSERT INTO notas_brutas VALUES (3, 'Pedro', 103, 'Geografia', 203, 'Oliveira', 9.0); INSERT INTO notas_brutas VALUES (1, 'João', 102, 'História', 202, 'Santos', 7.8); INSERT INTO notas_brutas VALUES (2, 'Maria', 103, 'Geografia', 203, 'Oliveira', 6.5); INSERT INTO notas_brutas VALUES (1, 'João', 104, 'Física', 204, 'Ferreira', 8.0); INSERT INTO notas_brutas VALUES (4, 'Ana', 101, 'Matemática', 201, 'Silva', 6.0); INSERT INTO notas_brutas VALUES (5, 'José', 102, 'História', 202, 'Santos', 9.2); INSERT INTO notas_brutas VALUES (3, 'Pedro', 104, 'Física', 204, 'Ferreira', 7.3); INSERT INTO notas_brutas VALUES (1, 'João', 105, 'Química', 205, 'Almeida', 8.9);
Essa estrutura pode parecer conveniente em um primeiro momento, mas possuí redundância, anomalias de atualização, inserção e exclusão, além de violação de boas práticas de modelagem relacional.
Problemas Observados:
- Redundância de dados: Nome do aluno, nome do professor e nome da disciplina se repetem.
- Dependências indiretas: O nome do professor depende da disciplina, não da nota.
- Atualizações inconsistentes: Se o nome de um professor mudar, é necessário atualizar em todas as linhas.
- Falta da chave primaria: Não existe uma chave primária definida.
✅ ETAPA 1 – Aplicando a 1ª Forma Normal (1FN)
Regras da 1FN:
- Os atributos devem conter valores atômicos (não multivalorados ou compostos).
- Não pode haver campos repetidos ou grupos de repetição.
- Toda tabela deve ter uma chave primária.
Problema: falta a chave primária.
Não Está em 1FN.
Considerando que:
- Um aluno pode cursar várias disciplinas.
- Uma disciplina pode ser cursada por vários alunos.
- Mas cada aluno só tem uma nota por disciplina.
--ADIÇÃO DA CHAVE PRIMARIA ALTER TABLE notas_brutas ADD CONSTRAINT notas_brutas_pk PRIMARY KEY(AlunoID,DisciplinaID);
✅ ETAPA 2 – Aplicando a 2ª Forma Normal (2FN)
Regras da 2FN:
- Deve estar em 1FN.
- Todos os atributos não-chave devem depender totalmente da chave primária (não parcialmente).
Problema: O campo NomeAluno depende apenas de AlunoID, não do par (AlunoID, DisciplinaID). Já o campo NomeDisciplina e NomeProfessor dependem apenas de DisciplinaID.
Solução: Separar os dados em entidades distintas.
- Alunos: (AlunoID, NomeAluno).
- Disciplinas: (DisciplinaID, NomeDisciplina).
- Professores: (ProfessorID, NomeProfessor).
- Notas: (AlunoID, DisciplinaID, Nota).
Agora, cada entidade representa uma tabela onde os atributos dependem da chave primária completa.
✅ A estrutura agora está em 2FN.
Comando SQL:
-- Tabela de Alunos CREATE TABLE alunos ( AlunoID NUMBER PRIMARY KEY, NomeAluno VARCHAR2(50) ); INSERT INTO alunos VALUES (1, 'João'); INSERT INTO alunos VALUES (2, 'Maria'); INSERT INTO alunos VALUES (3, 'Pedro'); INSERT INTO alunos VALUES (4, 'Ana'); INSERT INTO alunos VALUES (5, 'José'); -- Tabela de Professores CREATE TABLE professores ( ProfessorID NUMBER PRIMARY KEY, NomeProfessor VARCHAR2(50) ); INSERT INTO professores VALUES (201, 'Silva'); INSERT INTO professores VALUES (202, 'Santos'); INSERT INTO professores VALUES (203, 'Oliveira'); INSERT INTO professores VALUES (204, 'Ferreira'); INSERT INTO professores VALUES (205, 'Almeida'); -- Tabela de Disciplinas CREATE TABLE disciplinas ( DisciplinaID NUMBER PRIMARY KEY, NomeDisciplina VARCHAR2(50), ProfessorID NUMBER REFERENCES professores(ProfessorID) ); INSERT INTO disciplinas VALUES (101, 'Matemática', 201); INSERT INTO disciplinas VALUES (102, 'História', 202); INSERT INTO disciplinas VALUES (103, 'Geografia', 203); INSERT INTO disciplinas VALUES (104, 'Física', 204); INSERT INTO disciplinas VALUES (105, 'Química', 205); -- Tabela de Notas (relação Aluno-Disciplina) CREATE TABLE notas ( AlunoID NUMBER REFERENCES alunos(AlunoID), DisciplinaID NUMBER REFERENCES disciplinas(DisciplinaID), Nota NUMBER(3,1), PRIMARY KEY (AlunoID, DisciplinaID) ); -- Dados para tabela "notas" INSERT INTO notas VALUES (1, 101, 8.5); INSERT INTO notas VALUES (2, 102, 7.0); INSERT INTO notas VALUES (3, 103, 9.0); INSERT INTO notas VALUES (1, 102, 7.8); INSERT INTO notas VALUES (2, 103, 6.5); INSERT INTO notas VALUES (1, 104, 8.0); INSERT INTO notas VALUES (4, 101, 6.0); INSERT INTO notas VALUES (5, 102, 9.2); INSERT INTO notas VALUES (3, 104, 7.3); INSERT INTO notas VALUES (1, 105, 8.9);
✅ ETAPA 3 – Aplicando a 3ª Forma Normal (3FN)
Regras da 3FN:
- Deve estar em 2FN.
- Nenhum atributo não-chave pode depender transitivamente de atributos não chave.
O NomeProfessor depende de ProfessorID e já esta separado.
Solução: Na estrutura acima, NomeProfessor depende de ProfessorID, que já está separado. Portanto, a estrutura já está em 3FN.
✅ A estrutura está em 3FN.
Após a normalização, caso queira consultar os dados da mesma foram que eram exibidos na tabela sem a normalização, basta fazer um join entre as tabelas notas, alunas, disciplinas e professores.
Comando SQL:
SELECT
a.aluno_id,
a.nome AS nome_aluno,
d.disciplina_id,
d.nome AS nome_disciplina,
p.professor_id,
p.nome AS nome_professor,
n.nota
FROM notas n
JOIN alunos a ON n.aluno_id = a.aluno_id
JOIN disciplinas d ON n.disciplina_id = d.disciplina_id
JOIN professores p ON d.professor_id = p.professor_id
ORDER BY a.aluno_id, d.disciplina_id;
Comentários
Postar um comentário