Nos encontramos en el tercer artículo de la serie de migración de Oracle. En esta ocasión, nos fijamos en esos extraños operadores que modifican los criterios de la cláusula WHERE en Oracle (+). Como todo lo demás, PostgreSQL tiene una solución para eso.
RIGHT JOIN
Oracle admite, y muchos desarrolladores la utilizan, la sintaxis externa JOIN de ANSI utilizando operadores en la cláusula de calificaciones.
Por lo general, se parece a esto:
SELECT *
FROM person, places
WHERE person.id = places.person_id(+)
El objetivo de esta sintaxis es una combinación externa derecha. En términos de teoría de conjuntos, este es el subconjunto que incluye todos los lugares, independientemente de la persona.
El resultado de una pequeña muestra se vería así:
id | apellido | nombre | id | ubicación | id_persona |
---|---|---|---|---|---|
1 | (NULO) | (NULO) | 1 | Dallas | (NULO) |
2 | Roybal | Kirk | 2 | Londres | 2 |
3 | Riggs | Simón | 3 | París | 3 |
Esta sintaxis no es compatible con PostgreSQL.
Para lograr el mismo resultado, usaría la sintaxis SQL estándar para combinaciones externas.
SELECT *
FROM persons
RIGHT JOIN places
ON persons.id = places.person_id;
SQL también proporciona un adverbio aclaratorio OUTER
. Este clarificador es completamente opcional, como cualquier RIGHT JOIN
es por definición un OUTER
unirse.
UNIÓN COMPLETA
De manera similar, el uso de la sintaxis de Oracle para una unión completa no funciona en PostgreSQL.
SELECT *
FROM persons, places
WHERE persons.id(+) = places(+);
El objetivo de esta sintaxis es una lista completa de personas y lugares, ya sea que una persona esté asociada con un lugar o no.
El resultado sería así:
id | apellido | primer_nombre** | id | ubicación | id_persona |
---|---|---|---|---|---|
1 | (NULO) | (NULO) | 1 | Dallas | (NULO) |
2 | Roybal | Kirk | 2 | Londres | 2 |
3 | Riggs | Simón | 3 | París | 3 |
4 | Andrés | Dunstan | (NULO) | (NULO) | (NULO) |
Usando la sintaxis de PostgreSQL, la consulta se escribiría así:
SELECT *
FROM persons
FULL JOIN places
ON persons.id = places.person_id;
De nuevo, el OUTER
la palabra clave es completamente opcional.
UNIÓN CRUZADA
Una clara ventaja del enfoque de usar palabras clave en lugar de relaciones implícitas es que no puede crear accidentalmente un producto cruzado.
La sintaxis:
SELECT *
FROM persons
LEFT JOIN places;
Dará como resultado un error:
ERROR: syntax error at or near ";"
Indicando que la declaración no está completa en el marcador de final de línea ";".
PostgreSQL creará el producto de unión cruzada utilizando la sintaxis ANSI.
SELECT *
FROM persons, places;
id | apellido | nombre | identificación | ubicación | id_persona |
---|---|---|---|---|---|
1 | Dunstan | Andrés | 1 | Dallas | (nulo) |
1 | Dunstan | Andrés | 2 | Londres | 2 |
1 | Dunstan | Andrés | 3 | París | 3 |
1 | Dunstan | Andrés | 4 | Madrid | (nulo) |
2 | Royal | Kirk | 1 | Dallas | (nulo) |
2 | Royal | Kirk | 2 | Londres | 2 |
2 | Royal | Kirk | 3 | París | 3 |
2 | Royal | Kirk | 4 | Madrid | (nulo) |
3 | Riggs | Simón | 1 | Dallas | (nulo) |
3 | Riggs | Simón | 2 | Londres | 2 |
3 | Riggs | Simón | 3 | París | 3 |
3 | Riggs | Simón | 4 | Madrid | (nulo) |
6 | Wong | Marcar | 1 | Dallas | (nulo) |
6 | Wong | Marcar | 2 | Londres | 2 |
6 | Wong | Marcar | 3 | París | 3 |
6 | Wong | Marcar | 4 | Madrid | (nulo) |
Lo cual es más probable que sea un error de codificación que el resultado intencional.
Para obtener esta funcionalidad intencionalmente, se recomienda usar CROSS JOIN
declaración.
SELECT *
FROM persons
CROSS JOIN places;
De este modo, queda claro lo que se quiere decir en la declaración.
UNIÓN NATURAL
PostgreSQL es compatible con NATURAL JOIN
sintaxis, pero un poco bajo protesta.
SELECT *
FROM persons
NATURAL JOIN places;
Esto produce el siguiente resultado.
id | apellido | nombre | parent_id | ubicación | id_persona |
---|---|---|---|---|---|
1 | Dunstan | Andrés | (nulo) | Dallas | (nulo) |
2 | Royal | Kirk | 1 | Londres | 2 |
3 | Riggs | Simón | 1 | París | 3 |
Sin embargo, esta sintaxis es un problema. Para nuestro ejemplo, la columna "id" en ambas tablas no tiene nada que ver entre sí . Esta unión ha producido un resultado, pero uno con contenido completamente irrelevante.
Además, es posible que tenga una consulta que inicialmente presente el resultado correcto, pero que las declaraciones DDL subsiguientes afecten silenciosamente.
Considere:
ALTER TABLE person ADD COLUMN places_id bigint;
ALTER TABLE places ADD COLUMN places_id bigint;
ALTER TABLE person ADD COLUMN person_id bigint;
Ahora, ¿qué columna es NATURAL JOIN
? ¿utilizando? Las opciones son id, places_id, person_id y todas las anteriores. Dejaré la respuesta como ejercicio para el lector.
Esta sintaxis es una bomba de relojería para su código. Simplemente no lo uses.
Ok, entonces no estás convencido. Bueno, entonces al menos tenga algunas convenciones de codificación sanas. Para la tabla principal, asigne a la columna de identidad el nombre "myparenttable_id". Cuando haga referencia a él desde relaciones secundarias, use el mismo nombre, "myparenttable_id". Nunca nombre nada como "id", y nunca haga referencia a una columna con un nombre diferente. Ah, olvídalo. Simplemente no hagas esto.
Puede tener la tentación de eliminar la ambigüedad del acertijo anterior usando el USING
palabra clave. Eso se vería así:
SELECT *
FROM persons
JOIN places
USING (id);
Pero el USING
La palabra clave solo puede aprovechar las coincidencias exactas de nombres en las tablas. Lo cual, de nuevo, en nuestro ejemplo está totalmente equivocado.
La mejor opción de práctica para PostgreSQL es simplemente evitar el diseño de tablas mediante estándares de convenciones de codificación.
Resumen
Estas técnicas de palabras clave (vs. operadores) también están disponibles en Oracle. Son más multiplataforma y menos ambiguos. Solo eso los convertiría en las mejores prácticas.
Sumado a eso, exponen errores lógicos cuando se usan incorrectamente. Para cualquier desarrollo en PostgreSQL, recomendamos unilateralmente el uso de palabras clave explícitas.