C'est quoi un LATERAL rejoindre ?
La fonctionnalité a été introduite avec PostgreSQL 9.3. Le manuel :
Sous-requêtes apparaissant dans
FROMpeut être précédé du mot cléLATERAL. Cela leur permet de référencer les colonnes fournies parFROMprécédent éléments. (SansLATERAL, chaque sous-requête est évaluée indépendamment et ne peut donc pas renvoyer à un autreFROMarticle.)Fonctions de table apparaissant dans
FROMpeut é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 parFROMpré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
FROMclause ;
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
INNERetOUTERtypes de jointure, une condition de jointure doit être spécifiée, à savoir exactement l'une des valeursNATURAL,ONcondition_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.