数据操作语言
本章将详细介绍PostgreSQL中的数据操作语言(DML),包括INSERT、UPDATE、DELETE语句的使用方法和最佳实践。
5.1 INSERT语句
基本插入
使用INSERT语句向表中插入数据:
-- 插入单行数据
INSERT INTO users (username, email, first_name, last_name)
VALUES ('john_doe', 'john@example.com', 'John', 'Doe');
-- 插入多行数据
INSERT INTO users (username, email, first_name, last_name)
VALUES
('jane_smith', 'jane@example.com', 'Jane', 'Smith'),
('bob_wilson', 'bob@example.com', 'Bob', 'Wilson'),
('alice_brown', 'alice@example.com', 'Alice', 'Brown');
插入默认值
-- 插入默认值
INSERT INTO users (username, email)
VALUES ('test_user', 'test@example.com');
-- 显式指定默认值
INSERT INTO users (username, email, created_at)
VALUES ('test_user2', 'test2@example.com', DEFAULT);
从查询结果插入
-- 从另一个表插入数据
INSERT INTO archived_users (username, email, created_at)
SELECT username, email, created_at
FROM users
WHERE created_at < '2023-01-01';
-- 插入查询结果并添加常量值
INSERT INTO user_statistics (user_id, login_count, last_login_date)
SELECT id, 0, CURRENT_DATE
FROM users
WHERE is_active = true;
使用RETURNING子句
-- 插入数据并返回生成的ID
INSERT INTO users (username, email, first_name, last_name)
VALUES ('new_user', 'new@example.com', 'New', 'User')
RETURNING id, username;
-- 插入数据并返回所有字段
INSERT INTO products (name, price, category_id)
VALUES ('新产品', 99.99, 1)
RETURNING *;
5.2 UPDATE语句
基本更新
使用UPDATE语句修改表中的数据:
-- 更新单个字段
UPDATE users
SET email = 'newemail@example.com'
WHERE id = 1;
-- 更新多个字段
UPDATE users
SET
email = 'updated@example.com',
updated_at = CURRENT_TIMESTAMP
WHERE username = 'john_doe';
-- 更新所有记录(谨慎使用)
UPDATE users
SET is_active = true;
条件更新
-- 使用复杂条件更新
UPDATE products
SET price = price * 1.1
WHERE category_id = 1 AND price < 100;
-- 使用子查询更新
UPDATE users
SET last_login_date = CURRENT_TIMESTAMP
WHERE id IN (SELECT user_id FROM login_logs WHERE login_date = CURRENT_DATE);
使用RETURNING子句
-- 更新数据并返回结果
UPDATE users
SET email = 'updated@example.com'
WHERE id = 1
RETURNING id, username, email;
5.3 DELETE语句
基本删除
使用DELETE语句从表中删除数据:
-- 删除单条记录
DELETE FROM users WHERE id = 1;
-- 删除多条记录
DELETE FROM users WHERE created_at < '2023-01-01';
-- 删除所有记录(谨慎使用)
DELETE FROM temp_data;
条件删除
-- 使用复杂条件删除
DELETE FROM orders
WHERE status = 'cancelled'
AND created_at < CURRENT_DATE - INTERVAL '30 days';
-- 使用子查询删除
DELETE FROM users
WHERE id IN (
SELECT user_id
FROM user_sessions
WHERE last_activity < CURRENT_DATE - INTERVAL '1 year'
);
使用RETURNING子句
-- 删除数据并返回结果
DELETE FROM users
WHERE id = 1
RETURNING id, username, email;
截断表
-- 快速删除表中所有数据(比DELETE更快)
TRUNCATE TABLE temp_data;
-- 截断多个表
TRUNCATE TABLE temp_data, log_data;
-- 重启标识序列
TRUNCATE TABLE users RESTART IDENTITY;
5.4 批量操作
批量插入优化
-- 使用COPY命令进行大批量数据导入(更快)
COPY users(username, email, first_name, last_name)
FROM '/path/to/users.csv'
DELIMITER ','
CSV HEADER;
-- 使用批量插入
INSERT INTO users (username, email, first_name, last_name)
VALUES
('user1', 'user1@example.com', 'User', 'One'),
('user2', 'user2@example.com', 'User', 'Two'),
('user3', 'user3@example.com', 'User', 'Three'),
-- ... 更多数据
('user1000', 'user1000@example.com', 'User', 'Thousand');
批量更新优化
-- 使用CASE语句进行批量更新
UPDATE products
SET price = CASE
WHEN category_id = 1 THEN price * 1.1
WHEN category_id = 2 THEN price * 1.05
ELSE price
END
WHERE category_id IN (1, 2);
-- 使用临时表进行批量更新
UPDATE users
SET email = temp_users.new_email
FROM temp_users
WHERE users.id = temp_users.user_id;
5.5 事务处理
基本事务
-- 开始事务
BEGIN;
-- 执行多个操作
INSERT INTO users (username, email) VALUES ('new_user', 'new@example.com');
INSERT INTO user_profiles (user_id, bio) VALUES (currval('users_id_seq'), 'New user bio');
UPDATE user_statistics SET user_count = user_count + 1;
-- 提交事务
COMMIT;
-- 或者回滚事务
-- ROLLBACK;
保存点
BEGIN;
INSERT INTO users (username, email) VALUES ('user1', 'user1@example.com');
-- 设置保存点
SAVEPOINT sp1;
INSERT INTO user_profiles (user_id, bio) VALUES (currval('users_id_seq'), 'User bio');
-- 回滚到保存点
ROLLBACK TO sp1;
-- 继续其他操作
INSERT INTO user_statistics (user_count) VALUES (1);
COMMIT;
5.6 数据导入导出
导出数据
-- 导出表数据到CSV文件
COPY users TO '/path/to/users_export.csv'
DELIMITER ','
CSV HEADER;
-- 导出查询结果
COPY (
SELECT username, email, created_at
FROM users
WHERE is_active = true
) TO '/path/to/active_users.csv'
DELIMITER ','
CSV HEADER;
导入数据
-- 从CSV文件导入数据
COPY users(username, email, first_name, last_name)
FROM '/path/to/users_import.csv'
DELIMITER ','
CSV HEADER;
5.7 最佳实践
性能优化
- 批量操作:尽可能使用批量插入而不是逐条插入
- 索引考虑:在执行大量UPDATE/DELETE操作前考虑临时禁用索引
- 事务控制:合理使用事务,避免长时间持有锁
- WHERE子句:确保UPDATE/DELETE语句包含有效的WHERE条件
安全性
- SQL注入防护:使用参数化查询而不是字符串拼接
- 权限控制:为不同用户分配最小必要权限
- 数据备份:在执行重要数据操作前进行备份
实际应用示例
-- 电商订单处理示例
BEGIN;
-- 创建新订单
INSERT INTO orders (user_id, total_amount, status)
VALUES (1, 299.99, 'pending')
RETURNING id INTO order_id;
-- 添加订单项
INSERT INTO order_items (order_id, product_id, quantity, price)
VALUES
(order_id, 1, 1, 199.99),
(order_id, 2, 2, 50.00);
-- 更新产品库存
UPDATE products
SET stock_quantity = stock_quantity - 1
WHERE id = 1;
UPDATE products
SET stock_quantity = stock_quantity - 2
WHERE id = 2;
-- 更新用户统计
UPDATE user_statistics
SET total_orders = total_orders + 1,
total_spent = total_spent + 299.99
WHERE user_id = 1;
COMMIT;
提示:在执行数据操作时,特别是在生产环境中,务必先在测试环境中验证SQL语句的正确性和性能影响。