替换数据

最近更新时间: 2026-03-13 09:03:00

可以使用 MERGE INTO 语句来插入或者更新一条或多条数据。
语法如下:

MERGE INTO [ target_tablename ]
  USING [source_tablename]
  ON ( on_condition )
  [WHEN MATCHED THEN merge_update | merge_delete | DO NOTHING ] 
  [WHEN NOT MATCHED THEN merge_insert | DO NOTHING ]

参数说明:

  • target_tablename :指定需要进行数据替换的表。
  • source_tablename :指定源数据表。
  • on_condition :指定目标表和源表的ON条件,当ON条件为true,走matched分支,否则走not matched分支。
  • merge_update :merge的update部分语句,matched时候执行,如 update set ... where
  • merge_delete :merge的delete部分语句,matched时候执行,必须跟在merge_update之后使用,如delete ... where
  • merge_insert :merge的insert部分语句,not matched时候执行,如 insert values (...)

示例

1、替换表中数据,当源表数据和目标表数据不匹配时候进行insert
当目标表中无数据记录,可以使用 MERGE INTO 语句替换数据,结果等价于通过 INSERT 语句插入数据。
创建 tbase_merge_insert 表后不插入数据,创建源表tbase_source_table并插入一行数据,使用 MERGE INTO 语句往目标表插入一行数据,
merge的on条件为源表第一列 i 等于目标表第一列 i,在不匹配的条件下插入数据。

 tdsql=# create table tbase_merge_insert(i int, j int);
CREATE TABLE
 tdsql=# select * from tbase_merge_insert;
i | j
---+---
(0 rows)
 tdsql=# create table tbase_source_table(i int, j int);
CREATE TABLE
 tdsql=# insert into tbase_source_table values (1,1);
INSERT 0 1
 tdsql=# select * from tbase_source_table;
i | j
---+---
1 | 1
(1 row)

 tdsql=# merge into tbase_merge_insert using tbase_source_table on tbase_merge_insert.i=tbase_source_table.i when not matched then insert values (2,2);
MERGE 1
 tdsql=# select * from tbase_merge_insert;
i | j
---+---
2 | 2
(1 row)

从示例结果可以看出,tbase_merge_insert 表创建后未插入数据,执行 MERGE INTO 语句后,表中插入了一条记录。
merge的on条件改为目标表第一列i不等于源表第一列i,在不匹配的条件下插入数据。

 tdsql=# select * from tbase_merge_insert;
i | j
---+---
2 | 2
(1 row)

 tdsql=# select * from tbase_source_table;
i | j
---+---
1 | 1
(1 row)
 tdsql=# merge into tbase_merge_insert using tbase_source_table on tbase_merge_insert.i!=tbase_source_table.i when not matched then insert values (3,3);
MERGE 0
 tdsql=# select * from tbase_merge_insert;
i | j
---+---
2 | 2
(1 row)

从示例结果可以看出,tbase_merge_insert 表中已有一条记录(2,2),由于源表中的记录(1,1)满足1 != 2,此时on结果为true,但后续判断是在when not matched插入,所以无法往目标表插入新数据。
2、 替换表中数据,当源表数据和目标表数据匹配时候进行update。
创建目标表tbase_merge_update,插入一条记录(1,1), 此时清空源表,并往源表tbase_source_table也插入一条数据(1,1),merge语句的on条件改回为第一列i相等的条件。 再使用update去更新tbase_merge_update的记录的j列值为3。

 tdsql=# select * from tbase_source_table;
i | j
---+---
1 | 1
(1 row)

 tdsql=# create table tbase_merge_update (i int, j int);
CREATE TABLE
 tdsql=# insert into tbase_merge_update values (1,1);
INSERT 0 1
 tdsql=# select * from tbase_merge_update;
i | j
---+---
1 | 1
(1 row)
 tdsql=# merge into tbase_merge_update using tbase_source_table on tbase_source_table.i= tbase_merge_update.i when matched then update set j=3 ;
MERGE 1
 tdsql=# select * from tbase_merge_update;
i | j
---+---
1 | 3
(1 row)

从示例结果中可以看出,mergeon条件为true,此时做update目标表将记录(1,1)更新为了(1,3)
update还可以加上where条件做更多的限制,这里我们基于上一步的结果去做mergemerge语句on条件不变,update之后加上where进行更多限制。

 tdsql=# select * from tbase_merge_update;
i | j
---+---
1 | 3
(1 row)

 tdsql=# select * from tbase_source_table;
i | j
---+---
1 | 1
(1 row)
 tdsql=# merge into tbase_merge_update using tbase_source_table on tbase_source_table.i= tbase_merge_update.i when matched then update set j=4 where tbase_merge_update.i > 2 ;
MERGE 0
 tdsql=# select * from tbase_merge_update;
i | j
---+---
1 | 3
(1 row)

结果中可以看出,update之后where限制了当tbase_merge_update表的i列大于2时候才更新,因此merge结果为0行,tbase_merge_update表中没有记录更新。
3、 替换表中数据,当源表数据和目标表数据匹配时候进行delete。
使用 MERGE INTO 语句的 delete功能删除目标表中的记录,创建目标表tbase_merge_delete,插入一条记录(1,1), 此时清空源表,并往源表tbase_source_table也插入一条数据(1,1),merge语句的on条件改回为第一列i相等的条件。

 tdsql=# delete from tbase_source_table;
DELETE 1
 tdsql=# insert into tbase_source_table values(1,1);
INSERT 1
 tdsql=# select * from tbase_source_table;
i | j 
---+---
1 | 1
(1 row)
 tdsql=# create table tbase_merge_delete (i int, j int);
