当 sql_mode=only_full_group_by 时,在 mysql 中执行 Group By 工作的最佳方法是什么
What is the best way to do the job of Group By in mysql when sql_mode=only_full_group_by
我想执行一个查询,比如获取数据库中任何类型的最后一条记录,在我的本地主机上,我使用 Maria Db,查询如下:
SELECT *
FROM table_a
WHERE column_a=999
OR column_b=999
GROUP
BY `group`;
group
是我在其中保存类型的栏目,例如:营销,博客,订单等
此查询在本地运行良好,但在服务器上出现以下错误:
SQLSTATE[42000]:
Syntax error or access violation:
1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column
'db_name.table_a.id' which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by\n
The SQL being executed was:
SELECT * FROM `table_a` WHERE (`column_a`=999) OR (`column_b`=999) GROUP BY `group`"
根据MySQL document,我可以使用以下命令来实现:
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
但是我没有足够的 Db 权限并得到以下错误:
#1227 - Access denied; you need (at least one of) the SUPER privilege(s) for this operation
我要求主办方为我做这个,他们回答说他们不想做这个动作
我使用 YII2 框架,现在我想要一种方法来在框架的 database_config.php 选项上添加这个,或者将查询更改为具有相同结果的其他查询,并且不会损失性能
有几种方法可以“绕过”sql_mode
,但请注意,您得到的结果可能不正确。
首先你可以使用ANY_VALUE()。示例如下:
SELECT any_value(column_a), any_value(column_b), `group` FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
使用 ANY_VALUE()
函数时,您必须将 table 中的所有列写入 SELECT
并附加 ANY_VALUE()
除了您在GROUP BY
.
使用 MAX() 或 MIN() 可以 return 结果,但仍然可能不正确
结果,尤其是对于计数超过 1 的任何行:
SELECT MAX(column_a), MAX(column_b), `group`
FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
使用 GROUP_CONCAT
可以查看未分组列中的值。将结果与上面的其他查询进行比较,您可以看到 return 多于一个计数的行,其他查询 return 是否符合您的要求?
SELECT group_concat(column_a), group_concat(column_b), group_concat(`group`)
FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
我不确定你是否可以这样做,但你可以暂时关闭 sql_mode
然后你应该可以 运行 你的查询:
SET sql_mode=""; -- you don't need to set global privilege.
SELECT * FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
不过,最好的选择是保留sql_mode
原样并根据要求构建查询。
P/S:GROUP
在MySQL & MariaDB中都是保留字。您可以将它用作列名,但您必须始终添加反引号来定义列,否则,运行查询将 return 您出现类似
的错误
Query: select * from table_a group by group
Error Code: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'group' at line 1
ONLY_FULL_GROUP_BY
是 一件好事 ,它执行基本的 ANSI SQL 规则。不要更改它,而是修复您的代码。
从那里开始:你想要完整的记录,所以你不应该考虑聚合,而是过滤。
那么:在数据库table中,记录是无序;为了使您的问题有意义,您需要一个列来定义每组中行的顺序,以便明确“最后”记录的含义。让我假设您有这样的专栏,名为 id
.
这是解决每组前 1 问题的典型方法,使用相关子查询进行过滤:
SELECT *
FROM table_a a
WHERE
999 IN (column_a, column_b)
AND id = (
SELECT MAX(a1.id)
FROM table_a a1
WHERE 999 IN (a1.column_a, a1.column_b) AND a1.grp = a.grp
)
或者,如果您是 运行 MySQL 8.0,您可以使用 window 功能:
SELECT *
FROM (
SELECT a.*,
ROW_NUMBER() OVER(PARTITION BY grp ORDER BY id DESC) rn
FROM table_a a
WHERE 999 IN (column_a, column_b)
) a
WHERE rn = 1
旁注:group
是语言关键字,因此列名的选择不佳。我在查询中将其重命名为 grp
。
我想执行一个查询,比如获取数据库中任何类型的最后一条记录,在我的本地主机上,我使用 Maria Db,查询如下:
SELECT *
FROM table_a
WHERE column_a=999
OR column_b=999
GROUP
BY `group`;
group
是我在其中保存类型的栏目,例如:营销,博客,订单等
此查询在本地运行良好,但在服务器上出现以下错误:
SQLSTATE[42000]:
Syntax error or access violation:
1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column
'db_name.table_a.id' which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by\n
The SQL being executed was:
SELECT * FROM `table_a` WHERE (`column_a`=999) OR (`column_b`=999) GROUP BY `group`"
根据MySQL document,我可以使用以下命令来实现:
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
但是我没有足够的 Db 权限并得到以下错误:
#1227 - Access denied; you need (at least one of) the SUPER privilege(s) for this operation
我要求主办方为我做这个,他们回答说他们不想做这个动作
我使用 YII2 框架,现在我想要一种方法来在框架的 database_config.php 选项上添加这个,或者将查询更改为具有相同结果的其他查询,并且不会损失性能
有几种方法可以“绕过”sql_mode
,但请注意,您得到的结果可能不正确。
首先你可以使用ANY_VALUE()。示例如下:
SELECT any_value(column_a), any_value(column_b), `group` FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
使用 ANY_VALUE()
函数时,您必须将 table 中的所有列写入 SELECT
并附加 ANY_VALUE()
除了您在GROUP BY
.
使用 MAX() 或 MIN() 可以 return 结果,但仍然可能不正确 结果,尤其是对于计数超过 1 的任何行:
SELECT MAX(column_a), MAX(column_b), `group`
FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
使用 GROUP_CONCAT
可以查看未分组列中的值。将结果与上面的其他查询进行比较,您可以看到 return 多于一个计数的行,其他查询 return 是否符合您的要求?
SELECT group_concat(column_a), group_concat(column_b), group_concat(`group`)
FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
我不确定你是否可以这样做,但你可以暂时关闭 sql_mode
然后你应该可以 运行 你的查询:
SET sql_mode=""; -- you don't need to set global privilege.
SELECT * FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
不过,最好的选择是保留sql_mode
原样并根据要求构建查询。
P/S:GROUP
在MySQL & MariaDB中都是保留字。您可以将它用作列名,但您必须始终添加反引号来定义列,否则,运行查询将 return 您出现类似
Query: select * from table_a group by group
Error Code: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'group' at line 1
ONLY_FULL_GROUP_BY
是 一件好事 ,它执行基本的 ANSI SQL 规则。不要更改它,而是修复您的代码。
从那里开始:你想要完整的记录,所以你不应该考虑聚合,而是过滤。
那么:在数据库table中,记录是无序;为了使您的问题有意义,您需要一个列来定义每组中行的顺序,以便明确“最后”记录的含义。让我假设您有这样的专栏,名为 id
.
这是解决每组前 1 问题的典型方法,使用相关子查询进行过滤:
SELECT *
FROM table_a a
WHERE
999 IN (column_a, column_b)
AND id = (
SELECT MAX(a1.id)
FROM table_a a1
WHERE 999 IN (a1.column_a, a1.column_b) AND a1.grp = a.grp
)
或者,如果您是 运行 MySQL 8.0,您可以使用 window 功能:
SELECT *
FROM (
SELECT a.*,
ROW_NUMBER() OVER(PARTITION BY grp ORDER BY id DESC) rn
FROM table_a a
WHERE 999 IN (column_a, column_b)
) a
WHERE rn = 1
旁注:group
是语言关键字,因此列名的选择不佳。我在查询中将其重命名为 grp
。