2008-10-04 32 views
11

Cách tốt nhất để tạo ra ràng buộc không NULL trong MySQL sao cho fieldA và fieldB không thể là NULL. Tôi không quan tâm nếu một trong hai là NULL của chính nó, chỉ cần miễn là các lĩnh vực khác có một giá trị không NULL. Và nếu cả hai đều có giá trị NULL, thì nó thậm chí còn tốt hơn.Hoặc là các ràng buộc không rỗng trong MySQL

Trả lời

4

MySQL 5.5 giới thiệu SIGNAL, vì vậy chúng tôi không cần thêm cột trong câu trả lời của Bill Karwin nữa. Bill chỉ ra rằng bạn cũng cần một kích hoạt để cập nhật, vì vậy tôi đã bao gồm điều đó.

CREATE TABLE foo (
    FieldA INT, 
    FieldB INT 
); 

DELIMITER // 
CREATE TRIGGER InsertFieldABNotNull BEFORE INSERT ON foo 
FOR EACH ROW BEGIN 
    IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN 
    SIGNAL SQLSTATE '45000' 
    SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null'; 
    END IF; 
END// 
CREATE TRIGGER UpdateFieldABNotNull BEFORE UPDATE ON foo 
FOR EACH ROW BEGIN 
    IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN 
    SIGNAL SQLSTATE '45000' 
    SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null'; 
    END IF; 
END// 
DELIMITER ; 

INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK 
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK 
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error 
UPDATE foo SET FieldA = NULL; -- gives error 
2

tôi đã thực hiện một cái gì đó tương tự trong SQL Server, tôi không chắc chắn nếu nó sẽ làm việc trực tiếp trong MySQL, nhưng:

ALTER TABLE tableName ADD CONSTRAINT constraintName CHECK ((fieldA IS NOT NULL) OR (fieldB IS NOT NULL)); 

Ít nhất tôi tin rằng đó là cú pháp.

Tuy nhiên, hãy nhớ rằng bạn không thể tạo ràng buộc kiểm tra trên các bảng, bạn chỉ có thể kiểm tra các cột trong một bảng.

4

Đây là cú pháp tiêu chuẩn cho một hạn chế như vậy, nhưng MySQL blissfully bỏ qua các hạn chế sau

ALTER TABLE `generic` 
ADD CONSTRAINT myConstraint 
CHECK (
    `FieldA` IS NOT NULL OR 
    `FieldB` IS NOT NULL 
) 
+0

Vì đây là cú pháp SQL chuẩn, nên cũng nên làm việc với các cơ sở dữ liệu dựa trên SQL khác. (Nó chắc chắn hoạt động cho PostgreSQL.) – Neall

+0

Hướng dẫn sử dụng MySQL cho biết: "Mệnh đề CHECK được phân tích cú pháp nhưng bị bỏ qua bởi tất cả các công cụ lưu trữ." Tôi đã thử nó và đó là sự thật. –

+0

Nó thậm chí còn bị bỏ qua cho các bảng InnoDB? Điều đó thật tệ. – Neall

7

@Sklivvz: Kiểm tra với MySQL 5.0.51a, tôi thấy nó phân tích một hạn chế CHECK, nhưng không thi hành nó. Tôi có thể chèn (NULL, NULL) mà không có lỗi. Thử nghiệm cả MyISAM và InnoDB. Sau đó sử dụng SHOW CREATE TABLE cho thấy ràng buộc CHECK không có trong định nghĩa bảng, mặc dù không có lỗi nào được đưa ra khi tôi định nghĩa bảng.

Điều này khớp với số MySQL manual có nội dung: "Mệnh đề CHECK được phân tích cú pháp nhưng bị bỏ qua bởi tất cả các công cụ lưu trữ".

Vì vậy, đối với MySQL, bạn sẽ phải sử dụng trình kích hoạt để thực thi quy tắc này. Vấn đề duy nhất là các trình kích hoạt MySQL không có cách nào gây ra lỗi hoặc hủy bỏ một thao tác INSERT. Một điều bạn có thể làm trong trình kích hoạt gây ra lỗi là thiết lập cột NOT NULL thành NULL.

CREATE TABLE foo (
    FieldA INT, 
    FieldB INT, 
    FieldA_or_FieldB TINYINT NOT NULL; 
); 

DELIMITER // 
CREATE TRIGGER FieldABNotNull BEFORE INSERT ON foo 
FOR EACH ROW BEGIN 
    IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN 
    SET NEW.FieldA_or_FieldB = NULL; 
    ELSE 
    SET NEW.FieldA_or_FieldB = 1; 
    END IF; 
END// 

INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK 
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK 
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error 

Bạn cũng cần kích hoạt tương tự TRƯỚC KHI CẬP NHẬT.

+0

Bill, cố định câu trả lời của tôi cho phù hợp, cảm ơn, – Sklivvz

+0

Thay vì sử dụng cột 'NOT NULL' để buộc lỗi, bạn có thể làm một cái gì đó như' SET NEW.FieldA = 1/0' sẽ ném lỗi chia cho số không . Không phải là thông báo lỗi rất hữu ích *, nhưng ít nhất bạn không phải thêm các cột đặc biệt. Tôi thực sự muốn MySQL hỗ trợ các ràng buộc 'CHECK' thích hợp, hoặc ít nhất có cách tốt hơn để ném lỗi từ các trigger. :( – friedo

+0

@friedo: Vì câu hỏi của OP là về việc thực thi một số điều kiện không có giá trị đặc biệt, tôi cho rằng một thông báo lỗi vi phạm sẽ là thích hợp. để gán một chuỗi cho nó, nó làm tăng thông báo lỗi bao gồm chuỗi bạn sử dụng. :) –

7

Đây không phải là câu trả lời trực tiếp cho câu hỏi của bạn, nhưng một số thông tin bổ sung.

Khi giao dịch với nhiều cột và kiểm tra nếu tất cả là null hoặc một không phải là null, tôi thường sử dụng COALESCE() - đó là ngắn gọn, dễ đọc và dễ dàng duy trì nếu danh sách phát triển:

COALESCE(a, b, c, d) IS NULL -- True if all are NULL 

COALESCE(a, b, c, d) IS NOT NULL -- True if any one is not null 

này có thể được sử dụng trong kích hoạt của bạn.

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