Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

auto-junção vs junção interna


Acho útil pensar em todas as tabelas em uma instrução SELECT como representando seus próprios conjuntos de dados.

Antes de aplicar quaisquer condições, você pode pensar em cada conjunto de dados como completo (a tabela inteira, por exemplo).

Uma junção é apenas uma das várias maneiras de começar a refinar esses conjuntos de dados para encontrar as informações que você realmente deseja.

Embora um esquema de banco de dados possa ser projetado com certos relacionamentos em mente (Chave Primária <-> Chave Estrangeira), esses relacionamentos realmente só existem no contexto de uma consulta específica. O escritor de consulta pode relacionar o que quiser com o que quiser. Vou dar um exemplo disso depois...

Um INNER JOIN relaciona duas tabelas entre si. Muitas vezes, há várias operações JOIN em uma consulta para encadear várias tabelas. Pode ficar tão complicado quanto necessário. Para um exemplo simples, considere as três tabelas a seguir...
STUDENT

| STUDENTID | LASTNAME | FIRSTNAME |
------------------------------------
      1     |  Smith   |   John
      2     |  Patel   |  Sanjay
      3     |   Lee    |  Kevin
      4     |  Jackson |  Steven
ENROLLMENT

| ENROLLMENT ID | STUDENTID | CLASSID |
---------------------------------------
        1       |     2     |    3
        2       |     3     |    1
        3       |     4     |    2
CLASS

| CLASSID | COURSE | PROFESSOR |
--------------------------------
     1    | CS 101 |   Smith
     2    | CS 201 |  Ghandi
     3    | CS 301 |  McDavid
     4    | CS 401 |  Martinez

A tabela STUDENT e a tabela CLASS foram projetadas para se relacionarem por meio da tabela ENROLLMENT. Esse tipo de tabela é chamado de Tabela de junção .

Para escrever uma consulta para exibir todos os alunos e as turmas em que estão matriculados, usaria dois juntas internas...
SELECT stud.LASTNAME, stud.FIRSTNAME, class.COURSE, class.PROFESSOR
FROM STUDENT stud
INNER JOIN ENROLLMENT enr
    ON stud.STUDENTID = enr.STUDENTID
INNER JOIN CLASS class
    ON class.CLASSID = enr.CLASSID;

Leia o acima de perto e você deve ver o que está acontecendo. O que você receberá em troca é o seguinte conjunto de dados...
 | LASTNAME | FIRSTNAME | COURSE | PROFESSOR |
 ---------------------------------------------
     Patel  |   Sanjay  | CS 301 |  McDavid
      Lee   |   Kevin   | CS 101 |   Smith
    Jackson |  Steven   | CS 201 |  Ghandi

Usando as cláusulas JOIN, limitamos os conjuntos de dados de todas as três tabelas a apenas aqueles que correspondem entre si. As "correspondências" são definidas usando o ON cláusulas. Observe que, se você executasse essa consulta, não veja a linha CLASSID 4 da tabela CLASS ou a linha STUDENTID 1 da tabela STUDENT porque esses IDs não existem nas correspondências (neste caso, a tabela ENROLLMENT). Procure nos JOINs "LEFT"/"RIGHT"/"FULL OUTER" para obter mais informações sobre como fazer isso funcionar de maneira um pouco diferente.

Observe que, de acordo com meus comentários sobre "relacionamentos" anteriores, não há nenhuma razão por que você não pode executar uma consulta relacionando a tabela STUDENT e a tabela CLASS diretamente nas colunas LASTNAME e PROFESSOR. Essas duas colunas correspondem no tipo de dados e, veja bem! Eles até têm um valor em comum! Este provavelmente seria um conjunto de dados estranho para obter em troca. Meu ponto é que isso pode ser feito e você nunca sabe quais necessidades você pode ter no futuro para conexões interessantes em seus dados. Entenda o design do banco de dados, mas não pense em "relacionamentos" como regras que não podem ser ignoradas.

Enquanto isso... SELF JOINS!

Considere a tabela a seguir...
PERSON

| PERSONID | FAMILYID |  NAME  |
--------------------------------
      1    |     1    |  John
      2    |     1    | Brynn
      3    |     2    | Arpan
      4    |     2    | Steve
      5    |     2    |  Tim
      6    |     3    | Becca

Se você se sentiu inclinado a fazer um banco de dados de todas as pessoas que conhece e quais estão na mesma família, pode ser assim.

Se você quisesse devolver uma pessoa, PERSONID 4, por exemplo, você escreveria...
SELECT * FROM PERSON WHERE PERSONID = 4;

Você saberia que ele está na família com FAMILYID 2. Então, para encontrar todos das PESSOAS da família dele você escreveria...
SELECT * FROM PERSON WHERE FAMILYID = 2;

