SQLite REPLACE INTO 不是原地更新,而是:
因此:行物理位置改變(通常移至表尾)、未指定列置為 NULL/默認值、Rowid 可能變化。
CREATE TABLE student (
id TEXT, name TEXT NOT NULL, sex TEXT, email TEXT UNIQUE,
fenshu TEXT CHECK(fenshu > 0), tecid TEXT REFERENCES teacher(id),
class TEXT, PRIMARY KEY (id, name) -- 復合主鍵
);
| 操作 | SQL | 結果現象 | 解析 |
|---|---|---|---|
| 完整替換 | REPLACE INTO student (id,name,sex,email,fenshu,tecid,class) VALUES ('2','lisi','*F','123@qq.com','80','2','1'); | 原 id=2 行移至表尾,Rowid 變化 | DELETE+INSERT,物理位置改變 |
| 部分列替換 | REPLACE INTO student (id,name,sex,email,fenshu,tecid) VALUES ('2','lisi','*F','123@qq.com','80','2'); | class 列變為 NULL | 未指定列不保留舊值,按默認/NULL 填充 |
| 主鍵定位 | 同上 | 復合主鍵 (id,name) 唯一定位行 | REPLACE 依賴主鍵/唯一約束衝突判斷 |
| 無 WHERE 子句 | REPLACE ... WHERE id='2'; | 語法錯誤 | REPLACE 不支持 WHERE,僅按值衝突 |
| 記錄不存在 | REPLACE INTO student ... VALUES ('100','a',...); | 直接插入新行 | 無衝突等同 INSERT |
| 唯一約束衝突觸發刪除其他行 | 插入 email 重複行 | 原有 email 相同行被刪除 | UNIQUE 衝突 → 刪除舊行 → 插入新行 |
| 維度 | REPLACE | UPDATE |
|---|---|---|
| 定位方式 | 主鍵/唯一鍵值衝突 | WHERE 子句任意條件 |
| 影響行數 | 0 或 1 (衝突時) / 1 (無衝突) | 0~N (滿足 WHERE 的所有行) |
| 未指定列 | 置 NULL/默認值 | 保留原值 |
| 觸發器 | DELETE + INSERT 觸發器 | UPDATE 觸發器 |
| 外鍵級聯 | 觸發 ON DELETE/INSERT 級聯 | 觸發 ON UPDATE 級聯 |
| Rowid/物理位置 | 改變 | 不變 |
| 性能 | 較高開銷 (雙操作) | 較低 (原地修改) |
INSERT ... ON CONFLICT DO UPDATE (SQLite 3.24.0+),單語句、原地更新、性能更優。INSERT INTO student (id,name,sex,email,fenshu,tecid,class)
VALUES ('2','lisi','*F','123@qq.com','80','2','1')
ON CONFLICT(id,name) DO UPDATE SET
sex=excluded.sex, email=excluded.email, fenshu=excluded.fenshu,
tecid=excluded.tecid, class=excluded.class;
-- 原地更新,保留 Rowid,僅更新指定列,性能最優