Erro relacionado a only_full_group_by ao executar uma consulta no MySql

Atualizei meu sistema e instalei o MySql 5.7.9 com php para uma aplicação web na qual estou trabalhando. Eu tenho uma consulta que é criada dinamicamente, e quando executado em versões mais antigas do MySql funciona bem. Desde a actualização para a versão 5.7, recebo este erro:

Expressão #1 da lista SELECT não está na cláusula GROUP BY e contém coluna não agregada 'support_desk.mod_users_groups.group_id' que é não depende funcionalmente das colunas da cláusula GROUP BY; isto é incompatível com sql_mode=only_full_group_by

Observe a página do Manual do Mysql 5.7 sobre o tópico Modos SQL do Servidor.

Esta é a pergunta que me está a dar 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

Fiz algumas pesquisas no Google sobre o assunto, mas eu não... 39;não entendo só_full_group_by o suficiente para descobrir o que preciso fazer para corrigir a consulta. Posso apenas desligar a opção only_full_group_by, ou há algo mais que eu precise fazer?

Avise-me se precisar de mais informações.

Você pode tentar desativar a opção only_full_group_by executando o seguinte:

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

O MySQL 8 não aceita NO_AUTO_CREATE_USER, então isso precisa ser removido.

Comentários (4)
Solução

Eu apenas adicionaria 'group_id' ao 'GROUP BY'.

Quando SELIGUE uma coluna que não faz parte do GRUPO POR pode haver vários valores para essa coluna dentro dos grupos, mas só haverá espaço para um único valor nos resultados. Portanto, a base de dados usualmente precisa ser informada exatamente como fazer esses valores múltiplos em um único valor. Geralmente, isto é feito com uma função agregada como COUNT(), SUM(), MAX() etc.... Eu digo usualmente porque a maioria dos outros sistemas populares de banco de dados insistem nisto. Entretanto, no MySQL antes da versão 5.7 o comportamento padrão tem sido mais tolerante porque ele não vai reclamar e então arbitrariamente escolher qualquer valor! Ele também tem uma função ANY_VALUE() que poderia ser utilizada como outra solução para esta questão se você realmente precisasse do mesmo comportamento de antes. Esta flexibilidade tem um custo porque não é determinista, então eu não a recomendaria a menos que você tenha uma razão muito boa para precisar dela. O MySQL está agora ligando a configuração only_full_group_by por padrão por boas razões, então é melhor se acostumar e fazer suas consultas obedecerem a ela.

Então, porquê a minha resposta simples acima? I'fiz um par de suposições:

  1. o id_grupo é único. Parece razoável, é um 'ID' afinal de contas.

  2. o nome_do_grupo também é único. Esta pode não ser uma hipótese tão razoável. Se este não for o caso e você tiver alguns 'nomes_de_grupo' duplicados e depois seguir meu conselho para adicionar 'group_id' ao `GROUP BY', você pode descobrir que agora você terá mais resultados do que antes porque os grupos com o mesmo nome agora terão linhas separadas nos resultados. Para mim, isso seria melhor do que ter esses grupos duplicados escondidos porque o banco de dados selecionou um valor arbitrariamente!

É também uma boa prática para qualificar todas as colunas com o seu nome de tabela ou pseudónimo quando há's mais de uma tabela envolvida...

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
Comentários (7)

Se você não'não quer fazer nenhuma alteração na sua consulta atual, então siga os passos abaixo -

  1. vagabundo ssh na sua caixa

  2. Tipo: sudo vim /etc/mysql/my.cnf

  3. Vá até o fundo do arquivo e digite A para entrar no modo de inserção

  4. Copiar e colar

    [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. Digite esc para sair do modo de entrada

  6. Digite :wq para salvar e fechar o vim.

  7. Digite sudo service mysql restart para reiniciar o MySQL.

Comentários (2)