¿Puedo usar una función para un valor predeterminado en MySql?

93

Quiero hacer algo como esto:


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

Sin embargo, esto da como resultado un error, ¿hay alguna manera de llamar a una función para un valor predeterminado en mysql?

Gracias.

mmattax
fuente

Respuestas:

129

No, no puedes.

Sin embargo, puede crear fácilmente un disparador para hacer esto, como:

CREAR TRIGGER before_insert_app_users
  ANTES DE INSERTAR EN app_users 
  POR CADA FILA
  SET new.api_key = uuid ();
Harrison Fisk
fuente
2
@Ver stackoverflow.com/questions/6280789/… para completar los UUID en filas existentes.
Sam Barnum
2
Esto no es lo mismo que tener un valor DEFAULT. ¿Cómo cambiaría esta respuesta para establecer solo la clave si el valor fuera NULL?
ToolmakerSteve
1
Es triste que MySQL haya existido durante tanto tiempo, pero no puede implementar un UUID predeterminado para una columna sin un disparador. La razón de esto está incrustada en la tecnología de la década de 1980 que aparentemente todavía existe en el código base de MySQL (busque "no podemos tener cosas bonitas"): percona.com/blog/2013/04/08/…
RyanNerd
1
@RodolVelasco la función uuid está diseñada para ser altamente resistente a colisiones. Mucho más que md5. Tan pronto como md5 el uuid, tiene un mayor riesgo de colisión de identificación
Cruncher
2
SET new.api_key = COALESCE(new.api_key, uuid())para preservar los valores existentes.
Ryan
30

A partir de mysql v8.0.13 es posible usar una expresión como valor predeterminado para un campo:

El valor predeterminado especificado en una cláusula DEFAULT puede ser una constante literal o una expresión. Con una excepción, incluya los valores predeterminados de la expresión entre paréntesis para distinguirlos de los valores predeterminados constantes literales.

CREATE TABLE t1 (
  uuid_field     VARCHAR(32) DEFAULT (uuid()),
  binary_uuid    BINARY(16)  DEFAULT (UUID_TO_BIN(UUID()))
);
Sombra
fuente
1
Tenga en cuenta que según los documentos ya vinculados en la respuesta: ... las funciones almacenadas y las funciones definidas por el usuario no están permitidas . Es decir, las únicas funciones que se pueden utilizar como expresiones predeterminadas son las funciones integradas.
asherbar
2
A partir de mayo de 2020, esta debería ser la respuesta correcta. Las otras respuestas que utilizan desencadenantes son obsoletas.
John Stock
20

Como ya se dijo, no puede.

Si desea simular este comportamiento, puede usar un disparador de esta manera:

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;

Todavía tiene que actualizar filas previamente existentes, como esta:

UPDATE app_users SET uuid = (SELECT uuid());
Pamput
fuente
8

Desafortunadamente no, MySQL 5 requiere constantes por defecto. El tema se discutió con mucho más detalle en el enlace a continuación. Pero la única respuesta es permitir null y agregar un activador de tabla.

MySQL aceptó recientemente UUID como parte de su paquete de base de datos, y no es tan rico en funciones como nos gustaría.

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

TravisO
fuente
1
Debo agregar que permitir NULL y confiar en disparadores puede funcionar, pero la mayoría de los desarrolladores lo considerarían una solución muy pirateada. Yo personalmente no lo recomendaría, pero sí a cada uno.
TravisO
6

Creo que no puedes :

el valor predeterminado debe ser una constante; no puede ser una función o una expresión

Thibaut Barrère
fuente
No es cierto, puede usar getdate ()
amr osama
6
@amrosama - No, no puedes. getdate()ni siquiera es una función de MySQL. El enlace en la respuesta explica la única excepción: «puede especificar CURRENT_TIMESTAMP como predeterminado para una columna TIMESTAMP» .
Álvaro González
1
CURRENT_TIMESTAMP es la única "función" que se puede utilizar como valor predeterminado. Todo lo demás debe ser una constante (lamentablemente).
Troy Morehouse
3
Técnicamente, diría que AUTO_INCREMENT también puede verse como una "función" para establecer dinámicamente un valor predeterminado.
Rikaelus
1

Tenga en cuenta que los UUID()retornos de MySQL CHAR(36)y el almacenamiento de UUID como texto (como se muestra en las otras respuestas) es obviamente ineficiente. En su lugar, la columna debería ser BINARY(16), y puede usarla UUID_TO_BIN()al insertar datos y BIN_TO_UUID()al leerlos.

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;

Tenga en cuenta que, dado que MySQL no sabe realmente que se trata de un UUID, puede ser difícil solucionar problemas almacenados como binarios. Este artículo explica cómo crear una columna generada que convertirá el UUID en texto según sea necesario sin ocupar espacio ni preocuparse por mantener sincronizadas las versiones binarias y de texto separadas: https://mysqlserverteam.com/storing-uuid-values-in -mysql-tables /

StephenS
fuente
0

No estoy seguro de si las respuestas anteriores son para una versión anterior, pero vi en alguna parte que puede hacer esto usando la función unhex (). Lo probé y funciona. (maria db versión 10.2)

Tu puedes hacer

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

y funciona. Para ver el uuid simplemente haz hex (column_name).

ravindu1024
fuente
0

En MariaDB a partir de la versión 10.2.1 puedes. Consulte su documentación .

CREATE TABLE test ( uuid BINARY(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-','')) );
INSERT INTO test () VALUES ();
SELECT * FROM test;
ibotty
fuente