当前位置: 首页 > news >正文

PostgreSQL15——DML 语句

DML 语句

  • 一、插入数据
    • 1.1、插入数据
    • 1.2、插入多行数据
    • 1.3、复制数据
    • 1.4、返回插入的数据
  • 二、更新数据
    • 2.1、单表更新
    • 2.2、跨表更新
    • 2.3、返回更新后的数据
  • 三、删除数据
    • 3.1、单表删除
    • 3.2、跨表删除
    • 3.3、返回被删除的数据
  • 四、合并数据
    • 4.1、MERGE语句
    • 4.2、INSERT ON CONFLICT 语句

包括插入数据的 INSERT 语句、更新数据的UPDATE 语句、删除数据的 DELETE 语句,以及合并数据的 MERGE 语句。

-- 准备数据
CREATE TABLE dept (department_id int NOT NULL,department_name varchar(30) NOT NULL,CONSTRAINT dept_pkey PRIMARY KEY (department_id)
);
CREATE TABLE emp (employee_id int NOT NULL,first_name varchar(20) NULL,last_name varchar(25) NOT NULL,hire_date date not null default current_date,salary numeric(8,2) NULL,manager_id int NULL,department_id int NULL,CONSTRAINT emp_pkey PRIMARY KEY (employee_id),CONSTRAINT fk_emp_dept FOREIGN KEY (department_id) REFERENCES dept(department_id) ON DELETE CASCADE,CONSTRAINT fk_emp_manager FOREIGN KEY (manager_id) REFERENCES emp(employee_id)
);

一、插入数据

1.1、插入数据

INSERT 语句的简单形式如下:

INSERT INTO table_name(column1, column2, ...)
VALUES (value1, value2, ...);

其中,value1 是 column1 的值,value2 是 column2 的值。例如:

INSERT INTO dept(department_id, department_name) VALUES ( 10,
'Administration');SELECT * FROM dept;

如果 VALUES 列表为所有字段都指定了值,并且按照表的字段顺序出现,可以省略表名后的字段列表。因此,我们也可以使用以下插入语句:

INSERT INTO dept VALUES ( 20, 'Marketing');SELECT * FROM dept;

指定字段的值也可以使用 DEFAULT,表示使用定义字段时的默认值;如果没有指定默认值使用 NULL。

1.2、插入多行数据

PostgreSQL中的INSERT 语句支持一次插入多行数据,在VALUES 之后使用逗号进行分隔。例如:

INSERT INTO emp
VALUES (200, 'Jennifer', 'Whalen', '2020-01-01', 4400.00, NULL, 10),
(201, 'Michael', 'Hartstein', '2020-02-02', 13000.00, NULL, 20),
(202, 'Pat', 'Fay', default, 6000.00, 201, 20);SELECT * FROM emp;

在这里插入图片描述

以上语句一次增加了 3 名员工信息,日期可以使用字符形式的字面值(‘2020-01-01’), default表示使用默认的当前日期。

1.3、复制数据

INSERT INTO SELECT 语句可以将一个查询语句的结果插入表中。例如:

create table emp1 (like emp);INSERT INTO emp1
SELECT * FROM emp
WHERE department_id = 20;SELECT * FROM emp1;

在这里插入图片描述

我们首先基于 emp 创建了一个新表 emp1,然后通过查询语句将 emp 中的部分数据复制到emp1 中。

1.4、返回插入的数据

PostgreSQL 对SQL 标准进行了扩展,可以在 INSERT 语句之后使用 RETURNING 返回插入的数据值。例如:

INSERT INTO dept
values (30, 'Purchasing')
RETURNING department_id;

在这里插入图片描述

以上语句除了插入一条数据到 dept 表中之外,同时还返回了该数据的 department_id。

二、更新数据

2.1、单表更新

PostgreSQL 使用 UPDATE 语句更新表中已有的数据,基本的语法如下:

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE conditions;

