ข้อ จำกัด CHECK ใน MySQL ไม่ทำงาน


127

ก่อนอื่นฉันสร้างตารางเช่น

CREATE TABLE Customer (
  SD integer CHECK (SD > 0),
  Last_Name varchar (30),
  First_Name varchar(30)
);

แล้วแทรกค่าในตารางนั้น

INSERT INTO Customer values ('-2','abc','zz');

MySQL ไม่แสดงข้อผิดพลาด แต่ยอมรับค่า


เห็นด้วยบางส่วน เนื่องจากคุณพยายามใช้มันอาจสันนิษฐานได้ว่าคุณกำลังถามคำถามทั้งสองข้อ ในความเป็นจริงคำตอบที่คุณยอมรับส่วนใหญ่อธิบายว่าเหตุใดจึงไม่ได้ผล
igorrs

1
คุณสามารถลงคะแนนในคำขอคุณลักษณะนี้: bugs.mysql.com/bug.php?id=3464แต่ไม่ได้รับความสนใจใด ๆ เลยในทศวรรษ
Jared Beck

11
คุณสามารถใช้ตรวจสอบข้อ จำกัด ใน MariaDB จากรุ่น 10.2.1
joanq

คำตอบ:


141

MySQL 8.0.16เป็นเวอร์ชันแรกที่รองรับข้อ จำกัด ในการตรวจสอบ

อ่านhttps://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html

หากคุณใช้ MySQL 8.0.15 ขึ้นไปไฟล์ คู่มืออ้างอิง MySQL จะระบุว่า:

CHECKประโยคจะแยกกัน แต่ปฏิเสธโดยทุกเครื่องมือการจัดเก็บข้อมูล

ลองไก ...

mysql> delimiter //
mysql> CREATE TRIGGER trig_sd_check BEFORE INSERT ON Customer 
    -> FOR EACH ROW 
    -> BEGIN 
    -> IF NEW.SD<0 THEN 
    -> SET NEW.SD=0; 
    -> END IF; 
    -> END
    -> //
mysql> delimiter ;

หวังว่าจะช่วยได้


9
ที่นี่คุณจะพบวิธีการเรียกข้อผิดพลาดแทน: stackoverflow.com/a/7189396/1144966
petermeissner

41
นี่เป็นหนึ่งในเหตุผลที่เปล่งประกายมากมายที่ฉันจะใช้ PostgreSQL แทน MySQL ที่มีให้เลือก
Reinderien

5
ฉันสงสัยว่าการพัฒนา MySQL จะใช้เวลา 10 นาทีหรือ 15 นาทีเพื่อส่งคำเตือนหากตัวแยกวิเคราะห์พบCHECKข้อ จำกัด ที่กำหนดไว้
อ่า

74

ขออภัย MySQL ไม่รองรับข้อ จำกัด ในการตรวจสอบ SQL คุณสามารถกำหนดได้ในแบบสอบถาม DDL ของคุณด้วยเหตุผลด้านความเข้ากันได้ แต่จะถูกละเว้น

มีทางเลือกง่ายๆ

คุณสามารถสร้างBEFORE INSERTและBEFORE UPDATEทริกเกอร์ซึ่งทำให้เกิดข้อผิดพลาดหรือตั้งค่าฟิลด์เป็นค่าเริ่มต้นเมื่อไม่ตรงตามข้อกำหนดของข้อมูล

ตัวอย่างการBEFORE INSERTทำงานหลังจาก MySQL 5.5

DELIMITER $$
CREATE TRIGGER `test_before_insert` BEFORE INSERT ON `Test`
FOR EACH ROW
BEGIN
    IF CHAR_LENGTH( NEW.ID ) < 4 THEN
        SIGNAL SQLSTATE '12345'
            SET MESSAGE_TEXT := 'check constraint on Test.ID failed';
    END IF;
END$$   
DELIMITER ;  

ก่อนหน้า MySQL 5.5 คุณต้องทำให้เกิดข้อผิดพลาดเช่นเรียกขั้นตอนที่ไม่ได้กำหนด

ในทั้งสองกรณีนี้ทำให้เกิดการย้อนกลับธุรกรรมโดยปริยาย MySQL ไม่อนุญาตให้ใช้คำสั่ง ROLLBACK ภายในโพรซีเดอร์และทริกเกอร์

หากคุณไม่ต้องการย้อนกลับธุรกรรม (INSERT / UPDATE ควรผ่านแม้ว่าจะมี "ข้อ จำกัด ในการตรวจสอบ" ที่ล้มเหลวคุณสามารถเขียนทับค่าโดยใช้SET NEW.ID = NULLซึ่งจะตั้งค่ารหัสเป็นค่าเริ่มต้นของฟิลด์ซึ่งไม่สมเหตุสมผลสำหรับ id สรรพสินค้าใหญ่

แก้ไข: ลบคำพูดที่หลงผิด

เกี่ยวกับตัว:=ดำเนินการ:

ต่างจาก=ตัว:=ดำเนินการจะไม่ถูกตีความว่าเป็นตัวดำเนินการเปรียบเทียบ ซึ่งหมายความว่าคุณสามารถใช้:=ในคำสั่ง SQL ที่ถูกต้อง (ไม่ใช่เฉพาะในคำสั่ง SET) เพื่อกำหนดค่าให้กับตัวแปร

https://dev.mysql.com/doc/refman/5.6/en/assignment-operators.html

เกี่ยวกับคำพูดของตัวระบุ backtick:

อักขระเครื่องหมายคำพูดของตัวระบุคือ backtick (“ `”)

หากเปิดใช้งานโหมด ANSI_QUOTES SQL จะอนุญาตให้อ้างตัวระบุภายในเครื่องหมายคำพูดคู่

http://dev.mysql.com/doc/refman/5.6/en/identifiers.html


7
... ไม่ง่ายมากอย่างน้อยเมื่อเทียบกับ CHECK :( Coupla tutes: net.tutsplus.com/tutorials/databases/… , sitepoint.com/how-to-create-mysql-triggers
Ben

เอ่อมันดูเทอะทะมาก ฉันคิดว่าฉันค่อนข้างจะสร้างทูเพิลใน python และตรวจสอบค่าที่นั่นแทนที่จะใส่เข้าไป
OzzyTheGiant

คำถามด่วน: เหตุใดจึงใช้ไม่ได้โดยไม่ต้องตั้งค่าDELIMITER?
ddz

52

CHECK ข้อ จำกัด ถูกละเว้นโดย MySQL ตามที่อธิบายไว้ในความคิดเห็นย่อส่วนในเอกสาร: CREATE TABLE

CHECKประโยคจะแยกกัน แต่ปฏิเสธโดยทุกเครื่องมือการจัดเก็บข้อมูล


2
@thefiloe: ถูกต้องใน DBMS อื่นที่มีการใช้งานCHECKข้อ จำกัด อย่างถูกต้องหากการCHECKประเมินเป็นไปตามFALSEนั้นการแทรก (หรือการอัปเดต) จะไม่เสร็จสิ้นและเกิดข้อผิดพลาด
ypercubeᵀᴹ

แก้ไขใน MariaDB (ดูคำตอบนี้stackoverflow.com/a/44333349 )
Jérôme

@ Jérômeฉันรู้ว่าฉันมีคำตอบบางส่วน (ล่าสุด) ที่รวมถึงการปรับปรุงในส่วนนี้ (มีวิธีอื่น ๆ ในการแก้ไขปัญหานี้ทั้งใน MariaDB และ MySQL ก่อนที่ MariaDB จะใช้ข้อ จำกัด CHECK อย่างเหมาะสม) สิ่งที่ฉันไม่แน่ใจคือฉันควรไปแก้ไขคำตอบเก่าทั้งหมดของฉันหรือไม่!
ypercubeᵀᴹ

ฉันคิดว่าความคิดเห็นของฉันพร้อมลิงก์ไปยังคำตอบล่าสุดนั้นใช้ได้ หรือดีกว่าไม่มีอะไร บางทีฉันควรจะแก้ไข ฉันไม่ได้ตั้งใจที่จะกดดันให้คุณทำอะไร
Jérôme



1

ตรวจสอบข้อ จำกัด ได้รับการสนับสนุนตั้งแต่เวอร์ชัน 8.0.15 (ยังไม่ได้เปิดตัว)

https://bugs.mysql.com/bug.php?id=3464

[23 ม.ค. 16:24 น.] Paul Dubois

โพสต์โดยผู้พัฒนา: แก้ไขใน 8.0.15

ก่อนหน้านี้ MySQL อนุญาตรูปแบบที่ จำกัด ของไวยากรณ์ CHECK ข้อ จำกัด แต่แยกวิเคราะห์และเพิกเฉย ขณะนี้ MySQL ใช้คุณสมบัติหลักของข้อ จำกัด ในการตรวจสอบตารางและคอลัมน์สำหรับเอ็นจิ้นการจัดเก็บทั้งหมด มีการกำหนดข้อ จำกัด โดยใช้คำสั่ง CREATE TABLE และ ALTER TABLE


1

อัปเดตเป็น MySQL 8.0.16 เพื่อใช้checks:

ตั้งแต่ MySQL 8.0.16 CREATE TABLE อนุญาตให้ใช้คุณสมบัติหลักของข้อ จำกัด การตรวจสอบตารางและคอลัมน์สำหรับเอ็นจิ้นหน่วยเก็บข้อมูลทั้งหมด CREATE TABLE อนุญาตให้ใช้ไวยากรณ์ข้อ จำกัด CHECK ต่อไปนี้สำหรับทั้งข้อ จำกัด ของตารางและข้อ จำกัด ของคอลัมน์

MySQL ตรวจสอบเอกสาร


-2

ลองด้วยset sql_mode = 'STRICT_TRANS_TABLES'ORSET sql_mode='STRICT_ALL_TABLES'


2
แอคชูออลนั้นไม่ช่วย (MySQL 5.6) จะป้องกันการป้อนข้อมูลประเภทเท็จ แต่ไม่ป้อนข้อมูลที่ไม่เป็นไปตามCHECKข้อ จำกัด
petermeissner
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.