PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

O registro retornado da função tem colunas concatenadas


Geralmente, para decompor linhas retornado de uma função e obtém colunas individuais:
SELECT * FROM account_servicetier_for_day(20424, '2014-08-12');


Quanto à consulta:

Postgres 9.3 ou mais recente


Limpador com 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;

O LATERAL a palavra-chave está implícita aqui, as funções sempre podem se referir a FROM anterior Itens. O manual:

LATERAL também pode preceder uma chamada de função FROM item, mas neste caso é uma palavra de ruído, porque a expressão da função pode se referir a FROM anterior itens em qualquer caso.

Relacionado:
  • Inserir várias linhas em uma tabela com base no número em outra tabela

Notação curta com uma vírgula no FROM list é (principalmente) equivalente a um CROSS JOIN LATERAL (o mesmo que [INNER] JOIN LATERAL ... ON TRUE ) e, portanto, remove linhas do resultado em que a chamada de função não retorna nenhuma linha. Para manter essas linhas, use LEFT JOIN LATERAL ... ON TRUE :
...
FROM  account_tab a
LEFT  JOIN LATERAL account_servicetier_for_day(a.accountid, '2014-08-12') f ON TRUE
...

Além disso, não use NOT IN (subquery) quando você pode evitá-lo. É a mais lenta e complicada de várias maneiras de fazer isso:
  • Selecione as linhas que não estão presentes em outra tabela

Sugiro NOT EXISTS em vez de.

Postgres 9.2 ou anterior


Você pode chamar uma função de retorno de conjunto no SELECT list (que é uma extensão do Postgres do SQL padrão). Por motivos de desempenho, isso é melhor feito em uma subconsulta. Decomponha o tipo de linha (conhecido!) na consulta externa para evitar avaliações repetidas da função:
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;

Resposta relacionada de Craig Ringer com uma explicação, por que é melhor decompor na consulta externa:
  • Como evitar várias avaliações de função com a sintaxe (func()).* em uma consulta SQL?

Postgres 10 removeu esquisitices no comportamento de funções de retorno de conjunto no SELECT :
  • Qual ​​é o comportamento esperado para várias funções de retorno de conjunto na cláusula SELECT?