ysql5.7及以后默认sql_mode=“ONLY_FULL_GROUP_BY”。
含义:
sql中select后面的字段必须出现在group by后面,或者被聚合函数包裹,不然会抛出上面的错误 如以下错误:
Error Code: 1055. Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘×××’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
废话就不多说了,目前整理的有以下方案:
方案1:SQL命令修改sql_mode(不建议使用)
-- 1.使用select语句将sql_mode查询出来
select @@sql_mode;
-- 或者
select @@global.sql_mode;
-- 2.复制sql_mode结果,并将"ONLY_FULL_GROUP_BY"加进去,使用set或update语句更新sql_mode
set @@sql_mode =''; -- 改变已经存在的数据库sql_mode
set @@global.sql_mode=''; //改变全局配置sql_mode
这种方法是会话级别的,数据库重启后会失效。不建议在实际开发中使用。
方案2:配置文件修改sql_mode(不推荐使用)
不推荐使用的原因是,如果你不是DBA,也不是架构师,也不是领导我劝你别用,在大型项目中不可能因为你一个人菜而影响其他人的开发习惯或已有的开发规范。
Linux:
修改/etc/my.cnf文件使用编辑命令进行编辑,找到"[mysqld]“下的sql_mode,把"ONLY_FULL_GROUP_BY"j加进去并保存退出,然后使用命令"service mysqld restart"或”/etc/inint.d/mysqld restart"重启mysql服务。
windows:
修改MySQL文件下的/my.ini文件(默认安装请到C:\ProgramData\MySQL下找my.ini,自定义安装的自行查找或者百度),找到"[mysqld]"下的sql_mode,把"ONLY_FULL_GROUP_BY"j加进去,然后重启mysql服务器。不会用命令就按步骤来:我的电脑——(右键)管理——服务与应用程序——服务——MYSQL——开启(停止、重启动)。
方案3:GROUP_CONCAT()函数
使用GROUP_CONCAT()函数,语法:group_concat( [DISTINCT] 要连接的字段 [Order BY 排序字段 ASC/DESC] [Separator ‘分隔符’] ),我觉着意思就是在group by的前提下依据某个或多个字段进行排序,例如:insert_time,然后将每组排序后的某个字段进行拼接,例如:id,默认以英文","分割拼接。如果没看明白我讲的是啥,那您去百度一下吧。。。
例子:
SELECT ip, pc_name, GROUP_CONCAT( id ORDER BY collect_time DESC, insert_time DESC ) ids FROM t_sys_monitor GROUP BY ip, pc_name
结果:
因为根据时间排序已经将需要最新一条数据id放在第一位了,所以使用SUBSTRING_INDEX(列名,截取分隔符,第几位)函数截取即可获取需要的id,然后多表关联查询得到结果。
SELECT
t.id,
t.ip,
t.pc_name,
t.status,
t.collect_time,
t.update_time,
t.insert_time
FROM
t_sys_monitor t
RIGHT JOIN ( SELECT SUBSTRING_INDEX( GROUP_CONCAT( id ORDER BY collect_time DESC, insert_time DESC ), ',', 1 ) id FROM t_sys_monitor GROUP BY ip, pc_name ) t1 ON t.id = t1.id
ORDER BY
t.collect_time DESC,
t.insert_time DESC;
方案4:mysql8开窗函数及行号ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN)
1.根据ip,module分组查,collect_time倒排序查询
SELECT
t.*,
ROW_NUMBER() over ( PARTITION ip, module ORDER BY collet_time DESC ) rn
FROM
t_sys_monitor t
2.取当前行号为1的值(rn = 1)
SELECT
m.*
FROM
( SELECT t.*, ROW_NUMBER() over ( PARTITION ip, module ORDER BY collet_time DESC ) rn FROM t_sys_monitor t ) m
WHERE
m.rn = 1
方案5:any_value()函数
待更新。。。