前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一道SQL考题的思考

一道SQL考题的思考

作者头像
bisal
发布2019-12-10 19:01:13
3860
发布2019-12-10 19:01:13
举报
文章被收录于专栏:bisal的个人杂货铺

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

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

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

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

代码语言:javascript
复制
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
复制
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
复制
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
复制
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
复制
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
复制
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
复制
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
复制
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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档