我可以在MySql中使用函数作为默认值吗?


93

我想做这样的事情:


create table app_users
(
    app_user_id smallint(6) not null auto_increment primary key,
    api_key     char(36) not null default uuid()
);

但是,这会导致错误,是否可以在mysql中为默认值调用函数?

谢谢。

Answers:


129

不,你不能。

但是,您可以轻松创建触发器来执行此操作,例如:

创建触发器before_insert_app_users
  在app_users上插入之前 
  每行
  SET new.api_key = uuid();

2
@ 有关填充现有行中的UUID的信息,请参见stackoverflow.com/questions/6280789/…
Sam Barnum

2
这与具有DEFAULT值并不完全相同。如果值是NULL,如何将这个答案更改为仅设置键?
ToolmakerSteve

1
令人遗憾的是,MySQL已经存在了很长时间,但是如果没有触发器,您将无法为列实现默认的UUID。这样做的原因是嵌入在1980年的技术,显然还是在MySQL基础代码存在(搜索“我们不能有好东西”):percona.com/blog/2013/04/08/...
RyanNerd

1
@RodolVelasco uuid函数具有很高的抗碰撞性。比md5多得多。一旦您使用md5 uuid,您就有更高的ID冲突风险
Cruncher

2
SET new.api_key = COALESCE(new.api_key, uuid())保留现有价值。
瑞安

28

mysql v8.0.13开始,可以使用表达式作为字段的默认值:

DEFAULT子句中指定的默认值可以是文字常量或表达式。除一个例外,将表达式默认值放在括号内,以将其与文字常量默认值区分开。

CREATE TABLE t1 (
  uuid_field     VARCHAR(32) DEFAULT (uuid()),
  binary_uuid    BINARY(16)  DEFAULT (UUID_TO_BIN(UUID()))
);

1
请注意,根据答案中已链接的文档:...不允许使用存储的函数和用户定义的函数。即,唯一可用作默认表达式的函数是内置函数。
asherbar

1
截至2020年5月,这应该是正确的答案。使用触发器的其他答案已过时。
约翰·

20

如前所述,您不能。

如果要模拟此行为,可以按以下方式使用触发器:

CREATE TRIGGER before_insert_app_users
BEFORE INSERT ON app_users
FOR EACH ROW
  IF new.uuid IS NULL
  THEN
    SET new.uuid = uuid();
  END IF;

您仍然必须更新以前存在的行,如下所示:

UPDATE app_users SET uuid = (SELECT uuid());

8

不幸的是,MySQL 5要求使用常量作为默认值。在下面的链接中对该问题进行了更详细的讨论。但是唯一的答案是允许null并添加表触发器。

MySQL直到最近才将UUID作为其数据库包的一部分接受,并且它没有我们想要的功能丰富。

http://www.phpbuilder.com/board/showthread.php?t=10349169


1
我应该补充一点,允许NULL并依赖触发器可能会起作用,但是大多数开发人员会认为这是一个非常hack-y的解决方案。我个人不会推荐它,但要各自推荐。
TravisO 2013年

6

我相信你不能

默认值必须为常数;它不能是函数或表达式


不正确,您可以使用getdate()
amr osama 2012年

6
@amrosama-不,你不能。getdate()甚至不是MySQL函数。答案中的链接解释了唯一的例外:«您可以将CURRENT_TIMESTAMP指定为TIMESTAMP列的默认值»
阿尔瓦罗·冈萨雷斯

1
CURRENT_TIMESTAMP是唯一可用作默认值的“函数”。其他所有内容都必须是一个常量(不幸的是)。
Troy Morehouse 2015年

3
从技术上讲,我也可以将AUTO_INCREMENT视为动态设置默认值的“功能”。
Rikaelus

1

需要注意的是MySQL的UUID()回报CHAR(36),和存储的UUID为文本(在其他的答案如图所示)显然是低效的。相反,该列应为BINARY(16),您可以UUID_TO_BIN()在插入数据和BIN_TO_UUID()读回数据时使用。

CREATE TABLE app_users
(
    app_user_id SMALLINT(6) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    api_key     BINARY(16)
);

CREATE TRIGGER before_insert_app_users
BEFORE INSERT ON app_users
FOR EACH ROW
  IF new.api_key IS NULL
  THEN
    SET new.api_key = UUID_TO_BIN(UUID());
  END IF;

请注意,由于MySQL并不真正知道这是UUID,因此很难以二进制形式存储它的问题。本文介绍了如何创建一个生成的列,该列将根据需要将UUID转换为文本,而又不占用任何空间或担心保持单独的二进制和文本版本同步:https : //mysqlserverteam.com/storing-uuid-values-in -mysql表/


0

我不确定以上答案是否适用于较旧版本,但我发现可以使用unhex()函数执行此操作。我试过了,它有效。(Maria DB版本10.2)

你可以做

.... column_name binary(16) not null default unhex(replace(uuid(),'-',''))   

而且有效。要查看uuid,只需执行hex(column_name)。


0

在10.2.1版本开始的MariaDB中,可以。请参阅其文档

CREATE TABLE test ( uuid BINARY(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-','')) );
INSERT INTO test () VALUES ();
SELECT * FROM test;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.