Error relacionado con only_full_group_by al ejecutar una consulta en MySql

442

He actualizado mi sistema e instalado MySql 5.7.9 con php para una aplicación web en la que estoy trabajando. Tengo una consulta que se crea dinámicamente, y cuando se ejecuta en versiones anteriores de MySql funciona bien. Desde la actualización a 5.7 me sale este error:

La expresión # 1 de la lista SELECT no está en la cláusula GROUP BY y contiene la columna no agregada 'support_desk.mod_users_groups.group_id' que no depende funcionalmente de las columnas en la cláusula GROUP BY; esto es incompatible con sql_mode = only_full_group_by

Tenga en cuenta la página del Manual para Mysql 5.7 sobre el tema de los modos SQL del servidor .

Esta es la consulta que me está dando problemas:

SELECT mod_users_groups.group_id AS 'value', 
       group_name AS 'text' 
FROM mod_users_groups
LEFT JOIN mod_users_data ON mod_users_groups.group_id = mod_users_data.group_id 
WHERE  mod_users_groups.active = 1 
  AND mod_users_groups.department_id = 1 
  AND mod_users_groups.manage_work_orders = 1 
  AND group_name != 'root' 
  AND group_name != 'superuser' 
GROUP BY group_name 
HAVING COUNT(`user_id`) > 0 
ORDER BY group_name

Busqué en Google sobre el tema, pero no entiendo lo only_full_group_bysuficiente como para descubrir qué necesito hacer para solucionar la consulta. ¿Puedo desactivar la only_full_group_byopción o hay algo más que deba hacer?

Déjeme saber si usted necesita más información.

Dan Bemowski
fuente
aquí encontré la solución stackoverflow.com/a/7588442/612987
Wasim A.
21
Este tiene que ser el mensaje de error más complicado que he encontrado.
Rolf
2
@Rolf ¿Has visto el error para el mismo tipo de problema en Oracle? " not a GROUP BY expression" Eso es. También podrían tener un código de error numérico y ningún mensaje.
Bill Karwin

Respuestas:

359

Solo agregaría group_ida la GROUP BY.

Cuando se SELECTcrea una columna que no forma parte de GROUP BYella, podría haber múltiples valores para esa columna dentro de los grupos, pero solo habrá espacio para un único valor en los resultados. Por lo tanto, la base de datos generalmente necesita que se le diga exactamente cómo convertir esos valores múltiples en un valor. Comúnmente, esto se hace con una función agregada como COUNT(), etc. SUM(), MAX()lo digo generalmente porque la mayoría de los otros sistemas de bases de datos populares insisten en esto. Sin embargo, en MySQL anterior a la versión 5.7, el comportamiento predeterminado ha sido más indulgente porque no se quejará y luego elegirá arbitrariamente cualquier valor . También tiene unANY_VALUE()función que podría usarse como otra solución a esta pregunta si realmente necesitara el mismo comportamiento que antes. Esta flexibilidad tiene un costo porque no es determinista, por lo que no la recomendaría a menos que tenga una muy buena razón para necesitarla. MySQL ahora está activando la only_full_group_byconfiguración de forma predeterminada por buenas razones, por lo que es mejor acostumbrarse a ella y hacer que sus consultas la cumplan.

Entonces, ¿por qué mi respuesta simple anterior? He hecho un par de suposiciones:

1) el group_ides único. Parece razonable, es una 'ID' después de todo.

2) el group_nametambién es único. Esto puede no ser una suposición tan razonable. Si este no es el caso y usted tiene alguna duplicado group_namesy, a continuación, siga mi consejo para agregar group_ida la GROUP BY, es posible que ahora recibe más resultados que antes porque los grupos con el mismo nombre ahora tendrán filas separadas en los resultados. Para mí, esto sería mejor que tener estos grupos duplicados ocultos porque la base de datos ha seleccionado discretamente un valor arbitrariamente.

También es una buena práctica calificar todas las columnas con el nombre o alias de su tabla cuando hay más de una tabla involucrada ...

SELECT 
  g.group_id AS 'value', 
  g.group_name AS 'text' 
FROM mod_users_groups g
LEFT JOIN mod_users_data d ON g.group_id = d.group_id 
WHERE g.active = 1 
  AND g.department_id = 1 
  AND g.manage_work_orders = 1 
  AND g.group_name != 'root' 
  AND g.group_name != 'superuser' 
