MySQL的错误:SELECT列表是不是在GROUP BY子句

问题描述:

我有一个问题,我的查询和mysql引发以下错误:MySQL的错误:SELECT列表是不是在GROUP BY子句

#1055 - Expression #66 of SELECT list is not in GROUP BY clause and 
contains nonaggregated column 's.status' which is not functionally 
dependent on columns in GROUP BY clause; this is incompatible with 
sql_mode=only_full_group_by 

查询:

select p.*, 
pd.*, 
m.*, 
IF(s.status, s.specials_new_products_price, null) as specials_new_products_price, 
IF(s.status, s.specials_new_products_price, p.products_price) as final_price 
FROM products p 
LEFT JOIN specials s ON p.products_id = s.products_id 
LEFT JOIN manufacturers m using(manufacturers_id) , 
      products_description pd, 
      categories c, 
      products_to_categories p2c 
WHERE p.products_view = 1 
AND p.products_status = 1 
AND p.products_archive = 0 
AND c.virtual_categories = 0 
AND p.products_id = pd.products_id 
AND p.products_id = p2c.products_id 
AND p2c.categories_id = c.categories_id 
AND pd.language_id = 1 

GROUP BY p.products_id; 

当您使用GROUP BY ,只有在每个组有单个值时,才可以在选择列表中使用表达式。否则你会得到不明确的查询结果。

就你而言,MySQL认为s.status可能每组有多个值。例如,您正在按p.products_id分组,但s.status是另一个表specials中的一列,可能与表products处于一对多关系。因此,specials中可能有多个行,与​​相同,但status的值不同。如果是这样的话,查询使用status的哪个值?它含糊不清。

在您的数据中,您可能会碰巧限制行,因此products中的每行只有specials中的一行。但MySQL无法做出这样的假设。

MySQL 5.6和更早的版本让你编写这样的模糊查询,相信你知道你在做什么。但是MySQL 5.7默认实现更严格的执行(这可以不像以前的版本那样严格)。

解决办法是遵循这个规则:在你的选择列表中的每一列必须分为以下三种情况之一:

  • 列就像COUNT聚合函数内(),SUM(),MIN ,MAX(),AVERAGE()或GROUP_CONCAT()。
  • 该列是GROUP BY子句中指定的列之一。
  • 该列在功能上依赖于GROUP BY子句中指定的列。

更多解释阅读本优秀的博客:Debunking GROUP BY myths


回复你的评论,我只能猜测,因为你还没有发布你的表定义。

我猜products_descriptionmanufacturers在功能上依赖于products,所以可以将它们按原样列在选择列表中。但是这个假设可能不正确,我不知道你的模式。

无论如何,有关s.status的错误应通过使用聚合函数来解决。我以MAX()为例。

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; 

我也重写了正确的方式加入。应避免逗号式连接。

+1

打我吧!很好的解释。 –

+0

我试过不同的方式,像选择SQL_CALC_FOUND_ROWS s.products_id,或选择SQL_CALC_FOUND_ROWS计数(p.products_id),但没有解决方案任何想法重写这个? – kurama

+0

@ kurama您正在尝试汇总您正在分组的列。正如Bill所描述的那样,您需要确保选择列表中包含的其他列包含“GROUP BY”子句,或者它们已经汇总,或者依赖于分组列,以便分组正常工作。例如,从产品p组中选择p.products_id,s.status,sum(p.products_price),... p.products_id,s.status' –

您是否想做ORDER BYGROUP BY子句尝试为GROUP BY子句中列中的每个不同值返回一行,除非向该子句添加更多列。该错误正在抛出,因为您有其他未汇总的列未包含在该子句中 - 汇总的列将类似于MAX(p.products_id)SUM(p.products_price)。在您的查询中,有多个具有相同p.product_price和不同s.status值的行,因此GROUP BY无意义。

MySQL的分组方式处理:https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html 聚合函数:http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html

如果你想使用特定的列GROUP BY和得到的结果的ID的有一个好的技巧如何做到这一点:

SELECT `distinct_column`, MAX(`id`), MAX(`another_int_column`) FROM `table_name` GROUP BY `distinct_column` 

结果:

distinct_column id  another_int_column 
Abertamy   13579 11 
Adamov   17765 14 
Adolfovice  2924  3 
Achotín   2241  2 
Babice   17772 14 

现在,你必须从distinct_column和Wi不同的值它是相应行的值。

source

我认为ID和another_int_column必须是唯一的,但我不知道。