MariaDB数据插入 #
一、INSERT语句概述 #
1.1 基本语法 #
sql
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);
1.2 示例表结构 #
sql
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
age INT DEFAULT 0,
status TINYINT DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
二、基本插入 #
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, NOW());
-- AUTO_INCREMENT列使用NULL或0
INSERT INTO users
VALUES (0, 'Bob', 'bob@example.com', 28, 1, NOW());
2.3 使用SET语法 #
sql
-- MariaDB特有语法
INSERT INTO users
SET name = 'Alice',
email = 'alice@example.com',
age = 22;
三、批量插入 #
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. 减少网络往返
-- 2. 减少SQL解析次数
-- 3. 批量事务提交
3.2 批量插入优化 #
sql
-- 大批量插入优化
-- 1. 临时禁用索引(非唯一索引)
ALTER TABLE users DISABLE KEYS;
INSERT INTO users (name, email, age) VALUES
-- 大量数据...
('User10000', 'user10000@example.com', 25);
ALTER TABLE users ENABLE KEYS;
-- 2. 使用LOAD DATA INFILE(更快)
LOAD DATA INFILE '/path/to/users.csv'
INTO TABLE users
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
(name, email, age);
-- 3. 调整配置
SET unique_checks = 0;
SET foreign_key_checks = 0;
SET autocommit = 0;
-- 批量插入...
COMMIT;
SET unique_checks = 1;
SET foreign_key_checks = 1;
SET autocommit = 1;
四、从查询插入 #
4.1 INSERT … SELECT #
sql
-- 从其他表复制数据
INSERT INTO users_archive (name, email, age, status)
SELECT name, email, age, status
FROM users
WHERE created_at < '2023-01-01';
-- 创建备份表并复制
CREATE TABLE users_backup LIKE users;
INSERT INTO users_backup SELECT * FROM users;
-- 条件复制
INSERT INTO active_users (name, email)
SELECT name, email
FROM users
WHERE status = 1;
4.2 复杂查询插入 #
sql
-- 从多表查询插入
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 IGNORE #
sql
-- 忽略错误,继续插入其他行
INSERT IGNORE INTO users (id, name, email) VALUES
(1, 'John', 'john@example.com'), -- 已存在,忽略
(2, 'Jane', 'jane@example.com'), -- 插入成功
(3, 'Bob', 'bob@example.com'); -- 插入成功
-- 查看警告
SHOW WARNINGS;
5.2 ON DUPLICATE KEY UPDATE #
sql
-- 存在则更新,不存在则插入
INSERT INTO users (id, name, email, age) VALUES
(1, 'John Updated', 'john@example.com', 26)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
age = VALUES(age),
updated_at = NOW();
-- 使用新值
INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com')
ON DUPLICATE KEY UPDATE
name = VALUES(name),
email = VALUES(email);
-- MariaDB 10.3.3+ 可以使用别名
INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com') AS new
ON DUPLICATE KEY UPDATE
name = new.name,
email = new.email;
5.3 REPLACE INTO #
sql
-- 存在则删除后插入,不存在则插入
REPLACE INTO users (id, name, email) VALUES
(1, 'John New', 'john@example.com');
-- 注意:
-- 1. 会删除旧行,插入新行
-- 2. AUTO_INCREMENT会增加
-- 3. 会触发DELETE和INSERT触发器
-- 4. 外键约束可能导致失败
六、INSERT返回值 #
6.1 获取插入ID #
sql
-- 获取最后插入的AUTO_INCREMENT值
INSERT INTO users (name, email) VALUES ('Test', 'test@example.com');
SELECT LAST_INSERT_ID();
-- 在应用程序中使用
-- Python: cursor.lastrowid
-- PHP: mysqli_insert_id()
-- Java: Statement.getGeneratedKeys()
6.2 MariaDB 10.5+ RETURNING #
sql
-- MariaDB 10.5+ 支持RETURNING
INSERT INTO users (name, email, age)
VALUES ('John', 'john@example.com', 25)
RETURNING id, name, created_at;
+----+------+---------------------+
| id | name | created_at |
+----+------+---------------------+
| 1 | John | 2024-01-15 10:00:00 |
+----+------+---------------------+
-- 批量插入返回
INSERT INTO users (name, email) VALUES
('User1', 'user1@example.com'),
('User2', 'user2@example.com')
RETURNING id, name;
七、特殊插入场景 #
7.1 插入JSON数据 #
sql
-- 创建JSON列的表
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
attributes JSON
);
-- 插入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.2 插入时间数据 #
sql
-- 插入日期时间
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, created_at)
VALUES ('Event1', NOW());
INSERT INTO events (name, created_at)
VALUES ('Event2', CURRENT_TIMESTAMP);
-- 插入时间戳
INSERT INTO logs (message, log_time)
VALUES ('Error occurred', UNIX_TIMESTAMP());
7.3 插入BLOB数据 #
sql
-- 创建包含BLOB的表
CREATE TABLE files (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
file_data LONGBLOB,
file_type VARCHAR(50)
);
-- 从文件加载
INSERT INTO files (name, file_data, file_type)
SELECT
'document.pdf',
LOAD_FILE('/path/to/document.pdf'),
'application/pdf';
-- 注意:LOAD_FILE需要FILE权限和可读文件
八、性能优化 #
8.1 批量插入优化 #
sql
-- 优化配置
SET GLOBAL innodb_buffer_pool_size = 2G;
SET GLOBAL innodb_log_file_size = 512M;
SET GLOBAL innodb_flush_log_at_trx_commit = 2;
-- 批量插入
START TRANSACTION;
INSERT INTO users (name, email) VALUES
('User1', 'user1@example.com'),
('User2', 'user2@example.com'),
-- ... 更多数据
('User1000', 'user1000@example.com');
COMMIT;
8.2 延迟插入 #
sql
-- INSERT DELAYED(已弃用,MariaDB 10.0-10.4支持)
-- 数据先放入队列,稍后批量插入
INSERT DELAYED INTO logs (message) VALUES ('Log entry');
-- 推荐替代方案:使用存储过程或应用层批量插入
8.3 插入性能对比 #
| 方法 | 速度 | 说明 |
|---|---|---|
| 单行INSERT | 慢 | 每次都有网络和解析开销 |
| 多行INSERT | 快 | 减少网络往返 |
| LOAD DATA | 最快 | 批量加载文件 |
| INSERT … SELECT | 快 | 服务器端操作 |
九、安全考虑 #
9.1 防止SQL注入 #
sql
-- 错误:直接拼接SQL
-- INSERT INTO users (name) VALUES ('John'); DROP TABLE users;--')
-- 正确:使用预处理语句
PREPARE stmt FROM 'INSERT INTO users (name, email) VALUES (?, ?)';
SET @name = 'John';
SET @email = 'john@example.com';
EXECUTE stmt USING @name, @email;
DEALLOCATE PREPARE stmt;
-- 应用程序使用参数化查询
-- Python: cursor.execute("INSERT INTO users VALUES (%s, %s)", (name, email))
-- PHP: $stmt = $pdo->prepare("INSERT INTO users VALUES (?, ?)")
-- Java: PreparedStatement pstmt = conn.prepareStatement("INSERT INTO users VALUES (?, ?)")
9.2 权限控制 #
sql
-- 只授予必要的权限
GRANT INSERT ON mydb.users TO 'app_user'@'localhost';
-- 限制插入权限
REVOKE INSERT ON mydb.users FROM 'readonly'@'localhost';
十、常见问题 #
10.1 主键冲突 #
sql
-- 错误:Duplicate entry '1' for key 'PRIMARY'
INSERT INTO users (id, name) VALUES (1, 'John');
-- 解决方案1:使用AUTO_INCREMENT
INSERT INTO users (name) VALUES ('John');
-- 解决方案2:使用ON DUPLICATE KEY UPDATE
INSERT INTO users (id, name) VALUES (1, 'John')
ON DUPLICATE KEY UPDATE name = VALUES(name);
-- 解决方案3:使用INSERT IGNORE
INSERT IGNORE INTO users (id, name) VALUES (1, 'John');
10.2 唯一约束冲突 #
sql
-- 错误:Duplicate entry 'john@example.com' for key 'email'
INSERT INTO users (name, email) VALUES ('John', 'john@example.com');
-- 解决方案
INSERT INTO users (name, email) VALUES ('John', 'john@example.com')
ON DUPLICATE KEY UPDATE name = VALUES(name);
10.3 外键约束错误 #
sql
-- 错误:Cannot add or update a child row: a foreign key constraint fails
INSERT INTO orders (user_id, amount) VALUES (999, 100);
-- 解决方案:确保外键值存在
INSERT INTO users (id, name) VALUES (999, 'User999');
INSERT INTO orders (user_id, amount) VALUES (999, 100);
-- 或临时禁用外键检查
SET foreign_key_checks = 0;
INSERT INTO orders (user_id, amount) VALUES (999, 100);
SET foreign_key_checks = 1;
10.4 数据类型不匹配 #
sql
-- 错误:Incorrect integer value: 'abc' for column 'age'
INSERT INTO users (name, age) VALUES ('John', 'abc');
-- 解决方案:使用正确的数据类型
INSERT INTO users (name, age) VALUES ('John', 25);
-- 或使用类型转换
INSERT INTO users (name, age) VALUES ('John', CAST('25' AS SIGNED));
十一、总结 #
插入数据要点:
| 方法 | 语法 | 说明 |
|---|---|---|
| 单行插入 | INSERT INTO … VALUES | 基本插入 |
| 批量插入 | INSERT INTO … VALUES (…), (…) | 多行插入 |
| 查询插入 | INSERT INTO … SELECT | 从查询插入 |
| 冲突更新 | ON DUPLICATE KEY UPDATE | 存在则更新 |
| 冲突忽略 | INSERT IGNORE | 忽略错误 |
| 替换插入 | REPLACE INTO | 删除后插入 |
最佳实践:
- 使用批量插入提高性能
- 使用预处理语句防止SQL注入
- 合理处理插入冲突
- 大数据量使用LOAD DATA INFILE
- 注意事务和锁的使用
下一步,让我们学习数据更新操作!
最后更新:2026-03-27