【问题标题】:MySQL group by issue: incompatible with sql_mode=only_full_group_byMySQL 按问题分组:与 sql_mode=only_full_group_by 不兼容
【发布时间】:2016-11-18 12:50:38
【问题描述】:

任务:显示每个商店购买最多的产品。
3 个表格:商店、产品、付款。如果销售给 1 家商店的产品出现平局,则选择哪种产品并不重要,只需选择其中一种即可。

我对此查询的 group by 子句有疑问:

SELECT shop_id, product_id, 
(
  SELECT COUNT(*) 
  FROM payment 
  WHERE product.product_id = payment.product_id
) sold
FROM product
GROUP BY shop_id
HAVING MAX(sold)

在 MySQL 5.6 或更低版本中,此查询可以工作。 这将是正确的结果:

shop_id | product_id | sold
1         1            3
2         3            1
3         5            1

但在 5.7 上,我遇到了与 sql_mode=only_full_group_by 不兼容的问题,因为 select 中的 product_id 包含非聚合数据。

完整的错误信息:

Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'product.product_id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

所以我认为的解决方案是在组中添加 product_id,如下所示:

SELECT shop_id, product_id, 
(
  SELECT COUNT(*) 
  FROM payment 
  WHERE product.product_id = payment.product_id
) sold
FROM product
GROUP BY shop_id, product_id
HAVING MAX(sold)

修复了错误但返回了错误的结果,它不再使商店列唯一。我得到了这个:

shop_id | product_id | sold
1         1            3
1         2            4
2         3            1
2         4            1
3         5            1

SQLfiddle 使用 MySQL 5.6,但为了让每个人的生活更轻松:http://sqlfiddle.com/#!9/ca12bf9/6

【问题讨论】:

  • 不清楚的是为什么您在这里使用付款表
  • @e4c5 1 次付款有 1 个产品,1 个产品有 0..N 次付款。付款表中的每一行都代表一种已售出的产品,这就是为什么我要对其进行 COUNT 以了解特定产品已售出多少次。
  • 我也不确定原始结果是否正确,因为从原始数据来看,shop_id 2 销售了 1 个产品 3 和 4。您希望如何处理领带?这是应该考虑的事情。
  • @CGritton Ties 无关紧要,对不起,我忘了包括在内。如果有平局,它可以选择第一行或随机一个,但必须选择一个。

标签: mysql


【解决方案1】:

您的要求非常复杂。您从 MySQL 对GROUP BY 的非标准扩展中获得了有用的结果,这完全是偶然的。基于该扩展的结果与会说话的驴子没什么两样。效果不好并不奇怪,它完全有效。

这是你必须做的。

(1) 按产品和店铺汇总销售额。 (http://sqlfiddle.com/#!9/ca12bf9/12/0)

                   select product.product_id, product.shop_id, count(*) sale_count
                     from product
                     join payment on product.product_id = payment.product_id
                    group by product.product_id, product.shop_id

(2) 通过总结 (1) (http://sqlfiddle.com/#!9/ca12bf9/13/0) 找到每个商店中最畅销产品的销售数量

     SELECT MAX(sale_count) max_sale_count, shop_id
       FROM (
                   select product.product_id, product.shop_id, count(*) sale_count
                     from product
                     join payment on product.product_id = payment.product_id
                    group by product.product_id, product.shop_id
                 ) findmax
       GROUP BY shop_id

(3) 连接 (1) 到 (2) 以检索每个商店中销售最多的产品的标识。 (http://sqlfiddle.com/#!9/ca12bf9/11/0)

SELECT a.product_id, a.shop_id, b.max_sale_count
  FROM (
            select product.product_id, product.shop_id, count(*) sale_count
              from product
              join payment on product.product_id = payment.product_id
             group by product.product_id, product.shop_id    
       ) a
  JOIN (
         SELECT MAX(sale_count) max_sale_count, shop_id
                FROM (
                       select product.product_id, product.shop_id, count(*) sale_count
                         from product
                         join payment on product.product_id = payment.product_id
                        group by product.product_id, product.shop_id
                     ) findmax
               GROUP BY shop_id
       ) b ON a.shop_id = b.shop_id AND a.sale_count = b.max_sale_count

您提供的数据是平局。因此,两种不同的产品在您的一家商店中成为畅销产品。

正是这种查询将结构化置于结构化查询语言中。

【讨论】:

    【解决方案2】:

    您可以将 sql_mode 设置为空白 通过设置sql_mode ='' in my.ini

    或者你可以使用ANY_VALUE(product_id)

    在使用带有 group by 的非聚合列时,从不保证结果会是什么。

    https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_any-value

    更新 1http://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

    【讨论】:

    • 谢谢,ANY_VALUE 确实有效。但是肯定有一种方法可以在不使用 ANY_VALUE 或更改 sql 模式的情况下解决这个问题吗?
    • 在mysql之前的版本中,mysql隐式的做和5.7引入的函数一样的行为,你可以查看更多更新的答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 2020-02-29
    • 1970-01-01
    • 2016-10-03
    • 2018-03-12
    • 2018-04-13
    相关资源
    最近更新 更多