Ser*_*gio 6 mysql mysql-5.5 group-by mysql-5.7
从 MySQL 5.5 升级到 MySQL 5.7 后,我的一些查询出现错误:
错误 1055 (42000):
SELECT 列表的表达式 #1 不在 GROUP BY 子句中,并且包含非聚合列“grocery.Product_Category.category_id”,该列在功能上不依赖于 GROUP BY 子句中的列;这与 sql_mode=only_full_group_by 不兼容
我做了我的研究并找到了问题的原因以及如何解决它,基本上我只需要从@@sql_mode 中删除 ONLY_FULL_GROUP_BY ,一切都会再次工作。
但是,我想知道这是否是正确的做法。有没有替代方法,也许是构建查询的更好方法?
这是我的情况(http://sqlfiddle.com/#!9/6f1bd):
我有两个表(我在这里简化了它们的结构,但基本相同):产品和类别以及一个多对多关系表,以允许产品属于多个类别:
SELECT * FROM Product;
+------------+---------+
| product_id | name |
+------------+---------+
| 1 | Tomato |
| 2 | Orange |
| 3 | Banana |
| 4 | Lettuce |
| 5 | Carrot |
+------------+---------+
5 rows in set (0,00 sec)
SELECT * FROM Category;
+-------------+------------+
| category_id | name |
+-------------+------------+
| 1 | Fruits |
| 2 | Vegetables |
+-------------+------------+
2 rows in set (0,00 sec)
Run Code Online (Sandbox Code Playgroud)
我想从两个类别中获取产品,因此最简单的查询是:
SELECT * FROM Product JOIN Product_Category USING(product_id)
JOIN Category USING(category_id);
+-------------+------------+---------+------------+
| category_id | product_id | name | name |
+-------------+------------+---------+------------+
| 1 | 1 | Tomato | Fruits |
| 1 | 2 | Orange | Fruits |
| 1 | 3 | Banana | Fruits |
| 2 | 1 | Tomato | Vegetables |
| 2 | 4 | Lettuce | Vegetables |
| 2 | 5 | Carrot | Vegetables |
+-------------+------------+---------+------------+
6 rows in set (0,00 sec
Run Code Online (Sandbox Code Playgroud)
但是,如果一个产品同时存在于两个类别中,我只需要一次,那么执行 DISTINCT 选择将无济于事,因为 category_id 不同:
SELECT DISTINCT * FROM Product JOIN Product_Category USING(product_id) JOIN Category USING(category_id);
+-------------+------------+---------+------------+
| category_id | product_id | name | name |
+-------------+------------+---------+------------+
| 1 | 1 | Tomato | Fruits |
| 1 | 2 | Orange | Fruits |
| 1 | 3 | Banana | Fruits |
| 2 | 1 | Tomato | Vegetables |
| 2 | 4 | Lettuce | Vegetables |
| 2 | 5 | Carrot | Vegetables |
+-------------+------------+---------+------------+
6 rows in set (0,00 sec)
Run Code Online (Sandbox Code Playgroud)
因此,在 MySQL 5.5 中,我在 product_id 字段上使用了 GROUP BY 子句:
SELECT * FROM Product JOIN Product_Category USING(product_id)
JOIN Category USING(category_id) GROUP BY product_id;
+-------------+------------+---------+------------+
| category_id | product_id | name | name |
+-------------+------------+---------+------------+
| 1 | 1 | Tomato | Fruits |
| 1 | 2 | Orange | Fruits |
| 1 | 3 | Banana | Fruits |
| 2 | 4 | Lettuce | Vegetables |
| 2 | 5 | Carrot | Vegetables |
+-------------+------------+---------+------------+
5 rows in set (0,00 sec)
Run Code Online (Sandbox Code Playgroud)
这有效地删除了重复项,我知道结果不是确定性的,但我不在乎番茄是否出现在水果或蔬菜类别中,我所关心的只是在结果集中只得到一次。
但是这个使用 MySQL 5.7 的查询会导致上面提到的错误。
所以,我的问题是:是否有另一种(也许更好)的方法来获得相同的结果而不必从@@sql_mode 中删除 ONLY_FULL_GROUP_BY?
我建议以最小化需要放入 GROUP BY 的列数的方式重写查询。在您的情况下,您可以通过仅将分组应用于表来做到这一点Product_Category。
根据您的示例,该表具有以下条目:
+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 1 | 2 |
| 4 | 2 |
| 5 | 2 |
+------------+-------------+
Run Code Online (Sandbox Code Playgroud)
由于您希望产品名称在输出中是唯一的,因此请将此表按 分组product_id,并category_id选择例如每个产品的最小值:
SELECT
product_id,
MIN(category_id) AS category_id
FROM
Product_Category
GROUP BY
product_id
Run Code Online (Sandbox Code Playgroud)
这会给你这样的输出:
+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
+------------+-------------+
Run Code Online (Sandbox Code Playgroud)
您可以看到每个产品只列出一次。将该表连接到其他两个表不会产生重复项。因此,只需将上面的查询作为派生表替换为Product_Category查询中的(当然,也从中删除 GROUP BY ):
SELECT
*
FROM
Product
JOIN (
SELECT
product_id,
MIN(category_id) AS category_id
FROM
Product_Category
GROUP BY
product_id
) AS pc USING(product_id)
JOIN Category USING(category_id)
;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4030 次 |
| 最近记录: |