Eis aqui uma das dúvidas que encabeçam boa parte das mensagens e e-mails, de fóruns e listas de discussão, sobre o MySQL. Como proceder para que, em seu sistema na web ou website, haja referência entre duas (ou mais) tabelas de dados no MySQL por intermédio do vínculo de chave estrangeira, o recurso também conhecido como FOREIGN KEY dentro da modelagem estrutural de banco de dados?
A pergunta não é nova e, certamente você encontrará várias respostas durante uma pesquisa no google, boa parte delas fragmentadas. Algumas das respostas falarão sobre o tipo de tabela de dados InnoDB; outras abordarão instruções em SQL, que podem ser repassadas via shell básico de administração, por exemplo, do tipo: “mysql> ALTER TABLE tab_clientes ADD CONSTRAINT…”; alguns dos textos vão basear sua temática no sistema operacional Linux, outros no Windows. A questão é: Todos eles provavelmente tem sua taxa de coesão e razão, dependendo exclusivamente do seu enfoque, seu cenário de desenvolvimento específico à aplicabilidade ou não das respostas. Aqui vou me dirigir (basear os comentários macros) aos desenvolvedores que costumam usar o Apache2Triad no Windows. Para os que não sabem, o Apache2Triad é um empacotamento de softwares livres que, dentre outras aplicações, instala no seu Windows o servidor Apache com suporte a PHP e Pearl, MySQL, PostGreSQL, PHPxMail (servidor de e-mails), Uebimiau e o PHPsftpd. De todo modo quem utiliza o ambiente Linux como servidor de webpages/banco de dados MySQL, não vai encontrar dificuldades para adaptar este texto ao seu cenário! 😉
A primeira observação que se faz necessária é o fato de que no MySQL, a partir da versão 3.23.43b, foi incorporado o recurso de criação e manutenção de tabelas do tipo InnoDB. Tabelas do tipo InnoDB suportam restrições por chave estrangeira e o uso de stored procedures. Resumindo, se você quer modelar/desenvolver usando do recurso de chaves estrangeiras, suas tabelas terão que ser do tipo InnoDB. Como trata-se de um recurso incorporado desde versões bem mais antigas do MySQL, boa parte das distribuições Linux e o própiro Apache2Triad trazem embarcada esta possibilidade; bastanto apenas, em alguns casos, fazer a liberação (descomentar algumas linhas e comentar outras) no arquivo de configuração, criar algumas pastinhas e pronto… trabalho concluído! Deve ficar claro que, mesmo que suas tabelas sejam de outro tipo, por exemplo, MyISAM, é possível efetuar conversão.
A primeira coisa a se fazer para liberar o uso de tabelas do tipo InnoDB para usuários MySQL é editar o arquivo de configuração do SGBD, no caso do Apache2Triad em ambiente Windows o: C:\Windows\My.cnf. Este é o arquivo que contém basicamente todas as opções a nível de startamento e comportamento do daemon na memória. Se você analisar com cuidado, vai notar a seguinte linha descomentada: skip-innodb. Isso faz com o que o SGBD pule (skip) o recurso de tabelas InnoDB. Neste sentido, comente esta linha (colocando um cercadilha na frente dela: #skip-innodb).
O segundo passo é descomentar todas as linhas que habilitam a possibilidade de manutenção de tabelas do tipo InnoDB (o último bloco de instruções do arquivo). Descomente (retire a cercadilha da frente) da linha: innodb_log_group_home_dir = C:/apache2triad/mysql/iblogs até a linha innodb_lock_wait_timeout=50. Se você preferir pode baixar aqui o arquivo previamente modificado! 😉
Obs. importante: Note que algumas das linhas descomentadas por você, no caso do Apache2Triad, apontam para pastas que não existem por default. Neste caso, você precisa criar os diretórios: C:\apache2triad\mysql\iblogs e C:\apache2triad\mysql\ibdata antes de reiniciar o serviço. Se você já criou ambas as pastas, basta executar o services.msc e reiniciar o serviço MySQL do Apache2Triad. Pronto, se tudo deu certo até aqui, você já tem suporte à tabelas do tipo InnoDB (abra o phpmyadmin e faça o teste).
PHPMyAdmin “entendendo” o suporte à tabelas do tipo InnoDB
A partir de agora você pode criar suas tabelas, montar sua estrutura de base de dados de acordo com suas necessidades. No exemplo acima estou criando uma base chamada loja, que terá duas tabelas. Uma tabela conhecida como tab_cidades (cod_cidade, nome_cidade) e outra tabela, a que irá herdar a chave estrangeira de tab_cidades, chamada tab_clientes (cod_cliente, nome_cliente, cidade_cliente). Deve ficar saliente que você pode optar por criar toda a sua estrutura (base de dados + tabelas de dados) a partir de um arquivo SQL, definindo durante o ato de criação quem será chave estrangeira, bem como, o tipo da tabela (lembrando que ambas tem que ser do tipo InnoDB). De todo modo, aqui vamos deixar a SQL ao máximo de lado; portanto, crie as duas tabelas, com seus respectivos campos pelo próprio PHPMyAdmin (note que os campos “cod_cidade” e “cidade_cliente”, obviamente, precisam ser do mesmo tipo – INT).
PHPMyAdmin – Executando a instrução ALTER TABLE para implementar a chave estrangeira na tabela “tab_clientes”
Depois das tabelas criadas, vá para a aba SQL do PHPMyAdmin, referente a tabela tab_clientes (ela que irá receber a chave estrangeira) e digite algo assim (depois mande executar):
ALTER TABLE `tab_clientes` ADD CONSTRAINT `fk_cidade` FOREIGN KEY (`cidade_cliente`) REFERENCES `tab_cidades` (`cod_cidade`);
A instrução SQL acima, manda o MySQL alterar a estrutura da tabela “tab_clientes”, que agora passará a ter um índice chamado “fk_cidade” (o MySQL não custuma gerar índices automáticos, você precisa definí-los), cujo campo que será chave estrangeira na tabela é o “cidade_cliente”, o qual se referencia na prática ao campo “cod_cidade” da tabela de dados “tab_cidades”. Inerentemente à instrução acima, você pode querer casá-la com a opção ON DELETE CASCADE ou ON UPDATE CASCADE. Use estes recursos com muito cuidado e, procure ler mais sobre os efeitos de ambos quando propostos em sistemas de informações críticos.
PHPMyAdmin: Tentando cadastrar um cliente, fornecendo um código de cidade que não existe na tabela “tab_cidades”
Se tudo der certo e você tentar incluir um cliente novo na “tab_clientes”, definindo como cidade um código que não esteja previamente cadastrado na tabela “tab_cidades”, o MySQL irá apresentar um exceção. Da mesma forma se você tentar excluir uma cidade que tenha clientes previamente cadastrados com seu respectivo código na tabela “tab_clientes”. A isso se dá o nome de integridade referencial, um recurso absolutamente importante dentro do desenvolvimento de sistemas de informação com abordagem relacional.