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çãoFROM
item, mas neste caso é uma palavra de ruído, porque a expressão da função pode se referir aFROM
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?