Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一道SQL考题的思考

一道SQL考题的思考

作者头像
bisal
发布于 2019-12-10 11:01:13
发布于 2019-12-10 11:01:13
39000
代码可运行
举报
运行总次数:0
代码可运行

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://cloud.tencent.com/developer/article/1551925

最近参加了一次考试,有道题,考察的是个SQL基础,但确实具备迷惑,需求很简单,通过子查询,用一张表的数据,和另一张表进行匹配更新,

直接上实验,构造两张表,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> create table testupdate1 (id number, name varchar2(10));
Table created.

SQL> create table testupdate2 (id number, name varchar2(10));
Table created.

SQL> insert into testupdate1 values(1, 'a');
1 row created.

SQL> insert into testupdate1 values(2, 'b');
1 row created.

SQL> insert into testupdate2 values(1, 'e');
1 row created.

SQL> insert into testupdate2 values(3, 'c');
1 row created.

SQL> insert into testupdate2 values(4, 'd');
1 row created.

SQL> commit;                          
Commit complete.

SQL> select * from testupdate1;
        ID NAME
---------- ----------
         1 a
         2 b

SQL> select * from testupdate2;
        ID NAME
---------- ----------
         3 c
         4 d
         1 e

单独执行子查询,根据两张表id字段关联,能找到表2的name是e,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> select testupdate1.name from testupdate1, testupdate2 
     where testupdate1.id=testupdate2.id;
NAME
----------
e

根据子查询得到的字段name值,执行update,意图是更新表1的name字段,从实际执行看,两张表匹配的记录值(id=1)得到了更新(name=e),但是两张表不匹配的记录(id=2)更新成了空,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> update testupdate1
     set name=(select name from testupdate2
     where testupdate1.id=testupdate2.id);
2 rows updated.

SQL> select * from testupdate1;
        ID NAME
---------- ----------
         1 e
         2

他的陷阱,就在于子查询外部更新update操作,没限定条件,意思是对表1所有记录都更新,其实从执行返回,"2 rows updated."就可以得到验证,实际表1和表2要更新的应该只是1条记录,这个SQL只当表1和表2的id匹配,此时才可能用表2的name更新表1的name,否则要更新的name,就是空。

既然知道了原因,改造方式,可能有很多种。

方案1,在update层where条件中,限定testupdate1的id要在testupdate2中存在,表示只更新testupdate1和testupdate2匹配id的记录,返回“1 row updated.",可以说明,这个操作正确,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> update testupdate1
     set name=(select name from testupdate2
     where testupdate1.id=testupdate2.id)
     where testupdate1.id in (select id from testupdate2);
1 row updated.

SQL> select * from testupdate1;                                                          
        ID NAME
---------- ----------
         1 e
         2

方案2,在update中用exists,确认只更新testupdate1和testupdate2匹配id的记录,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> update testupdate1
     set name=(select name from testupdate2
     where testupdate1.id=testupdate2.id)
     where exists (select 1 from testupdate2
     where testupdate2.id=testupdate1.id);
1 row updated.

SQL> select * from testupdate1;
    ID NAME
---------- ----------
     1 e
     2 b

方案3,用内联视图,通过关联这两张表为一个视图,更新视图的列,但是直接执行,可能会抛出如下的错误,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> update
     (select testupdate1.name t1name, testupdate2.name t2name from testupdate1, testupdate2
     where testupdate1.id=testupdate2.id and testupdate1.id=1) t
     set t1name=t2name;
     *
ERROR at line 1:
ORA-01779: cannot modify a column which maps to a non key-preserved table

问题就是两张表缺少主键,用于唯一定位,创建两张表主键,此时就可以正常执行了,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> alter table testupdate1 add constraint pk_testupdate1 primary key (id);
Table altered.

SQL> alter table testupdate2 add constraint pk_testupdate2 primary key (id);
Table altered.

SQL> update (select testupdate1.name t1name, testupdate2.name t2name from testupdate1, testupdate2 where testupdate1.id=testupdate2.id and testupdate1.id=1) t set t1name=t2name; 
1 row updated.

SQL> select * from testupdate1;
    ID NAME
---------- ----------
     1 e
     2 b

方案4,用merge子句,将testupdate2的每条记录通过on和testupdate1进行比较,匹配的执行update,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQL> merge into testupdate1 t1 
     using (select testupdate2.name t2name, testupdate2.id t2id from testupdate2) t2 
     on (t2.t2id=t1.id) 
     when matched then 
     update set t1.name=t2.t2name;
1 row merged.

SQL> select * from testupdate1;
    ID NAME
---------- ----------
     1 e
     2 b

