Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MySQL:curiosidade total GROUP BY WITH ROLLUP


Porque você não está selecionando o item pelo qual está agrupando. Se você disse:
GROUP BY c.printable_name

Você obteria o NULL esperado. No entanto, você está agrupando por uma coluna diferente para que o MySQL não saiba que printable_name está participando de um grupo de rollup e seleciona qualquer valor antigo dessa coluna, na junção de all registros. (Portanto, é possível que você veja outros países além do Uzbequistão.)

Isso é parte de um problema mais amplo com o MySQL sendo permissivo sobre o que você pode SELECT em uma consulta GROUP BY. Por exemplo, você pode dizer:
SELECT gender FROM registrations GROUP BY country;

e o MySQL escolherá com prazer um dos valores de gênero para um registro de cada país, mesmo que não haja um vínculo causal direto (também conhecido como “dependência funcional”) entre país e gênero. Outros SGBDs recusarão o comando acima alegando que não há garantia de um gênero por país.(*)

Agora isso:
SELECT c.printable_name AS 'Country', count(*) AS '#' 
FROM registrations r 
INNER JOIN country c ON r.country = c.country_id 
GROUP BY country

está OK, porque há uma dependência funcional entre r.country e c.printable_name (assumindo que você descreveu corretamente seu country_id como uma CHAVE PRIMÁRIA).

No entanto, a extensão WITH ROLLUP do MySQL é um pouco hack na maneira como funciona. No estágio de linha de rollup no final, ele percorre todo o conjunto de resultados de pré-agrupamento para obter seus valores e depois define a coluna group-by como NULL. Ele também não anula outras colunas que tenham uma dependência funcional nessa coluna. Provavelmente deveria, mas o MySQL atualmente não entende tudo sobre dependências funcionais.

Portanto, se você selecionar c.printable_name, ele mostrará o valor do nome do país escolhido aleatoriamente, e se você selecionar c.country_id, ele mostrará o ID do país escolhido aleatoriamente — mesmo que c.country_id seja o critério de junção, então deve ser o mesmo que r.country, que é NULL!

O que você pode fazer para contornar o problema é:
  • grupo por printable_name em vez disso; deve estar OK se printable_names for único, ou
  • selecione "r.country" e printable_name e verifique se é NULL ou
  • esqueça WITH ROLLUP e faça uma consulta separada para a soma final. Isso será um pouco mais lento, mas também será compatível com ANSI SQL-92 para que seu aplicativo possa funcionar em outros bancos de dados.

(*:MySQL tem uma opção SQL_MODE ONLY_FULL_GROUP_BY que deveria resolver esse problema, mas vai longe demais e só permite selecionar colunas do GROUP BY, não colunas que têm uma dependência funcional do GROUP BY. Portanto, também fará com que as consultas válidas falhem, tornando-as geralmente inúteis.)