文章
各个数据库中违反唯一约束的处理方式
目录
下面分别对 SQLite、MySQL、Oracle、PostgreSQL 四种数据库中如何创建唯一约束、违反唯一约束时的默认行为,以及可用的冲突处理机制和示例做说明,最后以表格形式总结对比。#
1. SQLite#
- 创建唯一约束
CREATE TABLE ani_items ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, platform TEXT NOT NULL, UNIQUE(title, platform) );
```
- 默认行为
插入重复
(title, platform)时会报错,错误类型SQLITE_CONSTRAINT_UNIQUE,插入失败。 - 冲突处理语法
- 忽略冲突
- 忽略冲突
INSERT OR IGNORE INTO ani_items (...) VALUES (...);
```
- **标准 UPSERT**
```sql
INSERT INTO ani_items (...) VALUES (...) ON CONFLICT(title, platform) DO NOTHING;
```
- **冲突时更新**
```sql
INSERT INTO ani_items (...) VALUES (...) ON CONFLICT(title, platform) DO UPDATE SET update_count = excluded.update_count, update_time = excluded.update_time;
```
2. MySQL#
- 创建唯一约束
CREATE TABLE ani_items ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, platform VARCHAR(255) NOT NULL, UNIQUE KEY unique_title_platform (title, platform) ) ENGINE=InnoDB;
```
- 默认行为
插入重复键时会报
ERROR 1062 (23000): Duplicate entry ... for key 'unique_title_platform',插入失败并(若在事务中)回滚。 - 冲突处理语法
- 忽略冲突
- 忽略冲突
INSERT IGNORE INTO ani_items (...) VALUES (...);
```
- **替换行**
```sql
REPLACE INTO ani_items (...) VALUES (...);
```
- **UPSERT**
```sql
INSERT INTO ani_items (...) VALUES (...) ON DUPLICATE KEY UPDATE update_count = VALUES(update_count), update_time = VALUES(update_time);
```
3. Oracle#
- 创建唯一约束
CREATE TABLE ani_items ( id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, title VARCHAR2(255) NOT NULL, platform VARCHAR2(255) NOT NULL, CONSTRAINT unique_title_platform UNIQUE (title, platform) );
```
- 默认行为
插入重复键时会抛出
ORA-00001: unique constraint (….) violated异常,插入失败。 - 冲突处理机制
- MERGE 实现 UPSERT
- MERGE 实现 UPSERT
MERGE INTO ani_items t USING (SELECT :title AS title, :platform AS platform, :count AS update_count FROM dual) src ON (t.title = src.title AND t.platform = src.platform) WHEN MATCHED THEN UPDATE SET t.update_count = src.update_count WHEN NOT MATCHED THEN INSERT (title, platform, update_count) VALUES (src.title, src.platform, src.update_count);
```
- **PL/SQL 异常捕获**
```plain text
BEGIN INSERT INTO ani_items (...) VALUES (...); EXCEPTION WHEN DUP_VAL_ON_INDEX THEN NULL; -- 忽略或改用 UPDATE END;
```
4. PostgreSQL#
- 创建唯一约束
CREATE TABLE ani_items ( id SERIAL PRIMARY KEY, title TEXT NOT NULL, platform TEXT NOT NULL, UNIQUE (title, platform) );
```
- 默认行为
插入重复键时报
ERROR: duplicate key value violates unique constraint "ani_items_title_platform_key",插入失败并回滚事务。 - 冲突处理语法
- 忽略冲突
- 忽略冲突
INSERT INTO ani_items (...) VALUES (...) ON CONFLICT (title, platform) DO NOTHING;
```
- **UPSERT**
```sql
INSERT INTO ani_items (...) VALUES (...) ON CONFLICT (title, platform) DO UPDATE SET update_count = EXCLUDED.update_count, update_time = EXCLUDED.update_time;
```
对比汇总#
| 数据库 | 唯一约束创建 | 默认行为 | 冲突时“忽略” | 冲突时“插入或更新” |
|---|---|---|---|---|
| SQLite | UNIQUE(title, platform) | 报错、插入失败 | INSERT OR IGNOREON CONFLICT … DO NOTHING | ON CONFLICT … DO UPDATE SET … |
| MySQL | UNIQUE KEY unique_title_platform (title,platform) | 报错、插入失败并回滚 | INSERT IGNORE | ON DUPLICATE KEY UPDATE … |
| Oracle | CONSTRAINT unique_title_platform UNIQUE (…) | 抛出 ORA-00001 异常 | PL/SQL 捕获 DUP_VAL_ON_INDEX | MERGE INTO … WHEN MATCHED … WHEN NOT MATCHED |
| PostgreSQL | UNIQUE (title, platform) | 报错、插入失败并回滚 | ON CONFLICT … DO NOTHING | ON CONFLICT … DO UPDATE SET … |
如需针对某种数据库的具体示例代码(例如在 Rust 中用 sqlx 或其他驱动)请告诉我!