Posso usar uma função para um valor padrão no MySql?


93

Eu quero fazer algo assim:


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

No entanto, isso resulta em um erro, há uma maneira de chamar uma função para um valor padrão no mysql?

obrigado.

Respostas:


129

Não, você não pode.

No entanto, você pode facilmente criar um gatilho para fazer isso, como:

CRIAR TRIGGER before_insert_app_users
  ANTES DE INSERIR EM app_users 
  PARA CADA LINHA
  SET new.api_key = uuid ();

2
@See stackoverflow.com/questions/6280789/… para preencher UUIDs em linhas existentes.
— Sam Barnum

2
Isso não é exatamente o mesmo que ter um valor DEFAULT. Como alguém mudaria essa resposta para definir apenas a chave se o valor fosse NULL?
— Toolmaker Steve

1
É triste saber que o MySQL existe há tanto tempo, mas você não pode implementar um UUID padrão para uma coluna sem um gatilho. A razão para isso está embutida na tecnologia dos anos 80 que aparentemente ainda existe no código base do MySQL (pesquise "não podemos ter coisas boas"): percona.com/blog/2013/04/08/…
— RyanNerd

1
@RodolVelasco a função uuid foi construída para ser altamente resistente a colisões. Muito mais do que o MD5. Assim que você md5 o uuid, você tem um risco maior de colisão de id
— Cruncher

2
SET new.api_key = COALESCE(new.api_key, uuid())para preservar os valores existentes.
— Ryan

29

A partir do mysql v8.0.13 , é possível usar uma expressão como valor padrão para um campo:

O valor padrão especificado em uma cláusula DEFAULT pode ser uma constante literal ou uma expressão. Com uma exceção, coloque os valores padrão da expressão entre parênteses para distingui-los dos valores padrão constantes literais.

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

1
Observe que de acordo com os documentos já vinculados na resposta: ... funções armazenadas e funções definidas pelo usuário não são permitidas . Ou seja, as únicas funções que podem ser usadas como expressões padrão são funções internas.
— asherbar

2
Em maio de 2020, essa deveria ser a resposta correta. As outras respostas que usam gatilhos são obsoletas.
— John Stock

20

Como já foi dito, você não pode.

Se você deseja simular esse comportamento, pode usar um gatilho desta forma:

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;

Você ainda precisa atualizar as linhas existentes anteriormente, como este:

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

8

Infelizmente não, o MySQL 5 requer constantes para o padrão. O assunto foi discutido com muito mais detalhes no link abaixo. Mas a única resposta é permitir null e adicionar um gatilho de tabela.

O MySQL só recentemente aceitou UUID como parte de seu pacote de banco de dados e não é tão rico em recursos quanto gostaríamos.

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


1
Devo acrescentar que permitir NULL e confiar em gatilhos pode funcionar, mas a maioria dos desenvolvedores consideraria uma solução muito hack-y. Eu não recomendaria pessoalmente, mas para cada um.
— TravisO

6

Eu acredito que você não pode :

o valor padrão deve ser uma constante; não pode ser uma função ou uma expressão


Não é verdade, você pode usar getdate ()
— amr osama

6
@amrosama - Não, você não pode. getdate()não é nem mesmo uma função MySQL. O link na resposta explica a única exceção: «você pode especificar CURRENT_TIMESTAMP como o padrão para uma coluna TIMESTAMP» .
— Álvaro González

1
CURRENT_TIMESTAMP é a única "função" que pode ser usada como um valor padrão. Todo o resto deve ser uma constante (infelizmente).
— Troy Morehouse de

3
Tecnicamente, eu diria que AUTO_INCREMENT também pode ser visto como uma "função" para definir dinamicamente um valor padrão.
— Rikaelus

1

Observe que os UUID()retornos do MySQL CHAR(36)e o armazenamento de UUIDs como texto (como mostrado nas outras respostas) é obviamente ineficiente. Em vez disso, a coluna deve ser BINARY(16)e você pode usar UUID_TO_BIN()ao inserir dados e BIN_TO_UUID()ao lê-los de volta.

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;

Observe que, uma vez que o MySQL não sabe realmente que este é um UUID, pode ser difícil solucionar problemas com ele armazenado como binário. Este artigo explica como criar uma coluna gerada que converterá o UUID em texto conforme necessário, sem ocupar qualquer espaço ou se preocupar em manter versões binárias e de texto separadas em sincronia: https://mysqlserverteam.com/storing-uuid-values-in -mysql-tables /


0

Não tenho certeza se as respostas acima são para uma versão mais antiga, mas vi em algum lugar que você pode fazer isso usando a função unhex (). Eu tentei e funciona. (maria db versão 10.2)

Você pode fazer

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

e funciona. Para ver o uuid apenas faça hex (column_name).


0

No MariaDB a partir da versão 10.2.1 você pode. Veja sua documentação .

CREATE TABLE test ( uuid BINARY(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-','')) );
INSERT INTO test () VALUES ();
SELECT * FROM test;
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.