我们想把一个查询语句返回的结果集插入到多个目标表中。例如,希望把A表的数据分别插入到 B 表、C 表和 D 表。这3个表与 A 表的结构相同(相同的列和数据类型),并且当前不含任何数据。
解决办法就是把查询结果插入到多个目标表中。在oracle中我们可以使用insert all或者insert first语句,两者语法基本一致,区别在于:
-
insert first:对于每一行数据,只插入到第一个when条件成立的表,不继续检查其他条件。
-
insert all :对于每一行数据,对每一个when条件都进行检查,如果满足条件就执行插入操作。
但是在pg中是不支持该语法的,那么我们该如何实现多表插入的功能呢?
例子:
先看看在oracle中insert all的效果:
SQL> create table a(id int, c1 int, c2 int);
Table created.
SQL> create table b(id int, c1 int, c2 int);
Table created.
SQL> set autotrace on;
SQL> insert all
2 into a (id,c1) values (id, col1)
3 into b (id,c2) values (id, col2)
4 select rownum as id, trunc(dbms_random.value(0, 100)) as col1, trunc(dbms_random.value(0, 100)) as col2 from dual connect by level <=10000;
20000 rows created.
Execution Plan
----------------------------------------------------------
Plan hash value: 702343910
--------------------------------------------------------------------------------
--------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti
me |
--------------------------------------------------------------------------------
--------
| 0 | INSERT STATEMENT | | 1 | 39 | 2 (0)| 00
:00:01 |
| 1 | MULTI-TABLE INSERT | | | | |
|
| 2 | VIEW | | 1 | 39 | 2 (0)| 00
:00:01 |
| 3 | COUNT | | | | |
|
|* 4 | CONNECT BY WITHOUT FILTERING| | | | |
|
| 5 | FAST DUAL | | 1 | | 2 (0)| 00
:00:01 |
| 6 | INTO | A | | | |
|
| 7 | INTO | B | | | |
|
--------------------------------------------------------------------------------
--------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter(LEVEL<=10000)
Statistics
----------------------------------------------------------
1152 recursive calls
345 db block gets
1782 consistent gets
201 physical reads
376608 redo size
842 bytes sent via SQL*Net to client
1140 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
35 sorts (memory)
0 sorts (disk)
20000 rows processed
在pg中我们可以使用CTE语句来实现该功能。
建表:
bill=# create table a(id int, c1 int, c2 int);
CREATE TABLE
bill=# create table b(id int, c1 int, c2 int);
CREATE TABLE
可以发现pg不支持insert all语法:
bill=# insert all
bill-# into a (id,c1) values (id, col1)
bill-# into b (id,c2) values (id, col2)
bill-# select id, random() col1, random() col2 from generate_series(1,10000) t(id);
psql: ERROR: syntax error at or near "all"
LINE 1: insert all
^
使用CTE语句进行多表插入:
bill=# with tmp as (select id, random() col1, random() col2 from generate_series(1,10000) t(id)),
bill-# ins1 as (insert into a (id,c1) select id,col1 from tmp)
bill-# insert into b (id,c2) select id,col2 from tmp;
INSERT 0 10000
bill=# select count(*) from a;
count
-------
10000
(1 row)
bill=# select count(*) from b;
count
-------
10000
(1 row)
参考链接:
Oracle insert all 的语法:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9014.htm
https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9014.htm#i2125362
pg CTE语法:
https://www.postgresql.org/docs/11/static/queries-with.html