CREATE TABLE
 tdsql=# insert into tbase_merge_delete values (1,1);
INSERT 0 1
 tdsql=# select * from tbase_merge_delete;
i | j 
---+---
1 | 1
(1 row)
 tdsql=# merge into tbase_merge_delete using tbase_source_table on tbase_source_table.i= tbase_merge_delete.i when matched then update set j=10 delete where j=1;
MERGE 1
 tdsql=# select * from tbase_merge_delete;
i | j
---+---
(0 rows)

从示例中可以看出,merge的执行后将目标表tbase_merge_delete中的记录删除了(和Oracle实现有差异,TDSQL PG delete中的j列默认指代源表的j列)
4、 替换表中数据,在merge功能中同时使用insert、update去修改目标表。
创建新的目标表tbase_merge_insup,插入一行记录(2,2,'update'),清空源表数据,再往源表插入(2,2)(1,1)两条记录。

 tdsql=# create table tbase_merge_insup(i int, j int, op text);
CREATE TABLE
 tdsql=# insert into tbase_merge_insup values (2,2,'update');
INSERT 0 1
 tdsql=# delete from tbase_source_table;
 DELETE 1
 tdsql=# insert into tbase_source_table values(1,1),(2,2);
 INSERT 2
 tdsql=# select * from tbase_source_table;
i | j
---+---
1 | 1
2 | 2
(2 rows)

 tdsql=# select * from tbase_merge_insup;
i | j |   op   
---+---+--------
2 | 2 | update
(1 row)
 tdsql=# merge into tbase_merge_insup using tbase_source_table on tbase_source_table.i = tbase_merge_insup.i when not matched then insert values (1,1,'insert') when matched then update set op='tbase_update';
MERGE 2
 tdsql=# select * from tbase_merge_insup;
i | j |      op      
---+---+--------------
1 | 1 | insert
2 | 2 | tbase_update
(2 rows)

通过以上的例子可以看出,源表的记录(1,1)走到not matched分支,往目标表插入数据(1,1,insert),源表记录(2,2)走到matched分支,更新目标表插入的记录(2,2,update)(2,2,tbase_update)
5、 替换表中数据,在merge功能中同时使用insert、delete去修改目标表
创建新的目标表tbase_merge_insdel,插入一行记录(2,2,'delete'),清空源表数据,再往源表插入(2,2)(1,1)两条记录。

 tdsql=# create table tbase_merge_insdel(i int, j int, op text);
CREATE TABLE
 tdsql=# insert into tbase_merge_insdel values (2,2,'delete');
INSERT 0 1
 tdsql=# select * from tbase_merge_insdel;
i | j |   op   
---+---+--------
2 | 2 | delete
(1 row)
 tdsql=# delete from tbase_source_table;
 DELETE 2
 tdsql=# insert into tbase_source_table values(1,1),(2,2);
 INSERT 2
 tdsql=# select * from tbase_source_table;
i | j
---+---
1 | 1
2 | 2
(2 rows)
 tdsql=# merge into tbase_merge_insdel using tbase_source_table on tbase_source_table.i = tbase_merge_insdel.i when not matched then insert values (1,1,'insert') when matched then update set j=10 delete where j=2;
MERGE 2
 tdsql=# select * from tbase_merge_insdel;
i | j |   op   
---+---+--------
 1 |  1 | insert
(2 rows)

通过以上的例子可以看出,源表的记录(1,1)走到not matched分支,往目标表插入数据(1,1,insert),源表记录(2,2)走到matched分支,删除了目标表插入的记录(2,2,delete)。(和Oracle实现有差异,TDSQL PG delete中的j列默认指代源表的j列)
6、 oracle兼容模式下,使用merge替换表数据,可以同时使用insert、update、delete修改目标表数据
创建新的目标表tbase_merge_all,插入两行记录(2,2,'delete'),(2,2,update),清空源表数据,再往源表插入(2,2)(1,1)两条记录。

 tdsql=# create table tbase_merge_all(i int, j int, op text);
CREATE TABLE
 tdsql=# insert into tbase_merge_all values(2,2,'delete');
INSERT 0 1
 tdsql=# insert into tbase_merge_all values(2,2,'update');
INSERT 0 1
 tdsql=# select * from tbase_merge_all;
i | j |   op   
---+---+--------
2 | 2 | delete
2 | 2 | update
(3 rows)
 tdsql=# delete from tbase_source_table;
 DELETE 2
 tdsql=# insert into tbase_source_table values(1,1),(2,2);
 INSERT 2
 tdsql=# select * from tbase_source_table;
i | j
---+---
1 | 1
2 | 2
(2 rows)
 tdsql=# merge into tbase_merge_all using tbase_source_table on tbase_source_table.i = tbase_merge_all.i when not matched then insert values (1,1,'insert') when matched then update set op='tbase_update' where op='update' delete where op='tbase_update' or op='delete';
MERGE 2
 tdsql=# select * from tbase_merge_all;
i | j |   op   
---+---+--------
2 | 2 | delete
1 | 1 | insert
(2 rows)

通过以上的例子可以看出:

  • 源表的记录(1,1)走到not matched分支,往目标表插入数据(1,1,insert),
  • 源表记录(2,2)走到matched分支,匹配了目标表2行记录(2,2,'update'),(2,2,'delete''),先通过update操作更新了目标表记录(2,2,'update')(2,2,'tbase_update'),之后delete待操作的集合就变为update操作之后的结果记录(2,2,'tbase_update')而不包括(2,2,'delete')这条记录,因此delete通过where条件只能把这条记录删除,记录(2,2,'delete')不受影响。