SQL 使用另一个表的数据更新记录

SQL 使用另一个表的数据更新记录,你想使用另一个表的值来更新当前的表。例如,现在有一个 NEW_SAL 表,存储了部分员工调整后的工资。NEW_SAL 表的数据如下。

SQL 使用另一个表的数据更新记录 问题描述

你想使用另一个表的值来更新当前的表。例如,现在有一个 NEW_SAL 表,存储了部分员工调整后的工资。NEW_SAL 表的数据如下。

select *
  from new_sal
 
DEPTNO        SAL
------ ----------
    10       4000

DEPTNO 列是 NEW_SAL 表的主键。你希望使用 NEW_SAL 表的数据来更新 EMP 表中部分员工的工资和业务提成。如果 EMP 表中的 DEPTNO 列和 NEW_SAL 表中的 DEPTNO 列相匹配,则将 EMP 表中的 SAL 列更新为 NEW_SAL 表中的 SAL 列,EMP 表中的 COMM 列更新为 NEW_SAL 表中 SAL 列的 50%。EMP 表的全部数据如下所示。

select deptno,ename,sal,comm
  from emp
 order by 1
 
DEPTNO ENAME             SAL       COMM
------ ---------- ---------- ----------
    10 CLARK            2450
    10 KING             5000
    10 MILLER           1300
    20 SMITH             800
    20 ADAMS            1100
    20 FORD             3000
    20 SCOTT            3000
    20 JONES            2975
    30 ALLEN            1600        300
    30 BLAKE            2850
    30 MARTIN           1250       1400
    30 JAMES             950
    30 TURNER           1500          0
    30 WARD             1250        500

SQL 使用另一个表的数据更新记录 解决方案

NEW_SAL 表和 EMP 表连接起来,为 UPDATE 语句找出新的 COMM 值。正如本实例所示,在 UPDATE 语句里使用关联子查询是常用做法。另一种方法是创建一个视图(传统视图或者内嵌视图均可,这取决于数据库是否支持),然后更新该视图即可。
DB2 和 MySQL
使用关联查询来更新 EMP 表的 SAL 列和 COMM 列,同时也要使用另一个关联子查询来决定 EMP 表里有哪些行应该被更新。

1  update emp e set (e.sal,e.comm) = (select ns.sal, ns.sal/2
2                                       from new_sal ns
3                                      where ns.deptno=e.deptno)
4   where exists ( select null
5                    from new_sal ns
6                   where ns.deptno = e.deptno )

Oracle
DB2 的解决方案当然也适用于 Oracle,不过还有另外一种方法,即更新内嵌视图。

1 update (
2  select e.sal  as emp_sal, e.comm  as emp_comm,
3         ns.sal as ns_sal, ns.sal/2 as ns_comm
4    from emp e, new_sal ns
5   where e.deptno = ns.deptno
6  ) set emp_sal = ns_sal, emp_comm = ns_comm

PostgreSQL
DB2 的解决方案同样适用于 PostgreSQL,也可以在 UPDATE 语句里直接进行连接查询(非常方便)。

1 update emp
2    set sal  = ns.sal,
3        comm = ns.sal/2
4   from new_sal ns
5  where ns.deptno = emp.deptno

SQL Server
DB2 的解决方案同样适用于 SQL Server,也可以在 UPDATE 语句里直接进行连接查询(类似于 PostgreSQL 解决方案)。

1 update e
2    set e.sal  = ns.sal,
3        e.comm = ns.sal/2
4   from emp e,
5        new_sal ns
6  where ns.deptno = e.deptno

SQL 使用另一个表的数据更新记录 扩展知识

在讨论各种解决方案之前,我想先说一下在 UPDATE 语句里使用 SELECT 查询提供新值的问题。在 UPDATE 语句的关联子查询里使用 WHERE 子句不同于针对需要更新的表所使用的 WHERE 子句。如果你看一下“解决方案”部分的 UPDATE 语句就会明白,EMP 表和 NEW_SAL 表基于 DEPTNO 列连接之后,把查询结果传递给了 UPDATE 语句的 SET 子句。对于部门编号为 10 的员工而言,会将对应的有效值传递给 SET 子句,因为在 NEW_SAL 表里有与之相匹配的 DEPTNO。但是对其他部门的员工而言,又当如何呢? NEW_SAL 表里没有其他部门的数据,因此对于部门编号为 20 和 30 的员工来说,SAL 列和 COMM 列会变为 Null。除非使用 LIMITTOP 或者其他由数据库提供的限制结果集行数的机制,否则在 SQL 数据库里唯一能限制行数的办法就是使用 WHERE 子句。因此,为了正确地执行 UPDATE,有时候要针对需要更新的表使用 WHERE 子句,有时候却要在关联子查询里使用 WHERE 子句。
DB2 和 MySQL
为了确保不会误改 EMP 表的全部行,要记得在 UPDATE 语句的 WHERE 子句里使用关联子查询。因为仅仅在 SET 子句里执行连接查询(关联子查询)是不够的。UPDATE 语句的 WHERE 子句能够确保只更新 EMP 表中那些与 NEW_SAL 表的 DEPTNO 列相匹配的行。这适用于所有的关系数据库管理系统。
Oracle
Oracle 解决方案使用了可更新的连接视图,由相等连接查询来决定哪些行将被更新。我们可以单独执行该查询语句来确认哪些行会被更新,也可以单独执行该内嵌视图的查询语句来确认哪些行将被更新。若想正确地使用这种类型的 UPDATE,你必须先理解“键值保持”(key-preservation)。DEPTNO 列是 NEW_SAL 表的主键,所以它的值是唯一的。当 EMP 表和 NEW_SAL 表做连接查询时,NEW_SAL 表的 DEPTNO 列在结果集里却不是唯一的,如下所示。

select e.empno, e.deptno e_dept, ns.sal, ns.deptno ns_deptno
   from emp e, new_sal ns
  where e.deptno = ns.deptno
 
EMPNO     E_DEPT        SAL  NS_DEPTNO
----- ---------- ---------- ----------
 7782         10       4000         10
 7839         10       4000         10
 7934         10       4000         10

为了让 Oracle 能够通过上述连接查询更新基础表,其中一个基础表必须符合键值保持的要求。也就是说,如果它的值在连接查询的结果集里不是唯一的,那么至少在基础表里是唯一的。在本例中,NEW_SAL 表的主键是 DEPTNO 列,因而符合唯一性的要求。既然 DEPTNO 列在基础表里是唯一的,那么它就可以多次出现在连接查询的结果集里,并被判定为符合键值保持的要求,更新操作也因此得以成功执行。
PostgreSQL 和 SQL Server
对于这两个数据库而言,语法略有不同,但方法是一样的。支持在 UPDATE 语句里直接进行连接查询自是方便之极。由于指明了要更新哪个表(通过在 UPDATE 关键字之后给出表的名字),数据库系统也就会知道要修改哪个表。除此之外,由于在更新操作里使用了连接查询(因为显式地使用了 WHERE 子句),我们得以避免一些关联子查询的陷阱。尤其是如果不小心漏掉了此处的连接查询,那么就能很容易发现问题。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程