2009-08-03 12 views
49

Sorpresa - se trata de una consulta perfectamente válido en MySQL:¿Por qué MySQL permite consultas de "grupo por" SIN funciones agregadas?

select X, Y from someTable group by X 

Si ha intentado esta consulta en Oracle o SQL Server, se obtendría el mensaje de error natural:

Column 'Y' is invalid in the select list because it is not contained in 
either an aggregate function or the GROUP BY clause. 

Entonces, ¿cómo ¿MySQL determina qué Y mostrar para cada X? Solo elige uno. Por lo que puedo decir, solo elige la primera Y que encuentra. La racionalidad es que, si Y no es una función agregada ni en la cláusula group by, entonces especificar "select Y" en su consulta no tiene sentido para empezar. Por lo tanto, como motor de base de datos devolveré lo que quiera, y te gustará.

Incluso hay un parámetro de configuración MySQL para desactivar esta "holgura". http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by

Este artículo incluso menciona cómo MySQL ha sido criticado por ser ANSI-SQL no conforme a este respecto. http://www.oreillynet.com/databases/blog/2007/05/debunking_group_by_myths.html

Mi pregunta es: ¿Por qué fue MySQL diseñado de esta manera? ¿Cuál fue su razón de ser para romper con ANSI-SQL?

+0

Déjame ponerlo de esta manera. Veo que esta elección de diseño es equivalente a un lenguaje de programación que elige permitir e ignorar, por ejemplo, dejar que "nulo" sea un valor del lado izquierdo. p.ej. "null = 3". Simplemente no hay razón para dejar que eso suceda. Es el tipo de error que siempre y peligrosamente está mal. –

+3

@lumpynose, tonterías, que pueden haber sido ciertas antes 5.x – Johan

+4

@lumpynose ¿Puedes dar una referencia a tu afirmación? – Barranka

Respuesta

11

creo que era para manejar el caso en el que la agrupación por un campo implicaría otros campos también se están agrupadas:

SELECT user.id, user.name, COUNT(post.*) AS posts 
FROM user 
    LEFT OUTER JOIN post ON post.owner_id=user.id 
GROUP BY user.id 

En este caso el user.name siempre será única por user.id, entonces hay conveniencia en no requerir el nombre de usuario en la cláusula GROUP BY (aunque, como dices, hay un margen definido para problemas)

+1

¿Así que fue solo para guardar algo de mecanografía (como en la escritura de teclado)? Je. –

+2

Menos columnas en la cláusula GROUP BY significa un tiempo de ejecución más rápido, por lo que es un truco de optimización. Estoy usando de forma restrictiva 'MAX (nombre de usuario) AS nombre' en consultas similares en implementaciones ANSI SQL. – wqw

+0

@wqw: basura. user.name está en el grupo por o en un agregado. Esto es ambiguo en el mejor de los casos Ver comentarios en http://stackoverflow.com/questions/6060241/which-is-the-aast-expensive-aggregate-function-in-the-absence-of-any/6060419#6060419 Solo MySQL permite tales bollocks, por ejemplo http://stackoverflow.com/q/6642241/27535 – gbn

1

Desafortunadamente, casi todas las variedades SQL tienen situaciones donde rompen ANSI y tienen resultados impredecibles.

Me parece que querían que se tratara como la "PRIMERA (Y)" función que tienen muchos otros sistemas.

Lo más probable es que este constructo sea algo que el equipo de MySQL lamenta, pero no quiere dejar de apoyar debido a la cantidad de aplicaciones que se romperían.

Rob

19

Según this page (el manual en línea 5.0), que es para un mejor rendimiento y la comodidad del usuario.

+0

+1 Enlace directo a la respuesta –

+0

+1, para la respuesta de MySQL :). Utilizo esto todo el tiempo para evitar hacer una subconsulta que hace un 'ORDER BY ... LIMIT 1' ... solo debes tener cuidado al saber que los datos que recibes en columnas no agregadas serán aleatorios a todas las filas que coinciden con sus condiciones. –

+0

LInk está muerto, ¿puedes actualizarlo? o mejor aún, inserte los documentos aquí en caso de que se rompa nuevamente – szx

1

MySQL trata esta es una sola columna DISTINCT cuando usa GROUP BY sin una función de agregado. Al usar otras opciones, puede tener el resultado completo distinto, o tener que usar subconsultas, etc. La pregunta es si los resultados son realmente predecibles.

Además, buena información está en this thread.

-1

Es realmente una herramienta muy útil que todos los otros campos no tienen que estar en una función agregada cuando se agrupa por un campo. Puede manipular el resultado que se devolverá simplemente ordenándolo primero y luego agrupándolo. por ejemplo, si quería obtener información de inicio de sesión de usuario y quería ver la última vez que el usuario inició sesión, haría esto.

Tablas

USER 
user_id | name 

USER_LOGIN_HISTORY 
user_id | date_logged_in 

USER_LOGIN_HISTORY tiene múltiples filas para un usuario por lo que si me unía a los usuarios que volvería muchas filas. como soy sólo está interesado en la última entrada Me gustaría hacer esto

select 
    user_id, 
    name, 
    date_logged_in 

from(

    select 
    u.user_id, 
    u.name, 
    ulh.date_logged_in 

    from users as u 

    join user_login_history as ulh 
     on u.user_id = ulh.user_id 

    where u.user_id = 1234 

    order by ulh.date_logged_in desc 

)as table1 

group by user_id 

Esto volvería una fila con el nombre del usuario y la última vez que el usuario ha iniciado sesión.

+0

Mi ejemplo anterior es solo siendo utilizado puramente para mostrar cómo puede manipular el resultado devuelto.No digo que esta sea la forma en que devolvería esa información de la manera más simple. Utilizarías la función MAX. Con consultas mucho más complejas, resulta muy útil poder agrupar sin usar funciones agregadas en todos los demás campos –

+0

Este ejemplo artificial es a la vez más largo y más lento que simplemente realizar un "máximo" directo y, por lo tanto, no respalda su afirmación de que esta es "una herramienta muy útil" en absoluto. Si no puede siquiera imaginar un ejemplo de utilidad, cuestiono seriamente su utilidad. Tampoco creo que el uso intencional de lo que con frecuencia es una funcionalidad indeterminada vaya a ser * más * útil en * más * consultas complejas. –

0

Por lo que he leído en la página de referencia de mysql, dice: "Puede utilizar esta característica para obtener un mejor rendimiento al evitar la clasificación y agrupación innecesaria de columnas. Sin embargo, esto es útil principalmente cuando todos los valores en cada columna no agregada no nombrada en GROUP BY son los mismos para cada grupo ".

sugiero que lea esta página (enlace al manual de referencia de MySQL): http://dev.mysql.com/doc/refman/5.5/en//group-by-extensions.html

Cuestiones relacionadas