Dapatkah saya menggunakan fungsi untuk nilai default di MySql?

95

Saya ingin melakukan sesuatu seperti ini:


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

Namun ini menghasilkan kesalahan, apakah ada cara untuk memanggil fungsi untuk nilai default di mysql?

Terima kasih.

mmattax
sumber

Jawaban:

130

Tidak, tidak boleh.

Namun, Anda dapat dengan mudah membuat pemicu untuk melakukan ini, seperti:

BUAT PEMICU before_insert_app_users
  SEBELUM SISIPKAN app_users 
  UNTUK SETIAP BARIS
  SET new.api_key = uuid ();
Harrison Fisk
sumber
2
@ Lihat stackoverflow.com/questions/6280789/… untuk mengisi UUID di baris yang ada.
Sam Barnum
2
Ini tidak sama dengan memiliki nilai DEFAULT. Bagaimana seseorang mengubah jawaban ini untuk hanya menyetel kunci jika nilainya adalah NULL?
ToolmakerSteve
1
Sayangnya MySQL telah ada selama itu tetapi Anda tidak dapat menerapkan UUID default untuk kolom tanpa pemicu. Alasannya adalah karena teknologi 1980-an yang tampaknya masih ada di kode dasar MySQL (cari "kami tidak bisa memiliki hal-hal yang baik"): percona.com/blog/2013/04/08/…
RyanNerd
1
@RodolVelasco, fungsi uuid dibuat agar sangat tahan benturan. Lebih dari md5. Segera setelah Anda md5 uuid Anda memiliki risiko benturan id yang lebih tinggi
Cruncher
2
SET new.api_key = COALESCE(new.api_key, uuid())untuk melestarikan nilai-nilai yang ada.
Ryan
33

Pada mysql v8.0.13 dimungkinkan untuk menggunakan ekspresi sebagai nilai default untuk bidang:

Nilai default yang ditentukan dalam klausa DEFAULT dapat berupa konstanta literal atau ekspresi. Dengan satu pengecualian, apit nilai default ekspresi dalam tanda kurung untuk membedakannya dari nilai default konstanta literal.

CREATE TABLE t1 (
  uuid_field     VARCHAR(32) DEFAULT (uuid()),
  binary_uuid    BINARY(16)  DEFAULT (UUID_TO_BIN(UUID()))
);
Bayangan
sumber
2
Perhatikan bahwa sesuai dengan dokumen yang sudah ditautkan dalam jawaban: ... fungsi yang disimpan, dan fungsi yang ditentukan pengguna tidak diizinkan . Yaitu, satu-satunya fungsi yang dapat digunakan sebagai ekspresi default adalah fungsi bawaan.
asherbar
2
Mulai Mei 2020 ini harus menjadi jawaban yang benar. Jawaban lain yang menggunakan pemicu sudah usang.
John Stock
detail kecil: varchar(32)harusvarchar(36)
Jared Beck
@ JaredBeck Saya pikir 32 baik-baik saja jika Anda tidak menyimpan tanda hubung.
Alvin Thompson
@JohnStock Metode ini tidak mengizinkan penggunaan fungsi yang ditetapkan pengguna atau disimpan sehingga mungkin agak terlalu dini untuk menyatakan penggunaan pemicu sudah usang.
Alvin Thompson
21

Seperti yang sudah disebutkan, Anda tidak bisa.

Jika Anda ingin menyimulasikan perilaku ini, Anda dapat menggunakan pemicu dengan cara ini:

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;

Anda masih harus memperbarui baris yang ada sebelumnya, seperti ini:

UPDATE app_users SET uuid = (SELECT uuid());
Pamput
sumber
9

Sayangnya tidak, MySQL 5 membutuhkan konstanta sebagai default. Masalah ini dibahas lebih rinci dalam tautan di bawah ini. Tetapi satu-satunya jawaban adalah mengizinkan null dan menambahkan pemicu tabel.

MySQL baru-baru ini menerima UUID sebagai bagian dari paket DB mereka, dan itu tidak sekaya fitur yang kami inginkan.

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

TravisO
sumber
1
Saya harus menambahkan bahwa mengizinkan NULL dan mengandalkan pemicu dapat berfungsi, tetapi sebagian besar pengembang akan menganggapnya sebagai solusi yang sangat hack-y. Saya secara pribadi tidak akan merekomendasikannya tetapi untuk masing-masing mereka sendiri.
TravisO
7

Saya yakin Anda tidak bisa :

nilai default harus berupa konstanta; itu tidak bisa menjadi fungsi atau ekspresi

Thibaut Barrère
sumber
Tidak benar, Anda dapat menggunakan getdate ()
amr osama
6
@amrosama - Tidak, Anda tidak bisa. getdate()bahkan bukan fungsi MySQL. Tautan di jawaban menjelaskan satu-satunya pengecualian: «Anda dapat menentukan CURRENT_TIMESTAMP sebagai default untuk kolom TIMESTAMP» .
Álvaro González
1
CURRENT_TIMESTAMP adalah satu-satunya "fungsi" yang dapat digunakan sebagai nilai default. Segala sesuatu yang lain harus konstan (sayangnya).
Troy Morehouse
3
Secara teknis, saya akan mengatakan AUTO_INCREMENT juga dapat dilihat sebagai "fungsi" untuk menetapkan nilai default secara dinamis.
Rikaelus
1

Perhatikan bahwa UUID()pengembalian MySQL CHAR(36), dan menyimpan UUID sebagai teks (seperti yang ditunjukkan pada jawaban lain) jelas tidak efisien. Sebagai gantinya, kolomnya harus BINARY(16), dan Anda dapat menggunakan UUID_TO_BIN()saat memasukkan data dan BIN_TO_UUID()saat membacanya kembali.

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;

Perhatikan bahwa karena MySQL tidak benar-benar tahu bahwa ini adalah UUID, mungkin sulit untuk memecahkan masalah jika disimpan sebagai biner. Artikel ini menjelaskan cara membuat kolom yang dihasilkan yang akan mengubah UUID menjadi teks sesuai kebutuhan tanpa menghabiskan ruang apa pun atau mengkhawatirkan sinkronisasi versi biner dan teks: https://mysqlserverteam.com/storing-uuid-values-in -mysql-tables /

StephenS
sumber
0

Saya tidak yakin apakah jawaban di atas adalah untuk versi yang lebih lama, tetapi saya melihat di suatu tempat Anda dapat melakukan ini menggunakan fungsi unhex (). Saya mencobanya dan berhasil. (maria db versi 10.2)

Anda dapat melakukan

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

dan berhasil. Untuk melihat uuid cukup lakukan hex (nama_kolom).

ravindu1024
sumber
0

Di MariaDB mulai dari versi 10.2.1 Anda bisa. Lihat dokumentasinya .

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