C'est quoi un LATERAL
rejoindre ?
La fonctionnalité a été introduite avec PostgreSQL 9.3. Le manuel :
Sous-requêtes apparaissant dans
FROM
peut être précédé du mot cléLATERAL
. Cela leur permet de référencer les colonnes fournies parFROM
précédent éléments. (SansLATERAL
, chaque sous-requête est évaluée indépendamment et ne peut donc pas renvoyer à un autreFROM
article.)Fonctions de table apparaissant dans
FROM
peut également être précédé du mot-cléLATERAL
, mais pour les fonctions le mot clé est facultatif; les arguments de la fonction peuvent contenir des références aux colonnes fournies parFROM
précédent articles dans tous les cas.
Des exemples de code de base y sont donnés.
Plus comme un corrélé sous-requête
A LATERAL
join ressemble plus à une sous-requête corrélée, pas à une sous-requête simple, dans la mesure où les expressions à droite d'un LATERAL
join sont évalués une fois pour chaque ligne restante - tout comme un élément corrélé sous-requête - alors qu'une sous-requête simple (expression de table) est évaluée une fois seul. (Le planificateur de requêtes a cependant des moyens d'optimiser les performances pour l'un ou l'autre.)
Réponse associée avec des exemples de code pour les deux côte à côte, résolvant le même problème :
- Optimiser la requête GROUP BY pour récupérer la dernière ligne par utilisateur
Pour renvoyer plusieurs colonnes , un LATERAL
join est généralement plus simple, plus propre et plus rapide.
N'oubliez pas non plus que l'équivalent d'une sous-requête corrélée est LEFT JOIN LATERAL ... ON true
:
- Appeler plusieurs fois une fonction renvoyant un ensemble avec un argument de tableau
Choses qu'une sous-requête ne peut pas faire
Il y a choses qu'un LATERAL
join peut le faire, mais une sous-requête (corrélée) ne le peut pas (facilement). Une sous-requête corrélée ne peut renvoyer qu'une seule valeur, pas plusieurs colonnes ni plusieurs lignes - à l'exception des appels de fonction nus (qui multiplient les lignes de résultats s'ils renvoient plusieurs lignes). Mais même certaines fonctions de retour d'ensemble ne sont autorisées que dans le FROM
clause. Comme unnest()
avec plusieurs paramètres dans Postgres 9.4 ou version ultérieure. Le manuel :
Ceci n'est autorisé que dans le
FROM
clause ;
Cela fonctionne donc, mais ne peut pas (facilement) être remplacé par une sous-requête :
CREATE TABLE tbl (a1 int[], a2 int[]);
SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2); -- implicit LATERAL
La virgule (,
) dans le FROM
la clause est une notation courte pour CROSS JOIN
.LATERAL
est supposé automatiquement pour les fonctions de table.
À propos du cas particulier de UNNEST( array_expression [, ... ] )
:
- Comment déclarez-vous qu'une fonction set-returning n'est autorisée que dans la clause FROM ?
Fonctions de retour de set dans le SELECT
liste
Vous pouvez également utiliser des fonctions de retour d'ensemble comme unnest()
dans le SELECT
liste directement. Cela présentait un comportement surprenant avec plus d'une fonction de ce type dans le même SELECT
liste jusqu'à Postgres 9.6. Mais il a finalement été aseptisé avec Postgres 10 et est maintenant une alternative valable (même si ce n'est pas le SQL standard). Voir :
- Quel est le comportement attendu pour plusieurs fonctions renvoyant des ensembles dans la clause SELECT ?
S'appuyant sur l'exemple ci-dessus :
SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM tbl;
Comparaison :
dbfiddle pour la page 9.6 ici
dbfiddle pour la page 10 ici
Clarifier les informations erronées
Le manuel :
Pour le
INNER
etOUTER
types de jointure, une condition de jointure doit être spécifiée, à savoir exactement l'une des valeursNATURAL
,ON
condition_jointure , ouUSING
(join_column [, ...]). Voir ci-dessous pour la signification.
PourCROSS JOIN
, aucune de ces clauses ne peut apparaître.
Donc ces deux requêtes sont valides (même si elles ne sont pas particulièrement utiles) :
SELECT *
FROM tbl t
LEFT JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t ON TRUE;
SELECT *
FROM tbl t, LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;
Alors que celui-ci n'est pas :
SELECT *
FROM tbl t
LEFT JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;
C'est pourquoi l'exemple de code d'Andomar est correct (le CROSS JOIN
ne nécessite pas de condition de jointure) et is d'Attila ne l'était pas.