sábado, 17 de julho de 2010

Exemplo prático de normalização de banco de dados

Este post pretende ser muito menos teórico e muito mais prático sobre um tema que todo desenvolvedor já leu e, provavelmente, procurou saber mais. Normalização de bancos de dados.

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.

tabelaVendas - desnormalizada
idVendaidClienteitens
113 cadernos, 5 lápis, 1 mochila
2310 lápis, 2 borrachas, 300 folhas de sulfite
372 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.

tabelaVendas - quase 1NF
idVendaidClienteitem 1Qtd 1item 2Qtd 2item 3Qtd 3
11caderno3lápis5mochila1
23lápis10borracha2sulfite300
37mochila2borracha4

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.

tabelaVendas - 1NF
idVendaidClientelinhaDaVendaItemQtd
111caderno3
112lápis5
113mochila1
231lápis10
232borracha2
233sulfite300
371mochila2
372borracha4

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:
tabelaVendas2 - 1NF
idVendaidClienteDatalinhaDaVendaQtdidProdutodescProduto
1112/7/2010131caderno
1112/7/2010252lápis
1112/7/2010313mochila
2313/7/20101102lápis
2313/7/2010224borracha
2313/7/201033005sulfite
3715/7/2010123mochila
3715/7/2010244borracha

Vamos separar o que pertence a cada venda, do que pertence aos items de cada venda em duas tabelas.

tabelaVendas2 - 2NF
idVendaidClienteData
1112/7/2010
1112/7/2010
1112/7/2010
2313/7/2010
2313/7/2010
2313/7/2010
3715/7/2010
3715/7/2010

tabelaDetalheVenda - 2NF
idVendalinhaDaVendaQtdidProdutodescProduto
1131caderno
1252lápis
1313mochila
21102lápis
2224borracha
233005sulfite
3123mochila
3244borracha

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).

tabelaDetalheVenda - 3NF
idVendalinhaDaVendaQtdidProduto
1131
1252
1313
21102
2224
233005
3123
3244

tabelaProdutos - 3NF
idProdutodescricaoProduto
1caderno
2lápis
3mochila
4borracha
5sulfite

Pronto. Normalizado.
Se você tem interesse vale a pena também dar uma lida em como desnormalizar (de forma ordenada) um banco de dados, que também é conhecido como formas 4N ou superiores.
----------- keepReading

4 comentários: