oracle中update...select

本文介绍了一种使用SQL更新表中部分记录的方法,通过结合子查询和NULL值处理函数nvl,确保只有存在匹配项的记录才会被更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比如有两张表

 

USER_CHINESE

ID ZHONGWEN

1 张三

2 李四

3 王五

 

USER_ENGLISH
ID PINYIN
1 zhangsan
2 lisi
4 liuliu

现在我想让USER_CHINESE表中的汉字变成拼音。

sql语句是:
update USER_CHINESE t1
set t1.zhongwen = (select t2.pinyin from USER_ENGLISH t2 where t2.id = t1.id);

这时候,你可能觉得应该update两条。
可是结果是:3条被更新。

看结果:
USER_CHINESE
ID ZHONGWEN
1 zhangsan
2 lisi
3

真的是更新了三条。
由于id=3的没有匹配上,所以id=3的记录的ZHONGWEN字段改成null了。
所以,这点一定要注意。

记住:如果update或delete没有where条件,则一定是全表更新的。

如果你不想更新id=3的记录。sql语句可以这样写:
update USER_CHINESE t1
set t1.zhongwen = (select t2.pinyin from USER_ENGLISH t2 where t2.id = t1.id)
where t1.id ! = 3;
这个时候结果是:2条被更新。
USER_CHINESE
ID ZHONGWEN
1 zhangsan
2 lisi
3 王五

但是,如果我们每次都在update之前都先找一下匹配不上的id,然后加到where条件中,这样肯定不行。
所以,如果你想让能匹配上的记录更新,匹配不上的记录保持不变。sql语句应该这样写:
update USER_CHINESE t1
set t1.zhongwen = nvl((select t2.pinyin from USER_ENGLISH t2 where t2.id = t1.id),t1.zhongwen);
这个时候结果是:3条被更新。
USER_CHINESE
ID ZHONGWEN
1 zhangsan
2 lisi
3 王五
达到目的了。注意这个时候是3条被更新,不是两条。

