Solución:
tienes una “solución”, así que al decir
Me pregunto si existe una solución mejor.
Creo que quieres comentarlo. Permítanme centrarme en varios aspectos:
-
SELECT ID [...] GROUP BY word
, independientemente de tener o no unWITH ROLLUP
Está Mal. Estás seleccionando un campo cuyo valor es indeterminado. En particular, con MySQL se expone a devolver un valor aleatorio; o si usa un modo estricto (recomendado, y por defecto en las últimas versiones de MySQL), la consulta fallará: ‘db_9_b0ff7.test.ID’ no está en GROUP BY -
Ya sea formalmente o no,
WITH ROLLUP
Nota: (me refiero a la implementación de MySQL) es algo que es bueno tener en algunos casos porque evita una doble exploración de la tabla, pero no he visto mucho en el código de producción. No tiene nada de malo, pero eran una función exclusiva de MSSQL hasta que se implementó en SQL1999, y no estaba disponible ampliamente en el pasado o, como en el caso de MySQL fue una implementación limitada. Referencia: https://www.percona.com/blog/2007/09/17/using-group-by-with-rollup-for-reporting-performance-optimization/ -
No veo en principio un problema con su consulta final, si ejecutamos explicar en ambas consultas (sin ID), vemos:
MariaDB [test]> EXPLAIN SELECT if(count(word) = 0, "empty", ifnull(word, "total")) as word, count(*) as occurrences FROM test group by word with ROLLUPG *************************** 1. row *************************** id: 1 select_type: SIMPLE table: test type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4 Extra: Using filesort 1 row in set, 1 warning (0.00 sec) Warning (Code 1052): Column 'word' in group statement is ambiguous MariaDB [test]> EXPLAIN SELECT ifnull(word, "total") as word, count(*) as occurrences FROM ( SELECT ifnull(word, "empty") as word FROM test ) tmp GROUP BY word WITH ROLLUPG *************************** 1. row *************************** id: 1 select_type: SIMPLE table: test type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4 Extra: Using filesort 1 row in set, 1 warning (0.01 sec)
Normalmente, el odio hacia MySQL se debe a sus limitaciones en las primeras versiones de MySQL. No voy a decir que ahora sea perfecto, todavía habrá problemas, ya que el desarrollo de MySQL, como siempre ha sido, se centró en un RDBMS rápido, fácil de entrar y salir, y no en un motor relacional en toda regla. , pero una subconsulta en el lugar correcto está bien (después de todo, algunas consultas requerirán una subconsulta, pase lo que pase. Tu uso está bien– solo tendrá una sobrecarga de repasar las filas resumidas nuevamente y supongo que en el trato real, esas no serán significativas en comparación con el conjunto completo.
Nota: en mi instancia aquí arriba, la subconsulta no se muestra, pero puede verla con subconsultas materializadas en 5.6 aquí: http://sqlfiddle.com/#!9/b0ff7/7 (Ejecutará la consulta interna y luego la parte exterior, sin problema). Un índice definitivamente podría ayudar aquí (debido a la clasificación de archivos), pero eso depende del número final de registros. La subconsulta puede perjudicar el rendimiento si un índice (que no existe ahora) no se puede utilizar porque. Debe probar su versión específica de mysql y crear dicho índice.
- Creo que su problema es con el modelo de datos: en el mundo SQL (fuera de Oracle) NULL es un valor desconocido / no válido. Parece estar correlacionando eso con ‘vacío’, lo cual no es correcto; si se sabe que una palabra no existe, debería ser ” (la cadena vacía, no NULL). No se si puedes cambiar eso, pero No me gusta tu modelo actual. Entiendo que es posible que no tenga algo que decir al respecto, así que no me centraré en eso. ¿También cuentas palabras NULAS? Más razones para usar ” en lugar de NULL.
-
Ahora la pregunta final es, ¿es posible hacerlo sin una subconsulta en MySQL, y será mejor / menos feo? Realmente no veo un camino– podríamos hacer una unión, pero seguirá siendo una subconsulta. Puedo pensar en una alternativa, que es:
SELECT * FROM ( SELECT word, count(*) as occurrences FROM test GROUP BY word with rollup) tmp ORDER BY occurrences;
Eso asegura que la última fila contenga el resumen (y si hay otro nulo, es el valor nulo real). El orden ocurriría incluso en el caso de solo valores nulos. Por el contrario, es posible que sea incluso más lento, ya que requiere un pedido y, nuevamente, es posible que necesite un índice, y ese índice puede o no usarse.
Puede evitar las subconsultas y optimizar los caracteres escritos con esta consulta:
SELECT
ifnull(word, "empty") as word,
count(*) as occurrences
FROM test
GROUP BY ifnull(word, "empty") WITH ROLLUP
;
Esto básicamente reemplaza null
valores con su marcador “vacío” antes de realizar la agrupación:
- los recuentos nulos se pueden encontrar en la fila que contiene el valor “vacío” en la columna de agrupación
- los recuentos totales se pueden encontrar en la fila que contiene
null
valor en la columna de agrupación
Se puede utilizar un enfoque similar para PostgreSQL, esto no debería ser necesario para SQL Server ya que proporciona un GROUPING
función.