Eu tenho uma tabela que se parece com esse chamador 'makerar'
cname | wmname | avg
--------+-------------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
E eu quero selecionar a média máxima para cada cname.
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
mas vou receber um erro,
ERROR: column "makerar.wmname" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
então eu faço isso
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname, wmname;
no entanto, isso não fornecerá os resultados pretendidos e a saída incorreta abaixo é mostrada.
cname | wmname | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
Os resultados reais devem ser
cname | wmname | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | usopp | 5.0000000000000000
Como posso resolver esse problema?
Nota: Esta tabela é uma VIEW criada a partir de uma operação anterior.
sql
group-by
aggregate-functions
postgresql-9.1
Cara aleatório
fonte
fonte
wmname="usopp"
esperado e não por exemplowmname="luffy"
?Respostas:
Sim, este é um problema de agregação comum. Antes do SQL3 (1999) , os campos selecionados devem aparecer na
GROUP BY
cláusula [*].Para solucionar esse problema, você deve calcular o agregado em uma subconsulta e depois associá-lo a si mesmo para obter as colunas adicionais que você precisa mostrar:
Mas você também pode usar as funções da janela, que parecem mais simples:
A única coisa com esse método é que ele mostrará todos os registros (as funções da janela não agrupam). Mas ele mostrará o correto (ou seja, no
cname
nível máximo )MAX
para o país em cada linha, então é você quem decide:A solução, sem dúvida menos elegante, para mostrar as únicas
(cname, wmname)
tuplas que correspondem ao valor máximo, é:[*]: Curiosamente, mesmo que o tipo de especificação permita selecionar campos não agrupados, os principais mecanismos parecem não gostar muito dele. Oracle e SQLServer simplesmente não permitem isso. O Mysql costumava permitir isso por padrão, mas agora desde 5.7 o administrador precisa habilitar esta opção (
ONLY_FULL_GROUP_BY
) manualmente na configuração do servidor para que esse recurso seja suportado ...fonte
MAX
(veja a resposta por @ypercube, também há outra solução na minha resposta), mas não da maneira que você faz. Verifique a saída esperada.avg
porcname
), mas não restringe as linhas do resultado (como o OP deseja). Veja os resultados reais devem ser parágrafos na pergunta.ONLY_FULL_GROUP_BY
MySQL 5.7 não ativa a maneira como o padrão SQL especifica quando as colunas podem ser omitidas dogroup by
(ou faz o MySQL se comportar como o Postgres). Ele apenas reverte para o antigo comportamento, onde o MySQL retorna resultados aleatórios (= "indeterminados").No Postgres, você também pode usar a
DISTINCT ON (expression)
sintaxe especial :fonte
BY cname
?O problema com a especificação de campos não agrupados e não agregados em
group by
selects é que o mecanismo não tem como saber qual campo de registro ele deve retornar nesse caso. É o primeiro? É o último? Geralmente, não há registro que corresponda naturalmente ao resultado agregado (min
emax
são exceções).No entanto, existe uma solução alternativa: agregue também o campo obrigatório. No posgres, isso deve funcionar:
Note que isso cria uma matriz de todos os wnames, ordenados por avg, e retorna o primeiro elemento (as matrizes no postgres são baseadas em 1).
fonte
Usando a
rank()
função de janela :Nota
Qualquer um deles preservará vários valores máximos por grupo. Se você deseja apenas um registro único por grupo, mesmo que haja mais de um registro com avg igual a max, verifique a resposta do @ ypercube.
fonte
Para mim, não se trata de um "problema de agregação comum", mas apenas de uma consulta SQL incorreta. A resposta correta e única para "selecione a média máxima de cada nome de domínio ..." é
O resultado será:
Esse resultado, em geral, responde à pergunta "Qual é o melhor resultado para cada grupo?" . Vemos que o melhor resultado para a Espanha é 5 e para o Canadá o melhor resultado é 2. É verdade e não há erro. Se precisarmos exibir o wmname também, teremos que responder à pergunta: "Qual é a REGRA para escolher o wmname do conjunto resultante?" Vamos mudar um pouco os dados de entrada para esclarecer o erro:
Qual resultado você espera ao executar esta consulta
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
:? Deveria serspain+luffy
ouspain+usopp
? Por quê? Não é determinado na consulta como escolher "melhor" wmname se vários forem adequados, portanto, o resultado também não é determinado. É por isso que o interpretador SQL retorna um erro - a consulta não está correta.Em outras palavras, não há resposta correta para a pergunta "Quem é o melhor em
spain
grupo?" . Luffy não é melhor que usopp, porque usopp tem a mesma "pontuação".fonte
SELECT cname, id, MAX(avg) FROM makerar GROUP BY cname;
que deu esse erro enganoso.Isso parece funcionar bem
fonte
Recentemente, encontrei esse problema ao tentar contar usando
case when
e descobri que alterar a ordem das instruçõeswhich
ecount
corrige o problema:Em vez de usar - neste último, onde obtive erros que maçãs e laranjas devem aparecer em funções agregadas
fonte
which
afirmação?