SQLite不支持INSERT IF NOT EXISTS语法,需用INSERT OR IGNORE(依赖唯一约束)或INSERT...SELECT WHERE NOT EXISTS(纯逻辑判断)实现防重插。

SQLite 3 本身不支持 IF NOT EXISTS 直接修饰 INSERT 语句(比如 INSERT IF NOT EXISTS ... 这种写法会报错),必须靠约束 + 特殊语法或子查询来实现“不存在才插入”逻辑。
用 INSERT OR IGNORE 配合唯一约束
这是最常用、性能最好的方式,但前提是目标字段(如 id 或 username)已声明 UNIQUE 或 PRIMARY KEY。
-
INSERT OR IGNORE不会报错,也不会更新已有行,只静默跳过冲突 - 必须提前建表时加约束,例如:
CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT UNIQUE) - 执行时若
email已存在,整条INSERT OR IGNORE语句直接忽略,不抛异常也不影响其他操作 - 注意:它对
NOT NULL冲突也生效,但仅当该列有唯一性约束时才真正用于“防重插”
用 INSERT ... SELECT ... WHERE NOT EXISTS
不需要依赖唯一约束,纯逻辑判断,适合按多字段组合判断是否存在(比如 name 和 age 同时匹配才算重复)。
- 写法是:
INSERT INTO users (name, age) SELECT 'Alice', 25 WHERE NOT EXISTS (SELECT 1 FROM users WHERE name = 'Alice' AND age = 25) - 子查询里用
SELECT 1比SELECT *更轻量,语义也更清晰 - 缺点:每次执行都要全表扫描子查询条件,大数据量时明显变慢;且不能在没有
WHERE条件的INSERT中直接套用 - 不能用在参数化查询中直接拼接字符串——
WHERE NOT EXISTS部分需完整写死或由程序拼成合法 SQL
别误用 REPLACE INTO 当“只插入”
REPLACE INTO 的行为是“冲突则删再插”,不是“存在就跳过”。它会触发删除 + 插入两步,可能意外清空关联数据(如外键级联、触发器、自增 ID 重置)。
- 如果只是想避免重复,
REPLACE INTO会导致id变化(主键重新生成)、触发DELETE相关逻辑,副作用不可控 - 它等价于
INSERT OR REPLACE,底层先尝试插入,冲突时删原行再插新行 - 除非你明确需要“存在即覆盖”的语义,否则不要把它当作
INSERT IF NOT EXISTS的替代品
常见错误和绕不开的坑
实际写的时候最容易栽在这几个地方:
- 忘记建
UNIQUE约束就直接用INSERT OR IGNORE—— 它完全失效,照样重复插入 - 在
WHERE NOT EXISTS子查询里漏写FROM表名,或者括号不匹配,导致语法错误:near "WHERE": syntax error - 用 Python 的
sqlite3执行带子查询的INSERT时,参数不能跨主句和子查询绑定,得手动拼接或拆成两步 - SQLite 的
INSERT OR IGNORE对PRIMARY KEY冲突有效,但对UNIQUE约束上的NULL值不敏感(多个NULL不视为重复)
真正要稳住“只插一次”,核心就两条:要么靠约束 + INSERT OR IGNORE,要么靠子查询 + INSERT ... SELECT。选哪个,取决于你有没有现成的唯一性定义,以及能不能接受子查询带来的开销。

















