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

L'enregistrement renvoyé par la fonction a des colonnes concaténées

Généralement, pour décomposer les lignes renvoyé par une fonction et obtenir des colonnes individuelles :

SELECT * FROM account_servicetier_for_day(20424, '2014-08-12');

Quant à la requête :

Postgres 9.3 ou version ultérieure

Nettoyeur avec JOIN LATERAL :

SELECT '2014-08-12' AS day, 0 AS inbytes, 0 AS outbytes
     , a.username, a.accountid, a.userid
     , f.*   -- but avoid duplicate column names!
FROM   account_tab a
     , account_servicetier_for_day(a.accountid, '2014-08-12') f  -- <-- HERE
WHERE  a.isdsl = 1
AND    a.dslservicetypeid IS NOT NULL
AND    NOT EXISTS (
   SELECT 1
   FROM   dailyaccounting_tab
   WHERE  day = '2014-08-12'
   AND    accountid = a.accountid
   )
ORDER  BY a.username;

Le LATERAL le mot-clé est implicite ici, les fonctions peuvent toujours faire référence à FROM antérieur éléments. Le manuel :

LATERAL peut également précéder un appel de fonction FROM élément, mais dans ce cas, il s'agit d'un mot parasite, car l'expression de la fonction peut faire référence à un FROM antérieur articles dans tous les cas.

Connexe :

  • Insérer plusieurs lignes dans un tableau en fonction du nombre dans un autre tableau

Notation courte avec une virgule dans le FROM list est (principalement) équivalent à un CROSS JOIN LATERAL (identique à [INNER] JOIN LATERAL ... ON TRUE ) et supprime ainsi les lignes du résultat là où l'appel de fonction ne renvoie aucune ligne. Pour conserver ces lignes, utilisez LEFT JOIN LATERAL ... ON TRUE :

...
FROM  account_tab a
LEFT  JOIN LATERAL account_servicetier_for_day(a.accountid, '2014-08-12') f ON TRUE
...

Aussi, n'utilisez pas NOT IN (subquery) quand vous pouvez l'éviter. Il s'agit de la méthode la plus lente et la plus délicate :

  • Sélectionnez les lignes qui ne sont pas présentes dans un autre tableau

Je suggère que NOT EXISTS à la place.

Postgres 9.2 ou version antérieure

Vous pouvez appeler une fonction de retour d'ensemble dans le SELECT list (qui est une extension Postgres du SQL standard). Pour des raisons de performances, il est préférable de le faire dans une sous-requête. Décomposez le type de ligne (bien connu !) dans la requête externe pour éviter une évaluation répétée de la fonction :

SELECT '2014-08-12' AS day, 0 AS inbytes, 0 AS outbytes
     , a.username, a.accountid, a.userid
     , (a.rec).*   -- but avoid duplicate column names!
FROM  (
   SELECT *, account_servicetier_for_day(a.accountid, '2014-08-12') AS rec
   FROM   account_tab a
   WHERE  a.isdsl = 1
   AND    a.dslservicetypeid Is Not Null
   AND    NOT EXISTS (
       SELECT 1
       FROM   dailyaccounting_tab
       WHERE  day = '2014-08-12'
       AND    accountid = a.accountid
      )
   ) a
ORDER  BY a.username;

Réponse connexe de Craig Ringer avec une explication, pourquoi nous ferions mieux de décomposer dans la requête externe :

  • Comment éviter plusieurs évaluations de fonction avec la syntaxe (func()).* dans une requête SQL ?

Postgres 10 suppression des bizarreries dans le comportement des fonctions de retour d'ensemble dans le SELECT :

  • Quel est le comportement attendu pour plusieurs fonctions renvoyant des ensembles dans la clause SELECT ?