Czy mogę użyć funkcji dla wartości domyślnej w MySql?

95

Chcę zrobić coś takiego:


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

Jednak powoduje to błąd, czy istnieje sposób na wywołanie funkcji dla wartości domyślnej w mysql?

dzięki.

mmattax
źródło

Odpowiedzi:

130

Nie, nie możesz.

Możesz jednak łatwo utworzyć wyzwalacz, aby to zrobić, na przykład:

UTWÓRZ TRIGGER before_insert_app_users
  PRZED WSTAWIENIEM NA app_users 
  DLA KAŻDEGO RZĘDU
  SET new.api_key = uuid ();
Harrison Fisk
źródło
2
@ Zobacz stackoverflow.com/questions/6280789/ ... aby wypełnić identyfikatory UUID w istniejących wierszach.
Sam Barnum
2
To nie to samo, co posiadanie wartości DEFAULT. Jak można zmienić tę odpowiedź, aby ustawić klucz tylko wtedy, gdy wartość była równa NULL?
ToolmakerSteve
1
Smutne, że MySQL istnieje tak długo, jak ma, ale nie można zaimplementować domyślnego UUID dla kolumny bez wyzwalacza. Przyczyna tego tkwi w technologii lat 80-tych, która najwyraźniej nadal istnieje w kodzie bazowym MySQL (wyszukaj „nie możemy mieć fajnych rzeczy”): percona.com/blog/2013/04/08/…
RyanNerd
1
@RodolVelasco funkcja płynów jest zbudowana tak, aby była wysoce odporna na kolizje. Znacznie bardziej niż md5. Jak tylko md5 uuid, masz większe ryzyko kolizji identyfikatorów
Cruncher
2
SET new.api_key = COALESCE(new.api_key, uuid())aby zachować istniejące wartości.
Ryan
33

Od mysql v8.0.13 możliwe jest użycie wyrażenia jako wartości domyślnej dla pola:

Wartość domyślna określona w klauzuli DEFAULT może być stałą literalną lub wyrażeniem. Z jednym wyjątkiem wartości domyślne wyrażeń należy umieścić w nawiasach, aby odróżnić je od wartości domyślnych stałych literalnych.

CREATE TABLE t1 (
  uuid_field     VARCHAR(32) DEFAULT (uuid()),
  binary_uuid    BINARY(16)  DEFAULT (UUID_TO_BIN(UUID()))
);
Cień
źródło
2
Zauważ, że zgodnie z już połączonymi dokumentami w odpowiedzi: ... funkcje przechowywane i funkcje zdefiniowane przez użytkownika są niedozwolone . To znaczy, jedynymi funkcjami, których można używać jako domyślnych wyrażeń, są funkcje wbudowane.
asherbar
2
Od maja 2020 r. Powinna to być prawidłowa odpowiedź. Inne odpowiedzi wykorzystujące wyzwalacze są przestarzałe.
John Stock
drobny szczegół: varchar(32)powinien byćvarchar(36)
Jared Beck
@JaredBeck Myślę, że 32 jest w porządku, jeśli nie przechowujesz myślników.
Alvin Thompson
@JohnStock Ta metoda nie pozwala na korzystanie z funkcji zdefiniowanych przez użytkownika lub przechowywanych w pamięci, więc uznanie używania wyzwalaczy za przestarzałe może być nieco przedwczesne.
Alvin Thompson
21

Jak już wspomniano, nie możesz.

Jeśli chcesz zasymulować takie zachowanie, możesz użyć wyzwalacza w następujący sposób:

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;

Nadal musisz zaktualizować wcześniej istniejące wiersze, na przykład:

UPDATE app_users SET uuid = (SELECT uuid());
Pamput
źródło
9

Niestety nie, MySQL 5 domyślnie wymaga stałych. O wiele bardziej szczegółowo zagadnienie zostało omówione w linku poniżej. Ale jedyną odpowiedzią jest zezwolenie na null i dodanie wyzwalacza tabeli.

MySQL dopiero niedawno zaakceptował UUID jako część swojego pakietu DB i nie jest tak bogaty w funkcje, jak byśmy chcieli.

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

TravisO
źródło
1
Powinienem dodać, że zezwolenie na NULL i poleganie na wyzwalaczach może działać, ale większość programistów uznałaby to za bardzo hakerskie rozwiązanie. Nie polecałbym tego osobiście, ale każdemu osobiście.
TravisO
7

Myślę, że nie możesz :

wartość domyślna musi być stała; nie może być funkcją ani wyrażeniem

Thibaut Barrère
źródło
Nieprawda, możesz użyć getdate ()
amr osama
6
@amrosama - Nie, nie możesz. getdate()nie jest nawet funkcją MySQL. Link w odpowiedzi wyjaśnia jedyny wyjątek: «możesz określić CURRENT_TIMESTAMP jako wartość domyślną dla kolumny TIMESTAMP» .
Álvaro González
1
CURRENT_TIMESTAMP to jedyna „funkcja”, której można użyć jako wartości domyślnej. Wszystko inne musi być stałe (niestety).
Troy Morehouse
3
Technicznie rzecz biorąc, powiedziałbym, że AUTO_INCREMENT może być również postrzegane jako „funkcja” do dynamicznego ustawiania wartości domyślnej.
Rikaelus
1

Zwróć uwagę, że UUID()zwroty MySQL CHAR(36)i przechowywanie identyfikatorów UUID w postaci tekstu (jak pokazano w innych odpowiedziach) jest oczywiście nieefektywne. Zamiast tego kolumna powinna być BINARY(16)i możesz jej użyć UUID_TO_BIN()podczas wstawiania danych i BIN_TO_UUID()podczas ich ponownego odczytu.

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;

Zwróć uwagę, że ponieważ MySQL tak naprawdę nie wie, że jest to identyfikator UUID, może być trudno rozwiązać problemy z nim przechowywane jako binarne. W tym artykule wyjaśniono, jak utworzyć wygenerowaną kolumnę, która w razie potrzeby przekonwertuje identyfikator UUID na tekst bez zajmowania miejsca lub martwienia się o synchronizację oddzielnych wersji binarnych i tekstowych: https://mysqlserverteam.com/storing-uuid-values-in -mysql-tabele /

StephenS
źródło
0

Nie jestem pewien, czy powyższe odpowiedzi dotyczą starszej wersji, ale widziałem gdzieś, że możesz to zrobić za pomocą funkcji unhex (). Spróbowałem i działa. (maria db wersja 10.2)

Możesz to zrobić

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

i to działa. Aby zobaczyć identyfikator UUID, po prostu wykonaj hex (nazwa_kolumny).

ravindu1024
źródło
0

W MariaDB począwszy od wersji 10.2.1 możesz. Zobacz jego dokumentację .

CREATE TABLE test ( uuid BINARY(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-','')) );
INSERT INTO test () VALUES ();
SELECT * FROM test;
ibotty
źródło