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.

mmattax
fonte

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 ();
Harrison Fisk
fonte
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()))
);
Sombra
fonte
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());
Pamput
fonte
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

TravisO
fonte
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

Thibaut Barrère
fonte
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 /

StephenS
fonte
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).

ravindu1024
fonte
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;
ibotty
fonte