Lorsque vous utilisez GROUP BY, vous ne pouvez utiliser des expressions dans votre liste de sélection que si elles ont une seule valeur par groupe. Sinon, vous obtenez des résultats de requête ambigus.
Dans votre cas, MySQL pense que s.status
peut avoir plusieurs valeurs par groupe. Par exemple, vous regroupez par p.products_id
mais s.status
est une colonne d'une autre table specials
, peut-être dans une relation un-à-plusieurs avec la table products
. Il peut donc y avoir plusieurs lignes dans specials
avec le même products_id
, mais des valeurs différentes pour status
. Si tel est le cas, quelle valeur pour status
la requête doit-elle utiliser ? C'est ambigu.
Dans vos données, il se peut que vous limitiez les lignes de sorte que vous n'ayez qu'une seule ligne dans specials
pour chaque ligne dans products
. Mais MySQL ne peut pas faire cette supposition.
MySQL 5.6 et les versions antérieures vous permettent d'écrire de telles requêtes ambiguës, en sachant que vous savez ce que vous faites. Mais MySQL 5.7 permet une application plus stricte par défaut (cela peut être rendu moins strict pour se comporter comme les versions précédentes).
La solution consiste à suivre cette règle :chaque colonne de votre liste de sélection doit appartenir à l'un des trois cas suivants :
- La colonne se trouve dans une fonction d'agrégation telle que COUNT(), SUM(), MIN, MAX(), AVERAGE() ou GROUP_CONCAT().
- La colonne est l'une des colonnes nommées dans le
GROUP BY
clause. - La colonne dépend fonctionnellement de la ou des colonnes nommées dans le
GROUP BY
clause.
Pour plus d'explications, lisez cet excellent blog :Debunking GROUP BY myths
Concernant votre commentaire, je ne peux que faire une supposition car vous n'avez pas publié vos définitions de table.
Je suppose que products_description
et manufacturers
dépendent fonctionnellement des products
, vous pouvez donc les répertorier tels quels dans la liste de sélection. Mais cette hypothèse n'est peut-être pas correcte, je ne connais pas votre schéma.
Quoi qu'il en soit, l'erreur à propos de s.status
doit être résolu à l'aide d'une fonction d'agrégation. J'utilise MAX()
à titre d'exemple.
SELECT p.*,
pd.*,
m.*,
MAX(IF(s.status, s.specials_new_products_price, NULL))
AS specials_new_products_price,
MAX(IF(s.status, s.specials_new_products_price, p.products_price))
AS final_price
FROM products p
LEFT OUTER JOIN specials s ON p.products_id = s.products_id
INNER JOIN manufacturers m ON p.manufacturers_id = m.manufacturers_id
INNER JOIN products_description pd ON p.products_id = pd.products_id
INNER JOIN products_to_categories p2c ON p.products_id = p2c.products_id
INNER JOIN categories c ON p2c.categories_id = c.categories_id
WHERE p.products_view = 1
AND p.products_status = 1
AND p.products_archive = 0
AND c.virtual_categories = 0
AND pd.language_id = 1
GROUP BY p.products_id;
J'ai également réécrit vos jointures dans le bon sens. Les jointures de type virgule doivent être évitées.