1. 首页 > PostgreSQL教程 > 正文

PostgreSQL教程FG029-PG数据操作语言(DML):INSERT/UPDATE/DELETE高级用法

目录大纲

Part01-基础概念与理论知识

1.1 DML语句的概念与特点

数据操作语言(DML)是用于操作数据库中数据的SQL语句,主要包括INSERT、UPDATE和DELETE。DML语句的主要特点包括:

  • 修改数据:直接操作表中的数据
  • 事务性:操作可以回滚
  • 性能影响:可能影响数据库性能
  • 锁定:可能会锁定数据行或表

学习交流加群风哥微信: itpux-com

1.2 高级DML操作的应用场景

高级DML操作适合以下场景:

  • 批量数据处理:需要一次性处理大量数据
  • 复杂数据迁移:需要从一个表迁移数据到另一个表
  • 数据同步:需要保持不同表之间的数据同步
  • 数据转换:需要在插入或更新时进行数据转换
  • 条件更新:需要根据复杂条件更新数据

更多视频教程www.fgedu.net.cn

Part02-生产环境规划与建议

2.1 INSERT高级操作的规划与建议

INSERT高级操作规划建议:

  • 批量插入:使用COPY命令或批量INSERT语句提高性能
  • 数据验证:在插入前进行数据验证,确保数据质量
  • 错误处理:使用ON CONFLICT子句处理冲突
  • 性能考虑:避免在插入时触发过多触发器
  • 事务管理:对于大量插入,合理设置事务大小

风哥提示:批量插入时,建议使用COPY命令,它比INSERT语句快得多。

2.2 UPDATE与DELETE高级操作的注意事项

UPDATE与DELETE高级操作注意事项:

  • 条件检查:确保WHERE子句正确,避免误操作
  • 性能影响:大表的UPDATE/DELETE可能会影响性能
  • 锁定问题:可能会导致长时间锁定,影响并发
  • 事务日志:会生成大量WAL日志,需要考虑空间
  • 回滚考虑:大操作可能需要大量回滚空间

建议:

  • 分批处理:将大操作分成多个小批次
  • 使用索引:确保WHERE子句中的列有索引
  • 监控执行:监控长时间运行的UPDATE/DELETE操作
  • 备份:在执行大操作前进行备份

更多学习教程公众号风哥教程itpux_com

Part03-生产环境项目实施方案

3.1 INSERT高级用法

3.1.1 批量插入

— 批量插入多条数据
INSERT INTO fgedu_users (name, email) VALUES
(‘张三’, ‘zhangsan@fgedu.net.cn’),
(‘李四’, ‘lisi@fgedu.net.cn’),
(‘王五’, ‘wangwu@fgedu.net.cn’),
(‘赵六’, ‘zhaoliu@fgedu.net.cn’),
(‘钱七’, ‘qianqi@fgedu.net.cn’);

— 从另一个表插入数据
INSERT INTO fgedu_users_archive (id, name, email, created_at)
SELECT id, name, email, NOW()
FROM fgedu_users
WHERE created_at < '2026-01-01'; -- 使用DEFAULT VALUES插入默认值 INSERT INTO fgedu_logs DEFAULT VALUES;

3.1.2 INSERT ON CONFLICT(UPSERT)

— 创建带有唯一约束的表
CREATE TABLE fgedu_products (
id SERIAL PRIMARY KEY,
product_code VARCHAR(50) UNIQUE,
name VARCHAR(100),
price DECIMAL(10, 2)
);

— 插入数据,冲突时更新
INSERT INTO fgedu_products (product_code, name, price)
VALUES (‘P001’, ‘手机’, 5999.00)
ON CONFLICT (product_code) DO UPDATE
SET name = EXCLUDED.name,
price = EXCLUDED.price;

— 插入多条数据,冲突时忽略
INSERT INTO fgedu_products (product_code, name, price)
VALUES
(‘P001’, ‘智能手机’, 6999.00),
(‘P002’, ‘电脑’, 9999.00),
(‘P003’, ‘平板’, 3999.00)
ON CONFLICT (product_code) DO NOTHING;

from PostgreSQL视频:www.itpux.com

3.1.3 INSERT RETURNING

— 插入数据并返回插入的行
INSERT INTO fgedu_users (name, email)
VALUES (‘孙八’, ‘sunba@fgedu.net.cn’)
RETURNING id, name, email;

— 插入多条数据并返回
INSERT INTO fgedu_products (product_code, name, price)
VALUES
(‘P004’, ‘耳机’, 999.00),
(‘P005’, ‘键盘’, 1999.00)
RETURNING id, product_code, name;

3.2 UPDATE高级用法

3.2.1 条件更新

— 基于条件更新
UPDATE fgedu_products
SET price = price * 1.1
WHERE category = ‘电子产品’ AND price < 5000; -- 使用子查询更新 UPDATE fgedu_customers c SET total_orders = ( SELECT COUNT(*) FROM fgedu_orders o WHERE o.customer_id = c.id ); -- 多表关联更新 UPDATE fgedu_orders o SET status = 'completed' FROM fgedu_payments p WHERE o.id = p.order_id AND p.payment_date IS NOT NULL;

3.2.2 UPDATE RETURNING

— 更新数据并返回更新后的行
UPDATE fgedu_products
SET price = price * 0.9
WHERE product_code = ‘P001’
RETURNING id, product_code, name, price;

— 批量更新并返回
UPDATE fgedu_users
SET last_login = NOW()
WHERE last_login < '2026-01-01' RETURNING id, name, last_login;

学习交流加群风哥QQ113257174

3.2.3 复杂更新操作

— 使用CASE语句进行条件更新
UPDATE fgedu_employees
SET salary = CASE
WHEN department = ‘技术部’ THEN salary * 1.15
WHEN department = ‘市场部’ THEN salary * 1.10
ELSE salary * 1.05
END;

— 使用窗口函数进行更新
WITH ranked_employees AS (
SELECT
id,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank
FROM fgedu_employees
)
UPDATE fgedu_employees e
SET is_top_performer = (r.rank = 1)
FROM ranked_employees r
WHERE e.id = r.id;

3.3 DELETE高级用法

3.3.1 条件删除

— 基于条件删除
DELETE FROM fgedu_logs
WHERE log_date < '2026-01-01'; -- 使用子查询删除 DELETE FROM fgedu_orders WHERE id IN ( SELECT order_id FROM fgedu_order_items WHERE quantity = 0 ); -- 多表关联删除 DELETE FROM fgedu_order_items oi USING fgedu_orders o WHERE oi.order_id = o.id AND o.status = 'cancelled';

3.3.2 DELETE RETURNING

— 删除数据并返回删除的行
DELETE FROM fgedu_users
WHERE last_login < '2025-01-01' RETURNING id, name, email, last_login; -- 删除特定条件的数据并返回 DELETE FROM fgedu_products WHERE price < 100 RETURNING id, product_code, name, price;

from PostgreSQL视频:www.itpux.com

3.3.3 批量删除策略

— 分批删除(避免长时间锁定)
DO $$
DECLARE
batch_size INT := 1000;
deleted_rows INT := 1;
BEGIN
WHILE deleted_rows > 0 LOOP
DELETE FROM fgedu_old_logs
WHERE log_date < '2026-01-01' LIMIT batch_size; GET DIAGNOSTICS deleted_rows = ROW_COUNT; -- 暂停一下,避免系统负载过高 PERFORM pg_sleep(0.1); END LOOP; END; $$ LANGUAGE plpgsql;

Part04-生产案例与实战讲解

4.1 INSERT实战案例

4.1.1 数据迁移

— 创建源表
CREATE TABLE fgedu_old_customers (
customer_id INTEGER,
customer_name VARCHAR(100),
customer_email VARCHAR(100),
create_date DATE
);

— 插入测试数据
INSERT INTO fgedu_old_customers (customer_id, customer_name, customer_email, create_date) VALUES
(1, ‘张三’, ‘zhangsan@fgedu.net.cn’, ‘2024-01-01’),
(2, ‘李四’, ‘lisi@fgedu.net.cn’, ‘2024-02-01’),
(3, ‘王五’, ‘wangwu@fgedu.net.cn’, ‘2024-03-01’);

— 创建目标表
CREATE TABLE fgedu_new_customers (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE,
created_at TIMESTAMP DEFAULT NOW(),
status VARCHAR(20) DEFAULT ‘active’
);

— 迁移数据(带数据转换)
INSERT INTO fgedu_new_customers (name, email, created_at)
SELECT
customer_name,
LOWER(customer_email), — 转换为小写
create_date::TIMESTAMP
FROM fgedu_old_customers
WHERE customer_email IS NOT NULL;