<think>我们正在讨论的是SELECT...FORUPDATE语句的作用和适用场景。根据用户提供的引用,我们可以总结如下:1.**作用**:SELECT...FORUPDATE用于在事务中锁定特定的行,防止其他事务修改或删除这些行,直到当前事务结束(通过COMMIT或ROLLBACK)。这是一种悲观锁的实现方式。2.**适用场景**:当我们需要确保在事务处理过程中,被选中的行不会被其他事务修改时,使用该语句。常见于需要保证数据一致性的场景,如银行转账、库存扣减等。详细分析引用内容:-引用[1]指出,普通的SELECT语句不会加锁,不会妨碍其他DML和DDL操作。而SELECT...FORUPDATE则是手工加锁语句。-引用[2]介绍了该语句的语法,包括OF子句(指定要锁定的列)、WAIT/NOWAIT(控制等待锁的时间)和SKIPLOCKED(跳过锁定的行)。-引用[3]强调,该语句仅适用于InnoDB存储引擎,且必须在事务块中(BEGIN/COMMIT)才能生效。它会对查询结果集的每一行加排他锁(行锁或表锁),阻塞其他事务的更新和删除操作。-引用[4]和[5]说明,被锁定的行在其他事务中仍然可以被查询(普通SELECT),但不能被修改或删除。它属于行级锁,用于防止并发修改,确保数据的一致性。**适用场景举例**:1.**转账操作**:在转账事务中,先锁定两个账户的行,然后再进行金额的修改,防止其他事务同时修改账户余额。2.**库存扣减**:在订单创建时锁定库存行,确保库存不会被超卖。**注意事项**:-必须在事务中使用,否则锁会立即释放。-尽量使用索引条件,避免锁升级为表锁。-合理设置等待时间(WAIT)或使用NOWAIT,避免长时间阻塞。**示例**(MySQL):```sqlSTARTTRANSACTION;SELECT*FROMaccountsWHEREidIN(1,2)FORUPDATE;--锁定账户1和2--执行转账操作:从账户1扣款,向账户2加款UPDATEaccountsSETbalance=balance-100WHEREid=1;UPDATEaccountsSETbalance=balance+100WHEREid=2;COMMIT;--提交事务,释放锁```**总结**:SELECT...FORUPDATE是一种显式的行级锁机制,用于在事务中确保数据的一致性,适用于需要高数据一致性的并发场景。使用时需注意事务的范围和锁的粒度,避免性能问题。§§相关问题§§1.SELECT...FORUPDATE在哪些数据库引擎中可用?2.如何避免SELECT...FORUPDATE导致的死锁?3.SELECT...FORUPDATE和LOCKINSHAREMODE有什么区别?4.在高并发场景下使用SELECT...FORUPDATE需要注意什么?</think>### SELECT ... FOR UPDATE的作用及适用场景详解 `SELECT ... FOR UPDATE` 是数据库中的一种显式锁定机制,主要用于事务中对特定数据行进行独占锁定。下面我将从作用机制、适用场景和注意事项三方面详细解析: #### 一、核心作用机制 1. **行级排他锁**(行锁): - 对查询结果集中的**每一行数据**添加排他锁(X锁) - 其他事务可以查询这些行(普通SELECT),但**不能修改或删除**(阻塞DML操作)[^4][^5] - 锁持续到当前事务结束(COMMIT/ROLLBACK) 2. **锁定范围控制**: ```sql -- 基本语法 SELECT * FROM table WHERE condition FOR UPDATE; -- 高级控制(Oracle语法) SELECT * FROM orders WHERE status='PENDING' FOR UPDATE OF amount -- 仅锁定amount列 WAIT 5; -- 最多等待5秒 [^2] ``` - `OF column_list`:锁定特定列(减少锁粒度)[^2] - `WAIT n`:设置锁等待超时(防止无限等待)[^2] - `SKIP LOCKED`:跳过已锁定的行(避免阻塞)[^2] 3. **事务绑定特性**: - **仅生效于事务块内**(BEGIN/COMMIT之间)[^3] - InnoDB引擎中会**自动升级为间隙锁**(Gap Lock),防止幻读 - 提交事务时**自动释放所有锁**[^5] #### 二、典型适用场景 1. **并发数据修改保护**: ```sql -- 银行转账场景(防止余额覆盖) BEGIN; SELECT balance FROM accounts WHERE id=1001 FOR UPDATE; -- 锁定账户 UPDATE accounts SET balance = balance - 100 WHERE id=1001; COMMIT; ``` 2. **库存扣减防超卖**: ```sql -- 电商库存扣减 SELECT stock FROM products WHERE id=305 FOR UPDATE; IF stock > 0 THEN UPDATE products SET stock = stock - 1 WHERE id=305; END IF; ``` 3. **顺序依赖操作**: - 需要严格按顺序处理的业务(如订单状态流转) - 防止状态机被并发请求破坏 4. **悲观锁实现**: - 当预期冲突频率高时,优先使用FOR UPDATE而非乐观锁 - 典型应用:财务对账、票务系统座位锁定[^5] #### 三、关键注意事项 1. **性能影响**: - 锁范围过大可能导致**全表锁**(如无索引WHERE条件) - 长事务持有锁会**阻塞其他操作**(超时设计很重要)[^2] 2. **死锁风险**: ```sql -- 事务1 SELECT * FROM tableA WHERE id=1 FOR UPDATE; SELECT * FROM tableB WHERE id=2 FOR UPDATE; -- 事务2(相反顺序) SELECT * FROM tableB WHERE id=2 FOR UPDATE; SELECT * FROM tableA WHERE id=1 FOR UPDATE; ``` - 解决方案:**统一资源访问顺序**或使用`NOWAIT`[^2] 3. **最佳实践**: - 始终通过**索引列**锁定(避免锁升级) - 设置合理`WAIT`超时(如`WAIT 3`)[^2] - 锁定后**尽快提交事务**(减少锁持有时间) - MySQL中仅InnoDB引擎支持[^3] > **锁机制对比**: > | 特性 | FOR UPDATE(悲观锁) | 乐观锁(版本号) | > |---------------------|---------------------|-----------------| > | 冲突概率 | 高冲突场景 | 低冲突场景 | > | 实现方式 | 数据库行锁 | 应用层版本控制 | > | 性能开销 | 事务阻塞成本高 | 无锁,重试成本 | > | 数据一致性 | 强保证 | 最终一致 | #### 四、总结 `SELECT ... FOR UPDATE` 是通过**行级排他锁**实现悲观并发控制的利器,适用于: 1. 需要**原子性修改**的关键业务(金融、库存) 2. 防止**并发更新冲突**的场景 3. 需要**严格顺序执行**的操作链 使用时需注意锁粒度控制和事务时长,避免性能瓶颈。在低冲突场景可考虑乐观锁替代方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值