先放结论
UPDATE 需要更新的表名 B
SET B.更新字段1 = '更新内容1', B.更新字段2 = '更新内容2'
WHERE EXISTS (SELECT 1
FROM 关联表名 A
WHERE A.关联字段 = B.关联字段
AND A.筛选字段1 = '筛选字段1'
AND A.筛选字段2 = '筛选字段2'
AND B.筛选字段3 = '筛选字段3'
);
问题分析
需要写一个更新语句,但是更新的判断条件是两个表关联查询出来的
踩坑一
一开始是打算UPDATE写两个表,然后WHERE里面两表关联,就像这样:
--错误sql
UPDATE 表名1 A,表名2 B
SET A.更新字段1 = '更新内容1', A.更新字段2 = '更新内容2'
WHERE A.关联字段 = B.关联字段
AND A.筛选字段1 = '筛选字段1'
AND A.筛选字段2 = '筛选字段2'
AND B.筛选字段3 = '筛选字段3'
但是一直报错
很明显也不是缺失SET 关键字的问题
踩坑二
之后搜索怎么在Oracel关联两表更新。发现了下面这种写法
--正常sql
UPDATE 更新表名 A
SET A.更新字段1 = '更新内容1'
WHERE EXISTS (SELECT 1 FROM 关联表名 B WHERE A.关联字段 = B.关联字段)
但是也是没太仔细看,加上思维固化,写成了下面这种情况
--错误sql
UPDATE 更新表名 A
SET A.更新字段1 = '更新内容1'
WHERE EXISTS (SELECT 1
FROM 更新表名 A, 关联表名 B
WHERE A.关联字段 = B.关联字段
AND A.筛选字段1 = '筛选字段1')
可以看到在FROM里面比搜索出来的sql语句,多了更新的表名A
显而易见,还会有点问题
但是这次并不是报错,而是筛选不是自己预想的筛选,导致更新的数据非常多
像下图一样,更新语句跑了1分半,更新了46万条数据。。。
明显是有问题的(实际上只需要更新几十条),被更新的B表实际上也只有26万条数据,不知道46万条更新怎么来的
只能先回滚更新
通过对比发现是FROM多写了个更新的表名,修改之后可以正常的更新,没有问题
踩坑三
既然已经可以两表关联查询,更新其中一个表了,那能不能同时更新两个表呢?
想当然的认为sql应该是这样的
UPDATE 更新表1 A
SET A.更新字段1 = 'A表更新内容1' ,B.更新字段2 = 'B表更新内容2'
WHERE EXISTS (SELECT 1
FROM 更新表2 B
WHERE A.关联字段 = B.关联字段
AND A.筛选字段 = '筛选字段')
于是写出了下面的sql,但是事实证明这样写是不行的
语句分析
UPDATE 需要更新的表名 B
SET B.更新字段1 = '更新内容1', B.更新字段2 = '更新内容2'
WHERE EXISTS (SELECT 1
FROM 关联表名 A
WHERE A.关联字段 = B.关联字段
AND A.筛选字段1 = '筛选字段1'
AND A.筛选字段2 = '筛选字段2'
AND B.筛选字段3 = '筛选字段3'
);
A表和B表都有相同的关联字段,并且通过筛选字段校验。那么就有SELECT 1,那么EXISTS就会返回TRUE;最后进行更新操作。
EXISTS
EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False
EXISTS(包括 NOT EXISTS )子句的返回值是一个BOOL值。 EXISTS内部有一个子查询语句(SELECT … FROM…), 我将其称为EXISTS的内查询语句。其内查询语句返回一个结果集。 EXISTS子句根据其内查询语句的结果集空或者非空,返回一个布尔值。
此时在该更新sql中
--EXISTS的内查询语句为:
SELECT 1
FROM 关联表名 A
WHERE A.关联字段 = B.关联字段
AND A.筛选字段1 = '筛选字段1'
AND A.筛选字段2 = '筛选字段2'
AND B.筛选字段3 = '筛选字段3'
--WHERE判断EXISTS返回的BOOL值来决定是否更新
WHERE EXISTS
SELECT 1
当我们只关心数据表有多少记录行而不需要知道具体的字段值时
,SELECT 1 FROM TABLE
是一个很不错的SQL语句写法,它通常用于子查询。
SELECT 1 FROM TABLE可以减少系统开销,提高运行效率。因为此时数据库就不会去检索数据表里每条具体的记录和每条记录里每个具体的字段值并将它们放到内存里,而是查询到有多少记录行存在就输出多少个“1”,每个“1”代表有1行记录。
选用数字1是因为它所占用的内存空间最小,用数字0的效果也一样,即:SELECT 0 FROM TABLE。
从效率上来说,SELECT 1 > SELECT 字段 > SELECT *
在子查询中的应用
常规写法
SELECT * FROM t1 a WHERE EXISTS (SELECT * FROM t2 b WHERE a.id = b.id)
更优写法
SELECT * FROM t1 a WHERE EXISTS (SELECT 1 FROM t2 b WHERE a.id = b.id)