Sei sulla pagina 1di 6

Relacionamento de Tabelas no MySQL

O relacionamento de tabelas necessrio quando temos mais de uma tabela com informaes que podem e precisam ser cruzadas, por exemplo: categorias e produtos Cada registro na tabela produtos estar ligado a um registro da tabela categorias. S pra vocs saberem, existem trs nveis de relacionamento: nosso exemplo ser um relao de 1:N (fala-se um pra N ou um para muitos) onde cada categoria (1) contm um ou mais produtos (N) H tambm o 1:1 onde cada registro de uma tabela (1) est ligado a um e somente um registro de outra tabela (1) E h outro nvel de relacionamento, mais complexo, que o N:N onde um ou mais registros de uma tabela (N) esto relacionados a um ou mais registros de outra tabela (N), que seria o exemplo de duas tabelas produtos e tags onde um produto tem vrias tags e vrios produtos pertencem a uma tag. Para o nosso exemplo usaremos as tabelas categorias e produtos:
01 CREATE TABLE `categorias` ( 02 03 05 06 CREATE TABLE `produtos` ( 07 08 09 10 `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `categoria_id` INT NOT NULL , `nome` VARCHAR( 255 ) NOT NULL , `preco` DECIMAL( 10,2 ) NOT NULL `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,

`nome` VARCHAR( 255 ) NOT NULL 04 ) ENGINE = MYISAM;

11 ) ENGINE = MYISAM;

E vamos inserir alguns dados para exemplo:


1 -- Extraindo dados da tabela `categorias` 2 INSERT INTO `categorias` VALUES(1, 'Camisetas'); 3 INSERT INTO `categorias` VALUES(2, 'Canecas'); 4 5 -- Extraindo dados da tabela `produtos` 6 INSERT INTO `produtos` VALUES(1, 1, 'Camiseta Social', 15.00); 7 INSERT INTO `produtos` VALUES(2, 1, 'Camiseta Regata', 11.99); 8 INSERT INTO `produtos` VALUES(3, 2, 'Caneca Grande', 12.00);

Reparem que na tabela produtos temos uma coluna especial, que a categoria_id (INT) Ela quem ajudar a fazer a relao das duas tabelas Nessa coluna entrar o

ID da categoria a qual o produto pertence Ou seja: as duas camisetas pertencem a categoria Camisetas (ID 1) e o terceiro produto (a Caneca Grande) pertence a categoria Canecas (ID 2) e na coluna categoria_id que armazenamos esses IDs que identificam as categorias. Esse campo responsvel pela relao normalmente chamado de foreing key (fk) ou chave estrangeira.

Mas qual a utilidade dessa tal relao?


Sem usar o relacionamento voc poderia pegar todos os produtos e depois pegar as informaes das categorias com uma segunda consulta, assim:
01 <?php 02 03 // Consulta que pega todos os produtos 04 $sql = "SELECT * FROM `produtos` ORDER BY `nome` ASC"; 05 $query = mysql_query($sql); 06 while ($produto = mysql_fetch_assoc($query)) { 07 08 09 10 11 12 13 14 15 16 17 18 } 19 20 ?> echo 'Titulo: ' . $produto['nome'] . '<br />'; echo 'Preo: ' . $produto['preco'] . '<br />'; echo 'Categoria: ' . $categoria['nome']. '<br />'; echo '<hr />'; // Consulta para pegar os dados da categoria: $sqlC = "SELECT * FROM `categorias` WHERE `id` = " .$produto['categoria_id']; $queryC = mysql_query($sqlC); $categoria = mysql_fetch_assoc($queryC); // Aqui temos o array $produto com todos os valores do produto

At a tudo bem No tem nenhum pecado nisso Mas imagine que voc tem uma loja com 1000 produtos (o que no muito), seria executada 1 consulta para todos os produtos e, dentro do loop (while) seriam executadas outras 1000 consultas para pegar o nome da categoria a qual o produto pertence Ou seja, 1001 consultas, o que um absurdo.

A mgica da relao
Agora vamos montar uma consulta que DE UMA S VEZ ir pegar os dados de cada produto e tambm o nome da categoria Com isso reduziremos nossas 1001 consultas pra uma s! Sem mistrios, sem sub-consultas, nem consultas dentro do while()!

Mas antes de mostrar o script vou ajudar a vocs entenderem como a relao feita Antes a nossa consulta que pega apenas os produtos era assim:
SELECT * FROM `produtos` ORDER BY `nome` ASC

Sua traduo seria: SELECIONAR todas as colunas da TABELA `produtos` ORDENADO PELO `nome` ASCENDETEMENTE

Agora usaremos uma nova palavra do MySQL que o JOIN (traduo: unir) e serve para unir resultados de duas tabelas.. Existem trs tipos de JOIN mas no vou falar dos outros dois pois eles so MUITO pouco usados Falaremos do INNER JOIN que exige que haja um registro que corresponda a relao nas duas tabelas, ou seja: se houver um produto sem categoria ou a categoria no existir na tabela categorias esse produto omitido dos resultados. A nossa consulta ficar assim:
SELECT `produtos`.* FROM `produtos` INNER JOIN `categorias` ON`produtos` .`categoria_id` = `categorias`.`id` ORDER BY `produtos`.`nome` ASC

