前置知识: SQL

PostgreSQL DML 数据操作

2 min入门

PostgreSQL DML 数据操作 的完整教学讲解。

INSERT 插入

单行写法:插入单行 INSERT INTO <表名> (<列1>, <列2>) VALUES (<值1>, <值2>);

-- 插入一条用户记录
INSERT INTO users (username, email, age) VALUES ('zhangsan', 'zs@example.com', 25);

换行写法:插入多行 INSERT INTO <表名> (<列>) VALUES (<值1>), (<值2>), (<值3>);

-- 批量插入多行
INSERT INTO users (username, email) VALUES
  ('user1', 'u1@example.com'),
  ('user2', 'u2@example.com'),
  ('user3', 'u3@example.com');

单行写法:插入查询结果 INSERT INTO <目标表> SELECT * FROM <源表> [WHERE <条件>];

-- 将活跃用户插入备份表
INSERT INTO active_users_backup SELECT * FROM users WHERE status = 1;

换行写法:ON CONFLICT 冲突处理(upsert) INSERT INTO <表名> (<列>) VALUES (<值>) ON CONFLICT (<列>) DO UPDATE SET <列>=<值>;

-- 冲突时更新
INSERT INTO users (id, username, email) VALUES (1, 'zhangsan', 'new@example.com')
ON CONFLICT (id) DO UPDATE SET email = EXCLUDED.email, updated_at = NOW();

单行写法:冲突时什么都不做 INSERT INTO <表名> (<列>) VALUES (<值>) ON CONFLICT (<列>) DO NOTHING;

-- 冲突时忽略
INSERT INTO users (id, username) VALUES (1, 'zhangsan') ON CONFLICT (id) DO NOTHING;

换行写法:RETURNING 返回数据 INSERT INTO <表名> (<列>) VALUES (<值>) RETURNING <列>;

-- 插入并返回自增ID
INSERT INTO users (username, email) VALUES ('zhangsan', 'zs@example.com')
RETURNING id, username;

换行写法:RETURNING 返回所有列 INSERT INTO <表名> (<列>) VALUES (<值>) RETURNING *;

-- 插入并返回所有列
INSERT INTO users (username, email) VALUES ('zhangsan', 'zs@example.com')
RETURNING *;

UPDATE 更新

单行写法:更新单列 UPDATE <表名> SET <列>=<值> WHERE <条件>;

-- 更新指定用户年龄
UPDATE users SET age = 26 WHERE id = 1;

单行写法:更新多列 UPDATE <表名> SET <列1>=<值1>, <列2>=<值2> WHERE <条件>;

-- 同时更新多个字段
UPDATE users SET age = 26, status = 2 WHERE id = 1;

单行写法:基于表达式更新 UPDATE <表名> SET <列>=<表达式> WHERE <条件>;

-- 所有用户余额增加 10%
UPDATE users SET balance = balance * 1.10 WHERE status = 1;

换行写法:基于 FROM 关联更新 UPDATE <表1> SET <列>=<值> FROM <表2> WHERE <连接条件>;

-- 关联订单汇总表更新用户余额
UPDATE users SET balance = balance - o.total
FROM (SELECT user_id, SUM(total_amount) AS total FROM orders GROUP BY user_id) o
WHERE users.id = o.user_id;

换行写法:RETURNING 返回更新后数据 UPDATE <表名> SET <列>=<值> WHERE <条件> RETURNING <列>;

-- 更新并返回更新后的数据
UPDATE users SET status = 0 WHERE last_login < '2024-01-01'
RETURNING id, username, status;

换行写法:使用 CASE 条件更新 UPDATE <表名> SET <列> = CASE WHEN <条件> THEN <值> ELSE <默认> END WHERE <条件>;

-- 根据不同状态批量更新
UPDATE users SET status = CASE
  WHEN age < 18 THEN 1
  WHEN age >= 60 THEN 3
  ELSE 2
END WHERE age IS NOT NULL;

DELETE 删除

单行写法:按条件删除 DELETE FROM <表名> WHERE <条件>;

-- 删除指定用户
DELETE FROM users WHERE id = 1;

换行写法:基于 USING 关联删除 DELETE FROM <表1> USING <表2> WHERE <连接条件>;

-- 删除没有订单的用户
DELETE FROM users
USING orders
WHERE users.id = orders.user_id;

换行写法:基于子查询删除 DELETE FROM <表名> WHERE <列> IN (SELECT <列> FROM <表名> WHERE <条件>);

-- 删除符合条件的关联数据
DELETE FROM orders WHERE user_id IN (SELECT id FROM users WHERE status = 0);

换行写法:RETURNING 返回删除数据 DELETE FROM <表名> WHERE <条件> RETURNING <列>;

-- 删除并返回被删除的记录
DELETE FROM users WHERE status = 0 RETURNING id, username;

单行写法:删除所有数据 DELETE FROM <表名>;

-- 删除全表数据
DELETE FROM logs;

UPSERT 操作

换行写法:基于主键冲突更新 INSERT INTO <表> (<列>) VALUES (<值>) ON CONFLICT ON CONSTRAINT <约束名> DO UPDATE SET <列>=EXCLUDED.<列>;

-- 基于约束名冲突更新
INSERT INTO users (id, username) VALUES (1, 'newname')
ON CONFLICT ON CONSTRAINT users_pkey DO UPDATE SET username = EXCLUDED.username;

换行写法:基于多列冲突更新 INSERT INTO <表> (<列>) VALUES (<值>) ON CONFLICT (<列1>, <列2>) DO UPDATE SET <列>=<值>;

-- 复合唯一键冲突时更新
INSERT INTO order_items (order_id, product_id, quantity)
VALUES (1, 100, 5)
ON CONFLICT (order_id, product_id) DO UPDATE SET quantity = order_items.quantity + EXCLUDED.quantity;

MERGE 命令(PG15+)

换行写法:MERGE 条件合并 MERGE INTO <目标表> USING <源> ON <条件> WHEN MATCHED THEN UPDATE SET ... WHEN NOT MATCHED THEN INSERT ...;

-- 条件插入或更新
MERGE INTO users AS target
USING (SELECT 1 AS id, 'zhangsan' AS username, 'zs@example.com' AS email) AS source
ON target.id = source.id
WHEN MATCHED THEN UPDATE SET email = source.email
WHEN NOT MATCHED THEN INSERT (id, username, email) VALUES (source.id, source.username, source.email);

换行写法:MERGE 带删除(PG17+) MERGE INTO <目标表> USING <源> ON <条件> WHEN MATCHED AND <条件> THEN DELETE;

-- 匹配且满足条件时删除
MERGE INTO users AS t USING inactive_users AS s ON t.id = s.id
WHEN MATCHED AND t.status = 0 THEN DELETE;

事务控制

单行写法:开启事务 BEGIN; 或 START TRANSACTION;

-- 开启事务
BEGIN;

换行写法:提交事务 COMMIT;

-- 提交事务
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
COMMIT;

单行写法:回滚事务 ROLLBACK;

-- 回滚事务
ROLLBACK;

单行写法:设置保存点 SAVEPOINT <保存点名>;

-- 设置保存点
SAVEPOINT sp1;

单行写法:回滚到保存点 ROLLBACK TO <保存点名>;

-- 回滚到指定保存点
ROLLBACK TO sp1;

单行写法:查看隔离级别 SHOW transaction_isolation;

-- 查看当前事务隔离级别
SHOW transaction_isolation;

单行写法:设置隔离级别 SET TRANSACTION ISOLATION LEVEL <级别>;

-- 设置事务隔离级别为可重复读
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;