默认值仅在insert时完全省略字段或显式写default才生效,非留空、null或orm自动填充触发;values值数必须严格匹配列数,否则报错。

默认值只在 INSERT 时「完全省略该字段」或「显式写 DEFAULT」才生效,不是靠留空、NULL 或 ORM 自动填充触发的。
INSERT 不写字段名时,默认值根本不会用
直接写 INSERT INTO table_name VALUES (...),数据库会严格按表结构顺序匹配列数。哪怕所有列都有 DEFAULT,只要 VALUES 里值的数量不等于总列数,就报错——比如 MySQL 报 Column count doesn't match value count。
- ✅ 正确:显式列出要插入的字段,让其余字段走默认逻辑
INSERT INTO users (name, email) VALUES ('Leo', 'l@example.com')(created_at自动填CURRENT_TIMESTAMP) - ❌ 错误:
INSERT INTO users VALUES ('Leo', 'l@example.com')(表有 5 列,只给 2 个值,必失败) - ⚠️ 注意:即使你把所有字段都设了默认值,
VALUES ()在 MySQL 中也不合法;PostgreSQL 和 SQLite 支持,但 MySQL 要求至少一个值
用 DEFAULT 关键字强制走默认逻辑
当你必须用全字段插入(比如批量脚本固定列数),又想让某列跳过手动赋值、走默认行为,就用 DEFAULT 占位——它不是字符串,不能加引号,大小写不敏感。
- ✅ 支持的写法:
INSERT INTO logs (id, level, message, created_at) VALUES (101, 'ERROR', 'disk full', DEFAULT) - ⚠️ Oracle 不支持这种用法,得改用
INSERT INTO t DEFAULT VALUES或省略字段 - ⚠️ SQLite 对
DEFAULT CURRENT_TIMESTAMP是支持的,但不支持DEFAULT datetime('now')这类函数表达式
建表时设默认值的常见坑点
默认值是数据库原生能力,但不同字段类型和数据库版本对写法敏感。
- 字符串必须加单引号:
status VARCHAR(20) DEFAULT 'draft',写成DEFAULT draft会当列名解析而报错 - 数值不加引号:
score TINYINT DEFAULT 0,DEFAULT '0'可能触发隐式转换 - 时间推荐用
CURRENT_TIMESTAMP(MySQL/PostgreSQL),不能带括号:CURRENT_TIMESTAMP()是非法的 - MySQL 8.0.19 前,
TEXT/BLOB类型不支持DEFAULT;JSON 类型至今不支持空字符串默认值 - NOT NULL 字段若没设
DEFAULT,且 SQL mode 启用了STRICT_TRANS_TABLES,INSERT 省略该字段必报Field 'xxx' doesn't have a default value
DEFAULT VALUES 的适用边界
INSERT INTO table_name DEFAULT VALUES 是最简全默认插入方式,但限制极强。
- ✅ 适合场景:日志表、审计快照表等所有列都可由默认逻辑兜底的结构
- ❌ 语法禁止混合:
INSERT INTO t (a, b) DEFAULT VALUES是错误的——字段列表和DEFAULT VALUES互斥 - ⚠️ 它无法控制任意一列的值,历史数据也不会被修改,只影响后续新行
- ⚠️ 驱动层(如 PyMySQL、JDBC)可能把空字符串转成
NULL,导致绕过默认值逻辑,尤其在 NOT NULL 字段上容易静默失败
真正容易被忽略的是:默认值只对 INSERT 生效,UPDATE 不会自动回填;而很多 ORM(如 Hibernate)默认生成动态 SQL,会跳过未设值的字段,但若映射配置没开 dynamic-insert="true",反而可能把字段显式设为 NULL,直接破坏默认值逻辑。