GROUP BY 
  g.group_name, 
  g.group_id 
HAVING COUNT(d.user_id) > 0 
ORDER BY g.group_name
davmos
fuente
Gracias, eso funciona perfecto. También estoy de acuerdo en que necesito calificar las columnas. Elimina cualquier posibilidad de ambigüedad. Estoy en el proceso de reparar el código ahora. Un millón de gracias por la ayuda.
Dan Bemowski, el
Ni siquiera tengo una GROUP BYcláusula en mi consulta, pero recibo este error.
aitchkhan
@HaroonKhan, eso suena como una nueva pregunta. Avísame si lo preguntas y lo echaré un vistazo.
davmos
2
En MySQL 5.7 establecen una propiedad que requiere que todos los campos no agregados en una consulta sean GROUP BY. Entonces, una consulta como SELECT a, SUM (b) FROM table; significa que el campo "a" debe estar en un GROUP BY. Entonces, si no tiene un GROUP BY, debe agregarlo a la consulta. Se trata de si tiene al menos un campo agregado en la parte SELECCIONAR de su consulta.
user1567291
Tuve que arreglar la "advertencia" agregando el elemento al grupo por la cláusula como se sugiere en esta respuesta porque ninguna de las respuestas que sugirieron soluciones sql_mode funcionó. (mi MySQL estaba en un procedimiento almacenado pero no sé si eso era relevante)
zzapper
355

Puede intentar deshabilitar la only_full_group_byconfiguración ejecutando lo siguiente:

mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

MySQL 8 no acepta, NO_AUTO_CREATE_USERpor lo que debe eliminarse.

WeiYuan
fuente
85
Esta es una solución
alternativa
1
La actualización de /etc/mysql/my.cnf (como se ve a continuación) es una solución más sostenible ya que la configuración predeterminada tiende a volver después del reinicio. Y para aquellos que dicen que debe corregir la consulta, entonces eso no es bastante fácil a veces cuando necesita una consulta de depuración rápida y hace cosas como SELECT COUNT(*), t.* FROM my_table t GROUP BY coly tiene 20-50 columnas, ¿desea pasar tanto tiempo agregando cada columna a la ¿agrupar por?
Shadoweb
3
Esta "solución" es bastante peligrosa. Puede activar los modos que había deshabilitado anteriormente cambiándolos ciegamente en lugar de eliminar solo el indicador de configuración en cuestión. Esto puede conducir a un comportamiento inesperado y, en el peor de los casos, a resultados incorrectos o impedir que sus aplicaciones funcionen por completo. Por lo tanto, considero que esta respuesta es incorrecta.
Chris S.
1
Hice esto persistente a través de la actualización descubriendo mi vía sql_mode actual SELECT @@sql_mode;y luego agregando el resultado desde allí a my.cnf:sql_mode=[list of modes from query, minus ONLY_FULL_GROUP_BY]
wbharding el
323

puede desactivar el mensaje de advertencia como se explica en las otras respuestas o puede comprender lo que está sucediendo y solucionarlo.

A partir de MySQL 5.7.5, el modo SQL predeterminado incluye ONLY_FULL_GROUP_BY, lo que significa que cuando agrupa filas y luego selecciona algo de esos grupos, debe decir explícitamente de qué fila debe hacerse esa selección. Mysql necesita saber qué fila del grupo está buscando, lo que le brinda dos opciones

Mysql necesita saber qué fila del grupo está buscando, lo que le brinda dos opciones

  • También puede agregar la columna que desea a la declaración de grupo, group by rect.color, rect.valueque puede ser lo que desea en algunos casos, de lo contrario, devolvería resultados duplicados con el mismo color que quizás no desee
  • también puede usar funciones agregadas de mysql para indicar qué fila está buscando dentro de los grupos como AVG() MIN() MAX() lista completa
  • Y finalmente puede usarlo ANY_VALUE()si está seguro de que todos los resultados dentro del grupo son los mismos. Doc
