PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Fractionner l'enregistrement renvoyé par la fonction en plusieurs colonnes

Dans Postgres 9.3 ou plus tard, cela est mieux résolu avec un LATERAL rejoindre :

SELECT *
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LEFT   JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT  10;

Évite l'évaluation répétée de la fonction (pour chaque colonne de la sortie - la fonction doit être appelée pour chaque ligne d'entrée dans les deux sens).
LEFT JOIN LATERAL ... ON true pour éviter de supprimer des lignes du côté gauche si la fonction ne renvoie aucune ligne :

  • Quelle est la différence entre LATERAL et une sous-requête dans PostgreSQL ?

Suite dans votre commentaire :

uniquement les colonnes développées produites par l'appel de la fonction

SELECT x.*  -- that's all!
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LEFT   JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT  10;

Mais comme vous ne vous souciez pas des autres colonnes, vous pouvez simplifier :

SELECT x.*
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
     , hi_lo(a.actor_id, length(a.name), ma.movie_id) x
LIMIT  10;

Qui est un CROSS JOIN LATERAL implicite . Si la fonction peut réellement renvoyer "aucune ligne" de temps en temps, le résultat peut être différent :nous n'obtenons pas de valeurs NULL pour les lignes, ces lignes sont simplement éliminées - et LIMIT ne les compte plus.

Dans les anciennes versions (ou généralement) vous pouvez aussi simplement décomposer le type composite avec la bonne syntaxe :

SELECT *, (hi_lo(a.actor_id, length(a.name), ma.movie_id)).*  -- note extra parentheses!
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LIMIT  10;

L'inconvénient est que la fonction est évaluée une fois pour chaque colonne dans la sortie de la fonction en raison d'une faiblesse du planificateur de requêtes Postgres. Il est préférable de déplacer l'appel dans une sous-requête ou CTE et de décomposer le type de ligne dans le SELECT externe . Comme :

SELECT actor_id, movie_id, (x).*  -- explicit column names for the rest
FROM  (
   SELECT *, hi_lo(a.actor_id, length(a.name), ma.movie_id) AS x
   FROM   actors a 
   JOIN   movies_actors ma on a.actor_id = ma.movie_id 
   LIMIT  10
   ) sub;

Mais vous devez nommer des colonnes individuelles et ne pouvez pas vous en sortir avec SELECT * sauf si vous êtes d'accord avec le type de ligne dans le résultat de manière redondante.Related :

  • Éviter plusieurs appels sur la même fonction lors de l'expansion du résultat composite
  • Comment éviter plusieurs évaluations de fonction avec la syntaxe (func()).* dans une requête SQL ?