Diogo Besson :: tecnologia

Mysql joins e unions

Mysql joins e unions

Mysql joins e unions fala sobre as concatenações, junções e uniões de dados em consultas (querys) no ambiente do banco de dados MySQL

logo-mysql-110x57

O Mysql é uma base de dados opensource muito popular, cuja exploração comercial foi adquirida pela Oracle há algum tempo. Se vocẽ chegou até aqui, provavelmente já conhece pelo menos um pouco do sistema gerenciador de banco de dados, da linguagem utilizada por ele e da database propriamente dita, certo? ok… Então vamos falar sobre as concatenações, junções e uniões de dados em consultas (querys) nesse ambiente.

Vamos imaginar que você tem um banco de dados Mysql assim:

tabela UM:
id – 1 | nome – Salomão
id – 2 | nome – Silvania

tabela DOIS:
id – 1 | nome – Salomão
id – 3 | nome – Joelmir

Primeira forma, a junção simples

Faz-se uma seleção onde o fator id coincidente retornará o nome e o id do cidadão:

SELECT * FROM UM u, DOIS d WHERE u.id = d.id ;

result:

id – 1 | nome – Salomão | id – 1 | nome – Salomão

Segunda forma, o Inner Join

O Inner Join trás o mesmo resultado da consulta acima, porém com uma escrita de query diferente:

SELECT * FROM UM INNER JOIN DOIS ON UM.id = DOIS.id;

result:

id – 1 | nome – Salomão | id – 1 | nome – Salomão

Terceira forma, o Outer Join

Diferente do Inner Join, esta consulta também retornará registros da tabela que possam não ter uma associação ou correspondência em uma outra tabela.

Você deve especificar sempre qual é a tabela de junção que mostrará os registros faltantes. Usa-se lado esquerdo e direito para essa diferenciação.

portanto:

SELECT * FROM UM LEFT OUTER JOIN DOIS ON UM.id = DOIS.id;

retornará:

id – 1 | nome – Salomão | id – 1 | nome – Salomão
id – 2 | nome – Silvania | id – NULL | nome – NULL

e

SELECT * FROM UM RIGHT OUTER JOIN DOIS ON UM.id = DOIS.id;

retornará:

id – 1 | nome – Salomão | id – 1 | nome – Salomão
id – NULL | nome – NULL | id – 3 | nome – Joelmir

para encurtar você também pode usar LEFT JOIN e RIGHT JOIN ao invés de LEFT OUTER JOIN e RIGHT OUTER JOIN. Isso facilita um bocado.

Quarta forma, unindo outer joins ( ou usando full outer joins, como costume )

Quero todos os registros de todas as tabelas, coincidentes ou não coincidentes, à direita ou à esquerda. OK!!!

SELECT * FROM UM LEFT OUTER JOIN DOIS ON UM.id = DOIS.id UNION SELECT * FROM UM RIGHT OUTER JOIN DOIS ON UM.id = DOIS.id;

retornará:

id – 1 | nome – Salomão | id – 1 | nome – Salomão
id – 2 | nome – Silvania | id – NULL | nome – NULL

id – NULL | nome – NULL | id – 3 | nome – Joelmir

Aí você me diz: “que mentira! uniu nada… Por que o Salomão só apareceu uma vez?”

É porque o Mysql é inteligente pacas e excluiu os resultados repetidos, mas se você acha que vale a pena ver de novo, use o UNION ALL:

SELECT * FROM UM LEFT OUTER JOIN DOIS ON UM.id = DOIS.id UNION ALL SELECT * FROM UM RIGHT OUTER JOIN DOIS ON UM.id = DOIS.id;

que retornará:

id – 1 | nome – Salomão | id – 1 | nome – Salomão
id – 2 | nome – Silvania | id – NULL | nome – NULL
id – 1 | nome – Salomão | id – 1 | nome – Salomão

id – NULL | nome – NULL | id – 3 | nome – Joelmir

Uma beleza!

Usamos isso para mostrar, via código, o relacionamento de uma chave estrangeira “fictícia” em um banco que não previu o not null para o id da tabela consultada. Foi extremamente eficaz:

tabela hoteis:

id – 1 | nome – Hotel 1 | local – 1
id – 2 | nome – Hotel 2 | local – NULL

tabela locais:

id – 1 | bairro – CENTRO
id – 2 | bairro – SUL
id – 3 | bairro – NORTE

Selecionando: Select h.nome, l.bairro FROM hoteis h, locais l WHERE h.local = l.id;

retornará: nome – Hotel 1 | bairro – CENTRO

mas eu quero que todos os hoteis apareçam, mesmo se o bairro não estiver disponível no cadastro, portanto selecionando: Select h.nome, l.bairro FROM hoteis h LEFT JOIN locais l ON h.local = l.id;

retornará:

