造一个需求:
班级表有一个冗余字段——学生平均年龄;
学生表有班级表的外键class_id;
现在需要根据学生表的数据,同步班级表的冗余字段——学生平均年龄


文末有建表脚本
一个通用的步骤去理解需求:
update class c set student_avg_age where c.class_id = ?
select
s.class_id, avg(s.student_age) as temp_student_avg_age
from
student s GROUP BY s.class_id

update class c set student_avg_age = 12 where c.class_id = 1;
update class c set student_avg_age = 10 where c.class_id = 2;
select c.class_id, temp.temp_student_avg_age from class c join (
select
s.class_id, avg(s.student_age) as temp_student_avg_age
from
student s GROUP BY s.class_id
) temp
on c.class_id = temp.class_id

值得注意的是,通过表连接,现在数据的主视角是班级表。
# 型如这样的包装
update xxx
set
c.student_avg_age = temp.temp_student_avg_age
where
c.class_id = temp.class_id
# 最终的sql语句
update class c join (
select
s.class_id, avg(s.student_age) as temp_student_avg_age
from
student s GROUP BY s.class_id
) temp
on
c.class_id = temp.class_id
set
c.student_avg_age = temp.temp_student_avg_age
where
c.class_id = temp.class_id
子查询的语句表现得非常简单:
update class c set c.student_avg_age = (SELECT avg(s.student_age) FROM `student` s where s.class_id = c.class_id);
这里没有用上分组,原因是where s.class_id = c.class_id 在起着类似隐性分组的作用
分解来看,就能理解可以省略分组的原因:
upddate class_id = 1 的数据,先去查class_id = 1 的平均学生年龄。upddate class_id = 2 的数据,先去查class_id = 2 的平均学生年龄。