PostgreSQL 实现 Oracle 多表插入语句

news/2024/7/9 22:44:40 标签: postgresql, oracle, 数据库

Oracle 数据库提供了一个多表插入功能,也就是 INSERT ALL 语句。这个功能可以方便数据仓库中的 ETL 操作,基于不同逻辑将数据插入一个或者多个不同的表中。

PostgreSQL 被称为开源领域的 Oracle,虽然没有提供 INSERT ALL 语句,但是可以通过递归查询(WITH 语句)实现类似的功能。

首先创建一个源数据表和三个目标表:

CREATE TABLE src_table(
  id INTEGER NOT NULL PRIMARY KEY,
  name VARCHAR(10) NOT NULL
);
INSERT INTO src_table VALUES (1, '张三');
INSERT INTO src_table VALUES (2, '李四');
INSERT INTO src_table VALUES (3, '王五');

CREATE TABLE tgt_t1 AS
SELECT * FROM src_table WHERE FALSE;

CREATE TABLE tgt_t2 AS
SELECT * FROM src_table WHERE FALSE;

CREATE TABLE tgt_t3 AS
SELECT * FROM src_table WHERE FALSE;

无条件的多表插入语句

Oracle 中的 INSERT ALL 语句可以将数据输入插入一个或者多个表中,因此也被称为多表插入语句。第一种形式的 INSERT ALL 语句是无条件的插入语句,源数据中的每一行数据都会被插入到每个目标表中。

-- Oracle 语法
INSERT ALL
  INTO tgt_t1(id, name) VALUES(id, name)
  INTO tgt_t2(id, name) VALUES(id, name)
  INTO tgt_t3(id, name) VALUES(id, name)
SELECT * FROM src_table;

执行以上多表插入语句之后,三个目标表中都生成了 3 条记录。

PostgreSQL 可以使用以下 WITH 语句实现无条件的多表插入语句:

WITH s AS (
  SELECT id, name
  FROM src_table
)
,t1 AS (
  INSERT INTO tgt_t1(id, name)
  SELECT *
  FROM s
),
t2 AS (
  INSERT INTO tgt_t2(id, name)
  SELECT *
  FROM s
),
t3 AS (
  INSERT INTO tgt_t3(id, name)
  SELECT *
  FROM s
)
SELECT 1;

SELECT * FROM tgt_t1;
ID|NAME  |
--|------|
 1|张三  |
 2|李四  |
 3|王五  |

SELECT * FROM tgt_t2;
ID|NAME  |
--|------|
 1|张三  |
 2|李四  |
 3|王五  |

SELECT * FROM tgt_t3;
ID|NAME  |
--|------|
 1|张三  |
 2|李四  |
 3|王五  |

其中,s 代表了数据源,t1 实现了 tgt_t1 的数据插入,依此类推。最终通过一个 WITH 语句实现了三个表的插入操作。

💡虽然很多数据库都提供了通用表表达式(WITH 语句),但是目前只有 PostgreSQL 可以将 DML 语句的结果定义为一个通用表表达式。

有条件的多表插入语句

Oracle 提供的另一种形式的 INSERT ALL 语句是有条件的插入语句,可以将满足不同条件的数据插入不同的表中。例如:

-- Oracle 语法
INSERT ALL
  WHEN id <= 1 THEN
    INTO tgt_t1(id, name) VALUES(id, name)
  WHEN id BETWEEN 1 AND 2 THEN
    INTO tgt_t2(id, name) VALUES(id, name)
  ELSE
    INTO tgt_t3(id, name) VALUES(id, name)
SELECT * FROM src_table;

以上语句在 tgt_t1 中插入了 1 条数据,因为 id 小于等于 1 的记录只有 1 个。tgt_t2 中插入了 2 条数据,包括 id 等于 1 的记录。也就是说,前面的 WHEN 子句不会影响后续的条件判断,每个条件都会单独进行判断。tgt_t3 中插入了 1 条数据,ELSE 分支只会插入不满足前面所有条件的数据。

PostgreSQL 实现以上插入逻辑的方法如下:

WITH s AS (
  SELECT id, name
  FROM src_table
)
,t1 AS (
  INSERT INTO tgt_t1(id, name)
  SELECT *
  FROM s
  WHERE id <= 1
  RETURNING id
),
t2 AS (
  INSERT INTO tgt_t2(id, name)
  SELECT *
  FROM s
  WHERE id BETWEEN 1 AND 2
  RETURNING id
),
t3 AS (
  INSERT INTO tgt_t3(id, name)
  SELECT *
  FROM s
  WHERE id NOT IN (SELECT id FROM t1
                   UNION ALL 
                   SELECT id FROM t2)
)
SELECT 1;

t1 定义中的查询条件限制了 id 小于等于 1 的记录,同时使用 RETURNING 子句返回了插入 t1 中的所有 id;t2 也采用了类似的处理方式;t3 通过子查询插入了不满足 t1 和 t2 插入条件的其他数据。