nome – Hotel 1 | bairro – CENTRO
nome – Hotel 2 | bairro – NULL

Outras consultas:

A query: Select h.nome, l.bairro FROM hoteis h RIGHT JOIN locais l ON h.local = l.id;

retornará:

nome – Hotel 1 | bairro – CENTRO
nome – NULL | bairro – SUL
nome – NULL | bairro – NORTE

pois a tabela indicada na consulta é a “direita” 

O full outer join disso: Select h.nome, l.bairro FROM hoteis h LEFT JOIN locais l ON h.local = l.id UNION Select h.nome, l.bairro FROM hoteis h RIGHT JOIN locais l ON h.local = l.id;

retornará:

nome – Hotel 1 | bairro – CENTRO
nome – Hotel 2 | bairro – NULL
nome – NULL | bairro – SUL
nome – NULL | bairro – NORTE

e, pra ficar zuado e acabar com a festa: Select h.nome, l.bairro FROM hoteis h LEFT JOIN locais l ON h.local = l.id UNION ALL Select h.nome, l.bairro FROM hoteis h RIGHT JOIN locais l ON h.local = l.id;

resultará:

nome – Hotel 1 | bairro – CENTRO
nome – Hotel 2 | bairro – NULL
nome – Hotel 1 | bairro – CENTRO
nome – NULL | bairro – SUL
nome – NULL | bairro – NORTE

Pra não perder a piadinha infame: A união fez a força! hehehe

um abraço!

fontes:
http://stackoverflow.com/questions/4796872/full-outer-join-in-mysql
http://www.tizag.com/sqlTutorial/sqlunion.php
http://dev.mysql.com/doc/refman/5.0/en/join.html
http://dev.mysql.com/doc/refman/5.0/en/union.html 

4 Comments

  1. Alm

    como fazer se tabelas estiverem em bancos diferentes.
    Exemplo: tenho uma tabela somente para cliente em um BD1…
    em outro BD2 tenho uma tabela que tem dados de clientes com telefone.

    preciso fazer um select (join) que retorne dados presentes no BD1 mas que retorne as informações do BD2 com um campo específico.

  2. Diogo Besson

    Almir, véi… essa pra mim foi inédita.
    parabéns pela pergunta FODA!

    seguinte. existe uma parada no MySQL chamada "tabelas federadas". É um esquema onde você cria, dentro da sua conexão principal, uma tabela (copiada, clonada, sei lá…) que fisicamente existe em uma outra conexão de banco de dados.

    NUNCA usei isso, não sei as implicações de performance, não faço a menos idéia das possibilidades de sincronização pra manter a integridade entre as conexões diferentes… nada de nada de nada de nada….

    Os detalhes você pode encontrar em https://dev.mysql.com/doc/refman/5.5/en/federated… , ok?
    use com moderação 😀

    Pelo que eu entendi da sua dúvida, a partir dessa "gambiarra oficial", você vai conseguir fazer Joins com bancos externos numa boa.
    Depois conta pra gente como foi tua experiência.

    abraço!

  3. @douglasevaristo

    Fala cara tudo bom? Muito bom seu texto. Estou com uma duvida doida me matando e nao acho ninguem pra me ajudar. Vai que é vc kkkkk
    Seguinte: tenho um banco de dados assim
    clientes {id / nome / email}
    produtos { id / nome / valor}

    A questão é eu conseguir fazer um busca, nas duas tabelas (algo tipo nome LIKE '%$busca%') porem ao exibir esses dados eu saber se veio da tabela clientes ou produtos, isso porque fazer usando o UNION dá certo, porem eu não consigo saber de qual tabela veio o resultado. Será q vc entendeu? agradeço desde ja sua ajuda!

  4. Diogo Besson (Post author)

    Oi Douglas, eu vejo essa união de uma forma um pouco mais simples pra resolver teu problema. Buscando tabelas diferentes, que tal dar nomes diferentes ao campos? abra sua mente…

    exemplo:
    SELECT cli.nome as nome_cliente, pro.nome as nome_produto FROM clientes cli, produtos pro WHERE cli.nome LIKE ‘%$busca%’ OR pro.nome LIKE ‘%$busca%’

    claro que essa query tem problemas… você não está usando chaves estrangeiras pra relacionar clientes com produtos. uma tabela, por exemplo, de pedidos, deveria ter relacionamentos.
    só pra simplificar, tomei a liberdade de agrupar os resultados e retornar não duplicados, ok?
    ficou mais ou menos assim:
    SELECT cli.nome as nome_cliente, pro.nome as nome_produto FROM clientes cli, produtos pro WHERE cli.nome LIKE ‘%$busca%’ OR pro.nome LIKE ‘%$busca%’ GROUP BY nome_cliente, nome_produto

    espero ter dado uma clareada.
    abraço!

Leave a Comment

O seu endereço de e-mail não será publicado.