MySQL 中设置 DEFAULT 默认值时必须严格遵循字段类型规则:字符串类型要加单引号,数值类型通常不加引号,CURRENT_TIMESTAMP 不能带括号;在 MySQL 8.0.19 之前,TEXT/BLOB 类型不支持默认值;ALTER TABLE 修改默认值的语法会随版本不同而变化;另外,DEFAULT 仅在 INSERT 插入数据时生效,UPDATE 更新数据时需要显式使用 SET col = DEFAULT。

CREATE TABLE 时设置 DEFAULT 必须带引号、函数不加括号
在 MySQL 创建表并设置字段默认值时,字符串类型的默认值必须使用单引号包裹,例如 DEFAULT active 会直接报错,正确写法应为 DEFAULT 'active';数值类型则应直接写数字,像 DEFAULT '0' 虽然有时可执行,但可能触发隐式类型转换;时间类型默认值推荐使用 CURRENT_TIMESTAMP,但 CURRENT_TIMESTAMP() 属于非法写法,因为这里不能加括号。
如果某个字段定义了 NOT NULL,却没有设置 DEFAULT,同时 SQL mode 开启了 STRICT_TRANS_TABLES,那么执行 INSERT 时一旦省略该字段,就会直接报错:Field 'xxx' doesn't ha ve a default value。另外,在 MySQL 8.0.19 之前,TEXT/BLOB 类型本身就不支持设置默认值,因此即使显式写了 DEFAULT '',最终也会被 MySQL 拒绝。
ALTER TABLE 修改默认值要看 MySQL 版本选语法
在 MySQL 中通过 ALTER TABLE 修改字段默认值时,需要根据版本选择正确语法。MySQL 8.0.13 及以上版本推荐使用 ALTER COLUMN ... SET DEFAULT,语义更清晰,也更安全:
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'inactive';
而旧版本(例如 MySQL 5.7)则必须使用 MODIFY COLUMN,但这种方式会重定义整列,操作时很容易遗漏原有约束:
- 必须完整写出字段类型和原有限制条件,例如原字段是
VARCHAR(20) NOT NULL,如果写成MODIFY COLUMN status VARCHAR(20) DEFAULT 'inactive',就会在不知不觉中把NOT NULL去掉 - 如果要删除默认值,应使用
DROP DEFAULT,而不是写成DEFAULT NULL——后者依然表示存在默认值,而且还可能与NOT NULL产生冲突
INSERT 时 DEFAULT 不生效的三个典型原因
很多人在 MySQL 插入数据时明明设置了 DEFAULT 默认值,却发现没有生效,通常都是以下几个常见原因导致的:
- 客户端驱动(如 PyMySQL、JDBC)可能会把空字符串
''自动转换成NULL,而字段本身又设置了NOT NULL,于是会直接报错,根本不会进入默认值生效的逻辑 - 当
SQL mode包含STRICT_ALL_TABLES时,即使字段允许NULL,如果你显式插入NULL,MySQL 也不会回退使用默认值,而是按严格模式处理 - 很多人误以为
UPDATE更新字段时也会自动触发默认值,实际上并不会。DEFAULT只在INSERT时生效;如果想在更新时恢复默认值,必须手动写UPDATE SET col = DEFAULT
CURRENT_TIMESTAMP 作为默认值要卡版本和类型
在 MySQL 中把 CURRENT_TIMESTAMP 设为默认值时,还要注意版本与字段类型限制。DATETIME 字段使用 CURRENT_TIMESTAMP 作为默认值,要求 MySQL 版本不低于 5.6.5;如果还要配合 ON UPDATE 子句使用,则通常需要 ≥ 8.0.19。TIMESTAMP 类型原生支持时间戳默认值,并且底层按 UTC 存储、读取时转换为本地时区;而 DATETIME 保存的是字面时间值,不涉及时区转换。
如果给现有字段追加 CURRENT_TIMESTAMP 默认值时失败,不要急着怀疑 SQL 语法是否写错,建议先执行 SELECT @@sql_mode 检查当前 SQL 模式,重点确认是否包含 NO_ZERO_DATE。常见原因并不复杂:只要表中已经存在类似 '0000-00-00 00:00:00' 这样的非法时间值,在执行 ALTER 修改时,就很可能直接报出 Invalid default value for 'ts'。更稳妥的处理方式通常是先清理历史脏数据,或者仅在调试环境中临时降低 SQL mode,而不是一开始就盲目修改语法。
最后需要注意,字段默认值只会影响后续新的 INSERT 插入操作,已经存在的历史数据不会自动变化。也就是说,DEFAULT 不能用来“修复”旧记录。