Sua traduo seria: SELECIONAR todas as colunas [da tabela produtos] da TABELA `produtos` UNINDO A TABELA `categorias` ONDE a coluna `categoria_id` [da tabela produtos] IGUAL a coluna `id` [da tabela categorias] ORDENADO PELO `nome` [da tabela produtos] ASCENDETEMENTE

A nossa regra de relao acontece ali entre o ON e o ORDER BY, dizemos que a relao entre as tabelas usar como referencia a coluna categoria_id da tabela produtos sendo igual a coluna id da tabela categorias Se voc fosse usar algum WHERE ele entraria depois do ON e antes do ORDER BY.

Pra quem ainda no entendeu, o ON como o WHERE de uma consulta normal a regra da relao. Repare que agora precisamos usar um formato diferente para identificar as colunas usando: `tabela`.`coluna` Isso necessrio pois agora estamos trabalhando com duas tabelas.

Da forma que a nossa consulta est ainda no estamos pegando o nome da categoria fazemos isso adicionando mais um campo na parte do SELECT, assim:
SELECT `produtos`.*, `categorias`.`nome` FROM `produtos` INNER JOIN`categorias` ON `produtos `.`categoria_id` = `categorias`.`id` ORDER BY`produtos`.`nome` ASC

Agora estamos pegando tambm o valor da coluna nome do registro encontrado (pela relao) na tabela categorias.

S que agora temos um novo problema Nas duas tabelas existe uma coluna chamada nome, e quando estivermos l no PHP, dentro do while, no teramos como identificar de qual tabela pegamos as informaes (veja a prxima imagem), pois as duas seriam$produto['nome'] Precisamos ento renomear esse novo campo que adicionamos a busca, assim:
SELECT `produtos`.*, `categorias`.`nome` AS categoria FROM `produtos` INNERJOIN `categorias` ON `produtos`.`categoria_id` = `categorias`.`id` ORDER BY`produtos`.`nome` ASC

Agora o resultado de `categorias`.`nome` estar presente nos resultados como categoria e no nome Sei que parece complicado de incio mas vocs vo entender j j. E por fim, faremos mais uma modificao, pra evitar ficar usando `tabela`.`coluna` tambm podemos renomear as tabelas, e com isso diminuir otamanho da consulta:
SELECT p.*, c.`nome` AS categoria FROM `produtos` AS p INNER JOIN`categorias` AS c O N p.`categoria_id` = c.`id` ORDER BY p.`nome` ASC

Nesse caso p representar a tabela produtos e c representar a categorias.

Sei que parece uma consulta maior e mais complicada Mas voc far o MySQL trabalharmuito menos se fizer assim, com JOINS, do que fazer uma 2 consulta dentro do while Essa a forma mais correta de fazer consultas quando precisamos de informaes vindas de mais de uma tabela.

Agora vamos ao nosso novo script de PHP que, sem dvidas, bem mais prtico e eficiente:
01 <?php 02 03 // Consulta que pega todos os produtos e o nome da categoria de cada um

$sql = "SELECT p.*, c.`nome` AS categoria FROM `produtos` AS p INNER 04 JOIN `categorias` AS c ON p.`categoria_id` = c.`id` ORDER BY p.`nome` ASC"; 05 $query = mysql_query($sql); 06 while ($produto = mysql_fetch_assoc($query)) { 07 08 09 10 11 12 } 13 14 ?> // Aqui temos o array $produto com todos os dados encontrados echo 'Titulo: ' . $produto['nome'] . '<br />'; echo 'Preo: ' . $produto['preco'] . '<br />'; echo 'Categoria: ' . $produto['categoria']. '<br />'; echo '<hr />';

Os outros tipos de JOINs


Existem tambm outros dois tipos de JOIN: o LEFT JOIN e o RIGHT JOIN: Se usssemos o LEFT JOIN seriam retornados todos os produtos, independente se eles esto ligados a uma categoria (na tabela categorias) existente ou no. J o RIGHT JOIN seria exatamente o contrrio: seriam retornados todos os produtos que pertencem categorias existentes e tambm o nome das outras categorias que no tem ligao com nenhum produto. O uso desses outros tipos de JOIN muito raro e acho que no vale a pena ficar filosofando sobre eles enquanto se aprende sobre relacionamentos.

E a relao com mais de duas tabelas?

S pra exemplo, essa seria a consulta que pega os produtos, as categorias e o nome do usurio que cadastrou o produto e filtrando apenas pelos produtos ativos:
SELECT p.*, c.`nome` AS categoria, u.`nome` AS usuario FROM `produtos` AS pINNER JOIN `categorias` AS c ON p .`categoria_id` = c.`id` INNER JOIN`usuarios` AS u ON p.`usuario_id` = u.`id` WHERE (p.`ativo` = 1) ORDER BYp.`nome` ASC