不能。default后只允许常量、null或确定性表达式,不支持运行时求值的系统函数;函数必须在create table的default子句中定义(如mysql支持now()、uuid()),insert时用default才生效,而非在values中调用。

DEFAULT 能不能直接调用 NOW()、UUID() 这类函数?
不能。SQL 标准里 DEFAULT 后面只允许常量、NULL 或确定性表达式(如 1 + 1),不支持运行时求值的系统函数。你写 INSERT INTO t (ts) VALUES (DEFAULT),哪怕列定义是 ts DATETIME DEFAULT NOW(),那也只是触发建表时的默认值逻辑,不是在 INSERT 里“调用”函数。
真正生效的时机是列定义本身 —— 函数必须写在 CREATE TABLE 的 DEFAULT 子句里,而不是 INSERT 语句里。
怎么让 INSERT 自动填入当前时间或 UUID?
关键在建表阶段把函数设为列默认值,之后 INSERT 时用 DEFAULT 才能生效:
- MySQL:支持
NOW()、UUID()、CURRENT_TIMESTAMP 等直接写进 DEFAULT
- PostgreSQL:支持
NOW()、gen_random_uuid()(需 pgcrypto),但必须加括号,写成 DEFAULT NOW()
- SQLite:只支持常量,默认值不能是函数(
datetime('now') 是特例,但属于字面量表达式,非通用函数调用)
- SQL Server:用
GETDATE() 或 NEWID(),但语法是 DEFAULT (GETDATE()),括号不能省
NOW()、UUID()、CURRENT_TIMESTAMP 等直接写进 DEFAULT
NOW()、gen_random_uuid()(需 pgcrypto),但必须加括号,写成 DEFAULT NOW()
datetime('now') 是特例,但属于字面量表达式,非通用函数调用)GETDATE() 或 NEWID(),但语法是 DEFAULT (GETDATE()),括号不能省示例(MySQL):
CREATE TABLE logs ( id INT PRIMARY KEY AUTO_INCREMENT, created_at DATETIME DEFAULT NOW(), trace_id VARCHAR(36) DEFAULT UUID() );
之后执行:INSERT INTO logs (id) VALUES (DEFAULT); —— created_at 和 trace_id 就会自动填充。
INSERT 时显式写函数和用 DEFAULT 有什么区别?
本质区别在于执行时机和权限控制:
- 显式写
INSERT INTO t (ts) VALUES (NOW()):函数在客户端或服务器端执行一次,结果传入;如果插入多行,每行都用同一个求值结果(除非函数本身每次调用返回不同值) - 用
DEFAULT:函数在每一行插入时由数据库引擎单独求值,多行插入时各取各的时间/UUID,更符合“每行独立默认”的语义 - 某些场景下,显式写函数可能绕过列级权限(比如用户没权限读某列,但能 INSERT 带值的行);而
DEFAULT受列定义约束,更安全
常见踩坑:DEFAULT 不生效的几个原因
最常遇到的不是语法错,而是隐性限制:
- MySQL 5.7+ 对
TIMESTAMP列的DEFAULT NOW()有特殊规则:只能有一个TIMESTAMP列能用CURRENT_TIMESTAMP类默认值,否则报错Invalid default value for 'xxx' - PostgreSQL 中,如果列定义是
DEFAULT NOW(),但 INSERT 写了DEFAULT却没生效,检查是否漏了括号 ——DEFAULT NOW(无括号)是错的,必须是DEFAULT NOW() - 试图在 INSERT 的
VALUES里写DEFAULT(NOW()):这是无效语法,DEFAULT是关键字,不是函数,不能套参数 - SQLite 中
DEFAULT datetime('now')可以,但DEFAULT strftime('%s','now')会报错 —— 它只认有限的内置时间函数字面量
默认值函数的执行上下文依赖数据库实现,跨库迁移时最容易在这里翻车。别指望一个建表语句在 MySQL 和 PostgreSQL 上都能直接跑通。











