ฉันสามารถใช้ฟังก์ชันสำหรับค่าเริ่มต้นใน MySql ได้หรือไม่


95

ฉันต้องการทำสิ่งนี้:


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

อย่างไรก็ตามสิ่งนี้ทำให้เกิดข้อผิดพลาดมีวิธีเรียกใช้ฟังก์ชันสำหรับค่าเริ่มต้นใน mysql หรือไม่?

ขอบคุณ.

คำตอบ:


130

ไม่คุณทำไม่ได้

อย่างไรก็ตามคุณสามารถสร้างทริกเกอร์เพื่อทำสิ่งนี้ได้อย่างง่ายดายเช่น:

สร้าง TRIGGER before_insert_app_users
  ก่อนใส่ใน app_users 
  สำหรับแต่ละแถว
  ตั้งค่า new.api_key = uuid ();

2
@ ดูstackoverflow.com/questions/6280789/…สำหรับการเติมข้อมูล UUID ในแถวที่มีอยู่
Sam Barnum

2
สิ่งนี้ไม่เหมือนกับการมีค่า DEFAULT จะเปลี่ยนคำตอบนี้ได้อย่างไรเพื่อตั้งค่าคีย์หากค่าเป็น NULL
ToolmakerSteve

1
น่าเศร้าที่ MySQL มีมานานแล้ว แต่คุณไม่สามารถใช้ UUID เริ่มต้นสำหรับคอลัมน์โดยไม่มีทริกเกอร์ได้ เหตุผลนี้ฝังอยู่ในเทคโนโลยีของปี 1980 ซึ่งเห็นได้ชัดว่ายังคงมีอยู่ในรหัสฐานของ MySQL (ค้นหาคำว่า "เราไม่มีของดี"): percona.com/blog/2013/04/08/…
RyanNerd

1
@RodolVelasco ฟังก์ชัน uuid ถูกสร้างขึ้นเพื่อให้ทนต่อการชนได้ดี มากกว่า md5 ทันทีที่คุณ md5 uuid คุณมีความเสี่ยงสูงที่จะเกิดการชนกันของ id
Cruncher

2
SET new.api_key = COALESCE(new.api_key, uuid())เพื่อรักษาคุณค่าที่มีอยู่
Ryan

33

ในmysql v8.0.13คุณสามารถใช้นิพจน์เป็นค่าเริ่มต้นสำหรับฟิลด์:

ค่าดีฟอลต์ที่ระบุในส่วนคำสั่ง DEFAULT อาจเป็นค่าคงที่ตามตัวอักษรหรือนิพจน์ ด้วยข้อยกเว้นเดียวให้ใส่ค่าดีฟอลต์ของนิพจน์ภายในวงเล็บเพื่อแยกความแตกต่างจากค่าดีฟอลต์คงที่ตามตัวอักษร

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

2
โปรดทราบว่าตามเอกสารที่เชื่อมโยงอยู่แล้วในคำตอบ: ... ฟังก์ชั่นการจัดเก็บและฟังก์ชั่นที่ผู้ใช้กำหนดไม่ได้รับอนุญาต กล่าวคือฟังก์ชันเดียวที่สามารถใช้เป็นนิพจน์เริ่มต้นคือฟังก์ชันในตัว
asherbar

2
ในเดือนพฤษภาคม 2020 นี่น่าจะเป็นคำตอบที่ถูกต้อง คำตอบอื่น ๆ ที่ใช้ทริกเกอร์นั้นล้าสมัย
John Stock

รายละเอียดเล็กน้อย: varchar(32)ควรจะเป็นvarchar(36)
Jared Beck

@JaredBeck ฉันคิดว่า 32 ก็ดีถ้าคุณไม่เก็บเครื่องหมายขีดกลาง
Alvin Thompson

@JohnStock วิธีนี้ไม่อนุญาตให้ใช้ฟังก์ชันที่ผู้ใช้กำหนดเองหรือจัดเก็บไว้ดังนั้นจึงอาจใช้เวลาก่อนกำหนดเล็กน้อยที่จะประกาศว่าการใช้ทริกเกอร์ล้าสมัย
Alvin Thompson

21

ตามที่ระบุไว้แล้วคุณทำไม่ได้

หากคุณต้องการจำลองพฤติกรรมนี้คุณสามารถใช้ทริกเกอร์ด้วยวิธีนี้:

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;

คุณยังคงต้องอัปเดตแถวที่มีอยู่ก่อนหน้านี้ดังนี้:

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

9

ไม่น่าเสียดายที่ MySQL 5 ต้องการค่าคงที่สำหรับค่าเริ่มต้น ปัญหานี้ได้รับการกล่าวถึงในรายละเอียดเพิ่มเติมในลิงก์ด้านล่าง แต่คำตอบเดียวคืออนุญาตให้ว่างและเพิ่มทริกเกอร์ตาราง

MySQL เพิ่งยอมรับ UUID เป็นส่วนหนึ่งของแพ็คเกจ DB ของพวกเขาและมันไม่ได้มีคุณสมบัติมากมายอย่างที่เราต้องการ

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


1
ฉันควรเพิ่มว่าการอนุญาต NULL และการอาศัยทริกเกอร์อาจใช้งานได้ แต่นักพัฒนาส่วนใหญ่คิดว่าเป็นโซลูชันแฮ็ก y ฉันจะไม่แนะนำเป็นการส่วนตัว แต่สำหรับแต่ละคน
TravisO

7

ฉันเชื่อว่าคุณทำไม่ได้ :

ค่าเริ่มต้นต้องเป็นค่าคงที่ ไม่สามารถเป็นฟังก์ชันหรือนิพจน์ได้


ไม่จริงคุณสามารถใช้ getdate ()
amr osama

6
@amrosama - ไม่คุณทำไม่ได้ getdate()ไม่ใช่ฟังก์ชัน MySQL การเชื่อมโยงในคำตอบอธิบายข้อยกเว้นเท่านั้น: «คุณสามารถระบุ CURRENT_TIMESTAMP เป็นค่าเริ่มต้นสำหรับคอลัมน์ประทับเวลา»
ÁlvaroGonzález

1
CURRENT_TIMESTAMP เป็น "ฟังก์ชัน" เดียวที่สามารถใช้เป็นค่าเริ่มต้นได้ ทุกสิ่งทุกอย่างต้องเป็นค่าคงที่ (น่าเสียดาย)
Troy Morehouse

3
ในทางเทคนิคฉันจะบอกว่า AUTO_INCREMENT สามารถมองเห็นเป็น "ฟังก์ชัน" เพื่อตั้งค่าเริ่มต้นแบบไดนามิก
Rikaelus

1

โปรดทราบว่าUUID()ผลตอบแทนของ MySQL CHAR(36)และการจัดเก็บ UUID เป็นข้อความ (ดังที่แสดงในคำตอบอื่น ๆ ) นั้นไม่มีประสิทธิภาพอย่างเห็นได้ชัด ควรเป็นคอลัมน์แทนBINARY(16)และคุณสามารถใช้UUID_TO_BIN()เมื่อแทรกข้อมูลและBIN_TO_UUID()เมื่ออ่านย้อนกลับ

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;

โปรดทราบว่าเนื่องจาก MySQL ไม่ทราบว่านี่เป็น UUID จริงๆจึงอาจเป็นเรื่องยากที่จะแก้ไขปัญหาที่จัดเก็บเป็นไบนารี บทความนี้อธิบายวิธีการสร้างคอลัมน์ที่สร้างขึ้นซึ่งจะแปลง UUID เป็นข้อความตามต้องการโดยไม่ต้องใช้พื้นที่หรือกังวลเกี่ยวกับการซิงค์เวอร์ชันไบนารีและข้อความที่แยกจากกัน: https://mysqlserverteam.com/storing-uuid-values-in -mysql ตาราง /


0

ฉันไม่แน่ใจว่าคำตอบข้างบนเป็นเวอร์ชันเก่าหรือไม่ แต่ฉันเห็นบางแห่งที่คุณสามารถทำได้โดยใช้ฟังก์ชัน unhex () ฉันลองแล้วและได้ผล (มาเรีย db เวอร์ชัน 10.2)

คุณทำได้

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

และใช้งานได้ หากต้องการดู uuid เพียงแค่ทำ hex (column_name)


0

ใน MariaDB เริ่มจากเวอร์ชัน 10.2.1 คุณสามารถทำได้ ดูเอกสาร

CREATE TABLE test ( uuid BINARY(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-','')) );
INSERT INTO test () VALUES ();
SELECT * FROM test;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.