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.