— 查询迁移结果
SELECT * FROM fgedu_new_customers;

4.1.2 批量数据导入

— 创建表
CREATE TABLE fgedu_sales_data (
id SERIAL PRIMARY KEY,
sale_date DATE NOT NULL,
product_id INTEGER,
quantity INTEGER,
unit_price DECIMAL(10, 2),
total_amount DECIMAL(10, 2)
);

— 方法1:使用COPY命令(最快)
— COPY fgedu_sales_data (sale_date, product_id, quantity, unit_price, total_amount)
— FROM ‘/path/to/sales_data.csv’ DELIMITER ‘,’ CSV HEADER;

— 方法2:使用批量INSERT
INSERT INTO fgedu_sales_data (sale_date, product_id, quantity, unit_price, total_amount)
VALUES
(‘2026-04-01’, 1, 10, 100.00, 1000.00),
(‘2026-04-01’, 2, 5, 200.00, 1000.00),
(‘2026-04-02’, 1, 15, 100.00, 1500.00),
(‘2026-04-02’, 3, 8, 150.00, 1200.00),
(‘2026-04-03’, 2, 12, 200.00, 2400.00),
(‘2026-04-03’, 4, 3, 500.00, 1500.00),
(‘2026-04-04’, 1, 20, 100.00, 2000.00),
(‘2026-04-04’, 3, 10, 150.00, 1500.00);

— 查询导入结果
SELECT * FROM fgedu_sales_data;

风哥提示:对于大量数据导入,COPY命令是最高效的方式。

4.2 UPDATE实战案例

4.2.1 库存更新

— 创建产品表
CREATE TABLE fgedu_inventory (
product_id INTEGER PRIMARY KEY,
product_name VARCHAR(100),
current_stock INTEGER,
reorder_level INTEGER
);

— 插入测试数据
INSERT INTO fgedu_inventory (product_id, product_name, current_stock, reorder_level) VALUES
(1, ‘手机’, 50, 20),
(2, ‘电脑’, 30, 10),
(3, ‘平板’, 40, 15),
(4, ‘耳机’, 100, 30);

— 创建订单表
CREATE TABLE fgedu_sales_orders (
order_id SERIAL PRIMARY KEY,
product_id INTEGER,
quantity INTEGER,
order_date DATE
);

— 插入订单数据
INSERT INTO fgedu_sales_orders (product_id, quantity, order_date) VALUES
(1, 5, ‘2026-04-01’),
(2, 3, ‘2026-04-01’),
(3, 10, ‘2026-04-02’);

— 更新库存
UPDATE fgedu_inventory i
SET current_stock = i.current_stock – (
SELECT COALESCE(SUM(quantity), 0)
FROM fgedu_sales_orders o
WHERE o.product_id = i.product_id AND o.order_date = ‘2026-04-01’
)
WHERE i.product_id IN (
SELECT DISTINCT product_id
FROM fgedu_sales_orders
WHERE order_date = ‘2026-04-01’
);

— 查询更新后的库存
SELECT * FROM fgedu_inventory;

4.2.2 状态批量更新

— 创建订单表
CREATE TABLE fgedu_customer_orders (
id SERIAL PRIMARY KEY,
customer_id INTEGER,
order_date DATE,
total_amount DECIMAL(10, 2),
status VARCHAR(20) DEFAULT ‘pending’,
payment_date DATE
);

— 插入测试数据
INSERT INTO fgedu_customer_orders (customer_id, order_date, total_amount, status, payment_date) VALUES
(1, ‘2026-04-01’, 1000.00, ‘pending’, ‘2026-04-01’),
(2, ‘2026-04-01’, 2000.00, ‘pending’, NULL),
(3, ‘2026-04-02’, 1500.00, ‘pending’, ‘2026-04-02’),
(4, ‘2026-04-02’, 3000.00, ‘pending’, NULL);

— 批量更新已付款订单的状态
UPDATE fgedu_customer_orders
SET status = ‘paid’
WHERE payment_date IS NOT NULL AND status = ‘pending’;

— 查询更新结果
SELECT * FROM fgedu_customer_orders;

更多视频教程www.fgedu.net.cn

4.3 DELETE实战案例

4.3.1 清理过期数据

— 创建日志表
CREATE TABLE fgedu_application_logs (
id SERIAL PRIMARY KEY,
log_time TIMESTAMP DEFAULT NOW(),
log_level VARCHAR(20),
message TEXT
);