其中, WHERE 决定了需要更新的数据行,只有满足条件的数据才会更新;如果省略WHERE条件,将会更新表中的所有数据,需要谨慎使用。

以下语句将编号为 200 的员工从原部门调动到 Marketing,并且涨薪 1000:

UPDATE emp
SET salary = salary + 1000, department_id = 20
WHERE employee_id = 200;

2.2、跨表更新

除了以上形式的更新语句之外,PostgreSQL 还支持通过关联其他表中的数据进行更新。以下语句利用 emp 中的数据更新 emp1 表:

UPDATE emp1
SET salary = emp.salary, department_id = emp.department_id, manager_id = emp.manager_id
FROM emp
WHERE emp1.employee_id = emp.employee_id;

使用FROM 子句访问emp 中的数据,并且在WHERE 子句中指定了两个表的关联条件。这种语句与多表连接查询(JOIN)类似,有时候也称为多表连接更新(UPDATE JOIN)。

2.3、返回更新后的数据

PostgreSQL 同样对UPDATE 语句进行了扩展,支持使用RETURNING 返回更新后的数据值。例如:

UPDATE emp
set salary = salary + 1000, department_id = 20
WHERE employee_id = 200
RETURNING first_name, last_name, salary;

在这里插入图片描述

三、删除数据

3.1、单表删除

删除数据可以使用 DELETE 语句:

DELETE FROM table_name
WHERE conditions;

同样,只有满足 WHERE 条件的数据才会被删除;如果省略,将会删除表中所有的数据。

以下语句用于删除 emp1 中员工编号为 201 的数据:

DELETE
FROM emp1
WHERE employee_id = 201;

3.2、跨表删除

PostgreSQL 同样支持通过关联其他表进行数据删除。以下语句利用 emp 表删除 emp1 表中的数据:

DELETE
FROM emp1
USING emp
WHERE emp1.employee_id = emp.employee_id;

注意,跨表删除使用 USING 关键字引用其他的表,而不是JOIN。以上语句了 emp1 中员工编号存在于 emp 表中的数据,等价于以下子查询实现:

DELETE
FROM emp1
WHERE emp1.employee_id in (SELECT employee_id FROM emp);

3.3、返回被删除的数据

PostgreSQL 中的 DELETE 语句也可以使用 RETURNING 返回被删除的数据。例如:

-- 先插入一些数据
INSERT INTO emp1
SELECT * FROM emp
WHERE department_id = 20;DELETE
FROM emp1
RETURNING *;

在这里插入图片描述

我们先从 emp 复制了一些数据到 emp1 中,然后删除所有数据并且返回这些记录。

四、合并数据

4.1、MERGE语句

SQL 标准中定义了一个用于合并数据的 MERGE 语句,可以基于指定条件执行插入、更新或者删除操作。PostgreSQL 15 实现了MERGE 语句,基本语法如下:

MERGE INTO target
USING source
ON join_condition
{ WHEN MATCHED THEN { UPDATE| DELETE | DO NOTHING } |
WHEN NOT MATCHED THEN { INSERT | DO NOTHING } }
;
  • target 是合并操作的目标表;
  • source 是合并数据的来源,可以是表名或者查询语句;
  • ON子句是判断源数据在目标表中是否存在的条件;
  • WHEN MATCHED THEN 分支指定了数据匹配(已经存在)时执行的操作;
  • WHEN NOT MATCHED THEN 分支指定了数据不存在时的操作。

我们创建一个示例表 account:

CREATE TABLE account (id INTEGER PRIMARY KEY,balance NUMERIC NOT NULL,status VARCHAR(1) NOT NULL CHECK (status IN ('Y', 'N'))
);

使用以下语句为 account 表新增一条记录:

MERGE INTO account a
USING (VALUES(1, 0, 'Y')) s(id, balance, status)
ON a.id = s.id
WHEN MATCHED THEN
UPDATE SET balance = s.balance, status = s.status
WHEN NOT MATCHED THEN
INSERT (id, balance, status)
VALUES (s.id, s.balance, s.status);

