SQLite3触发器无法自动补历史数据,必须分INSERT/UPDATE/DELETE单独编写,且主键对齐、NULL防护、手动初始化三者缺一不可;TRUNCATE不触发任何触发器,需禁用或改用DELETE并立即初始化物化表。

SQLite 3 不能用触发器“自动补历史数据”,也不能靠单个触发器覆盖所有场景——必须分 INSERT/UPDATE/DELETE 单独写,且主键、NULL、初始化三者缺一不可。
为什么统计表总对不上?主键没对齐就全崩了
多维聚合表(比如按 date、category、region 分组的汇总)的主键必须是这三列组合。否则:
- 主键缺失维度 → 多条逻辑不同的记录挤进同一行,互相覆盖
- 主键不唯一 →
INSERT OR REPLACE INTO或ON CONFLICT找不到冲突目标,静默插入重复行 - 没建联合索引 →
WHERE date = ? AND category = ?更新时全表扫描,高并发下锁等待甚至死锁
AFTER INSERT / UPDATE / DELETE 必须拆开写
混在一个触发器里极易漏算或重复加减。每类操作对统计值的影响方向不同:
-
AFTER INSERT:只加新值,但必须判断NEW.amount IS NOT NULL,否则total = total + NULL整行变NULL -
AFTER UPDATE:先SET total = total - OLD.amount,再SET total = total + NEW.amount,两个都要防NULL -
AFTER DELETE:只减旧值,同样要OLD.amount IS NOT NULL判断
别指望一个 AFTER INSERT OR UPDATE OR DELETE 能兜住全部逻辑——SQLite 不支持在触发器里写条件分支(如 IF),只能靠语句结构硬拆。
TRUNCATE 和初始化是两道生死线
TRUNCATE TABLE 在 SQLite 中根本不会触发任何 DML 触发器,它直接清空页,连 AFTER DELETE 都收不到。后果是:汇总表残留旧数据,彻底失准。
- 要么禁用
TRUNCATE权限,文档明确要求“清空请用DELETE FROM xxx” - 要么新建汇总表后立刻手动初始化:
INSERT INTO summary SELECT ... GROUP BY ... ON CONFLICT DO UPDATE - 初始化语句必须带
ON CONFLICT,否则并发建表+初始化时可能因重复插入失败
视图不能被触发器更新,物化表才是真出路
SQLite 的视图是只读虚表,UPDATE view_name 直接报错 near "view_name": syntax error。所谓“维护视图统计”,实际只能:
- 建一张普通表(如
mv_daily_sales)作为物化缓存 - 用触发器监听基表变更,只刷新受影响的行(别全表重算)
- 写法上避免
SELECT ... FROM inserted这种伪表(SQLite 不支持),改用WHERE id IN (SELECT id FROM orders WHERE ...)子查询
最常被忽略的是:触发器从不回溯历史数据,也不感知批量导入是否绕过它——这些都得靠外部机制兜底。










