sql >> Base de Datos >  >> RDS >> Mysql

MySQL:Total GROUP BY CON ROLLUP curiosidad

Porque no está SELECCIONANDO el elemento por el que está AGRUPANDO. Si dijiste:

GROUP BY c.printable_name

Obtendrías el NULL esperado. Sin embargo, está agrupando por una columna diferente, por lo que MySQL no sabe que printable_name está participando en un grupo acumulativo y selecciona cualquier valor antiguo de esa columna, en la unión de all registros (Por lo tanto, es posible que vea otros países además de Uzbekistán).

Esto es parte de un problema más amplio en el que MySQL es permisivo con lo que puede SELECCIONAR en una consulta GROUP BY. Por ejemplo, puedes decir:

SELECT gender FROM registrations GROUP BY country;

y MySQL elegirá felizmente uno de los valores de género para un registro de cada país, aunque no existe un vínculo causal directo (también conocido como "dependencia funcional") entre el país y el género. Otros DBMS rechazarán el comando anterior con el argumento de que no se garantiza que haya un género por país.(*)

Ahora, esto:

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á bien, porque hay una dependencia funcional entre r.country y c.printable_name (suponiendo que hayas descrito correctamente tu country_id como PRIMARY KEY).

Sin embargo, la extensión WITH ROLLUP de MySQL es un poco complicada en la forma en que funciona. En la etapa de la fila acumulada al final, se ejecuta sobre todo el conjunto de resultados de la agrupación previa para obtener sus valores y luego establece la columna agrupar por en NULL. Tampoco anula otras columnas que tienen una dependencia funcional en esa columna. Probablemente debería, pero MySQL actualmente no entiende todo acerca de las dependencias funcionales.

Entonces, si selecciona c.printable_name, le mostrará el valor de nombre de país que eligió al azar, y si selecciona c.country_id, le mostrará el ID de país que eligió al azar — aunque c.country_id es el criterio de unión, por lo que debe ser lo mismo que r.country, ¡que es NULL!

Lo que puede hacer para solucionar el problema es:

  • agrupar por printable_name en su lugar; debería estar bien si printable_names son únicos, o
  • seleccione "r.country" así como printable_name, y verifique que sea NULL, o
  • olvídese de WITH ROLLUP y realice una consulta separada para la suma final. Esto será un poco más lento pero también será compatible con ANSI SQL-92 para que su aplicación pueda funcionar en otras bases de datos.

(*:MySQL tiene una opción SQL_MODE ONLY_FULL_GROUP_BY se supone que soluciona este problema, pero va demasiado lejos y solo le permite seleccionar columnas de GROUP BY, no columnas que tienen una dependencia funcional en GROUP BY. Por lo tanto, también hará que las consultas válidas fallen, por lo que generalmente es inútil).