SQL标准于增加了一个新的数据操作语句:MERGE(合并),它可以同时完成INSERT语句和UPDATE语句,甚至DELETE语句的操作。
标准合并语句
它的基本语法如下:
MERGE INTO target [AS t_alias]USING source_table [AS s_alias]ON (conditions)WHEN MATCHED THENUPDATESET col1 = expr1,col2 = expr2,...WHEN NOT MATCHED THENINSERT (col1, col2,...) VALUES (expr1, expr2...);
其中,target_table是合并操作的目标表。
USING子句指定了数据源,可以是一个表或者查询语句。
ON子句指定了数据合并的条件,通常使用主键或者唯一键相等作为合并的条件。
对于数据源中的每条记录,如果目标表中存在匹配的记录,则执行WHEN MATCHED THEN分支的更新操作;如果目标表中不存在匹配的记录,则执行WHEN NOT MATCHED THEN分支的插入操作。
案例分析
案例使用的示例表
下面的操作会用到两个表,其中employee表中存储了员工的基本信息,包括姓名、入职日期、部门编号、薪资等字段。以下是该表中的部分数据:
emp_devp表是employee的备份表。
这两个表的初始化脚本可以在文章底部获取。
示例一
使用MERGE语句将employee表中dept_id为4的员工信息合并到emp_devp表中:
MERGE INTO emp_devp tUSING (SELECT emp_id, emp_name, sex, dept_id, manager,hire_date, job_id, salary, bonus, emailFROM employeeWHERE dept_id = 4) sON (t.emp_id = s.emp_id)WHEN MATCHED THENUPDATESET t.emp_name = s.emp_name, t.sex = s.sex, t.dept_id = s.dept_id, t.manager = s.manager,t.hire_date = s.hire_date, t.job_id = s.job_id, t.salary = s.salary, t.bonus = s.bonus, t.email = s.emailWHEN NOT MATCHED THENINSERT (emp_id, emp_name, sex, dept_id, manager,hire_date, job_id, salary, bonus, email) VALUES (s.emp_id, s.emp_name, s.sex, s.dept_id, s.manager,s.hire_date, s.job_id, s.salary, s.bonus, s.email);
以上合并操作的判断条件为数据源和目标表中的emp_id是否相等。如果相等,则更新目标表中的数据;否则,插入数据到目标表。
第一次运行以上语句时,emp_devp表中没有任何数据,因此对于数据源中的每条记录都会执行WHEN NOT MATCHED THEN分支,也就是插入数据。
以上语句执行成功之后,我们可以查看合并后的数据:
示例二
MERGE语句还支持DELETE子句,可以用于删除目标表中匹配的数据,例如:
MERGE INTO emp_devp tUSING (SELECT emp_id, emp_name, sex, dept_id, manager,hire_date, job_id, salary, bonus, emailFROM employeeWHERE dept_id = 4) sON (t.emp_id = s.emp_id)WHEN MATCHED THENUPDATESET t.emp_name = s.emp_name, t.sex = s.sex, t.dept_id = s.dept_id, t.manager = s.manager,t.hire_date = s.hire_date, t.job_id = s.job_id, t.salary = s.salary, t.bonus = s.bonus, t.email = s.emailDELETE WHERE t.emp_name = '赵氏'WHEN NOT MATCHED THENINSERT (emp_id, emp_name, sex, dept_id, manager,hire_date, job_id, salary, bonus, email) VALUES (s.emp_id, s.emp_name, s.sex, s.dept_id, s.manager,s.hire_date, s.job_id, s.salary, s.bonus, s.email);
我们在WHEN MATCHED THEN分支中增加了一个DELETE子句和一个WHERE条件。
如果运行以上语句,emp_devp表中姓名为“赵氏”的员工记录将会被删除。
通过查询,发现emp_name为“赵氏”的记录被删除了。
示例表和脚本
--员工信息表CREATE TABLE employee( emp_id NUMBER, emp_name VARCHAR2(50) NOT NULL, sex VARCHAR2(10) NOT NULL, dept_id INTEGER NOT NULL, manager INTEGER, hire_date DATE NOT NULL, job_id INTEGER NOT NULL, salary NUMERIC(8,2) NOT NULL, bonusNUMERIC(8,2), emailVARCHAR2(100) NOT NULL, comments VARCHAR2(500), create_by VARCHAR2(50) NOT NULL, create_ts TIMESTAMP NOT NULL, update_by VARCHAR2(50) , update_ts TIMESTAMP) ;COMMENT ON TABLE employee IS '员工信息表';COMMENT ON COLUMN employee.emp_id IS '员工编号,自增主键';COMMENT ON COLUMN employee.emp_name IS '员工姓名';COMMENT ON COLUMN employee.sex IS '性别';COMMENT ON COLUMN employee.dept_id IS '部门编号';COMMENT ON COLUMN employee.manager IS '上级经理';COMMENT ON COLUMN employee.hire_date IS '入职日期';COMMENT ON COLUMN employee.job_id IS '职位编号';COMMENT ON COLUMN employee.salary IS '月薪';COMMENT ON COLUMN employee.bonus IS '年终奖金';COMMENT ON COLUMN employee.email IS '电子邮箱';COMMENT ON COLUMN ments IS '备注信息';COMMENT ON COLUMN employee.create_by IS '创建者';COMMENT ON COLUMN employee.create_ts IS '创建时间';COMMENT ON COLUMN employee.update_by IS '修改者';COMMENT ON COLUMN employee.update_ts IS '修改时间';INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (1,'刘备', '男', 1, NULL, DATE '2000-01-01', 1, 30000, 10000, 'liubei@', NULL, 'Admin', TIMESTAMP '2000-01-01 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (2,'关羽', '男', 1, 1, DATE '2000-01-01', 2, 26000, 10000, 'guanyu@', NULL, 'Admin', TIMESTAMP '2000-01-01 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (3,'张飞', '男', 1, 1, DATE '2000-01-01', 2, 24000, 10000, 'zhangfei@', NULL, 'Admin', TIMESTAMP '2000-01-01 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (4,'诸葛亮', '男', 2, 1, DATE '-03-15', 3, 24000, 8000, 'zhugeliang@', NULL, 'Admin', TIMESTAMP '-03-15 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (5,'黄忠', '男', 2, 4, DATE '-10-25', 4, 8000, NULL, 'huangzhong@', NULL, 'Admin', TIMESTAMP '-10-25 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (6,'魏延', '男', 2, 4, DATE '-04-01', 4, 7500, NULL, 'weiyan@', NULL, 'Admin', TIMESTAMP '-04-01 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (7,'孙尚香', '女', 3, 1, DATE '2002-08-08', 5, 12000, 5000, 'sunshangxiang@', NULL, 'Admin', TIMESTAMP '2002-08-08 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (8,'孙丫鬟', '女', 3, 7, DATE '2002-08-08', 6, 6000, NULL, 'sunyahuan@', NULL, 'Admin', TIMESTAMP '2002-08-08 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (9,'赵云', '男', 4, 1, DATE '-12-19', 7, 15000, 6000, 'zhaoyun@', NULL, 'Admin', TIMESTAMP '-12-19 10:00:00', 'Admin', TIMESTAMP '-12-31 10:00:00');INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (10,'廖化', '男', 4, 9, DATE '-02-17', 8, 6500, NULL, 'liaohua@', NULL, 'Admin', TIMESTAMP '-02-17 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (11,'关平', '男', 4, 9, DATE '-07-24', 8, 6800, NULL, 'guanping@', NULL, 'Admin', TIMESTAMP '-07-24 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (12,'赵氏', '女', 4, 9, DATE '-11-10', 8, 6600, NULL, 'zhaoshi@', NULL, 'Admin', TIMESTAMP '-11-10 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (13,'关兴', '男', 4, 9, DATE '-07-30', 8, 7000, NULL, 'guanxing@', NULL, 'Admin', TIMESTAMP '-07-30 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (14,'张苞', '男', 4, 9, DATE '-05-31', 8, 6500, NULL, 'zhangbao@', NULL, 'Admin', TIMESTAMP '-05-31 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (15,'赵统', '男', 4, 9, DATE '-05-03', 8, 6000, NULL, 'zhaotong@', NULL, 'Admin', TIMESTAMP '-05-03 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (16,'周仓', '男', 4, 9, DATE '-02-20', 8, 8000, NULL, 'zhoucang@', NULL, 'Admin', TIMESTAMP '-02-20 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (17,'马岱', '男', 4, 9, DATE '-09-16', 8, 5800, NULL, 'madai@', NULL, 'Admin', TIMESTAMP '-09-16 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (18,'法正', '男', 5, 2, DATE '-04-09', 9, 10000, 5000, 'fazheng@', NULL, 'Admin', TIMESTAMP '-04-09 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (19,'庞统', '男', 5, 18, DATE '-06-06', 10, 4100, 2000, 'pangtong@', NULL, 'Admin', TIMESTAMP '-06-06 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (20,'蒋琬', '男', 5, 18, DATE '-01-28', 10, 4000, 1500, 'jiangwan@', NULL, 'Admin', TIMESTAMP '-01-28 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (21,'黄权', '男', 5, 18, DATE '-03-14', 10, 4200, NULL, 'huangquan@', NULL, 'Admin', TIMESTAMP '-03-14 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (22,'糜竺', '男', 5, 18, DATE '-03-27', 10, 4300, NULL, 'mizhu@', NULL, 'Admin', TIMESTAMP '-03-27 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (23,'邓芝', '男', 5, 18, DATE '-11-11', 10, 4000, NULL, 'dengzhi@', NULL, 'Admin', TIMESTAMP '-11-11 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (24,'简雍', '男', 5, 18, DATE '-05-11', 10, 4800, NULL, 'jianyong@', NULL, 'Admin', TIMESTAMP '-05-11 10:00:00', NULL, NULL);INSERT INTO employee(EMP_ID,emp_name, sex, dept_id, manager, hire_date, job_id, salary, bonus, email, comments, create_by, create_ts, update_by, update_ts) VALUES (25,'孙乾', '男', 5, 18, DATE '-10-09', 10, 4700, NULL, 'sunqian@', NULL, 'Admin', TIMESTAMP '-10-09 10:00:00', NULL, NULL);--员工信息表备份表CREATE TABLE emp_devp( emp_id NUMBER, emp_name VARCHAR2(50) NOT NULL, sex VARCHAR2(10) NOT NULL, dept_id INTEGER NOT NULL, manager INTEGER, hire_date DATE NOT NULL, job_id INTEGER NOT NULL, salary NUMERIC(8,2) NOT NULL, bonusNUMERIC(8,2), emailVARCHAR2(100) NOT NULL) ;COMMENT ON TABLE emp_devp IS '员工信息表备份表';COMMENT ON COLUMN emp_devp.emp_id IS '员工编号,自增主键';COMMENT ON COLUMN emp_devp.emp_name IS '员工姓名';COMMENT ON COLUMN emp_devp.sex IS '性别';COMMENT ON COLUMN emp_devp.dept_id IS '部门编号';COMMENT ON COLUMN emp_devp.manager IS '上级经理';COMMENT ON COLUMN emp_devp.hire_date IS '入职日期';COMMENT ON COLUMN emp_devp.job_id IS '职位编号';COMMENT ON COLUMN emp_devp.salary IS '月薪';COMMENT ON COLUMN emp_devp.bonus IS '年终奖金';COMMENT ON COLUMN emp_devp.email IS '电子邮箱';