数据类型规范可以具有显式或隐式默认值。
数据类型规范中的 DEFAULT
子句明确地指示了列的默认值。示例:值
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
子句处理的方面取决于版本,如下所述。
在 DEFAULT
子句中指定的默认值可以是一个文字常量或一个表达式。除了一个例外,enclose 表达式默认值在括号中,以区别于文字常量默认值。示例:
CREATE TABLE t1 (
-- literal defaults
i INT DEFAULT 0,
c VARCHAR(10) DEFAULT '',
-- expression defaults
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
函数作为默认值,不需要括号。见 第 13.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
,则语句将被记录和执行,但错误日志中将写入警告消息,因为副本可能会 diverge。当 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 通常的类型转换规则隐式强制转换为声明的类型。请参阅第 14.3 节,“表达式评估中的类型转换”。
如果数据类型规范不包括明确的 DEFAULT
值,MySQL 将根据以下方式确定默认值:
如果列可以取 NULL
作为值,则该列将被定义为具有明确的 DEFAULT NULL
子句。
如果列不能取 NULL
作为值,MySQL 将该列定义为没有明确的 DEFAULT
子句。
对于不能取 NULL
的列,如果 INSERT
或 REPLACE
语句中没有为该列指定值,或者 UPDATE
语句将该列设置为 NULL
,MySQL 将根据当前的 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
),默认值是该类型的适当的 “零” 值。这也是TIMESTAMP
的情况,如果启用了explicit_defaults_for_timestamp
系统变量(见 第 7.1.8 节,“服务器系统变量”)。否则,对于表中的第一个TIMESTAMP
列,默认值是当前日期和时间。见 第 13.2 节,“日期和时间数据类型”。