Feito e feito! O SQL, é claro, pode fazer isso em uma consulta usando, você adivinhou, um SELF JOIN.

O que realmente desencadeia a necessidade de um SELF JOIN aqui é que a tabela contém uma coluna única (PERSONID) e uma coluna que serve como uma espécie de "Categoria" (FAMILYID). Esse conceito é chamado de Cardinalidade e neste caso representa um um para muitos ou 1:M relação. Há apenas um de cada PESSOA mas há muitos PESSOAS em uma FAMÍLIA .

Então, o que queremos retornar é tudo dos membros de uma família se um membro do PERSONID da família é conhecido...
SELECT fam.*
FROM PERSON per
JOIN PERSON fam
    ON per.FamilyID = fam.FamilyID
WHERE per.PERSONID = 4;

Aqui está o que você ganharia...
| PERSONID | FAMILYID |  NAME  |
--------------------------------
      3    |     2    | Arpan
      4    |     2    | Steve
      5    |     2    |  Tim

Vamos notar algumas coisas. As palavras SELF JOIN não ocorrem em qualquer lugar. Isso porque um SELF JOIN é apenas um conceito. A palavra PARTICIPE na consulta acima poderia ter sido um LEFT JOIN em vez disso e coisas diferentes teriam acontecido. O ponto de um SELF JOIN é que você está usando a mesma tabela duas vezes.

Considere minha caixa de sabão de antes em conjuntos de dados. Aqui começamos com o conjunto de dados da tabela PERSON duas vezes. Nenhuma das instâncias do conjunto de dados afeta o outro, a menos que digamos que sim.

Vamos começar na parte inferior da consulta. O por O conjunto de dados está sendo limitado apenas às linhas em que PERSONID =4. Conhecendo a tabela sabemos que retornará exatamente uma linha. A coluna FAMILYID nessa linha tem um valor de 2.

Na cláusula ON estamos limitando a fam conjunto de dados (que neste momento ainda é toda a tabela PERSON) apenas para as linhas em que o valor de FAMILYID corresponde a um ou mais dos FAMILYIDs dos por conjunto de dados. Conforme discutimos, sabemos o por conjunto de dados tem apenas uma linha, portanto, um valor FAMILYID. Portanto, a família o conjunto de dados agora contém apenas linhas em que FAMILYID =2.

Por fim, na parte superior da consulta, estamos selecionando todas as linhas da fam conjunto de dados.

Voilá! Duas consultas em uma.

Concluindo, um INNER JOIN é um dos vários tipos de operações JOIN. Eu fortemente sugiro ler mais LEFT, RIGHT e FULL OUTER JOINs (que são, coletivamente, chamados de OUTER JOINs ). Eu pessoalmente perdi uma oportunidade de trabalho por ter um conhecimento fraco de OUTER JOINs uma vez e não vou deixar isso acontecer novamente!

Uma AUTOUNICAÇÃO é simplesmente qualquer operação JOIN onde você está relacionando uma tabela a ela mesma. A maneira como você escolhe JOIN essa tabela para si mesma pode usar um INNER JOIN ou um OUTER JOIN. Observe que com um SELF JOIN , para não confundir seu mecanismo SQL, você deve use aliases de tabela (fam e per acima. Invente o que fizer sentido para sua consulta) ou não há como diferenciar as diferentes versões da mesma mesa.

Agora que você entende a diferença, abra sua mente e perceba que uma única consulta pode conter todos os tipos diferentes de JOINs de uma só vez. É apenas uma questão de quais dados você deseja e como você precisa torcer e dobrar sua consulta para obtê-los. Se você estiver executando uma consulta e obtendo o resultado dessa consulta e usando-o como entrada de outra consulta, provavelmente poderá usar um JOIN para torná-lo uma consulta em vez disso.

Para brincar com o SQL, tente visitar W3Schools.com Há um banco de dados armazenado localmente com várias tabelas projetadas para se relacionarem de várias maneiras e cheias de dados! Você pode CREATE, DROP, INSERT, UPDATE e SELECT tudo o que quiser e retornar o banco de dados ao seu padrão a qualquer momento. Experimente todos os tipos de SQL para experimentar diferentes truques. Eu aprendi muito lá, eu mesmo.

Desculpe se isso foi um pouco prolixo, mas eu pessoalmente lutei com o conceito de JOINs quando estava começando a aprender SQL e explicar um conceito usando um monte de outros conceitos complexos me atolou. Melhor começar por baixo às vezes.

Espero que ajude. Se você pode colocar JOINs no bolso de trás, pode fazer mágica com o SQL!

Boa consulta!