azerafati
fuente
25
¿No creo que MySQL sea compatible con el FIRST()método / función?
Ben Guild
3
Creo que MySQL (al menos antes de 5.7) por defecto toma el primer valor que encuentra en un grupo. Por lo tanto, no existe FIRST () porque solía ser sinónimo de la función GROUP BY.
DrDamnit
2
@DrDamnit, creo que era más como una selección aleatoria en tales casos que dieron lugar a confusión y permitiendo de este modo ONLY_FULL_GROUP_BYpor defecto
azerafati
66
Ya sabía la respuesta, pero el ejemplo con el rectángulo de color es tan fácil de entender que lo reutilizaré la próxima vez que alguien me pregunte.
user327961
@azerafati ¿hay algo como FIRST () o alguna consulta que pueda usarse para obtener el primer valor, como es el caso?
Haris
169

Si no desea realizar ningún cambio en su consulta actual, siga los pasos a continuación:

  1. ssh vagabundo en tu caja
  2. Tipo: sudo vim /etc/mysql/my.cnf
  3. Desplácese hasta la parte inferior del archivo y escriba Apara ingresar al modo de inserción
  4. Copiar y pegar

    [mysqld]
    sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    
  5. Escriba escpara salir del modo de entrada

  6. Escriba :wqpara guardar y cerrar vim.
  7. Escriba sudo service mysql restartpara reiniciar MySQL.
Ajai
fuente
Solo un aviso para todos los usuarios de Vagrant que intentan usar esto con AdonisJS necesita esto para ejecutar la paginatefunción.
Michael J. Calkins
Obviamente, esto no es solo para usuarios de Vagrant, sino para cualquier sistema Unix. Tenga en cuenta que para mí la ubicación del my.cnfarchivo era /etc. Als nota la nueva sintaxis desdeMySQL 5.7.8: sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
Valentin Grégoire
Funciona para mí en Mint 19.3 (ubuntu 18.04) gracias
Marco López
71

Use ANY_VALUE()para referirse a la columna no agregada.

SELECT name,           address , MAX(age) FROM t GROUP BY name; -- fails
SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name; -- works

Desde documentos MySQL 5.7 :

Puede lograr el mismo efecto sin deshabilitar ONLY_FULL_GROUP_BY utilizando ANY_VALUE()para hacer referencia a la columna no agregada.

...

Esta consulta puede ser inválida con ONLY_FULL_GROUP_BYhabilitado porque la columna de dirección no agregada en la lista de selección no está nombrada en la GROUP BYcláusula:

SELECT name, address, MAX(age) FROM t GROUP BY name;

...

Si sabe que, para un conjunto de datos dado, cada valor de nombre de hecho determina de manera única el valor de la dirección, la dirección depende funcionalmente del nombre. Para decirle a MySQL que acepte la consulta, puede usar la ANY_VALUE()función:

SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;
Italo Borssatto
fuente
1
Como alguien que se había estado enfrentando a este problema por un tiempo, me gusta especialmente esta solución porque no requiere que cambie ningún archivo o configuración en su configuración de MySQL. Curiosamente, no veo ANY_VALUE mencionado en ningún otro lugar en discusiones similares, funciona perfectamente para mí con mi GROUP_BY contains nonaggregated columnerror.
adstwlearn
50

Intentaré explicarte de qué se trata este error.
A partir de MySQL 5.7.5, la opción ONLY_FULL_GROUP_BYestá habilitada de manera predeterminada.
Por lo tanto, de acuerdo con el estándar SQL92 y anteriores:

no permite consultas para las cuales la lista de selección, la condición HAVING o la lista ORDER BY hacen referencia a columnas no agregadas que no están nombradas en la cláusula GROUP BY ni dependen funcionalmente de (columnas determinadas por GROUP BY)

( leer más en documentos )

Así por ejemplo:

SELECT * FROM `users` GROUP BY `name`;

Recibirá un mensaje de error después de ejecutar la consulta anterior.

# 1055 - La expresión # 1 de la lista SELECT no está en la cláusula GROUP BY y contiene la columna no agregada 'testsite.user.id' que no depende funcionalmente de las columnas en la cláusula GROUP BY; esto es incompatible con sql_mode = only_full_group_by

¿Por qué?
Debido a que MySQL no comprende exactamente qué valores de los registros agrupados recuperar, y este es el punto.

IE digamos que tiene estos registros en su userstabla:
yo

Y ejecutará la consulta no válida que se muestra arriba.
Y obtendrá el error que se muestra arriba, porque hay 3 registros con nombre John, y es bueno, pero todos tienen emailvalores de campo diferentes .
Entonces, MySQL simplemente no entiende cuál de ellos devolver en el registro agrupado resultante.

Puede solucionar este problema simplemente cambiando su consulta de esta manera:

SELECT `name` FROM `users` GROUP BY `name`

Además, es posible que desee agregar más campos a la sección SELECCIONAR, pero no puede hacerlo, si no están agregados, pero hay muleta que podría usar (pero no se recomienda):

SELECT ANY_VALUE(`id`), ANY_VALUE(`email`), `name` FROM `users` GROUP BY `name`

ingrese la descripción de la imagen aquí

Ahora, usted puede preguntar, ¿por qué ANY_VALUEno se recomienda usar ?
Debido a que MySQL no sabe exactamente qué valor de los registros agrupados recuperar, y al usar esta función, le está pidiendo que busque alguno de ellos (en este caso, se obtuvo el correo electrónico del primer registro con nombre = John).
Exactamente, no puedo pensar en por qué querrías que este comportamiento exista.

Por favor, si no me comprende, lea más sobre cómo funciona la agrupación en MySQL, es muy simple.

Y al final, aquí hay una consulta más simple pero válida.
Si desea consultar el recuento total de usuarios según las edades disponibles, puede anotar esta consulta

SELECT `age`, COUNT(`age`) FROM `users` GROUP BY `age`;

Lo cual es totalmente válido, de acuerdo con las reglas de MySQL.
Y así.

Es importante comprender cuál es exactamente el problema y solo entonces escribir la solución.

Abraham Tugalov
fuente
Gracias por esta buena respuesta. ¿Qué sucede si también quiero los correos electrónicos, como una matriz en el grupo de resultados?
Josiah
1
Siempre puede GROUP_CONCAT campo requerido para obtener cada entrada que hay.
Abraham Tugalov
Oh! entonces hay una manera! Por favor, ayúdenme en esta pregunta
Josiah
Gracias por esta gran respuesta. ¿Qué pasa si quiero hacer GROUP BY DAY(created_date)? Parece que no funciona si DAY()se agrega.
esquimal
41

Estoy usando Laravel 5.3, mysql 5.7.12, en laravel homestead (0.5.0, creo)

Incluso después de configurar explícitamente la edición /etc/mysql/my.cnfpara reflejar:

[mysqld]
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

Seguía recibiendo el error.

Tuve que cambiar config/database.phpde truea false:

    'mysql' => [
        'strict' => false, //behave like 5.6
        //'strict' => true //behave like 5.7
    ], 

Otras lecturas:

https://laracasts.com/discuss/channels/servers/set-set-sql-mode-on-homestead https://mattstauffer.co/blog/strict-mode-and-other-mysql-customizations-in-laravel -5-2

Ryan
fuente
Dang! Eso fue útil para los usuarios de Laravel. +1 por eso.
Okafor T Kosiso
20

Si está utilizando wamp 3.0.6 o cualquier versión superior que no sea la versión 2.5 estable, puede enfrentar este problema, en primer lugar, el problema es con sql. tienes que nombrar los campos en consecuencia. pero hay otra forma de resolverlo. Haga clic en el icono verde de wamp. mysql-> mysql settings-> sql_mode-> none. o desde la consola puede cambiar los valores predeterminados.

mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
PiyaChakraborty
fuente
fantástico, basándose en lo que dijo, inserte el comando show variables like '%sql_mode%';en la línea de comando mysql, la configuración sql_mode expondrá
Jade Han
19

Adición de líneas (mención abajo) en el archivo: /etc/mysql/my.cnf

[mysqld]
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

Trabaja bien para mi. Versión del servidor: 5.7.18-0ubuntu0.16.04.1 - (Ubuntu)

Jagdeep Singh
fuente
1
¿Estás usando RDS?
Mubasshir Pawle
@MubasshirPawle No
Jagdeep Singh
16

Vaya a mysql o phpmyadmin y seleccione la base de datos, luego simplemente ejecute esta consulta y funcionará. esta trabajando bien para mi.

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
Anil Gupta
fuente
Genial ... Gracias :)
mohitesachin217
Mi placer :) @mohit
Anil Gupta
Me ahorró un montón de tiempo, gracias.
JoeRaid
1
Bienvenido hermano @TharinduEranga
Anil Gupta
1
Pero el problema con la solución es que cada vez que reinicio mysql necesito ejecutar la consulta nuevamente. Significa que la solución no es permanente ni persistente.
Mushfiqur Rahman
10

