2010-01-22 37 views
111

Trước tiên tôi tạo ra một bảng nhưKIỂM TRA khó khăn trong MySQL không hoạt động

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ị một lỗi, nó chấp nhận các giá trị.

+0

Đồng ý một phần. Cho rằng bạn đã cố gắng sử dụng nó, nó có thể được giả định rằng bạn đã hỏi cả hai câu hỏi. Trong 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: http://bugs.mysql.com/bug.php?id=3464 nhưng nó không nhận được bất kỳ sự chú ý nào trong một thập kỷ. –

+0

Tôi muốn biết lý do xóa phiếu bầu đối với câu hỏi này. – nhahtdh

Trả lời

15

Hạn chế CHECK dường như không được triển khai trong MySQL.

Xem báo cáo lỗi này: https://bugs.mysql.com/bug.php?id=3464

+17

Tôi không biết điều này và nó thực sự gây phiền nhiễu! – Ben

+0

Đã sửa lỗi trong MariaDB (xem câu trả lời này https://stackoverflow.com/a/44333349). –

112

Các MySQL Reference Manual nói:

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

Thử cò ...

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 ; 

Hy vọng rằng sẽ giúp.

+5

Ở đây bạn sẽ tìm thấy cách kích hoạt một lỗi thay vì: http://stackoverflow.com/a/7189396/1144966 – petermeissner

+23

Đây là một trong những cầu vồng lấp lánh rộng lớn của các 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

+1

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

-1

thử với set sql_mode = 'STRICT_TRANS_TABLES' HOẶC SET sql_mode='STRICT_ALL_TABLES'

+2

mà actuall không giúp (MySQL 5.6) nó ngăn cản nhập dữ liệu loại sai nhưng không nhập dữ liệu không đáp ứng ràng buộc '' KIỂM TRA' ' – petermeissner

47

CHECK hạn chế được bỏ qua bởi MySQL như được giải thích trong một chú thích rất nhỏ trong các tài liệu: CREATE TABLE

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

+81

... thật đáng kinh ngạc . – usr

+2

@thefiloe: Đúng, trong DBMS khác với việc thực hiện chính xác ràng buộc 'CHECK', nếu' CHECK' đánh giá thành 'FALSE' thì việc chèn (hoặc cập nhật) không được thực hiện và một lỗi gây ra. –

+0

Đã sửa lỗi trong MariaDB (xem câu trả lời này https://stackoverflow.com/a/44333349). –

65

Rất tiếc, 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 bạn vì lý do tương thích nhưng chúng chỉ bị bỏ qua.

Có một lựa chọn đơn giản

Bạn có thể tạo BEFORE INSERTBEFORE UPDATE trigger mà một trong hai gây ra một lỗi hoặc thiết lập hiện trường để giá trị mặc định của nó khi các yêu cầu của dữ liệu không được đáp ứng.

Ví dụ cho BEFORE INSERT làm việc kể từ 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 một thủ tục không xác định.

Trong cả hai trường hợp, điều này gây ra một cuộn ngược giao dịch tiềm ẩn. 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 khôi phục giao dịch (INSERT/UPDATE nên chuyển 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 sử dụng SET NEW.ID = NULL sẽ đặt id thành giá trị mặc định của trường, không thực sự có ý nghĩa cho một id tho

Chỉnh sửa: Đã xóa báo giá đi lạc.

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

Không giống như =, các nhà điều hành := không bao giờ được hiểu như là một 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 một giá trị cho một biến.

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

Về trích dẫn nhận dạng backtick:

Nhân vật nhận dạng trích dẫn là backtick (“`”)

Nếu chế độ ANSI_QUOTES SQL được kích hoạt, nó cũng được phép để trích dẫn số nhận dạng trong dấu ngoặc kép đôi

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

+6

... không đơn giản lắm, ít nhất là so với CHECK: (. Coupla tutes: http://net.tutsplus.com/tutorials/databases/introduction-to-mysql-triggers/, http: //www.sitepoint.com/how-to-create-mysql-triggers/ – Ben

+0

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

+0

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

Các vấn đề liên quan