web-dev-qa-db-fra.com

Existe-t-il une capacité ANY_VALUE pour mysql 5.6?

je travaille actuellement avec mysql 5.7 en développement et 5.6 en production. Chaque fois que j'exécute une requête avec un groupe en cours de développement, j'obtiens une erreur comme "Code d'erreur: 1055. L'expression # 1 de la liste SELECT n'est pas dans GROUP BY"

Voici la requête.

SELECT c.id, c.name, i.* 
 FROM countries c, images i 
WHERE i.country_id = c.id
GROUP BY c.id; Fixed for 5.7; 

SELECT c.id, c.name,
       ANY_VALUE(i.url) url, 
       ANY_VALUE(i.lat) lat, 
       ANY_VALUE(i.lng) lng 
  FROM countries c, images i
 WHERE i.country_id = c.id
 GROUP BY c.id;

Pour résoudre ce problème, j'utilise la fonction mysql de 5.7 ANY_VALUE, mais le principal problème est que ce n'est pas disponible dans mysql 5.6

Donc, si je corrige l'instruction SQL pour le développement, j'obtiendrai une erreur de production.

Connaissez-vous une solution ou un polifill pour la fonction ANY_VALUE dans mysql 5.6?

16
Tim

Vous utilisez mal l'extension MySQL non standard notoire à GROUP BY . Le SQL standard rejettera toujours votre requête, car vous mentionnez des colonnes qui ne sont pas des agrégats et ne sont pas mentionnées dans GROUP BY. Dans votre système de développement, vous essayez de contourner cela avec ANY_VALUE().

En production, vous pouvez désactiver le mode MySQL ONLY_FULL_GROUP_BY. Essayez de le faire this :

  SET @mode := @@SESSION.sql_mode;
  SET SESSION sql_mode = '';
  /* your query here */
  SET SESSION sql_mode = @mode;

Cela permettra à MySQL d'accepter votre requête.

Mais regardez, votre requête n'est pas vraiment correcte. Lorsque vous pouvez le persuader de s'exécuter, il renvoie une ligne choisie au hasard dans la table images. Ce type d'indétermination cause souvent de la confusion aux utilisateurs et à votre équipe de support technique.

Pourquoi ne pas améliorer la requête, il choisit donc une image particulière. Si votre table images a une colonne d'auto-incrémentation id, vous pouvez le faire pour sélectionner la "première" image.

SELECT c.id, c.name, i.*
  FROM countries c
  LEFT JOIN (
       SELECT MIN(id) id, country_id
         FROM images
        GROUP BY country_id
       ) first ON c.id = first.country_id
  LEFT JOIN images i ON first.id = i.id

Cela renverra une ligne par pays avec une image prévisible affichée.

17
O. Jones

Au lieu de ANY_VALUE , vous pouvez utiliser les fonctions d'agrégation MIN ou MAX.

Vous pouvez également envisager de ne pas définir le ONLY_FULL_GROUP_BY Mode SQL, qui est défini par défaut pour MySql 5.7, et est responsable de la différence que vous rencontrez avec MySql 5.6. Vous pouvez ensuite retarder la mise à jour de vos requêtes jusqu'à ce que vous ayez migré tous vos environnements vers MySql 5.7.

Laquelle des deux est la meilleure option, est discutable, mais à long terme, il sera préférable d'adapter vos requêtes afin qu'elles adhèrent au ONLY_FULL_GROUP_BY règle. Utiliser MIN ou MAX peut certainement être utile pour cela.

17
trincot

Pendant des décennies, vous pouviez écrire des requêtes qui n'étaient pas valides en SQL standard mais parfaitement valides mysql

Dans SQL standard, une requête qui inclut une clause GROUP BY ne peut pas faire référence à des colonnes non agrégées dans la liste de sélection qui ne sont pas nommées dans la clause GROUP BY. Par exemple, cette requête est illégale dans SQL standard car la colonne de nom non agrégé dans la liste de sélection n'apparaît pas dans le GROUP BY:

SELECT o.custid, c.name, MAX (o.payment) FROM order AS o, customers AS c WHERE o.custid = c.custid GROUP BY o.custid; Pour que la requête soit légale, la colonne de nom doit être omise de la liste de sélection ou nommée dans la clause GROUP BY.

MySQL étend l'utilisation SQL standard de GROUP BY afin que la liste de sélection puisse faire référence à des colonnes non agrégées non nommées dans la clause GROUP BY.

Cela vient de la page du manuel Mysql 5.6 sur GROUP BY . Si vous regardez la même page pour 5.7.6 vous voyez que les choses ont changé. Et changé radicalement !!

Cette page vous donne également la solution. Désactiver ONLY_FULL_GROUP_BY Cela permettra à votre ancienne requête 5.6 de fonctionner sur 5.7.6 (supprimez ANY_VALUE de votre requête car elle n'est pas disponible en 5.7.6 mais utilisez plutôt ONLY_FULL_GROUP_BY).

4
e4c5