SQL 合并记录,你想根据相关记录是否已经存在来插入、更新或删除一个表的记录。(如果记录存在,则更新它;如果不存在,则插入一条新记录;如果更新之后的记录不满足某个条件,则删除它。)例如,你希望按照如下的条件来修改 EMP_COMMISSION
表。
SQL 合并记录 问题描述
你想根据相关记录是否已经存在来插入、更新或删除一个表的记录。(如果记录存在,则更新它;如果不存在,则插入一条新记录;如果更新之后的记录不满足某个条件,则删除它。)例如,你希望按照如下的条件来修改 EMP_COMMISSION
表。
如果 EMP_COMMISSION
表的员工数据在 EMP
表里也存在相关记录,则更新其业务提成(COMM
)为 1000。
2. 对于所有可能会把 COMM
列更新为 1000 的员工,如果他们的 SAL
低于 2000,则删除相关记录(他们不应该存在于 EMP_COMMISSION
表中)。
3. 否则,就要从 EMP
表取出相应的 EMPNO
、ENAME
和 DEPTNO
,并插入 EMP_COMMISSION
表。
总之,你希望根据 EMP
表的给定行是否与 EMP_COMMISSION
表里的某条记录相匹配来决定要执行 UPDATE
语句还是 INSERT
语句。然后,如果 UPDATE
的结果导致某个员工的业务提成太高的话,你希望执行 DELETE
语句。
下面分别列出了当前 EMP
表和 EMP_COMMISSION
表里的数据。
select deptno,empno,ename,comm
from emp
order by 1
DEPTNO EMPNO ENAME COMM
------ ---------- ------ ----------
10 7782 CLARK
10 7839 KING
10 7934 MILLER
20 7369 SMITH
20 7876 ADAMS
20 7902 FORD
20 7788 SCOTT
20 7566 JONES
30 7499 ALLEN 300
30 7698 BLAKE
30 7654 MARTIN 1400
30 7900 JAMES
30 7844 TURNER 0
30 7521 WARD 500
select deptno,empno,ename,comm
from emp_commission
order by 1
DEPTNO EMPNO ENAME COMM
---------- ---------- ---------- ----------
10 7782 CLARK
10 7839 KING
10 7934 MILLER
SQL 合并记录 解决方案
Oracle 是目前仅有的只使用单个 SQL 语句就能解决本问题的关系数据库管理系统。这就是 MERGE
语句,在实际执行时,它会根据需要自动转换成相应的 UPDATE
语句或者 INSERT
语句,如下所示。
1 merge into emp_commission ec
2 using (select * from emp) emp
3 on (ec.empno=emp.empno)
4 when matched then
5 update set ec.comm = 1000
6 delete where (sal < 2000)
7 when not matched then
8 insert (ec.empno,ec.ename,ec.deptno,ec.comm)
9 values (emp.empno,emp.ename,emp.deptno,emp.comm)
SQL 合并记录 扩展知识
在上述的解决方案里,第 3 行的连接条件决定了哪些行已经存在,因而需要对它们执行更新操作。该连接查询是在 EMP_COMMISSION
表(别名为 EC
)和子查询(别名为 emp
)之间进行的。若连接操作成功,则相关的两行被认为是相匹配的,进而 WHEN MATCHED
子句里的 UPDATE
语句会被执行。同样,如果根据 EMPNO
列,EMP
表中的行在 EMP_COMMISSION
表里没有相匹配的行,则它会被插入到 EMP_COMMISSION
表中。在 EMP
表里,只有 DEPTNO
等于 10 的员工,其 EMP_COMMISSION
表的 COMM
才会被更新,而其他员工的数据都会被插入到 EMP_COMMISSION
表。另外,员工 MILLER 的 DEPTNO
等于 10,本来他的业务提成(COMM
)应该被更新,但是由于他的工资(SAL
)低于 2000,因而他会被从 EMP_COMMISSION
表删除掉。