DEFAULT NULL仅在INSERT完全不提该字段时生效,显式写NULL或DEFAULT行为相同;NOT NULL字段上设DEFAULT NULL会建表失败;CURRENT_TIMESTAMP作默认值需加ON UPDATE才自动更新;字符串默认值须转义单引号且长度受限;不同数据库对默认值支持差异大。
MySQL 中 DEFAULT NULL 和显式设为 NULL 的区别
字段声明为 default null,不代表插入时自动填 null;它只是告诉 mysql:当 insert 语句**完全不提这个字段**时,才用 null 填充。如果语句里写了 col = default 或显式传了 null,行为一致;但若字段有 not null 约束,default null 会直接报错,因为 null 不被允许。
-
DEFAULT NULL在NOT NULL字段上非法,建表会失败 - INSERT INTO t() VALUES() —— 此时才触发
DEFAULT NULL - INSERT INTO t(c) VALUES(NULL) —— 这是显式赋值,和 DEFAULT 无关
- 如果字段没设 DEFAULT,又没在 INSERT 中出现,且类型允许 NULL,则隐式为 NULL(但这是 SQL 标准行为,不是 DEFAULT 起作用)
CURRENT_TIMESTAMP 默认值的写法与自动更新陷阱
MySQL 5.6.5+ 支持 CURRENT_TIMESTAMP 作默认值,但必须注意:它默认**不开启自动更新**。很多人以为设了 DEFAULT CURRENT_TIMESTAMP 就能“每次改行都更新时间”,其实不会——除非额外加 ON UPDATE CURRENT_TIMESTAMP。
- 仅
DEFAULT CURRENT_TIMESTAMP:只在 INSERT 时生效一次 -
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP:INSERT 和 UPDATE 都触发 - 不能对非
TIMESTAMP或DATETIME类型用CURRENT_TIMESTAMP - MySQL 8.0+ 允许
DATETIME也支持DEFAULT CURRENT_TIMESTAMP,但老版本只认TIMESTAMP - 同一张表最多只能有一个
TIMESTAMP列带ON UPDATE CURRENT_TIMESTAMP(旧版限制,8.0 已放宽)
字符串字段设默认值要防空格、引号和字符集问题
给 VARCHAR 或 TEXT 设默认字符串,看着简单,实际容易因字符集、长度或转义翻车。比如 DEFAULT '2024-01-01' 没问题,但 DEFAULT 'user's data' 会因单引号中断语法;更隐蔽的是,如果表字符集是 utf8mb4,而连接字符集是 latin1,默认值可能存成乱码。
- 字符串默认值必须用单引号包裹,内部单引号需转义为两个单引号:
DEFAULT 'O''Reilly' - 默认值长度不能超过字段定义长度(如
VARCHAR(10)不能设DEFAULT 'hello world') - 避免用函数或表达式做默认值(如
DEFAULT CONCAT('v', 1)),MySQL 5.7 及以前不支持 - 建表时显式指定字符集,比如
name VARCHAR(50) CHARACTER SET utf8mb4 DEFAULT 'N/A'
PostgreSQL 和 SQLite 的默认值逻辑差异
MySQL 的 DEFAULT 是“语法层面的填充规则”,而 PostgreSQL 把默认值当作表达式执行(支持函数、运算),SQLite 则最保守:只接受字面量或 NULL、CURRENT_TIME 等极少数关键字。这意味着同样一句 DEFAULT NOW(),在三个引擎中兼容性完全不同。
- PostgreSQL:支持
DEFAULT now()、DEFAULT (current_date + 1),括号可选但推荐加上 - SQLite:只认
DEFAULT CURRENT_TIMESTAMP、DEFAULT NULL、DEFAULT 'abc',不支持函数调用 - MySQL:5.7+ 支持
DEFAULT (UUID())这类函数,但需加括号;不加括号如DEFAULT UUID()会报错 - 跨库迁移时,别假设
CURRENT_TIMESTAMP行为一致——SQLite 的CURRENT_TIMESTAMP是字符串字面量,不随行更新
实际配置时最容易漏掉的,是字符集继承关系和 ON UPDATE 的显式声明。这两个点不写清楚,上线后时间戳不动、中文变问号,查起来反而比重写还费劲。










