Opa opa! Hoje vamos a mais um tutorial “step by step” onde vou falar e mostrar como fazer relacionamento entre tabelas no MySQL.
O relacionamento de tabelas é necessário quando temos mais de uma tabela com informações 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 vocês saberem, existem três níveis de relacionamento: nosso exemplo será um relação de 1:N (fala-se “um pra N” ou “um para muitos”) onde cada categoria (1) contém um ou mais produtos (N)… Há também 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 nível de relacionamento, mais complexo, que é o N:N onde um ou mais registros de uma tabela (N) estão relacionados a um ou mais registros de outra tabela (N), que seria o exemplo de duas tabelas “produtos” e “tags” onde um produto tem várias tags e vários produtos pertencem a uma tag.
Não vou me aprofundar muito no assunto… Vou falar apenas da relação mais comum (1:N) e dar exemplos de como trabalhar com elas.
Para o nosso exemplo de hoje usaremos duas tabelas, chamadas “categorias” e “produtos”:
CREATE TABLE `categorias` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `nome` VARCHAR( 255 ) NOT NULL ) ENGINE = MYISAM; CREATE TABLE `produtos` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `categoria_id` INT NOT NULL , `nome` VARCHAR( 255 ) NOT NULL , `preco` DECIMAL( 10,2 ) NOT NULL ) ENGINE = MYISAM;
E vamos inserir alguns dados para exemplo:
-- Extraindo dados da tabela `categorias` INSERT INTO `categorias` VALUES(1, 'Camisetas'); INSERT INTO `categorias` VALUES(2, 'Canecas'); -- Extraindo dados da tabela `produtos` INSERT INTO `produtos` VALUES(1, 1, 'Camiseta Social', 15.00); INSERT INTO `produtos` VALUES(2, 1, 'Camiseta Regata', 11.99); 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 relação 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 responsável pela relação é normalmente chamado de “foreing key” (fk) ou “chave estrangeira”.
Mas qual a utilidade dessa tal “relação”?
Sem usar o relacionamento você poderia pegar todos os produtos e depois pegar as informações das categorias com uma segunda consulta, assim:
<?php
// Consulta que pega todos os produtos
$sql = "SELECT * FROM `produtos` ORDER BY `nome` ASC";
$query = mysql_query($sql);
while ($produto = mysql_fetch_assoc($query)) {
// Aqui temos o array $produto com todos os valores do produto
// 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);
echo 'Titulo: ' . $produto['nome'] . '<br />';
echo 'Preço: ' . $produto['preco'] . '<br />';
echo 'Categoria: ' . $categoria['nome']. '<br />';
echo '<hr />';
}
?>Até aí tudo bem… Não tem nenhum pecado nisso… Mas imagine que você tem uma loja com 1000 produtos (o que não é 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 mágica da relação
Agora vamos montar uma consulta que DE UMA SÓ VEZ irá pegar os dados de cada produto e também o nome da categoria… Com isso reduziremos nossas 1001 consultas pra… uma só! Sem mistérios, sem sub-consultas, nem consultas dentro do while()! ![]()
Mas antes de mostrar o script vou ajudar a vocês entenderem como a relação é feita… Antes a nossa consulta que pega apenas os produtos era assim:
SELECT * FROM `produtos` ORDER BY `nome` ASC
Sua tradução seria: SELECIONAR todas as colunas da TABELA `produtos` ORDENADO PELO `nome` ASCENDETEMENTE

Agora usaremos uma nova “palavra” do MySQL que é o JOIN (tradução: “unir”) e serve para unir resultados de duas tabelas.. ![]()
Existem três tipos de JOIN mas não vou falar dos outros dois pois eles são MUITO pouco usados… Falaremos do “INNER JOIN” que exige que haja um registro que corresponda a relação nas duas tabelas, ou seja: se houver um produto sem categoria ou a categoria não 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 tradução 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 relação” acontece ali entre o ON e o ORDER BY, dizemos que a relação 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 não entendeu, o ON é como o WHERE de uma consulta normal… É a regra da relação.
Repare que agora precisamos usar um formato diferente para identificar as colunas usando: `tabela`.`coluna`… Isso é necessário pois agora estamos trabalhando com duas tabelas.
Da forma que a nossa consulta está ainda não 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 também o valor da coluna “nome” do registro encontrado (pela relação) 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, não teríamos como identificar de qual tabela pegamos as informações (veja a próxima imagem), pois as duas seriam $produto['nome']… Precisamos então renomear esse novo campo que adicionamos a busca, assim:
SELECT `produtos`.*, `categorias`.`nome` AS categoria FROM `produtos` INNER JOIN `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 não “nome”… Sei que parece complicado de início mas vocês vão entender já já.
E por fim, faremos mais uma modificação, pra evitar ficar usando `tabela`.`coluna` também 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 ON 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 trabalhar muito 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 informações vindas de mais de uma tabela.
Agora vamos ao nosso novo script de PHP que, sem dúvidas, é bem mais prático e eficiente:
<?php
// 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 JOIN `categorias` AS c ON p.`categoria_id` = c.`id` ORDER BY p.`nome` ASC";
$query = mysql_query($sql);
while ($produto = mysql_fetch_assoc($query)) {
// Aqui temos o array $produto com todos os dados encontrados
echo 'Titulo: ' . $produto['nome'] . '<br />';
echo 'Preço: ' . $produto['preco'] . '<br />';
echo 'Categoria: ' . $produto['categoria']. '<br />';
echo '<hr />';
}
?>Os outros tipos de JOINs
Existem também outros dois tipos de JOIN: o LEFT JOIN e o RIGHT JOIN:
Se usássemos o LEFT JOIN seriam retornados todos os produtos, independente se eles estão ligados a uma categoria (na tabela categorias) existente ou não.
Já o RIGHT JOIN seria exatamente o contrário: seriam retornados todos os produtos que pertencem categorias existentes e também o nome das outras categorias que não tem ligação com nenhum produto.
O uso desses outros tipos de JOIN é muito raro e acho que não vale a pena ficar filosofando sobre eles enquanto se aprende sobre relacionamentos.
E a relação com mais de duas tabelas?
Só pra exemplo, essa seria a consulta que pega os produtos, as categorias e o nome do usuário que cadastrou o produto e filtrando apenas pelos produtos ativos:
SELECT p.*, c.`nome` AS categoria, u.`nome` AS usuario FROM `produtos` AS p INNER 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 BY p.`nome` ASC

Sim.. eu adoro consultas gigantescas. ![]()
Você também vai gostar de ler:
- PHP e MySQL para iniciantes – Consulta Avançada
- Entendendo a paginação de registros no MySQL
- Cadastrando múltiplos registros no MySQL ao mesmo tempo
- Como criar um Sistema de Login com Níveis de Permissão
- PHP e MySQL para iniciantes – Consulta Simples
Postado em Artigos, MySQL, PHP, Tutoriais
Com as tags Artigo, Busca, Consultas, INSERT, MySQL, PHP, Relacionamento, Relationship, Resultados, Scripts, SQL, Tutorial
Escrito por Thiago Belem
Gostou desse artigo?
Não se esqueça de assinar o RSS e divulgue-o para o mundo:
