Errore relativo a only_full_group_by durante l'esecuzione di una query in MySql


442

Ho aggiornato il mio sistema e ho installato MySql 5.7.9 con php per un'applicazione web su cui sto lavorando. Ho una query che viene creata in modo dinamico e quando viene eseguita nelle versioni precedenti di MySql funziona bene. Dall'aggiornamento a 5.7 ottengo questo errore:

L'espressione n. 1 dell'elenco SELECT non è nella clausola GROUP BY e contiene la colonna non aggregata 'support_desk.mod_users_groups.group_id' che non dipende funzionalmente dalle colonne nella clausola GROUP BY; questo è incompatibile con sql_mode = only_full_group_by

Nota la pagina del manuale per Mysql 5.7 sull'argomento Modalità server SQL .

Questa è la domanda che mi sta dando problemi:

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

Ho fatto un po 'di google sul problema, ma non capisco only_full_group_byabbastanza per capire cosa devo fare per risolvere la query. Posso semplicemente disattivare l' only_full_group_byopzione o c'è qualcos'altro che devo fare?

Fammi sapere se hai bisogno di maggiori informazioni.


qui ho trovato la soluzione stackoverflow.com/a/7588442/612987
Wasim A.

21
Questo deve essere il messaggio di errore più contorto che abbia mai incontrato.
Rolf,

2
@Rolf Hai visto l'errore per lo stesso tipo di problema in Oracle? " not a GROUP BY expression" Questo è tutto. Potrebbero anche avere un codice numerico di errore e nessun messaggio.
Bill Karwin,

Risposte:


360

Vorrei solo aggiungere group_id al GROUP BY.

Quando SELECTsi inserisce una colonna che non fa parte del gruppo GROUP BY, potrebbero esserci più valori per quella colonna all'interno dei gruppi, ma nei risultati ci sarà solo spazio per un singolo valore. Pertanto, di solito è necessario dire al database esattamente come trasformare quei valori multipli in un unico valore. Comunemente, questo è fatto con una funzione di aggregazione come COUNT(), SUM(), MAX()ecc ... Dico di solito perché la maggior parte di altri sistemi di database popolari insistono su questo. Tuttavia, in MySQL prima della versione 5.7 il comportamento predefinito è stato più tollerante perché non si lamenterà e quindi sceglierà arbitrariamente qualsiasi valore ! Ha anche unANY_VALUE()funzione che potrebbe essere utilizzata come un'altra soluzione a questa domanda se fosse necessario lo stesso comportamento di prima. Questa flessibilità ha un costo perché non è deterministica, quindi non lo consiglierei a meno che tu non abbia un'ottima ragione per averne bisogno. MySQL ora attiva l' only_full_group_byimpostazione per impostazione predefinita per buoni motivi, quindi è meglio abituarsi e fare in modo che le query siano conformi.

Allora perché la mia semplice risposta sopra? Ho formulato un paio di ipotesi:

1) il group_idè unico. Sembra ragionevole, dopo tutto è un "ID".

2) group_nameè anche unico. Questo potrebbe non essere un presupposto così ragionevole. Se questo non è il caso e hai qualche duplicato group_namese segui il mio consiglio per aggiungeregroup_id alGROUP BY , potresti scoprire che ora ottieni più risultati di prima perché i gruppi con lo stesso nome ora avranno righe separate nei risultati. Per me, sarebbe meglio che nascondere questi gruppi duplicati perché il database ha silenziosamente selezionato un valore arbitrariamente!

È anche buona norma qualificare tutte le colonne con il nome o l'alias della tabella quando è coinvolta più di una tabella ...

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

Grazie, funziona perfettamente. Sono anche d'accordo che devo qualificare le colonne. Elimina ogni possibilità di ambiguità. Sono in procinto di riparare il codice ora. Grazie mille per l'aiuto.
Dan Bemowski il

Non ho nemmeno una GROUP BYclausola nella mia query, ma ricevo questo errore.
aitchkhan,

@HaroonKhan, sembra una nuova domanda. Fammi sapere se lo chiedi e darò un'occhiata.
davmos,

2
In MySQL 5.7 hanno impostato una proprietà che richiede che tutti i campi non aggregati in una query siano GROUP BY. Quindi una query come SELECT a, SUM (b) FROM table; significa che il campo "a" deve essere in un GROUP BY. Quindi, se non si dispone di un GROUP BY, è necessario aggiungerlo alla query. Si tratta di avere almeno un campo aggregato nella parte SELECT della query.
user1567291,

ho dovuto correggere l '"avvertimento" aggiungendo l'articolo al gruppo per clausola come suggerito in questa risposta perché nessuna delle risposte che suggeriva correzioni sql_mode ha funzionato. (il mio MySQL era in una procedura memorizzata ma non so se fosse rilevante)
zzapper il

355

Puoi provare a disabilitare l' only_full_group_byimpostazione eseguendo quanto segue:

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 non accetta NO_AUTO_CREATE_USERquindi deve essere rimosso.


85
Questa è una soluzione, è meglio risolvere la tua query piuttosto che mettere a tacere l'avvertimento
azerafati

1
L'aggiornamento di /etc/mysql/my.cnf (come visto di seguito) è una soluzione più sostenibile poiché le impostazioni predefinite tendono a tornare dopo il riavvio. E per quelli che dicono che dovresti correggere la query, a volte non è abbastanza facile quando hai bisogno di una query di debug veloce e fai cose come SELECT COUNT(*), t.* FROM my_table t GROUP BY cole hai 20-50 colonne, vuoi dedicare così tanto tempo ad aggiungere ogni colonna al raggruppare per?
Shadoweb,

3
Questa "soluzione" è piuttosto pericolosa. Puoi attivare le modalità che hai disabilitato in precedenza modificandole ciecamente invece di rimuovere solo il flag delle impostazioni in questione. Ciò può comportare comportamenti imprevisti e, nel peggiore dei casi, portare a risultati errati o impedire il funzionamento completo delle tue app. Quindi considero questa risposta come sbagliata.
Chris S.,

1
Ho reso questo persistente attraverso l'aggiornamento, capendo il mio sql_mode corrente tramite SELECT @@sql_mode;e quindi aggiungendo il risultato da lì a my.cnf:sql_mode=[list of modes from query, minus ONLY_FULL_GROUP_BY]
wbharding

323

puoi disattivare il messaggio di avviso come spiegato nelle altre risposte oppure puoi capire cosa sta succedendo e risolverlo.

A partire da MySQL 5.7.5, la modalità SQL predefinita include ONLY_FULL_GROUP_BY, il che significa che quando si raggruppano le righe e si seleziona qualcosa da quei gruppi, è necessario dire esplicitamente da quale riga deve essere effettuata tale selezione. Mysql deve sapere quale riga del gruppo stai cercando, il che ti offre due opzioni

Mysql deve sapere quale riga del gruppo stai cercando, il che ti offre due opzioni

  • È inoltre possibile aggiungere la colonna desiderata all'istruzione di gruppo group by rect.color, rect.valueche può essere ciò che si desidera in alcuni casi, altrimenti si restituirebbero risultati duplicati con lo stesso colore che non si desidera
  • puoi anche usare le funzioni aggregate di mysql per indicare quale riga stai cercando all'interno dei gruppi come AVG() MIN() MAX() l'elenco completo
  • E infine puoi usare ANY_VALUE()se sei sicuro che tutti i risultati all'interno del gruppo siano gli stessi. doc

25
Non penso che MySQL supporti il FIRST()metodo / la funzione?
Ben Guild,

3
Credo che MySQL (almeno prima del 5.7) abbia come impostazione predefinita il valore che trova in un gruppo. Quindi, non esiste FIRST () perché era sinonimo della stessa funzione GROUP BY.
DrDamnit,

2
@DrDamnit, credo che in questi casi sia stata più simile alla selezione casuale che ha portato alla confusione e quindi all'abilitazione ONLY_FULL_GROUP_BYdi default
azerafati,

6
Conoscevo già la risposta, ma l'esempio con il rettangolo colorato è così facile da capire, la riutilizzerò la prossima volta che qualcuno me lo chiederà.
user327961

@azerafati esiste qualcosa come FIRST () o qualche query che può essere utilizzata per ottenere il primo valore, come nel caso di me.
Haris,

169

Se non desideri apportare modifiche alla query corrente, procedi nel seguente modo:

  1. vagabondo ssh nella tua scatola
  2. Genere: sudo vim /etc/mysql/my.cnf
  3. Scorri fino alla fine del file e digita Aper accedere alla modalità di inserimento
  4. Copia e incolla

    [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. Digitare escper uscire dalla modalità di input

  6. Digitare :wqper salvare e chiudere vim.
  7. Digitare sudo service mysql restartper riavviare MySQL.

Solo un avvertimento per tutti gli utenti di Vagrant che cercano di utilizzare questo con AdonisJS, questo è necessario per eseguire la paginatefunzione.
Michael J. Calkins,

Questo ovviamente non è solo per gli utenti di Vagrant, ma per qualsiasi sistema Unix. Nota che per me la posizione del my.cnffile era /etc. Als nota la nuova sintassi daMySQL 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,

Funziona per me in Mint 19.3 (ubuntu 18.04) grazie
Marco López

71

Utilizzare ANY_VALUE()per fare riferimento alla colonna non aggregata.

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

Dai documenti di MySQL 5.7 :

Puoi ottenere lo stesso effetto senza disabilitare ONLY_FULL_GROUP_BY utilizzandoANY_VALUE() per fare riferimento alla colonna non aggregata.

...

Questa query potrebbe non essere valida con ONLY_FULL_GROUP_BYabilitato perché la colonna dell'indirizzo non aggregato nell'elenco di selezione non è nominata nella GROUP BYclausola:

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

...

Se si sa che, per un determinato set di dati, ciascun valore di nome in realtà determina in modo univoco il valore dell'indirizzo, l'indirizzo è effettivamente funzionalmente dipendente dal nome. Per dire a MySQL di accettare la query, è possibile utilizzare la ANY_VALUE()funzione:

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

1
Come qualcuno che si è imbattuto in questo problema per un po 'di tempo, mi piace particolarmente questa soluzione perché non richiede di modificare alcun file o impostazione nella configurazione di MySQL. È interessante notare che non vedo ANY_VALUE menzionato altrove in discussioni simili - funziona perfettamente per me con il mio GROUP_BY contains nonaggregated columnerrore.
adstwlearn,

50

Proverò a spiegarti di cosa tratta questo errore.
A partire da MySQL 5.7.5, l'opzione ONLY_FULL_GROUP_BYè abilitata per impostazione predefinita.
Pertanto, secondo lo standard SQL92 e precedenti:

non consente query per le quali l'elenco di selezione, la condizione HAVING o l'elenco ORDER BY si riferiscono a colonne non aggregate che non sono né indicate nella clausola GROUP BY né che sono funzionalmente dipendenti dalle colonne (determinate in modo univoco da) GROUP BY

( leggi di più nei documenti )

Quindi, per esempio:

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

Riceverai un messaggio di errore dopo aver eseguito la query sopra.

# 1055 - L'espressione n. 1 dell'elenco SELECT non è nella clausola GROUP BY e contiene la colonna non aggregata 'testite.user.id' che non dipende funzionalmente dalle colonne nella clausola GROUP BY; questo è incompatibile con sql_mode = only_full_group_by

Perché?
Perché MySQL non capisce esattamente quali valori recuperare da record raggruppati da recuperare, e questo è il punto.

IE dice che hai questi record nella tua userstabella:
yo

E eseguirai una query non valida mostrata sopra.
E otterrai l'errore mostrato sopra, perché, ci sono 3 record con nome John, ed è bello, ma, tutti hanno diversiemail valori di campo .
Quindi, MySQL semplicemente non capisce quale di essi restituire nel record raggruppato risultante.

Puoi risolvere questo problema semplicemente modificando la tua query in questo modo:

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

Inoltre, potresti voler aggiungere più campi alla sezione SELEZIONA, ma non puoi farlo, se non sono aggregati, ma c'è una stampella che potresti usare (ma altamente sconsigliata):

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

inserisci qui la descrizione dell'immagine

Ora, potresti chiederti, perché l'uso non ANY_VALUEè altamente raccomandato?
Dato che MySQL non sa esattamente quale valore di record raggruppati recuperare, e usando questa funzione, gli si chiede di recuperarne uno (in questo caso, è stata recuperata l'email del primo record con nome = John).
Esatto, non riesco a trovare idee sul perché tu voglia che questo comportamento esista.

Per favore, se non mi capisci, leggi di più su come funziona il raggruppamento in MySQL, è molto semplice.

E alla fine, ecco un'altra query semplice ma valida.
Se si desidera eseguire una query sul conteggio totale degli utenti in base alle età disponibili, è possibile scrivere questa query

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

Che è pienamente valido, secondo le regole di MySQL.
E così via.

È importante capire qual è esattamente il problema e solo allora scrivere la soluzione.


Grazie per questa bella risposta E se volessi anche le e-mail, come array nel gruppo di risultati?
Giosia il

1
Puoi sempre campo obbligatorio GROUP_CONCAT per ottenere tutte le voci presenti.
Abraham Tugalov,

Oh! quindi c'è un modo! Per favore, aiutatemi in questa domanda
Josiah, il

Grazie per questa ottima risposta. E se volessi fare GROUP BY DAY(created_date)? Sembra che non funzioni se DAY()viene aggiunto.
eschimese,

41

Sto usando Laravel 5.3, mysql 5.7.12, su laravel homestead (0.5.0, credo)

Anche dopo aver impostato esplicitamente la modifica /etc/mysql/my.cnfin modo da riflettere:

[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

Stavo ancora ricevendo l'errore.

Ho dovuto cambiare config/database.phpda truea false:

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

Ulteriori letture:

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


Dang! Questo è stato utile per gli utenti di Laravel. +1 per quello.
Okafor T Kosiso,

20

Se si utilizza wamp 3.0.6 o una versione superiore diversa dalla 2.5 stabile, è possibile che si verifichi questo problema, in primo luogo il problema è con sql. devi nominare i campi di conseguenza. ma c'è un altro modo per risolverlo. clicca sull'icona verde di wamp. mysql-> impostazioni mysql-> sql_mode-> nessuna. oppure dalla console è possibile modificare i valori predefiniti.

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';

fantastico, basandosi su ciò che ha detto, inserisci il comando show variables like '%sql_mode%';nella riga di comando mysql, esporrà l'impostazione sql_mode
Jade Han

19

Aggiunta di righe (menzionate di seguito) nel file: /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

Lavora bene per me. Versione server: 5.7.18-0ubuntu0.16.04.1 - (Ubuntu)


1
stai usando RDS?
Mubasshir Pawle,

@MubasshirPawle No
Jagdeep Singh,

16

Vai su mysql o phpmyadmin e seleziona il database, quindi esegui semplicemente questa query e funzionerà. Funziona bene per me.

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

Ottimo..Grazie :)
mohitesachin217

Il mio piacere :) @mohit
Anil Gupta,

Mi hai salvato un sacco di tempo, grazie.
Joe

1
Benvenuto fratello @TharinduEranga
Anil Gupta,

1
Ma il problema con la soluzione è ogni volta che riavvio mysql ho bisogno di eseguire nuovamente la query. Significa che la soluzione non è permanente o persistente.
Mushfiqur Rahman,

10

Per mac:

1.Copia l'impostazione predefinita my-default.cnf in /etc/my.cnf

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

2. Cambia sql_mode in my.cnf usando il tuo editor preferito e impostalo su questo

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. Riavviare il server MySQL.

mysql.server restart

Grazie, ha funzionato anche per me. Ma io uso mysql default di Mac, quindi non ho percorso brew. 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 Riavvia il server MySQL.
Yong Gao,

7

Questo è ciò che mi ha aiutato a capire l'intero problema:

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

E nel seguito un altro esempio di query problematica.

Problematico:

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 = #

Risolto aggiungendo questo alla fine:

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

Nota: vedi il messaggio di errore in PHP, ti dice dove si trova il problema.

Esempio:

Errore di query MySQL 1140: nella query aggregata senza GROUP BY, l'espressione n. 4 dell'elenco SELECT contiene la colonna non aggregata 'db.gameplay.timestamp'; questo è incompatibile con sql_mode = only_full_group_by - Query: SELECT COUNT (*) come tentativi, SUM (trascorso) come trascorso, totale, userid, timestamp, questionid, answerid, SUM (corretto) come corretto, trascorso, ipaddress DA gameplay DOVE timestamp> = DATE_SUB (ORA (), INTERVALLO 1 GIORNO) E userid = 1

In questo caso, l' espressione n. 4 mancava in GROUP BY.


1
Grazie per aver ricordato stackoverflow.com/questions/20074562/...
cwhsu

Ottima risposta per risolvere questo problema. Grazie mille
Hansana Athukorala,

7

Per localhost / wampserver 3 possiamo impostare sql-mode = user_mode per rimuovere questo errore:

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

quindi riavviare wamp o apache


1
So che questa potrebbe non essere una soluzione a lungo termine per questo problema, ma per il momento ha sicuramente aiutato. La mia società di hosting, Go Daddy, utilizza MySQL V5.6.33 e WampServer 3 utilizza MySQL V5.7.14. Grazie per questa soluzione di soluzione rapida
Alan N

4

È possibile aggiungere un unique indexa group_id; se sei sicuro che group_idsia unico.

Può risolvere il tuo caso senza modificare la query .

Una risposta tardiva, ma non è stata ancora menzionata nelle risposte. Forse dovrebbe completare le risposte già complete disponibili. Almeno ha risolto il mio caso quando ho dovuto dividere una tabella con troppi campi.


2

Se si verifica questo errore con Symfony usando il generatore di query dottrine e se questo errore è causato da un ordine :

Presta attenzione alla selectcolonna che desideri groupBye usa addGroupByinvece di groupBy:

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

Funziona su Symfony3 -


1

Ci scusiamo per non aver usato il tuo SQL esatto

Ho usato questa query per superare l'avviso Mysql.

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

nota la chiave per me essere

count(*) AS cnt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.