Exemplo prático de normalização de banco de dados
Exemplo prático de normalização de banco de dados
A normalização de tabelas é um passo fundamental no design de um banco de dados e da arquitetura de um sistema. Este é um tutorial passo a passo sobre o tema.
Publicado em: 13/10/2010 Avaliação: de 5.0 baseada em 544 votos.
O por que?
Claro, antes de meter a mão na massa, a motivação do post. Já vi em muitos foruns perguntas cuja resposta pode ser dada por um design apropriado do banco de dados, feitas tanto por quem está começando, quanto por quem já tem algum tempo de estrada.
Você irá precisar de normalizar os dados em duas situações principais: quando um campo do banco será variável como um vetor, ou quando julgar necessário manter informações devidamente separadas.
Exemplo 1. Vendas e nota fiscal.
Considere a seguinte tabela que armazena as vendas de uma papelaria.
| idVenda | idCliente | itens |
|---|---|---|
| 1 | 1 | 3 cadernos, 5 lápis, 1 mochila |
| 2 | 3 | 10 lápis, 2 borrachas, 300 folhas de sulfite |
| 3 | 7 | 2 mochilas, 4 borrachas |
Como podemos ver, o campo itens armazena uma quantidade variável de informação. Vamos aplicar a normalização aí na primeira forma normal, ou 1NF.
| idVenda | idCliente | item 1 | Qtd 1 | item 2 | Qtd 2 | item 3 | Qtd 3 |
|---|---|---|---|---|---|---|---|
| 1 | 1 | caderno | 3 | lápis | 5 | mochila | 1 |
| 2 | 3 | lápis | 10 | borracha | 2 | sulfite | 300 |
| 3 | 7 | mochila | 2 | borracha | 4 |
OK, separamos as colunas para ter um e apenas um tipo de dado, mas ainda assim podemos ver que o design dessa tabela ainda é bem falho. E se um consumidor quiser comprar mais de 4 itens na mesma compra? mesmo que vc crie 200 campos, certamente haverá um ou outro caso onde esse limite será um problema, sem contar nas desvantagens óbvias de tamanho da tabela, espaço ocupado (com informações nulas), e no trabalho para criar queries e relatórios em cima de uma tabela assim. Mas esta ainda não é a versão terminada da 1NF. Podemos fazer um design um pouco melhor para obter isso.
| idVenda | idCliente | linhaDaVenda | Item | Qtd |
|---|---|---|---|---|
| 1 | 1 | 1 | caderno | 3 |
| 1 | 1 | 2 | lápis | 5 |
| 1 | 1 | 3 | mochila | 1 |
| 2 | 3 | 1 | lápis | 10 |
| 2 | 3 | 2 | borracha | 2 |
| 2 | 3 | 3 | sulfite | 300 |
| 3 | 7 | 1 | mochila | 2 |
| 3 | 7 | 2 | borracha | 4 |
Pronto, chegamos assim à primeira forma normal. Sem valores multiplos dentro de um campos, e sem multiplos campos para a mesma função.
Os mais atentos devem ter percebido um pequeno "problema" na tabela acima. Não há nenhum campo que funcione bem como chave-primária. A chave-primária para se obter uma linha é a combinação das colunas idVenda e linhaDaVenda.
Para resolver isso aplicamos a segunda forma normal, 2NF, que diz que cada linha tem uma chave-primária representada por um e apenas um campo.
Considere a tabela anterior com um pouco mais de detalhes:
| idVenda | idCliente | Data | linhaDaVenda | Qtd | idProduto | descProduto |
|---|---|---|---|---|---|---|
| 1 | 1 | 12/7/2010 | 1 | 3 | 1 | caderno |
| 1 | 1 | 12/7/2010 | 2 | 5 | 2 | lápis |
| 1 | 1 | 12/7/2010 | 3 | 1 | 3 | mochila |
| 2 | 3 | 13/7/2010 | 1 | 10 | 2 | lápis |
| 2 | 3 | 13/7/2010 | 2 | 2 | 4 | borracha |
| 2 | 3 | 13/7/2010 | 3 | 300 | 5 | sulfite |
| 3 | 7 | 15/7/2010 | 1 | 2 | 3 | mochila |
| 3 | 7 | 15/7/2010 | 2 | 4 | 4 | borracha |
Vamos separar o que pertence a cada venda, do que pertence aos items de cada venda em duas tabelas.
| idVenda | idCliente | Data |
|---|---|---|
| 1 | 1 | 12/7/2010 |
| 1 | 1 | 12/7/2010 |
| 1 | 1 | 12/7/2010 |
| 2 | 3 | 13/7/2010 |
| 2 | 3 | 13/7/2010 |
| 2 | 3 | 13/7/2010 |
| 3 | 7 | 15/7/2010 |
| 3 | 7 | 15/7/2010 |
| idVenda | linhaDaVenda | Qtd | idProduto | descProduto |
|---|---|---|---|---|
| 1 | 1 | 3 | 1 | caderno |
| 1 | 2 | 5 | 2 | lápis |
| 1 | 3 | 1 | 3 | mochila |
| 2 | 1 | 10 | 2 | lápis |
| 2 | 2 | 2 | 4 | borracha |
| 2 | 3 | 300 | 5 | sulfite |
| 3 | 1 | 2 | 3 | mochila |
| 3 | 2 | 4 | 4 | borracha |
Note que as duas tabelas estão agora relacionadas pelo campo idVenda, que é chave-primária da primeira tabela e chave-estrangeira na segunda.
Estamos agora a um passo da terminar a normalização destas entidades (geralmente se aplica a normalização até sua terceira forma normal. Dificilmente formas de normalização superiores se fazem necessárias). Vamos separar os dados dos produtos da tabela de detalhes de venda (Note que a tabela de vendas já está completamente normalizada).
| idVenda | linhaDaVenda | Qtd | idProduto |
|---|---|---|---|
| 1 | 1 | 3 | 1 |
| 1 | 2 | 5 | 2 |
| 1 | 3 | 1 | 3 |
| 2 | 1 | 10 | 2 |
| 2 | 2 | 2 | 4 |
| 2 | 3 | 300 | 5 |
| 3 | 1 | 2 | 3 |
| 3 | 2 | 4 | 4 |
| idProduto | descricaoProduto |
|---|---|
| 1 | caderno |
| 2 | lápis |
| 3 | mochila |
| 4 | borracha |
| 5 | sulfite |
Pronto. Normalizado.