SQLite数据插入 #
一、INSERT语句概述 #
1.1 基本语法 #
sql
-- INSERT 基本语法
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);
-- 示例表结构
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE,
age INTEGER,
status INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
1.2 插入方式 #
sql
-- SQLite 支持多种插入方式:
-- 1. 指定列插入
-- 2. 全列插入
-- 3. 批量插入
-- 4. 查询插入
-- 5. 默认值插入
二、基本插入 #
2.1 指定列插入 #
sql
-- 指定列名插入
INSERT INTO users (name, email, age)
VALUES ('John', 'john@example.com', 25);
-- 查看结果
SELECT * FROM users;
-- id | name | email | age | status | created_at
-- ---|------|--------------------|-----|--------|------------------
-- 1 | John | john@example.com | 25 | 1 | 2024-01-15 10:00:00
2.2 全列插入 #
sql
-- 插入所有列(按表定义顺序)
INSERT INTO users
VALUES (NULL, 'Jane', 'jane@example.com', 30, 1, CURRENT_TIMESTAMP);
-- AUTOINCREMENT 列使用 NULL
INSERT INTO users
VALUES (NULL, 'Bob', 'bob@example.com', 28, 1, datetime('now'));
2.3 使用DEFAULT关键字 #
sql
-- 使用默认值
INSERT INTO users (name, email, age, status)
VALUES ('Alice', 'alice@example.com', 22, DEFAULT);
-- 省略有默认值的列
INSERT INTO users (name, email, age)
VALUES ('Charlie', 'charlie@example.com', 35);
2.4 使用表达式 #
sql
-- 使用表达式
INSERT INTO users (name, email, age, created_at)
VALUES (
'David',
lower('DAVID@EXAMPLE.COM'),
20 + 5,
datetime('now', '+1 day')
);
-- 使用子查询
INSERT INTO users (name, email, age)
SELECT 'Eve', 'eve@example.com', AVG(age) FROM users;
三、批量插入 #
3.1 多行VALUES #
sql
-- 一次插入多行
INSERT INTO users (name, email, age) VALUES
('User1', 'user1@example.com', 20),
('User2', 'user2@example.com', 25),
('User3', 'user3@example.com', 30),
('User4', 'user4@example.com', 35);
-- 性能优势:
-- 1. 减少SQL解析次数
-- 2. 减少事务开销
-- 3. 批量写入优化
3.2 批量插入优化 #
sql
-- 大批量插入优化技巧
-- 1. 使用事务
BEGIN TRANSACTION;
INSERT INTO users (name, email, age) VALUES
('User1', 'user1@example.com', 20),
('User2', 'user2@example.com', 25),
-- ... 更多数据
('User1000', 'user1000@example.com', 25);
COMMIT;
-- 2. 临时关闭同步
PRAGMA synchronous = OFF;
-- 批量插入
PRAGMA synchronous = NORMAL;
-- 3. 使用 WAL 模式
PRAGMA journal_mode = WAL;
四、从查询插入 #
4.1 INSERT … SELECT #
sql
-- 从其他表复制数据
CREATE TABLE users_archive (
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT,
archived_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users_archive (id, name, email)
SELECT id, name, email FROM users WHERE status = 0;
-- 创建备份表
CREATE TABLE users_backup AS SELECT * FROM users;
-- 或先创建结构再插入
CREATE TABLE users_copy LIKE users;
INSERT INTO users_copy SELECT * FROM users;
4.2 复杂查询插入 #
sql
-- 从多表查询插入
CREATE TABLE order_summary (
order_id INTEGER PRIMARY KEY,
customer_name TEXT,
total_amount REAL
);
INSERT INTO order_summary (order_id, customer_name, total_amount)
SELECT
o.id,
c.name,
SUM(oi.quantity * oi.price)
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN order_items oi ON o.id = oi.order_id
GROUP BY o.id, c.name;
-- 使用子查询
INSERT INTO user_stats (user_id, order_count)
SELECT
u.id,
(SELECT COUNT(*) FROM orders WHERE user_id = u.id)
FROM users u;
五、冲突处理 #
5.1 INSERT OR REPLACE #
sql
-- INSERT OR REPLACE:存在则替换,不存在则插入
INSERT OR REPLACE INTO users (id, name, email, age)
VALUES (1, 'John Updated', 'john@example.com', 26);
-- 注意:
-- 1. REPLACE 会删除旧行,插入新行
-- 2. AUTOINCREMENT 值会增加
-- 3. 会触发 DELETE 和 INSERT 触发器
-- 4. 其他列的值会丢失(除非在新行中指定)
5.2 INSERT OR IGNORE #
sql
-- INSERT OR IGNORE:忽略冲突,继续执行
INSERT OR IGNORE INTO users (id, name, email) VALUES
(1, 'John', 'john@example.com'), -- 已存在,忽略
(2, 'Jane', 'jane@example.com'), -- 插入成功
(3, 'Bob', 'bob@example.com'); -- 插入成功
-- 查看结果:只有新数据被插入
SELECT * FROM users;
5.3 UPSERT (SQLite 3.24.0+) #
sql
-- UPSERT:更灵活的冲突处理
-- ON CONFLICT DO UPDATE
-- 基本语法
INSERT INTO users (id, name, email, age)
VALUES (1, 'John', 'john@example.com', 26)
ON CONFLICT(id) DO UPDATE SET
name = excluded.name,
age = excluded.age;
-- 使用 WHERE 条件
INSERT INTO users (id, name, email, age)
VALUES (1, 'John', 'john@example.com', 26)
ON CONFLICT(id) DO UPDATE SET
name = excluded.name,
age = excluded.age
WHERE excluded.age > users.age;
-- ON CONFLICT DO NOTHING
INSERT INTO users (id, name, email)
VALUES (1, 'John', 'john@example.com')
ON CONFLICT(id) DO NOTHING;
-- 多列冲突
INSERT INTO users (email, name, age)
VALUES ('john@example.com', 'John', 26)
ON CONFLICT(email) DO UPDATE SET
name = excluded.name,
age = excluded.age;
5.4 冲突处理对比 #
sql
-- 对比各种冲突处理方式
-- 1. INSERT OR REPLACE
-- 删除旧行,插入新行
-- 所有未指定的列会变为NULL或默认值
-- 2. INSERT OR IGNORE
-- 忽略冲突行,继续插入其他行
-- 已存在的行保持不变
-- 3. UPSERT (推荐)
-- 存在则更新指定列,不存在则插入
-- 可以精确控制更新哪些列
-- 可以添加WHERE条件
六、获取插入ID #
6.1 last_insert_rowid() #
sql
-- 获取最后插入的 ROWID
INSERT INTO users (name, email) VALUES ('Test', 'test@example.com');
SELECT last_insert_rowid();
-- 在应用程序中使用
-- Python: cursor.lastrowid
-- PHP: $pdo->lastInsertId()
-- Java: Statement.getGeneratedKeys()
6.2 RETURNING子句 (SQLite 3.35.0+) #
sql
-- RETURNING:插入后返回数据
INSERT INTO users (name, email, age)
VALUES ('John', 'john@example.com', 25)
RETURNING id, name, created_at;
-- 批量插入返回
INSERT INTO users (name, email) VALUES
('User1', 'user1@example.com'),
('User2', 'user2@example.com')
RETURNING id, name;
-- 返回所有列
INSERT INTO users (name, email)
VALUES ('Alice', 'alice@example.com')
RETURNING *;
七、特殊数据插入 #
7.1 插入NULL值 #
sql
-- 插入NULL
INSERT INTO users (name, email, age)
VALUES ('Test', 'test@example.com', NULL);
-- 省略列(使用默认值或NULL)
INSERT INTO users (name, email)
VALUES ('Test', 'test@example.com');
-- age 列为 NULL
7.2 插入日期时间 #
sql
-- 插入日期时间
CREATE TABLE events (
id INTEGER PRIMARY KEY,
name TEXT,
event_date DATE,
event_time TIME,
event_datetime DATETIME
);
-- 使用字符串格式
INSERT INTO events (name, event_date, event_time, event_datetime)
VALUES (
'Meeting',
'2024-01-15',
'10:30:00',
'2024-01-15 10:30:00'
);
-- 使用函数
INSERT INTO events (name, event_datetime)
VALUES ('Event1', datetime('now'));
INSERT INTO events (name, event_date)
VALUES ('Event2', date('now'));
INSERT INTO events (name, event_time)
VALUES ('Event3', time('now'));
-- 使用时间计算
INSERT INTO events (name, event_datetime)
VALUES ('Event4', datetime('now', '+7 days'));
7.3 插入JSON数据 #
sql
-- 插入JSON数据
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT,
attributes TEXT -- JSON存储为TEXT
);
-- 插入JSON字符串
INSERT INTO products (name, attributes)
VALUES ('Laptop', '{"brand": "Dell", "ram": "16GB", "storage": "512GB"}');
-- 使用JSON函数
INSERT INTO products (name, attributes)
VALUES ('Phone', json_object('brand', 'Apple', 'model', 'iPhone 15'));
-- 插入JSON数组
INSERT INTO products (name, attributes)
VALUES ('Tablet', json_array('iPad', 'Samsung Tab', 'Surface'));
7.4 插入BLOB数据 #
sql
-- 插入二进制数据
CREATE TABLE files (
id INTEGER PRIMARY KEY,
name TEXT,
data BLOB,
mime_type TEXT
);
-- 插入十六进制数据
INSERT INTO files (name, data, mime_type)
VALUES ('test', X'010203040506070809', 'application/octet-stream');
-- 使用 zeroblob
INSERT INTO files (name, data, mime_type)
VALUES ('empty', zeroblob(1024), 'application/octet-stream');
-- 从文件加载(需要扩展)
-- INSERT INTO files (name, data)
-- SELECT 'file.pdf', readfile('/path/to/file.pdf');
八、性能优化 #
8.1 批量插入性能对比 #
sql
-- 性能对比(插入10000条记录)
-- 方法1:单条插入(最慢)
-- 约 10-30 秒
BEGIN;
INSERT INTO users (name, email) VALUES ('User1', 'user1@example.com');
INSERT INTO users (name, email) VALUES ('User2', 'user2@example.com');
-- ... 重复10000次
COMMIT;
-- 方法2:多行VALUES(较快)
-- 约 1-3 秒
BEGIN;
INSERT INTO users (name, email) VALUES
('User1', 'user1@example.com'),
('User2', 'user2@example.com'),
-- ... 更多数据
('User10000', 'user10000@example.com');
COMMIT;
-- 方法3:事务 + 批量(推荐)
-- 约 0.5-1 秒
BEGIN;
-- 每1000条一个INSERT
INSERT INTO users (name, email) VALUES ('User1', ...) ... ('User1000', ...);
INSERT INTO users (name, email) VALUES ('User1001', ...) ... ('User2000', ...);
-- ...
COMMIT;
8.2 插入优化配置 #
sql
-- 优化配置
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA cache_size = -10000; -- 10MB
-- 大批量插入
PRAGMA temp_store = MEMORY;
-- 执行批量插入
BEGIN TRANSACTION;
-- 插入操作
COMMIT;
九、安全考虑 #
9.1 防止SQL注入 #
sql
-- 错误:直接拼接SQL
-- INSERT INTO users (name) VALUES ('John'); DROP TABLE users;--')
-- 正确:使用参数化查询
-- Python
-- cursor.execute("INSERT INTO users (name, email) VALUES (?, ?)", (name, email))
-- PHP
-- $stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
-- $stmt->execute([$name, $email]);
-- Java
-- PreparedStatement pstmt = conn.prepareStatement("INSERT INTO users VALUES (?, ?)");
-- pstmt.setString(1, name);
-- pstmt.setString(2, email);
9.2 输入验证 #
sql
-- 使用 CHECK 约束验证数据
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL CHECK(length(name) >= 2),
email TEXT CHECK(email LIKE '%@%.%'),
age INTEGER CHECK(age >= 0 AND age <= 150)
);
-- 插入无效数据会失败
INSERT INTO users (name, email, age) VALUES ('A', 'invalid', 200);
-- Error: CHECK constraint failed
十、常见问题 #
10.1 主键冲突 #
sql
-- 错误:UNIQUE constraint failed
INSERT INTO users (id, name) VALUES (1, 'John');
-- 解决方案1:使用 UPSERT
INSERT INTO users (id, name) VALUES (1, 'John')
ON CONFLICT(id) DO UPDATE SET name = excluded.name;
-- 解决方案2:使用 INSERT OR REPLACE
INSERT OR REPLACE INTO users (id, name) VALUES (1, 'John');
-- 解决方案3:使用 INSERT OR IGNORE
INSERT OR IGNORE INTO users (id, name) VALUES (1, 'John');
10.2 唯一约束冲突 #
sql
-- 错误:UNIQUE constraint failed: users.email
INSERT INTO users (name, email) VALUES ('John', 'john@example.com');
-- 解决方案
INSERT INTO users (name, email) VALUES ('John', 'john@example.com')
ON CONFLICT(email) DO UPDATE SET name = excluded.name;
10.3 外键约束错误 #
sql
-- 启用外键
PRAGMA foreign_keys = ON;
-- 错误:FOREIGN KEY constraint failed
INSERT INTO orders (user_id, total) VALUES (999, 100);
-- 解决方案:确保外键值存在
INSERT INTO users (id, name) VALUES (999, 'User999');
INSERT INTO orders (user_id, total) VALUES (999, 100);
10.4 NOT NULL约束错误 #
sql
-- 错误:NOT NULL constraint failed
INSERT INTO users (email) VALUES ('test@example.com');
-- 解决方案:提供所有必需的值
INSERT INTO users (name, email) VALUES ('Test', 'test@example.com');
-- 或使用默认值
ALTER TABLE users ADD COLUMN name TEXT NOT NULL DEFAULT 'Anonymous';
十一、总结 #
插入方法对比 #
| 方法 | 语法 | 说明 |
|---|---|---|
| 单行插入 | INSERT INTO … VALUES | 基本插入 |
| 批量插入 | INSERT INTO … VALUES (…), (…) | 多行插入 |
| 查询插入 | INSERT INTO … SELECT | 从查询插入 |
| 冲突更新 | ON CONFLICT DO UPDATE | 存在则更新 |
| 冲突忽略 | INSERT OR IGNORE | 忽略错误 |
| 替换插入 | INSERT OR REPLACE | 删除后插入 |
最佳实践 #
- 使用批量插入提高性能
- 使用事务包装批量操作
- 使用 UPSERT 处理冲突
- 使用参数化查询防止注入
- 使用 RETURNING 获取插入数据
下一步,让我们学习数据更新操作!
最后更新:2026-03-27