Navicat 16 修改 SQLite 字段类型实为静默表重建,执行“建新表→导数据→删旧表→改名”,不展示真实SQL、不校验兼容性、默认丢弃约束且 AUTOINCREMENT 可能失效,故应手动编写可控迁移脚本。
ALTER TABLE 在 SQLite 中不支持修改字段类型,Navicat 的表设计器点“保存”不会执行 ALTER TABLE ... MODIFY COLUMN(该语法根本不存在),而是静默触发**表重建流程**——建新表、导数据、删旧表、改名。这个过程不可见、不可控,极易丢数据或破坏约束。
为什么不能直接改类型?
sqlite 原生只允许:alter table ... add column 和 alter table ... rename to。改类型必须靠手动重建表。navicat 16/17 在你点“保存”时自动走这套逻辑,但:
• 不展示真实执行的 sql
• 不校验数据是否能 cast 成目标类型(比如 text → integer 遇到 "n/a" 直接变 0)
• 默认丢弃 not null、check、外键约束
• primary key autoincrement 很可能失效,新插入 id 从 1 开始重复
点“保存”前必须手动检查三件事
Navicat 不会弹窗确认,也不会回滚失败操作。一旦删了旧表,新表因类型转换失败而中断,数据就没了。
• 拉到底部看“SQL 预览”面板——那只是示意 SQL,**不是真实执行语句**,不能信
• 右键表 → “对象信息” → 切换到“DDL”页,复制当前建表语句,逐行比对约束、主键、默认值是否完整保留
• 先验证数据兼容性:比如要把 col 从 TEXT 改成 INTEGER,跑一句 SELECT COUNT(*) FROM table WHERE col NOT GLOB '[0-9]*' AND col != '' 粗筛非数字值
更安全的做法:手写重建逻辑
依赖图形界面改类型风险太高。真要改,建议在查询窗口里显式控制每一步:
• 用 PRAGMA table_info(table_name) 查原结构
• 手写 CREATE TABLE new_table (...),明确声明所有约束和 AUTOINCREMENT
• 用 INSERT INTO new_table SELECT ... CAST(col AS INTEGER) ... FROM old_table 控制转换逻辑
• 加 WHERE typeof(col) = 'text' 或条件过滤异常值
• 最后 DROP TABLE old_table + ALTER TABLE new_table RENAME TO old_table
strftime('%Y-%m', col) 就行;强行重建表,反而容易把简单问题搞复杂。