Para Mac:

1. Copie my-default.cnf predeterminado a /etc/my.cnf

sudo cp $(brew --prefix mysql)/support-files/my-default.cnf /etc/my.cnf

2.Cambie sql_mode en my.cnf usando su editor favorito y configúrelo en este

sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

3. Reinicie el servidor MySQL.

mysql.server restart
Tanvir Hasan Anick
fuente
Gracias, funcionó para mí también. Pero uso mysql predeterminado de Mac, por lo que no tengo ruta de preparación. Solo sudo cp my-default.cnf /etc/my.cnf
Mike Nguyen
2
@Mike Nguyen sudo cp /usr/local/mysql-5.7.17-macos10.12-x86_64/support-files/my-default.cnf /etc/my.cnf sudo vi /etc/my.cnf set sql_model sql_mode = STRICT_TRANS_TABLES , NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION Reinicie el servidor MySQL.
Yong Gao
7

Esto es lo que me ayudó a entender todo el problema:

  1. https://stackoverflow.com/a/20074634/1066234
  2. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

Y en el siguiente otro ejemplo de una consulta problemática.

Problemático:

SELECT COUNT(*) as attempts, SUM(elapsed) as elapsedtotal, userid, timestamp, questionid, answerid, SUM(correct) as correct, elapsed, ipaddress FROM `gameplay`
                        WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 1 DAY)
                        AND cookieid = #

Resuelto agregando esto al final:

  GROUP BY timestamp, userid, cookieid, questionid, answerid, elapsed, ipaddress

Nota: Vea el mensaje de error en PHP, le dice dónde está el problema.

Ejemplo:

Error de consulta MySQL 1140: en la consulta agregada sin GROUP BY, la expresión # 4 de la lista SELECT contiene la columna no agregada 'db.gameplay.timestamp'; esto es incompatible con sql_mode = only_full_group_by - Consulta: SELECT COUNT (*) como intentos, SUM (transcurrido) como elapsedtotal, userid, timestamp, questionid, answerid, SUM (correcto) como correcto, transcurrido, ipaddress DESDE el juego DONDE marca de tiempo> = DATE_SUB (AHORA (), INTERVALO 1 DÍA) Y userid = 1

En este caso, faltaba la expresión # 4 en GROUP BY.

Kai Noack
fuente
1
Gracias por señalar stackoverflow.com/questions/20074562/…
cwhsu
Gran respuesta para resolver este problema. Muchas gracias
Hansana Athukorala
7

Para localhost / wampserver 3 podemos configurar sql-mode = user_mode para eliminar este error:

click on wamp icon -> MySql -> MySql Setting -> sql-mode -> user_mode

luego reinicie wamp o apache

Braham Dev Yadav
fuente
1
Sé que esto puede no ser una solución a largo plazo para este problema, pero ciertamente ayudó por ahora. Mi empresa de hosting, Go Daddy, está usando MySQL V5.6.33 y WampServer 3 usa MySQL V5.7.14. Gracias por esta solución rápida
Alan N
4

Puedes agregar un unique indexa group_id; si estás seguro de que group_ides único

Puede resolver su caso sin modificar la consulta .

Una respuesta tardía, pero aún no se ha mencionado en las respuestas. Tal vez debería completar las respuestas ya completas disponibles. Al menos resolvió mi caso cuando tuve que dividir una tabla con demasiados campos.

micaball
fuente
2

Si tiene este error con Symfony usando el generador de consultas de doctrina , y si este error es causado por un pedido por :

Preste atención a selectla columna que desea groupByy use en addGroupBylugar de groupBy:

$query = $this->createQueryBuilder('smth')->addGroupBy('smth.mycolumn');

Funciona en Symfony3 -

Gangai Johann
fuente
1

Disculpas por no usar tu SQL exacto

Usé esta consulta para superar la advertencia de Mysql.

SELECT count(*) AS cnt, `regions_id`
FROM regionables 
WHERE `regionable_id` = '115' OR `regionable_id` = '714'
GROUP BY `regions_id`
HAVING cnt > 1

tenga en cuenta la clave para mí ser

count(*) AS cnt
Harry Bosh
fuente