在这里插入图片描述

由于id 等于1 的记录不存在,以上语句将会执行 WHEN NOT MATCHED THEN 分支,插入一条新的记录。

接下来我们将插入源数据中的 balance 修改为 100,再次执行 MERGE 语句:

MERGE INTO account a
USING (VALUES(1, 100, 'Y')) s(id, balance, status)
ON a.id = s.id
WHEN MATCHED THEN
UPDATE SET balance = s.balance, status = s.status
WHEN NOT MATCHED THEN
INSERT (id, balance, status)
VALUES (s.id, s.balance, s.status);SELECT * FROM account;

在这里插入图片描述

以上语句将会执行 WHEN MATCHED THEN 分支,更新 account 表中id 等于1 的记录。

最后,我们在MERGE 语句中增加一个分支,用于删除数据:

MERGE INTO account a
USING (VALUES(1, 100, 'N')) s(id, balance, status)
ON a.id = s.id
WHEN MATCHED AND s.status = 'N' THEN
DELETE
WHEN MATCHED THEN
UPDATE SET balance = s.balance, status = s.status
WHEN NOT MATCHED THEN
INSERT (id, balance, status)
VALUES (s.id, s.balance, s.status);SELECT * FROM account;

在这里插入图片描述

语句中的 WHEN MATCHED AND s.status = ‘N’ THEN 表示如果源数据存在,并且源数据中的状态为 N,则删除目标表中的对应记录。因此,最后的查询语句没有返回结果。

4.2、INSERT ON CONFLICT 语句

对于PostgreSQL 14 以及更早版本,可以通过 INSERT INTO … ON CONFLICT… 实现数据合并的功能。

INSERT INTO table_name(column1, column2, ...)
{VALUES (value1, value2, ...) | SELECT ...}
ON CONFLICT conflict_target conflict_action;

其中,conflict_target 是判断数据是否已经存在的条件:

  • ( { index_column_name | ( index_expression ) } ) ,基于某个具有索引的字段或者表达式进
    行判断;
  • ON CONSTRAINT constraint_name,基于某个唯一约束进行判断。
  • conflict_action 表示冲突时采取的操作:
  • DO NOTHING,如果数据已经存在,不做任何操作;
  • DO UPDATE SET,如果数据已经存在,更新该数据;可以

使用 WHERE 子句进一步限制需要更新的数据。
这种语句通过为 INSERT 语句增加 ON CONFLICT 选项,组合了 INSERT 和UPDATE 语句的功能,因此也被称为 UPSERT 语句。

emp 表中已经存在编号为 200 的员工,如果我们再次插入该编号将会提示主键冲突:

INSERT INTO emp
values (200, 'Jennifer', 'Whalen', '2020-01-01', 4400.00, NULL, 10)ERROR:  Key (employee_id)=(200) already exists.duplicate key value violates unique constraint "emp_pkey" ERROR:  duplicate key value violates unique constraint "emp_pkey"
SQL state: 23505
Detail: Key (employee_id)=(200) already exists.

此时,我们可以增加冲突处理,从而避免语句出错:

INSERT INTO emp
values (200, 'Jennifer', 'Whalen', '2020-01-01', 4400.00, NULL, 10)
on conflict (employee_id)
do nothing;

以上语句基于 employee_id 字段是否重复进行判断,冲突时不做任何处理。

另一种处理冲突的方式就是进行数据更新:

SELECT department_id
FROM emp
WHERE employee_id = 200;

在这里插入图片描述

INSERT INTO emp
values (200, 'Jennifer', 'Whalen', '2020-01-01', 4400.00, NULL, 10)
on conflict on constraint emp_pkey
do update
set first_name = EXCLUDED.first_name,
last_name = EXCLUDED.last_name,
hire_date = EXCLUDED.hire_date,
salary = EXCLUDED.salary,
manager_id =EXCLUDED.manager_id,
department_id = EXCLUDED.department_id;SELECT *
FROM emp
WHERE employee_id = 200;

在这里插入图片描述

该员工的部门编号在前面被修改为 20;我们通过主键约束 emp_pkey 进行重复数据的判断,然后更新该员工的数据;EXCLUDED 是一个特殊的表,代表了原本应该插入的数据行;最终该员工的部门编号被更新为 10。


文章转载自:

http://qzqhrqmf.Ltpmy.cn
http://tRArVmz8.Ltpmy.cn
http://gnm9riiH.Ltpmy.cn
http://jK2Q7IpD.Ltpmy.cn
http://G9Q8Pm6K.Ltpmy.cn
http://CEtGx5WY.Ltpmy.cn
http://DYb8wC36.Ltpmy.cn
http://rSlYkHcK.Ltpmy.cn
http://OeBkzCT9.Ltpmy.cn
http://dSS0SPV5.Ltpmy.cn
http://qr1Mjf2p.Ltpmy.cn
http://LnNToKh8.Ltpmy.cn
http://ckZrafx7.Ltpmy.cn
http://e9sZ8Ang.Ltpmy.cn
http://oQVo7E5p.Ltpmy.cn
http://YGDqqh8c.Ltpmy.cn
http://oRCuMCka.Ltpmy.cn
http://5cGuQR3G.Ltpmy.cn
http://JxWCxMYW.Ltpmy.cn
http://qOl9MXzX.Ltpmy.cn
http://zBjSPKfs.Ltpmy.cn
http://gWYRwNVw.Ltpmy.cn
http://s6y7qDFf.Ltpmy.cn
http://yaw8Gm3l.Ltpmy.cn
http://sM5sbJVd.Ltpmy.cn
http://QfCUTC4G.Ltpmy.cn
http://59t6Q9ro.Ltpmy.cn
http://Kf9Alnnq.Ltpmy.cn
http://4e7SJqhR.Ltpmy.cn
http://3fsOz8dR.Ltpmy.cn
http://www.dtcms.com/a/367944.html

相关文章:

  • 机器学习-决策树(下)
  • 如何将视频从 iPhone 转移到 Mac
  • 基于Echarts+HTML5可视化数据大屏展示-旅游智慧中心
  • AI API Tester体验:API测试工具如何高效生成接口测试用例、覆盖异常场景?
  • 四六级学习资料管理系统的设计与实现(代码+数据库+LW)
  • (3)Seata AT 模式的事务一致性保证机制
  • MySQL主从同步--主从复制进阶
  • VisionMaster 4.2.0安装
  • FastVLM-0.5B 模型解析
  • 球坐标系下调和函数的构造:多项式边界条件的求解方法
  • 基于SpringBoot的旅游管理系统的设计与实现(代码+数据库+LW)
  • 【面试】框架常见面试(追问)
  • Android/Java 中接口(Interface)的使用场景、用途和方法
  • android 读取cpu+m1类型的nfc卡片,设置只读写m1的内容
  • 扫描件、PDF、图片都能比对!让文档差异无所遁形
  • 【FastDDS】Discovery ( 05-Discovery Server Settings)
  • 嵌入式第四十六天(51单片机(通信))
  • 通过Gen AI SDK调用gemini 2.5 pro,单独上传pdf文件 | ai agent 开发笔记 2025.9.2 Day 2
  • Linux服务器暴走,用Netdata+cpolar轻松驯化
  • Node.js 做 Web 后端优势为什么这么大?
  • Windows 文件资源管理器无法预览文件内容word、ppt、excel、pdf
  • android 四大组件—BroadcastReceiver
  • 聊一聊 .NET 中的 CancellationTokenSource
  • Ubuntu 22 redis集群搭建
  • 开发环境 之 编辑器、编译器、IDE梳理
  • adobe acrobat 安装到使用再到PDF编辑【适合小白,只看一篇就够!!!】
  • [VF2] Boot Ubuntu和Debian发行版
  • 模型剪枝----ResNet18剪枝实战
  • CSS Position 属性
  • 【Android】制造一个ANR并进行简单分析