官方文档地址: 11.6 Data Type Default Values
数据类型规范可以有显式或隐式的默认值。
数据类型规范中的DEFAULT value
子句显式指示列的默认值。例如:
CREATE TABLE t1 (
i INT DEFAULT -1,
c VARCHAR(10) DEFAULT '',
price DOUBLE(16,2) DEFAULT 0.00
);
SERIAL DEFAULT VALUE
是特殊情况。在整数列的定义中,它是NOT NULL AUTO_INCREMENT UNIQUE
的别名。
显式DEFAULT
子句处理的某些方面依赖于版本,如下所述。
MySQL 8.0.13 中的显式默认值处理
DEFAULT
子句中指定的默认值可以是文字常量或表达式。有一个例外,将表达式默认值括在括号内,以区别于文字常量默认值。例子:
CREATE TABLE t1 (
-- 常量默认值
i INT DEFAULT 0,
c VARCHAR(10) DEFAULT '',
-- 表达式默认值
f FLOAT DEFAULT (RAND() * RAND()),
b BINARY(16) DEFAULT (UUID_TO_BIN(UUID())),
d DATE DEFAULT (CURRENT_DATE + INTERVAL 1 YEAR),
p POINT DEFAULT (Point(0,0)),
j JSON DEFAULT (JSON_ARRAY())
);
例外的是,对于TIMESTAMP
和DATETIME
列,可以指定CURRENT_TIMESTAMP
函数作为默认值,不使用括号。参见 11.2.5 TIMESTAMP 和 DATETIME 的自动初始化和更新。
BLOB
、TEXT
、GEOMETRY
和JSON
数据类型只能在默认值被写成表达式时才有效,即使表达式值是一个文字值:
- 这是允许的(默认字面量指定为表达式):
CREATE TABLE t2 (b BLOB DEFAULT ('abc'));
- 这会产生一个错误(默认字面量未指定为表达式):
CREATE TABLE t2 (b BLOB DEFAULT 'abc');
表达式默认值必须遵循以下规则。如果表达式包含不允许的构造,则会发生错误。
- 允许使用文字值、内置函数(确定性和非确定性的)和操作符。
- 子查询,参数,变量,存储功能,用户自定义函数是不允许的。
- 表达式默认值不能依赖于具有
AUTO_INCREMENT
属性的列。 - 一个列的表达式默认值可以引用表中的其他列,但表达式默认值引用的列必须是表定义中较早出现的列。也就是说,表达式默认值不能包含对生成的列或具有表达式默认值的列的前向引用。
排序约束也适用于使用ALTER TABLE
对表列重新排序。如果生成的表具有一个表达式默认值,该值包含对生成的列的正向引用,或者包含一个表达式默认值的列,则该语句将失败。
注意
如果表达式默认值的任何组件依赖于 SQL 模式,那么对表的不同使用可能会产生不同的结果,除非在所有使用过程中 SQL 模式是相同的。
对于CREATE TABLE ... LIKE
和CREATE TABLE ... SELECT
,目标表保留原始表的表达式默认值。
如果表达式的默认值引用了一个不确定的函数,那么任何导致计算表达式的语句对于基于语句的复制都是不安全的。这包括INSERT
和UPDATE
语句。在这种情况下,如果禁用了二进制日志记录,则会正常执行语句。如果启用了二进制日志记录,并将binlog_format
设置为STATEMENT
,则会记录并执行该语句,但会在错误日志中写入一条警告消息,因为复制从程序可能会产生分歧。当binlog_format
设置为MIXED
或ROW
时,语句将正常执行。
当插入一个新的行时,带有表达式默认值列的可以通过省略列名或指定列为DEFAULT
来插入(就像带有文字默认值的列一样):
mysql> CREATE TABLE t4 (uid BINARY(16) DEFAULT (UUID_TO_BIN(UUID())));
mysql> INSERT INTO t4 () VALUES();
mysql> INSERT INTO t4 () VALUES(DEFAULT);
mysql> SELECT BIN_TO_UUID(uid) AS uid FROM t4;
+--------------------------------------+
| uid |
+--------------------------------------+
| f1109174-94c9-11e8-971d-3bf1095aa633 |
| f110cf9a-94c9-11e8-971d-3bf1095aa633 |
+--------------------------------------+
但是,使用DEFAULT(col_name)
来指定列的默认值,允许使用具有文字默认值的列,不允许使用表达式默认值的列。
并不是所有的存储引擎都允许表达式默认值。如果没有,则会出现ER_UNSUPPORTED_ACTION_ON_DEFAULT_VAL_GENERATED
错误。
如果一个默认值计算的数据类型与声明的列类型不同,那么根据通常的 MySQL 类型转换规则,将隐式强制转换为声明的类型。参见 12.3 表达式求值中的类型转换。
MySQL 8.0.13 之前显式默认值处理
有一个例外,DEFAULT
子句中指定的默认值必须是文字常量;它不能是函数或表达式。例如,这意味着不能将日期列的默认值设置为NOW()
或CURRENT_DATE
等函数的值。例外的是,对于TIMESTAMP
和DATETIME
列,您可以指定CURRENT_TIMESTAMP
作为默认值。参见 11.2.5 TIMESTAMP 和 DATETIME 的自动初始化和更新。
不能为BLOB
、TEXT
、GEOMETRY
和JSON
数据类型分配默认值。
如果一个默认值计算的数据类型与声明的列类型不同,那么根据通常的 MySQL 类型转换规则,将隐式强制转换为声明的类型。参见 12.3 表达式求值中的类型转换。
隐式默认值处理
如果数据类型规范中没有明确的默认值,MySQL 会按照如下方式确定默认值:
如果该列可以接受NULL
作为值,则使用显式DEFAULT NULL
子句定义该列。
如果该列不能以NULL
作为值,MySQL 将没有明确的DEFAULT
子句来定义该列。
对于没有显式DEFAULT
子句的NOT NULL
列中的数据输入,如果INSERT
或REPLACE
语句不包含该列的值,或者UPDATE
语句将该列设置为NULL
,MySQL 根据当时的 SQL 模式处理列:
- 如果启用了严格的 SQL 模式,那么事务性表将出现错误,语句将回滚。对于非事务性表,会发生错误,但如果是多行语句的第二行或后续行发生错误,则会插入前面的行。
- 如果没有启用严格 SQL 模式,MySQL 将列设置为列数据类型的默认隐式值。
假设表t
的定义如下:
CREATE TABLE t (i INT NOT NULL);
在本例中,i
没有显式默认值,因此在严格模式下,下面的每个语句都会产生一个错误,并且没有插入任何行。当不使用严格模式时,只有第三个语句产生错误;前两个语句插入了隐式的默认值,但第三个语句失败,因为DEFAULT(i)
不能产生值:
INSERT INTO t VALUES();
INSERT INTO t VALUES(DEFAULT);
INSERT INTO t VALUES(DEFAULT(i));
对于给定的表,SHOW CREATE TABLE
语句显示哪些列具有显式的DEFAULT
子句。
隐式默认值的定义如下:
- 对于数值类型,默认值是
0
,但是对于用AUTO_INCREMENT
属性声明的整数或浮点类型,默认值是序列中的下一个值。 - 对于
TIMESTAMP
以外的日期和时间类型,默认值是该类型的适当“零”值。如果启用了explicit_defaults_for_timestamp
系统变量,那么对于TIMESTAMP
也是如此(参见 5.1.8 Server System Variables)。否则,对于表中的第一个TIMESTAMP
列,默认值是当前日期和时间。参见 11.2 日期和时间数据类型。 - 对于
ENUM
以外的字符串类型,默认值为空字符串。对于ENUM
,默认值是第一个枚举值。