php - 当 sql_mode=only_full_group_by 时,在 mysql 中完成 Group By 工作的最佳方法是什么
问题描述
我想执行一个查询,例如在我的本地主机上获取 DB 中任何类型的最后一条记录,我使用 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 文档,我可以使用以下命令来实现这一点:
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 选项中,或者将查询更改为具有相同结果的其他内容,并且不会损失性能
解决方案
ONLY_FULL_GROUP_BY
是一件好事,它强制执行基本的 ANSI SQL 规则。不要更改它,而是修复您的代码。
从那里开始:你想要整个记录,所以你不应该考虑聚合,而是过滤。
然后:在数据库表中,记录是无序的;为了使您的问题有意义,您需要一个定义每个组中行的顺序的列,因此“最后”记录的含义是明确的。让我假设您有这样的列,称为id
.
以下是此 top-1-per-group 问题的典型方法,使用相关子查询进行过滤:
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,则可以使用窗口函数:
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
。
推荐阅读
- node.js - NodeJS async.each/parallel 用于动态数组
- c - 1000以下所有3或5的倍数之和在C中给出错误答案
- r - R data.table:使用 %like% 和 setkey
- binary - 这个映射是哪个二进制操作?
- mysql - 具有限制的联合查询的行的 rand()
- python - Python:沿着连接点集的线的等距点
- monitoring - 通过 ITRS Geneos 进行 Rundeck 监控
- html - 将文本框放置在图像上
- javascript - 无法在 Angular2 中进行 http 服务调用?
- twig - twig drupal中的拆分url功能