Chegamos ao terceiro artigo da série de migração da Oracle. Desta vez, olhamos para aqueles operadores estranhos que modificam os critérios da cláusula WHERE no Oracle (+). Como tudo, o PostgreSQL tem uma solução para isso.
RIGHT JOIN
A Oracle suporta, e muitos desenvolvedores usam, a sintaxe ANSI outer JOIN usando operadores para a cláusula de qualificação.
Normalmente, isso se parece com isso:
SELECT *
FROM person, places
WHERE person.id = places.person_id(+)
O objetivo desta sintaxe é uma junção externa direita. Em termos da teoria dos conjuntos, este é o subconjunto que inclui todos os lugares, independentemente da pessoa.
O resultado de uma pequena amostra ficaria assim:
id | last_name | first_name | id | local | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Dallas | (NULO) |
2 | Roybal | Kirk | 2 | Londres | 2 |
3 | Riggs | Simão | 3 | Paris | 3 |
Esta sintaxe não é suportada no PostgreSQL.
Para obter o mesmo resultado, você usaria a sintaxe SQL padrão para associações externas.
SELECT *
FROM persons
RIGHT JOIN places
ON persons.id = places.person_id;
SQL também fornece um advérbio esclarecedor
OUTER
. Este clarificador é completamente opcional, como qualquer RIGHT JOIN
é por definição um OUTER
Junte-se. UNIÇÃO COMPLETA
Da mesma forma, usar a sintaxe do Oracle para uma junção completa não funciona no PostgreSQL.
SELECT *
FROM persons, places
WHERE persons.id(+) = places(+);
O objetivo desta sintaxe é uma lista completa de pessoas e lugares, independentemente de uma pessoa estar associada a um lugar ou não.
O resultado ficaria assim:
id | last_name | first_name** | id | local | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Dallas | (NULO) |
2 | Roybal | Kirk | 2 | Londres | 2 |
3 | Riggs | Simão | 3 | Paris | 3 |
4 | André | Dunstan | (NULO) | (NULL) | (NULO) |
Usando a sintaxe do PostgreSQL, a consulta seria escrita assim:
SELECT *
FROM persons
FULL JOIN places
ON persons.id = places.person_id;
Novamente, o
OUTER
palavra-chave é completamente opcional. CROSS JOIN
Uma vantagem distinta da abordagem de usar palavras-chave em vez de relacionamentos implícitos é que você não pode criar acidentalmente um produto cruzado.
A sintaxe:
SELECT *
FROM persons
LEFT JOIN places;
Resultará em um erro:
ERROR: syntax error at or near ";"
Indicando que a instrução não está completa no marcador final de linha “;”.
O PostgreSQL criará o produto de junção cruzada usando a sintaxe ANSI.
SELECT *
FROM persons, places;
id | sobrenome | first_name | código | local | person_id |
---|---|---|---|---|---|
1 | Dunstan | André | 1 | Dallas | (nulo) |
1 | Dunstan | André | 2 | Londres | 2 |
1 | Dunstan | André | 3 | Paris | 3 |
1 | Dunstan | André | 4 | Madri | (nulo) |
2 | Roybal | Kirk | 1 | Dallas | (nulo) |
2 | Roybal | Kirk | 2 | Londres | 2 |
2 | Roybal | Kirk | 3 | Paris | 3 |
2 | Roybal | Kirk | 4 | Madri | (nulo) |
3 | Riggs | Simão | 1 | Dallas | (nulo) |
3 | Riggs | Simão | 2 | Londres | 2 |
3 | Riggs | Simão | 3 | Paris | 3 |
3 | Riggs | Simão | 4 | Madri | (nulo) |
6 | Wong | Marcar | 1 | Dallas | (nulo) |
6 | Wong | Marcar | 2 | Londres | 2 |
6 | Wong | Marcar | 3 | Paris | 3 |
6 | Wong | Marcar | 4 | Madri | (nulo) |
O que é mais provável um erro de codificação do que o resultado intencional.
Para obter essa funcionalidade intencionalmente, é recomendável usar o
CROSS JOIN
demonstração. SELECT *
FROM persons
CROSS JOIN places;
Tornando assim inequívoco o que se quis dizer na declaração.
UNIÇÃO NATURAL
PostgreSQL suporta o
NATURAL JOIN
sintaxe, mas um pouco sob protesto. SELECT *
FROM persons
NATURAL JOIN places;
Isso produz o seguinte resultado.
id | sobrenome | first_name | parent_id | local | person_id |
---|---|---|---|---|---|
1 | Dunstan | André | (nulo) | Dallas | (nulo) |
2 | Roybal | Kirk | 1 | Londres | 2 |
3 | Riggs | Simão | 1 | Paris | 3 |
No entanto, essa sintaxe é um problema. Para o nosso exemplo, a coluna "id" em ambas as tabelas não tem nada a ver uma com a outra . Essa junção produziu um resultado, mas com conteúdo completamente irrelevante.
Além disso, você pode ter uma consulta que apresenta inicialmente o resultado correto, mas as instruções DDL subsequentes afetam silenciosamente.
Considerar:
ALTER TABLE person ADD COLUMN places_id bigint;
ALTER TABLE places ADD COLUMN places_id bigint;
ALTER TABLE person ADD COLUMN person_id bigint;
Agora, qual coluna é o
NATURAL JOIN
usando? As opções são id, places_id, person_id e todas as opções acima. Deixo a resposta como exercício para o leitor. Essa sintaxe é uma bomba-relógio para o seu código. Só não use.
Ok, então você não está convencido. Bem, então pelo menos tenha algumas convenções de codificação sãs. Para a tabela pai, nomeie a coluna de identidade como “myparenttable_id”. Ao referenciar a partir de relações filho, use o mesmo nome, “myparenttable_id”. Nunca nomeie nada como “id” e nunca faça referência a uma coluna com um nome diferente. Ah, esqueça. Apenas não faça isso.
Você pode ficar tentado a desambiguar o quebra-cabeça anterior usando o
USING
palavra-chave. Isso ficaria assim:SELECT *
FROM persons
JOIN places
USING (id);
Mas o
USING
A palavra-chave só pode aproveitar as correspondências de nome exatas nas tabelas. O que novamente, em nosso exemplo, está totalmente errado. A escolha de melhor prática para o PostgreSQL é simplesmente evitar projetar tabelas por padrões de convenção de codificação.
Resumo
Essas técnicas de palavras-chave (vs. operadores) também estão disponíveis no Oracle. Eles são mais multiplataforma e menos ambíguos. Isso por si só os tornaria melhores práticas.
Somado a isso, expõem erros lógicos quando utilizados de forma inadequada. Para qualquer desenvolvimento no PostgreSQL, recomendamos unilateralmente o uso de palavras-chave explícitas.