💡RETURNING 子句可以返回 DML 语句操作修改的数据,它也是 PostgreSQL 专有的功能。

有条件的 INSERT FIRST 语句

Oracle 还提供了有条件的 INSERT FIRST 语句,它的原理和 CASE 表达式类似,只会执行第一个满足条件的插入语句,然后继续处理源数据中的其他记录。例如:

INSERT FIRST
  WHEN id <= 1 THEN
    INTO tgt_t1(id, name) VALUES(id, name)
  WHEN id BETWEEN 1 AND 2 THEN
    INTO tgt_t2(id, name) VALUES(id, name)
  ELSE
    INTO tgt_t3(id, name) VALUES(id, name)
SELECT * FROM src_table;

以上语句和上一个示例的差别在于源数据中的每个记录只会插入一次,tgt_t2 中不会插入 id 等于 1 的数据。

PostgreSQL 模拟以上 INSERT FIRST 语句的方法如下:

WITH s AS (
  SELECT id, name
  FROM src_table
)
,t1 AS (
  INSERT INTO tgt_t1(id, name)
  SELECT *
  FROM s
  WHERE id <= 1
  RETURNING id
),
t2 AS (
  INSERT INTO tgt_t2(id, name)
  SELECT *
  FROM s
  WHERE id BETWEEN 1 AND 2
  AND id NOT IN (SELECT id FROM t1)
  RETURNING id
),
t3 AS (
  INSERT INTO tgt_t3(id, name)
  SELECT *
  FROM s
  WHERE id NOT IN (SELECT id FROM t1
                   UNION ALL 
                   SELECT id FROM t2)
)
SELECT 1;

t2 的定义中排除的 t1 中的记录,t3 的定义中排除的 t1 以及 t2 中的记录,以此类推。


http://www.niftyadmin.cn/n/5245542.html

相关文章

【日常总结】mybatis-plus WHERE BINARY 中文查不出来

目录 一、场景 二、问题 三、原因 四、解决方案 五、拓展&#xff08;全表全字段修改字符集一键更改&#xff09; 准备工作&#xff1a;做好整个库备份 1. 全表一键修改 Stage 1&#xff1a;运行如下查询 Stage 2&#xff1a;复制sql语句 Stage 3&#xff1a;执行即可…

混沌映射初始化种群与随机初始化种群初始种群分布图对比

自行切换混沌映射&#xff0c;代码如下&#xff1a; Lb -1; % 搜索空间下界 Ub 1; % 搜索空间上界N_iter 500; % 最大迭代次数 N 30; % 种群个数 dim 2; % 种群维度 Z zeros(N, dim);% 随机生成一个d维向量 Z(1, :) rand(1, dim);% 利用logistic生成N个向量 for i…

企业级 接口自动化测试框架:Pytest+Allure+Excel

1. Allure 简介 简介 Allure 框架是一个灵活的、轻量级的、支持多语言的测试报告工具&#xff0c;它不仅以 Web 的方式展示了简介的测试结果&#xff0c;而且允许参与开发过程的每个人可以从日常执行的测试中&#xff0c;最大限度地提取有用信息。 Allure 是由 Java 语言开发…

【无线网络技术】——无线个域网(学习笔记)

&#x1f4d6; 前言&#xff1a;手机、PC机、电视等消费类产品非常普及&#xff0c;人们希望有一种短距离、低成本、小功耗的无线通信方式&#xff0c;实现不同功能单一设备的互联&#xff0c;提供小范围内设备的自组网机制&#xff0c;并通过一定的安全接口完成自组小网与广域…

c++实验多态程序设计

运行程序&#xff0c;分析结果。 #include <iostream> using namespace std; class B { public: virtual void f1(double x) { cout<<"B::f1(double)"<<x<<endl; } void f2(double x) { cout<<"B::f2(double)"<<…

SQL Server数据库的备份和还原

6.2 SQL Server备份和还原 数据库管理员最担心的情况就是数据库瘫痪&#xff0c;造成数据丢失&#xff0c;而备份作为数据的副本&#xff0c;可以有 效地保护和恢复数据。本节将介绍数据备份的原因&#xff0c;备份的方式.SOL Server的恢复模式.以及备 份策略和备份设备。 6.2…

机器学习---环境准备

一、pySpark环境准备 1、window配置python环境变量 window安装python&#xff0c;配置python环境变量。安装python后,在环境变量path中加入安装的路径&#xff0c;cmd中输入python&#xff0c;检验python是否安装成功。 注意&#xff1a;如果使用的是anaconda安装的python环境…

【Jmeter】JSON Extractor变量包含转义字符,使用Beanshell脚本来消除

如果使用Jmeter的JSON Extractor提取的变量包含特殊字符&#xff0c;直接引用时会包含转义字符。可以使用Beanshell脚本来进行字符串转换&#xff0c;从而消除这些转义字符。 import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONArray; import com.ali…