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

Posted

技术标签:

【中文标题】MySQL 错误:SELECT 列表不在 GROUP BY 子句中【英文标题】:MySQL Error: SELECT list is not in GROUP BY clause 【发布时间】:2016-12-06 21:58:34 【问题描述】:

我的查询有问题,mysql 抛出以下错误:

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

【问题讨论】:

【参考方案1】:

当您使用 GROUP BY 时,您可以在选择列表中使用表达式,前提是它们每个组都有一个值。否则会得到不明确的查询结果。

在您的情况下,MySQL 认为 s.status 每个组可能有多个值。例如,您按p.products_id 进行分组,但s.status 是另一个表specials 中的列,可能与表products 存在一对多关系。所以specials 中可能有多行具有相同的products_id,但status 的值不同。如果是这种情况,查询应该使用status 的哪个值?模棱两可。

在您的数据中,您可能碰巧限制了行,使得specials 中的每一行在products 中只有一行。但是 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;

我还以正确的方式重写了您的联接。应避免使用逗号式连接。

【讨论】:

打败我!很好的解释。 我尝试了不同的方式,比如选择 SQL_CALC_FOUND_ROWS s.products_id,或者选择 SQL_CALC_FOUND_ROWS count(p.products_id) 但没有解决方案有什么想法重写这个吗? @kurama 您正在尝试聚合您要分组的列。正如 Bill 所描述的,您需要确保选择列表中包含的其他列包含在 GROUP BY 子句中,或者它们是聚合的,或者依赖于分组列,以便分组正常工作。例如,select p.products_id, s.status, sum(p.products_price), ... from products p group by p.products_id, s.status【参考方案2】:

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

MySQL Group By 处理: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

【讨论】:

【参考方案3】:

如果您想在特定列上使用 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 的不同值以及相应行的值。

source

我认为 id 和 another_int_column 必须是唯一的,但我不确定。

【讨论】:

【参考方案4】:

不知道为什么没有人强调对 s.status 列使用 ANY_VALUE() 内置函数。

看看这个:https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_any-value

【讨论】:

以上是关于MySQL 错误:SELECT 列表不在 GROUP BY 子句中的主要内容,如果未能解决你的问题,请参考以下文章

SQLSTATE [42000]:语法错误或访问冲突:1055 SELECT 列表的表达式 #3 不在 GROUP BY 子句中并且包含非聚合

谁昨天没有报告? mysql不在列表中

SELECT 列表不在 GROUP BY 子句中,并且包含非聚合列 [重复]

MySQL - 使用不在列表中的列对 Group By 语句排序 [重复]

通过显示错误 3065(HY000) 具有不同和顺序的 MySQL 查询

MySQL TIMESTAMP 列 - 按天分组