2009-06-21 11 views
35

Estoy tratando de agregar características a una aplicación preexistente y me encontré con una vista MySQL algo como esto:MySQL - Selección de una columna no en Agrupar por

SELECT 
    AVG(table_name.col1), 
    AVG(table_name.col2), 
    AVG(table_name.col3), 
    table_name.personID, 
    table_name.col4 
FROM table_name 
GROUP BY table_name.personID; 

bien así que hay algunas funciones de agregado. Puede seleccionar personID porque está agrupando por él. Pero también selecciona una columna que no está en una función agregada y no forma parte de la cláusula GROUP BY. ¿¿¿Cómo es esto posible??? ¿Simplemente elige un valor aleatorio porque los valores definitivamente no son únicos por grupo?

De donde vengo (servidor MSSQL), eso es un error. ¿Puede alguien explicarme este comportamiento y por qué está permitido en MySQL?

Respuesta

40

Es cierto que esta característica permite algunas consultas ambiguas y silenciosamente devuelve un conjunto de resultados con un valor arbitrario elegido de esa columna. En la práctica, tiende a ser el valor de la fila dentro del grupo que primero se almacena físicamente.

Estas consultas no son ambiguas si solo elige columnas que dependen funcionalmente de la (s) columna (s) en los criterios GROUP BY. En otras palabras, si solo puede haber un valor distinto de la columna "ambigua" por valor que define el grupo, no hay problema. Esta consulta sería ilegal en Microsoft SQL Server (y ANSI SQL), a pesar de que no puede lógicamente dar lugar a la ambigüedad:

SELECT AVG(table1.col1), table1.personID, persons.col4 
FROM table1 JOIN persons ON (table1.personID = persons.id) 
GROUP BY table1.personID; 

Además, MySQL tiene un modo de SQL para hacer que se comporte según la norma: ONLY_FULL_GROUP_BY

FWIW, SQLite también permite estas ambiguas cláusulas GROUP BY, pero elige el valor de última fila en el grupo.


Por lo menos en la versión que probé. Lo que significa ser arbitrario es que MySQL o SQLite podrían cambiar su implementación en el futuro y tener un comportamiento diferente. Por lo tanto, no debe confiar en que el comportamiento se mantenga tal como está actualmente en casos ambiguos como este. Es mejor reescribir las consultas para que sean deterministas y no ambiguas. Es por eso que MySQL 5.7 ahora habilita ONLY_FULL_GROUP_BY de forma predeterminada.

+3

Me gustaría comentar que esto no es del todo cierto. A partir de ANSI SQL-99 los campos seleccionados deben ser agregados, son funcionalmente dependientes de la cláusula group by. Por lo tanto, seleccionar user_name al agrupar por user_id es totalmente correcto. SQL Server y Oracle no cumplen con esto, porque no permitirían que se seleccione user_name cuando solo user_id está en el grupo por lista; y MySQL no cumple, porque no verifica si cada columna seleccionada depende realmente funcionalmente de user_id. –

+0

@ThorstenKettner, gracias, tienes razón. Se ha mejorado MySQL 5.7, y es mucho más inteligente en este caso de compatibilidad con ANSI SQL. –

9

Debería haber buscado en Google por un poco más de tiempo ... Parece que encontré my answer.

MySQL extiende el uso de GROUP BY por lo que puede utilizar columnas no agregadas o cálculos en la lista SELECT que no aparecen en el GROUP BY cláusula. Puede utilizar esta función en para obtener un mejor rendimiento al evitar la clasificación innecesaria de columnas y la agrupación . Por ejemplo, no es necesario a agrupar customer.name en el siguiente consulta

En SQL estándar, tendría que agregar customer.name a la cláusula GROUP BY. En MySQL, el nombre es redundante.

Aún así, eso parece ... equivocado.

+3

Tienes razón en que parece equivocado. ¡Es! Aunque estoy seguro de que hay algunos casos excepcionales, como lo señaló Bill Karwin anteriormente, con demasiada frecuencia he visto desarrolladores que no conocen los datos lo suficientemente bien o cómo funciona realmente esta característica, escriben consultas con cláusulas de grupo incorrecto por y obtener malos resultados Esta función debería estar desactivada de manera predeterminada y permitirse anularla deliberadamente con una opción de consulta para usar en casos en que el ingeniero esté lo suficientemente informado como para usarla. –

+0

No es más "incorrecto" que tener los resultados de retorno 'SELECT * FROM table1' en un orden determinado y consistente: es una característica, no un error. – kmoser

-1
select * from personel where p_id IN(select 
min(dbo.personel.p_id) 
FROM 
personel 
GROUP BY dbo.personel.p_adi) 
+1

Esto definitivamente no responde a la pregunta – Ojen

+0

@Ojen No lo hace, pero _kind_ of_ explica lo que está sucediendo. El código anterior es un ejemplo de cómo este comportamiento no estándar se puede modelar utilizando SQL estándar. – Griddo

Cuestiones relacionadas