Você pode recuperar convenientemente o passageiro com o nome mais longo por grupo com
DISTINCT ON
. Mas não vejo como combinar isso (ou qualquer outra maneira simples) com sua consulta original em um único
SELECT
. Sugiro juntar duas subconsultas separadas:SELECT *
FROM ( -- your original query
SELECT orig
, count(*) AS flight_cnt
, count(distinct passenger) AS pass_cnt
, percentile_cont(0.5) WITHIN GROUP (ORDER BY bags) AS bag_cnt_med
FROM table1
GROUP BY orig
) org_query
JOIN ( -- my addition
SELECT DISTINCT ON (orig) orig, passenger AS pass_max_len_name
FROM table1
ORDER BY orig, length(passenger) DESC NULLS LAST
) pas USING (orig);
USING
na cláusula join convenientemente gera apenas uma instância de orig
, então você pode simplesmente usar SELECT *
no SELECT
externo . Se
passenger
pode ser NULL, é importante adicionar NULLS LAST
:De vários nomes de passageiros com o mesmo comprimento máximo no mesmo grupo, você recebe uma escolha arbitrária - a menos que você adicione mais expressões a
ORDER BY
como desempate. Explicação detalhada na resposta vinculada acima. Desempenho?
Normalmente, uma única varredura é superior, especialmente com varreduras sequenciais.
A consulta acima usa dois varreduras (talvez varreduras de índice / somente índice). Mas a segunda varredura é comparativamente barata, a menos que a tabela seja muito grande para caber no cache (principalmente). Lukas sugeriu uma consulta alternativa com apenas um único
SELECT
adicionando:, (ARRAY_AGG (passenger ORDER BY LENGTH (passenger) DESC))[1] -- I'd add NULLS LAST
A ideia é inteligente, mas última vez que testei ,
array_agg
com ORDER BY
não teve um desempenho tão bom. (A sobrecarga de ORDER BY
por grupo é substancial, e o manuseio de array também é caro.) A mesma abordagem pode ser mais barata com uma função de agregação personalizada
first()
como instruído no Postgres Wiki aqui
. Ou, ainda mais rápido, com uma versão escrita em C, disponível no PGXN
. Elimina o custo extra para manipulação de array, mas ainda precisamos de ORDER BY
por grupo . Pode ser mais rápido para poucos grupos. Você então adicionaria: , first(passenger ORDER BY length(passenger) DESC NULLS LAST)
Gordon e Lukas mencione também a função de janela
first_value()
. As funções da janela são aplicadas depois funções agregadas. Para usá-lo no mesmo SELECT
, precisaríamos agregar passenger
de alguma forma primeiro - pegue 22. Gordon resolve isso com uma subconsulta - outro candidato para um bom desempenho com o Postgres padrão. first()
faz o mesmo sem subconsulta e deve ser mais simples e um pouco mais rápido. Mas ainda não será mais rápido do que um DISTINCT ON
separado para a maioria dos casos com poucas linhas por grupo. Para muitas linhas por grupo, uma técnica CTE recursiva normalmente é mais rápida. Existem técnicas ainda mais rápidas se você tiver uma tabela separada contendo todos os orig
relevantes e exclusivos valores. Detalhes:A melhor solução depende de vários fatores. A prova do pudim está no comer. Para otimizar o desempenho, você precisa testar com sua configuração. A consulta acima deve estar entre as mais rápidas.