— 插入测试数据
INSERT INTO fgedu_application_logs (log_time, log_level, message) VALUES
(NOW() – INTERVAL ’30 days’, ‘INFO’, ‘Application started’),
(NOW() – INTERVAL ’25 days’, ‘ERROR’, ‘Database connection failed’),
(NOW() – INTERVAL ’20 days’, ‘INFO’, ‘User logged in’),
(NOW() – INTERVAL ’15 days’, ‘WARNING’, ‘Disk space low’),
(NOW() – INTERVAL ’10 days’, ‘INFO’, ‘Backup completed’),
(NOW() – INTERVAL ‘5 days’, ‘ERROR’, ‘API request failed’),
(NOW(), ‘INFO’, ‘System status check’);

— 清理30天前的日志
DELETE FROM fgedu_application_logs
WHERE log_time < NOW() - INTERVAL '30 days'; -- 清理非错误日志(保留错误日志) DELETE FROM fgedu_application_logs WHERE log_level != 'ERROR' AND log_time < NOW() - INTERVAL '15 days'; -- 查询清理结果 SELECT * FROM fgedu_application_logs ORDER BY log_time DESC;

4.3.2 级联删除

— 创建部门表
CREATE TABLE fgedu_departments (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL
);

— 创建员工表(带外键)
CREATE TABLE fgedu_dept_employees (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
department_id INTEGER REFERENCES fgedu_departments(id) ON DELETE CASCADE
);

— 插入测试数据
INSERT INTO fgedu_departments (name) VALUES
(‘技术部’),
(‘市场部’),
(‘财务部’);

INSERT INTO fgedu_dept_employees (name, department_id) VALUES
(‘张三’, 1),
(‘李四’, 1),
(‘王五’, 2),
(‘赵六’, 3);

— 删除部门(会级联删除相关员工)
DELETE FROM fgedu_departments WHERE id = 1;

— 查询结果
SELECT * FROM fgedu_departments;
SELECT * FROM fgedu_dept_employees;

学习交流加群风哥微信: itpux-com

Part05-风哥经验总结与分享

5.1 DML操作的性能优化

5.1.1 INSERT操作优化

  • 使用批量插入:减少SQL语句的执行次数
  • 使用COPY命令:对于大量数据导入,COPY命令比INSERT快得多
  • 禁用触发器:在批量插入时暂时禁用触发器
  • 合理设置事务:批量操作时使用适当大小的事务
  • 使用UNLOGGED表:对于临时数据,可以使用UNLOGGED表提高性能

5.1.2 UPDATE操作优化

  • 使用索引:确保WHERE子句中的列有索引
  • 分批更新:将大更新操作分成多个小批次
  • 避免全表更新:尽量使用WHERE子句限制更新范围
  • 使用部分索引:对于特定条件的更新,使用部分索引
  • 监控执行计划:使用EXPLAIN分析更新操作的执行计划

5.1.3 DELETE操作优化

  • 使用索引:确保WHERE子句中的列有索引
  • 分批删除:避免长时间锁定表
  • 使用TRUNCATE:对于清空整个表,TRUNCATE比DELETE快
  • 考虑分区表:对于时间序列数据,使用分区表可以快速删除整个分区
  • 监控空间使用:删除数据后,考虑运行VACUUM回收空间

更多学习教程公众号风哥教程itpux_com

5.2 常见问题与解决方案

5.2.1 INSERT常见问题

问题 解决方案
唯一约束冲突 使用ON CONFLICT子句处理冲突
插入性能慢 使用批量插入或COPY命令
内存不足 减少批量大小,增加内存配置

5.2.2 UPDATE常见问题

问题 解决方案
更新锁定超时 分批更新,使用行级锁
更新性能慢 添加索引,优化WHERE子句
更新后数据不一致 使用事务确保原子性

5.2.3 DELETE常见问题

问题 解决方案
删除速度慢 分批删除,使用索引
删除后空间不释放 运行VACUUM FULL或VACUUM ANALYZE
级联删除导致性能问题 考虑使用触发器或应用层处理

5.2.4 最佳实践总结

  • 根据数据量选择合适的DML操作方式
  • 使用索引提高查询和更新性能
  • 合理使用事务,确保数据一致性
  • 监控DML操作的执行情况
  • 定期维护数据库,包括VACUUM和ANALYZE

from PostgreSQL视频:www.itpux.com

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息