KIỂM TRA ràng buộc trong MySQL không hoạt động


126

Đầu tiên tôi tạo một bảng như

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

và sau đó chèn các giá trị trong bảng đó

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

MySQL không hiển thị lỗi, nó chấp nhận các giá trị.


Một phần đồng ý. Cho rằng bạn đã cố gắng sử dụng nó, có thể giả định rằng bạn đã hỏi cả hai câu hỏi. Trên thực tế, câu trả lời bạn đã chấp nhận chủ yếu là giải thích lý do tại sao nó không hoạt động.
igorrs

1
Bạn có thể bỏ phiếu cho yêu cầu tính năng này: bug.mysql.com/orms.php?id=3464 nhưng nó đã không nhận được bất kỳ sự chú ý nào trong một thập kỷ.
Jared Beck

11
Bạn có thể sử dụng các ràng buộc CHECK trong MariaDB từ phiên bản 10.2.1 .
joanq

Câu trả lời:


140

MySQL 8.0.16 là phiên bản đầu tiên hỗ trợ các ràng buộc CHECK.

Đọc https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraint.html

Nếu bạn sử dụng MySQL 8.0.15 trở về trước, Hướng dẫn tham khảo MySQL cho biết:

Các CHECKkhoản được phân tách nhưng bỏ qua tất cả các công cụ lưu trữ.

Hãy thử kích hoạt ...

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 ;

Mong rằng sẽ giúp.


9
Tại đây, bạn sẽ tìm thấy cách kích hoạt một lỗi thay thế: stackoverflow.com/a/7189394/1144966
petermeissner

41
Đây là một trong những cầu vồng lấp lánh rộng lớn của những lý do mà tôi sẽ luôn sử dụng PostgreSQL thay vì MySQL đưa ra một lựa chọn nào.
Reinderien

5
Tôi tự hỏi liệu sẽ là 10 phút hay 15 phút phát triển trong MySQL để đưa ra cảnh báo nếu trình phân tích cú pháp gặp phải một CHECKràng buộc được xác định. Ahhh, điều đó quá đơn giản ...
gaborsch

75

Thật không may, MySQL không hỗ trợ các ràng buộc kiểm tra SQL. Bạn có thể xác định chúng trong truy vấn DDL của mình vì lý do tương thích nhưng chúng chỉ bị bỏ qua.

Có một cách thay thế đơn giản

Bạn có thể tạo BEFORE INSERTBEFORE UPDATEkích hoạt gây ra lỗi hoặc đặt trường thành giá trị mặc định khi các yêu cầu của dữ liệu không được đáp ứng.

Ví dụ để BEFORE INSERTlàm việc sau 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 ;  

Trước MySQL 5.5, bạn phải gây ra lỗi, ví dụ: gọi thủ tục không xác định.

Trong cả hai trường hợp, điều này gây ra một rollback giao dịch ngầm. MySQL không cho phép chính câu lệnh ROLLBACK trong các thủ tục và trình kích hoạt.

Nếu bạn không muốn phục hồi giao dịch (CHERTN / CẬP NHẬT sẽ vượt qua ngay cả với "ràng buộc kiểm tra" không thành công, bạn có thể ghi đè giá trị bằng cách SET NEW.ID = NULLđặt id thành giá trị mặc định của trường, không thực sự có ý nghĩa đối với id tho

Chỉnh sửa: Đã xóa trích dẫn đi lạc.

Liên quan đến :=nhà điều hành:

Không giống như =, :=toán tử không bao giờ được hiểu là toán tử so sánh. Điều này có nghĩa là bạn có thể sử dụng :=trong bất kỳ câu lệnh SQL hợp lệ nào (không chỉ trong các câu lệnh SET) để gán giá trị cho một biến.

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

Liên quan đến trích dẫn định danh backtick:

Ký tự trích dẫn định danh là backtick (`` `)

Nếu chế độ SQL ANSI_QUOTES được bật, bạn cũng có thể trích dẫn định danh trong dấu ngoặc kép

http://dev.mysql.com/doc/refman/5.6/vi/identifier.html


7
... không phải là rất đơn giản, ít nhất là so với SÉC :( coupla tutes:. net.tutsplus.com/tutorials/databases/... , sitepoint.com/how-to-create-mysql-triggers
Ben

ugh này trông rất cồng kềnh. Tôi nghĩ rằng tôi thà tạo ra một tuple trong python và kiểm tra các giá trị ở đó thay vì đưa nó vào.
OzzyTheGiant

Câu hỏi nhanh: tại sao điều này không hoạt động mà không thiết lập DELIMITER?
ddz

52

CHECK các ràng buộc bị bỏ qua bởi MySQL như được giải thích trong một nhận xét rất nhỏ trong các tài liệu: CREATE TABLE

Các CHECKkhoản được phân tách nhưng bỏ qua tất cả các công cụ lưu trữ.


2
@thefiloe: Chính xác, trong DBMS khác với việc thực hiện đúng các CHECKràng buộc, nếu việc CHECKđánh giá FALSEthì việc chèn (hoặc cập nhật) không được thực hiện và gây ra lỗi.
ypercubeᵀᴹ

Đã sửa lỗi trong MariaDB (xem câu trả lời này stackoverflow.com/a/44333349 ).
Jérôme

@ Jérôme Tôi biết, tôi có một số câu trả lời (gần đây) bao gồm các cải tiến trong lĩnh vực này (đã có những cách khác để khắc phục vấn đề này, cả trong MariaDB và MySQL, trước khi MariaDB thực hiện đúng các ràng buộc CHECK). Điều tôi không chắc là liệu tôi có nên đi và chỉnh sửa tất cả các câu trả lời cũ của mình không!
ypercubeᵀᴹ

Tôi cho rằng bình luận của tôi với một liên kết đến một câu trả lời gần đây là tốt. Hoặc tốt hơn là không có gì. Có lẽ tôi nên chỉnh sửa. Tôi không có ý gây áp lực cho bạn để làm bất cứ điều gì.
Jérôme



1

Kiểm tra các ràng buộc được hỗ trợ kể từ phiên bản 8.0.15 (chưa được phát hành)

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

[23 tháng 1 16:24] Paul Dubois

Đăng bởi nhà phát triển: Đã sửa trong 8.0.15.

Trước đây, MySQL đã cho phép một dạng cú pháp ràng buộc CHECK giới hạn, nhưng đã phân tích cú pháp và bỏ qua nó. MySQL hiện thực hiện các tính năng cốt lõi của các ràng buộc KIỂM TRA bảng và cột, cho tất cả các công cụ lưu trữ. Các ràng buộc được xác định bằng cách sử dụng các câu lệnh CREATE TABLE và ALTER TABLE.


1

Cập nhật lên MySQL 8.0.16 để sử dụng checks:

Kể từ MySQL 8.0.16, CREATE TABLE cho phép các tính năng cốt lõi của các ràng buộc KIỂM TRA bảng và cột, cho tất cả các công cụ lưu trữ. CREATE TABLE cho phép cú pháp ràng buộc KIỂM TRA sau đây, cho cả ràng buộc bảng và ràng buộc cột

Tài liệu kiểm tra MySQL


-2

thử với set sql_mode = 'STRICT_TRANS_TABLES'ORSET sql_mode='STRICT_ALL_TABLES'


2
Actuall không giúp được gì (MySQL 5.6), nó ngăn chặn việc nhập dữ liệu sai loại nhưng không nhập dữ liệu không đáp ứng các CHECKràng buộc
petermeissner
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.