从理解上,前两种更为常见,多了解两种,作为知识补充。另外,以上的测试,都在数据量很小的情况下,所以没性能问题,如果在实际中用,就需要考虑如何高效执行,因此,能不能满足功能要求,和能不能在真实环境使用,其实是两个问题,其实很重要,但时,往往容易忽略。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/12/02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
一道SQL考题的更多思考
问题1,方案1执行update,select的结果应该是(1e,2b),存在不匹配的记录,不会进行更新,是我贴错了,我的锅,
bisal
2019/12/20
5840
一道SQL考题的更多思考
SQL基础--> 数据处理(DML、RETURNING、MERGE INTO)
--=================================================
Leshami
2018/08/07
9150
复盘eygle在甲骨文大会上演讲中的示例,看看什么是大师的由点及面
盖总(eygle)在刚结束的甲骨文大会的演讲中,通过一个简单的UPDATE语句,为我们展示了什么叫由点及面的优化,什么叫由点及面的知识覆盖度,不在于这个案具体如何操作,更应关注或更值得我们借鉴的是这种学习态度和方法思路,大师是如何炼成的?我想这个案例可以带给我们一些启迪。
bisal
2019/01/29
5300
外键要建立索引的原理和实验
项目中,我们要求凡是有主子关系的表都要使用外键约束,来保证主子表之间关系的正确,不推荐由应用自己控制这种关系。
bisal
2019/01/29
2.8K0
深入解析:你听说过Oracle数据库的更新重启动吗?
杨廷琨 云和恩墨高级咨询顾问, ITPUB Oracle 数据库管理版版主 ,人称 “杨长老”,十数年如一日坚持进行 Oracle 技术研究与写作,号称 “Oracle 的百科全书”。迄今已经在自己的博客上发表了超过 3000 篇技术文章。2010 年,与 Eygle 共同主编出版了《Oracle DBA 手记》一书,2007 年被 Oracle 公司授予 ACE 称号。
数据和云
2018/07/27
6890
深入解析:你听说过Oracle数据库的更新重启动吗?
从ORA-01752的错误,透过现象看本质
这几天开发同学反映了一个问题,有一个Java写的夜维程序,用于每天定时删除历史过期数据,3月10日之前经过了内测,但这两天再次执行的时候,有一条SQL语句一直报ORA-01752的错误,由于近期做过一次开发库的迁移,从一个机房搬迁至另一个机房,而且开发同学确认这期间未变代码逻辑,所以怀疑是否和数据迁移有关,这个错误被测试同学提为了bug,卡在版本测试中,有可能造成进度延误,所以属于比较紧急的问题。
bisal
2019/01/29
1.1K0
ORA-60死锁的实验
SQL> create table tbl_ora_60 (      id number(5),      name varchar2(5)      ); SQL> insert into tbl_ora_60 values(1, 'a'); 1 row created. SQL> insert into tbl_ora_60 values(2, 'b'); 1 row created. SQL> commit; Commit complete. SQL> select * from tbl_ora_60;         ID NAME ---------- -----          1 a          2 b 实验开始 Session1: SQL> update tbl_ora_60 set name='c' where id=1; 1 row updated. Session2: SQL> update tbl_ora_60 set name='d' where id=2; 1 row updated. Session1: SQL> update tbl_ora_60 set name='e' where id=2; hang住 Session2: SQL> update tbl_ora_60 set name='f' where id=1; hang住 此时,Session1: SQL> update tbl_ora_60 set name='e' where id=2; update tbl_ora_60 set name='e' where id=2        * ERROR at line 1: ORA-00060: deadlock detected while waiting for resource 说明: Session1                                            Session2 获取id=1的资源锁                                                         获取id=2的资源锁 等待id=2的资源锁                                                         等待id=1的资源锁 id=2的SQL报ORA-60,自动rollback 1、因为id=2的资源锁是Session2先获取的,因此Oracle会自动rollback产生死锁时后需要资源锁的SQL,Session1的更新id=2操作被rollback。 2、从中可以发现,真正报ORA-60错误的SQL获取的资源(此例中id=2),并不是触发死锁产生的那个资源(此例中id=1),此例用的是同一个表的不同行,对不同表的相同行也如此,也可以解释之前夜维出现ORA-60时显示的SQL之间表是不同的原因,因为夜维执行的某个表更新与当前应用执行的某个表更新之间存在互锁的情况,因此可能导致夜维SQL报ORA-60或应用报ORA-60的错误。 此时,Session1: SQL> select * from tbl_ora_60;         ID NAME ---------- -----          1 c          2 b 说明:此处可以证明产生报错后,Oracle自动执行的rollback操作是基于单条SQL,不是整个事务的,所以这里只有id=2的记录被rollback,id=1的执行仍正常。 Session2: SQL> update tbl_ora_60 set name='f' where id=1; hang住 继续,Session1: SQL> commit; Commit complete. Session2: SQL> update tbl_ora_60 set name='f' where id=1; 1 row updated. Session1: SQL> select * from tbl_ora_60;         ID NAME ---------- -----          1 c          2 b 只有id=1更新成功。 Session2: SQL> select * from tbl_ora_60;         ID NAME ---------- -----          1 f          2 d id=1和id=2都更新成功,但未COMMIT。 SQL> commit; Commit complete. Sess
bisal
2019/01/29
4980
变与不变: Undo构造一致性读的例外情况
嘉年华听了恩墨学院的一个主题:《重现ORA-01555 细说Oracle 12c Undo数据管理》,吕星昊老师介绍了UNDO的概念以及ORA-1555的产生,并介绍了12c以来Oracle的UNDO相关的新特性。
数据和云
2018/12/18
4290
变与不变: Undo构造一致性读的例外情况
使用SQL中的数据操作语言 (DML)
DML 使用 INSERT、UPDATE、DELETE 和 MERGE 在 SQL 中添加、更新和删除数据。
云云众生s
2024/04/05
2030
表中已存重复数据的情况,如何增加唯一性约束?
这周某系统上线,有一个需求就是,为一张表修改唯一性约束,原因就是之前发现,由于唯一性约束设置不当,导致业务处理出现异常。
bisal
2019/01/30
2.2K0
【DB笔试面试664】在Oracle中,模拟死锁产生的一个场景。
Oracle中的死锁比较复杂,产生死锁的原因也有很多种,曾经有面试官让面试人员口头模拟死锁产生的一个场景。
AiDBA宝典
2019/10/23
7190
【DB笔试面试664】在Oracle中,模拟死锁产生的一个场景。
NULL判断对SQL的影响
看到一条SQL,很具迷惑性,原始语句包含了业务属性,因此使用模拟的操作来复现这个问题。
bisal
2021/09/06
1K0
NULL判断对SQL的影响
SQL 基础--> 视图(CREATE VIEW)
视图来源于表,所有对视图数据的修改最终都会被反映到视图的基表中,这些修改必须服从基表的完整性约束,并同样会触发定义
Leshami
2018/08/07
8060
左右db_block_size了解和实验
创建一个区大小为 40k SYS@ORCL>show parameter db_block_size
全栈程序员站长
2022/07/06
3110
一个触发器需求的案例
我对触发器,了解非常有限,只能试着来,乍一看判断空,即NULL,是不能用“=”,需要使用IS NULL/IS NOT NULL,改了一下,执行报错,
bisal
2019/01/29
7050
SQL基础-->数据库事务(TRANSACTION)
数据库事务是指作为单个逻辑工作单元执行的一系列操作,可以认为事务就是一组不可分割的SQL语句
Leshami
2018/08/07
6450
通过闪回事务查看数据dml的情况 (r2笔记69天)
昨天有一个网友问我,怎么能够查询一个表中最后一条插入的记录,我大概回复了,可以通过闪回事务来实现,但是得看什么时候插入的数据,也需要一定的运气。 如果通过闪回事务来得到对应的undo_sql,可能多个dml语句对应一个事务,所以我们需要得到的是一个完整的事务的信息,里面包括对应的Undo_sql,这样才算得到比较完整的sql语句。 我在本地自己做了一个测试。 创建一个test表,然后插入一些记录,然后尝试修改一些数据。 SQL> DROP TABLE TEST; Table dropped. SQL>
jeanron100
2018/03/14
5250
关于trigger过滤最大值的问题(54天)
今天碰到一个问题,开发有一个比较紧的需要,想问问我数据库这边能不能帮上忙。 如果开发那边来做,需要改代码,如果数据库这边能临时支持,代码就可以多做些测试,然后再打补丁了。 需求的情况大体是这样:有一个表的字段是number(11,4),意味着数据保持4为精度,总共长度支持11位,最大值位9999999.9999 如果超过了那个最大值(比如99999999,有8个9),想在update语句update之前能够把那个值改成9999999就可以了。 听起来好像可以使用trigger来做。简单做了个测试。 新建一
jeanron100
2018/03/13
8510
alter table新增字段操作究竟有何影响?(下篇)
没想到距此篇博文的上半部分发表(http://blog.csdn.net/bisal/article/details/45418303)已经有半年的时间,上篇博文是5月小长假的时候,在开往杭州的高铁上完成的,话说第二天就有了我的小baby:),难道写博客还有助孕的效果?需要的朋友不妨一试,哈哈,归根结底,还是需要作为IT从业者的我们,紧张工作之余,要有放松的安排,不仅是身体上的放松,还要有精神、心灵上的放松,俗话说得好“天空飘来五个字,那都不是事,是事也就烦一会,一会就没事”。
bisal
2019/01/30
7520
从 MySQL 执行 update 报错 ERROR 1292 说起
事情是这样的,上周五下班前通过自动化工具执行开发人员事先写好的 SQL 时,自动化工具执行失败了,于是手动去生产环境执行,就发生了错误 “ERROR 1292 (22007): Truncated incorrect DOUBLE value”,截断不正确的 DOUBLE 值,难道是数据类型长度不够,接下来我们查看一下表结构。
JiekeXu之路
2023/09/06
6940
从 MySQL 执行 update 报错 ERROR 1292 说起
相关推荐
一道SQL考题的更多思考
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验