【MySQL】记一次update批量更新操作

本文主要记录一次update......select操作,适用于sql操作小白。

应用场景:由于甲方需求变更,数据库表里增加了一个统计字段或者统计字段的计算逻辑发生了变化,导致统计字段的值需要更新或者重新计算。

能想到的解决方法以下几种:

  • 通过Java代码在业务里面修改数据
  • 通过直接操作数据库表的方式修改数据

第一种方式可以采用selectByIdupdateById这种方式进行循环更新,也可以进行批量更新,总之实现的方式比较多且比较简单。

但这里采用的是第二种方式进行数据更新。

前置条件

假设有一个课程表,里面记录了a、b、c、d这四门课的成绩,以及总成绩(需求版本1:总成绩等于各科成绩之和)。其中建表语句

sql 复制代码
# 建表语句
create table student_course
(
    student_id  int auto_increment primary key,
    course_a    int null,
    course_b    int null,
    course_c    int null,
    course_d    int null,
    total_score int null
)
    collate = utf8mb4_general_ci;

插入如下的测试数据:

sql 复制代码
INSERT INTO demo_data.student_course (student_id, course_a, course_b, course_c, course_d, total_score) VALUES (1, 80, 90, 70, 90, 330);
INSERT INTO demo_data.student_course (student_id, course_a, course_b, course_c, course_d, total_score) VALUES (2, 60, 60, 60, 80, 260);
​

在上述的基础数据之上,甲方爸爸突然告诉你计算总成绩的方式要变成couse_a * 0.5 + course_b * 0.5 + course_c + course_d的方式,且以前入库的历史数据也要变成这样。为了完成这个需求聪明的你一定想到了先修改java代码在重新上传之前的历史数据,但是如果之前的源文件丢失了那么就是一个悲伤的事情了,虽然也可以通过其他方式解决这个问题。为了能够早点完成这个需求,用更多的时间去学习 摸鱼,这里我们选择最简单粗暴的方式,直接进行数据库层面的操作,操作之前记得先备份数据,否则可就出大问题了。

单行记录的更新

首先单条数据的单个字段更新,语法如下:

sql 复制代码
update tableName ... inner join (selete ... from tableName) on 关联条件 where 过滤条件。

按照上面的语法编写sql语句,

sql 复制代码
update student_course t1 inner join (select student_course.student_id,
                              sum(student_course.course_a * 0.5 + student_course.course_b * 0.5
                                  + student_course.course_c + student_course.course_d) as totalA
                       from student_course
                       group by student_course.student_id) as t2
on t1.student_id = t2.student_id
set t1.total_score = t2.totalA
where t1.student_id  = 1

运行这段sql语句可得到如下输出,可以看到运行结果符合我们的预期。

于是乎我们兴致勃勃的将sql修改为如下:

sql 复制代码
update student_course t1 inner join (select student_course.student_id,
                              sum(student_course.course_a * 0.5 + student_course.course_b * 0.5
                                  + student_course.course_c + student_course.course_d) as totalA
                       from student_course
                       group by student_course.student_id) as t2
on t1.student_id = t2.student_id
set t1.total_score = t2.totalA
where t1.student_id  in (select t1.student_id from student_course);

手起刀落,bia🐔一运行于是乎就得到了如下的运行结果:

可以看到并没有达到预期的效果。MySQL果断的拒绝了我们并抛出一句错误信息You can't specify target table 'xxx' for update in FROM clause。翻译过来大概就是:无法在FROM子句中指定更新的目标表。

批量更新

由于mysql拒绝了我们,但是甲方又把刀架在脖子上让我们修改,因此时间、任务重我们就必须让mysql同意我们的更新语句,但是解决方法是如何的呢?其解决方法就是给from后面的sql子句中多穿一层衣服()即可,就是这么简单!因此修改sql语句中的in部分如下所示:

sql 复制代码
where t1.student_id  in (select student_id from (select student_id from student_course) as t3);

此时运sql语句我们就可以得到如下输出:

可以看到我们得到预期的结果,需求勉强实现。但是这里还需要注意下面两个坑:

  • 多个字段同时更新的问题要用逗号隔开,不能用and关键字否则将达不到预期的效果。
sql 复制代码
update student_course set course_a = 90 and course_b = 100 where student_id = 1

这里的预期结果是 course_a更新为 90course_b更新为100,实际上只是将course_a更新为了0,这里的原因是mysql错误的 (误解了我们的要表达的意思)将90 and course_b = 100当作运算条件运算了即原来的course_b = 90 != 100 其运算结果为false,而mysql0表示为false0 != 90 所以就将course_a的值更新为了0

所以为了避免错误要将and变为逗号;

sql 复制代码
update student_course set course_a = 90 , course_b = 100 where student_id = 1
  • 第二个坑主要就是因为自己太菜了,在运行sql逻辑的时候,由于实际的业务都计算逻辑并没有这么简单,导致在某些数据上实际的统计结果和之前的计算方式的计算结果是一样的,导致mysql一直输出affect 0 row,结果被我误以为sql不正确。实际上是起了作用的。真是一个悲伤的故事!

参考资料

相关推荐
向宇it14 分钟前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行16 分钟前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
W21551 小时前
Liunx下MySQL:表的约束
数据库·mysql
星河梦瑾1 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富1 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想1 小时前
JMeter 使用详解
java·jmeter
言、雲1 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇1 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
Yvemil72 小时前
《开启微服务之旅:Spring Boot 从入门到实践》(三)
java
Anna。。2 小时前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea