《PostgreSQL 开发指南》 第 22 篇 DML 语句
本篇介绍如何对表中的数据进行修改操作,包括插入数据的
INSERT语句、更新数据的
UPDATE语句、删除数据的
DELETE语句,以及合并数据的
INSERT ON CONFLICT语句。
我们首先创建创建两个示例表:
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) );
关于创建表的
CREATE TABLE语句,可以参考第 06 篇 管理数据表。
插入数据
PostgreSQL 提供了
INSERT语句,可以用于插入一行或者多行数据。
插入单行数据
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; department_id|department_name| -------------|---------------| 10|Administration |
如果
VALUES列表为所有字段都指定了值,并且按照表的字段顺序出现,可以省略表名后的字段列表。因此,我们也可以使用以下插入语句:
INSERT INTO dept VALUES ( 20, 'Marketing'); select * from dept; department_id|department_name| -------------|---------------| 10|Administration | 20|Marketing |
指定字段的值也可以使用 DEFAULT,表示使用定义字段时的默认值;如果没有指定默认值使用 NULL 值。
插入多行数据
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; employee_id|first_name|last_name|hire_date |salary |manager_id|department_id| -----------|----------|---------|----------|--------|----------|-------------| 200|Jennifer |Whalen |2020-01-01| 4400.00| | 10| 201|Michael |Hartstein|2020-02-02|13000.00| | 20| 202|Pat |Fay |2020-04-14| 6000.00| 201| 20|
以上语句一次增加了 3 名员工信息,日期可以使用字符形式的字面值(‘2020-01-01’),default 表示使用默认的当前日期。
复制数据
INSERT INTO SELECT语句可以将一个查询语句的结果插入表中。例如:
create table emp1 (like emp); insert into emp1 select * from emp where department_id = 20; select * from emp1; employee_id|first_name|last_name|hire_date |salary |manager_id|department_id| -----------|----------|---------|----------|--------|----------|-------------| 201|Michael |Hartstein|2020-02-02|13000.00| | 20| 202|Pat |Fay |2020-04-14| 6000.00| 201| 20|
我们首先基于 emp 创建了一个新表 emp1,然后通过查询语句将 emp 中的部分数据复制到 emp1 中。
返回插入的数据
PostgreSQL 对 SQL进行了扩展,可以在
INSERT语句之后使用
RETURNING返回插入的数据值。例如:
insert into dept values (30, 'Purchasing') returning department_id; department_id| -------------| 30|
以上语句除了插入一条数据到 dept 表中,同时还返回了该数据的 department_id。
更新数据
单表更新
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;
跨表更新
除了以上形式的更新语句之外,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)。
返回更新后的数据
PostgreSQL 同样对
UPDATE语句进行了扩展,支持使用
RETURNING返回更新后的数据值。例如:
update emp set salary = salary + 1000, department_id = 20 where employee_id = 200 returning first_name, last_name, salary; first_name|last_name|salary | ----------|---------|-------| Jennifer |Whalen |6400.00|
我们再次更新编号为 200 的员工的信息,并且返回了更新之后的记录。
删除数据
删除数据可以使用
DELETE语句:
DELETE FROM table_name WHERE conditions;
同样,只有满足
WHERE条件的数据才会被删除;如果省略,将会删除表中所有的数据。
单表删除
以下语句用于删除 emp1 中员工编号为 201 的数据:
delete from emp1 where employee_id = 201;
如果没有编号为 201 的数据,不会删除任何数据。
跨表删除
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);
返回被删除的数据
PostgreSQL 中的
DELETE语句也可以使用
RETURNING返回被删除的数据。例如:
-- 先插入一些数据 insert into emp1 select * from emp where department_id = 20; delete from emp1 returning *; employee_id|first_name|last_name|hire_date |salary |manager_id|department_id| -----------|----------|---------|----------|--------|----------|-------------| 201|Michael |Hartstein|2020-02-02|13000.00| | 20| 202|Pat |Fay |2020-04-14| 6000.00| 201| 20| 200|Jennifer |Whalen |2020-01-01| 6400.00| | 20|
我们先从 emp 复制了一些数据到 emp1 中,然后删除所有数据并且返回这些记录。
合并数据
在 SQL 标准中还定义了一个合并数据的语句:
MERGE。PostgreSQL 没有实现该语句,但是可以通过
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) SQL Error [23505]: ERROR: duplicate key value violates unique constraint "emp_pkey" 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; department_id| -------------| 20| 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; employee_id|first_name|last_name|hire_date |salary |manager_id|department_id| -----------|----------|---------|----------|-------|----------|-------------| 200|Jennifer |Whalen |2020-01-01|4400.00| | 10|
该员工的部门编号在前面被修改为 20;我们通过主键约束 emp_pkey 进行重复数据的判断,然后更新该员工的数据;EXCLUDED 是一个特殊的表,代表了原本应该插入的数据行;最终该员工的部门编号被更新为 10。
欢迎点赞👍、评论📝、收藏❤️!
查看专栏详情 立即解锁全部专栏- 点赞
- 收藏
- 分享
- 文章举报
- 《PostgreSQL 开发指南》 第 19 篇 集合操作
- 《PostgreSQL 开发指南》 第 18 篇 子查询
- 《PostgreSQL 开发指南》 第 20 篇 通用表表达式
- iOS开发中使用SQL语句操作数据库的基本用法指南
- 《PostgreSQL 开发指南》 第 17 篇 常用函数(二)
- Oracle学习笔记之第八节sql语句(开发课学生指南051)
- 《深入浅出mysql数据库开发、优化与管理维护》sql基础(DDL、DML、DCL语句)
- 《PostgreSQL 开发指南》 第 21 篇 窗口函数
- Android 开发工程师面试指南
- Knockout应用开发指南 第八章:简单应用举例(2)
- Windows Mobile开发环境搭建指南
- POSTGRESQL 存储过程 select into 和 insert into select 两种表复制语句之间的差别
- Quartz.net官方开发指南 第四课:关于Triggers更多内容
- JBPM开发入门指南(1)
- Quartz.net官方开发指南 第十一课: 高级(企业级)属性
- flutter系列集合之App项目集成flutter混合开发详细指南大神必学
- Postgresql中SQL语句用法
- 一步一步教你使用AgileEAS.NET基础类库进行应用开发-基础篇-使用UDA操纵SQL语句
- ios开发之Swift学习指南(一)
- Mesos Framework开发指南 一