Hai cột nullable một yêu cầu phải có giá trị


10

Câu hỏi không giải thích:

Có cách nào để có một ràng buộc gồm 2 giá trị null luôn yêu cầu 1 phải có giá trị không? Ví dụ: hai cột ngày đều null nhưng có ít nhất 1 yêu cầu phải có giá trị

Mô tả vấn đề:

Hãy nói rằng tôi có bảng gọi là Chi phí

và có 2 ngày:

advision_Exense_Exption_date DATE NULLABLE chi phí_payment_date DATE NULLABLE

logic của 2 cột đó là như sau:

Tôi đã mua một cái gì đó và tôi biết tôi phải trả tiền cho nó, một ngày nào đó, như hóa đơn điện thoại. Tôi sẽ nhập khoản này dưới dạng chi phí với cost_payment_date. Ngày này là ngày được cho là tôi nên thanh toán nhưng không phải là ngày thanh toán thực tế, như ngày hết hạn của hóa đơn.

Trong trường hợp khác, tôi bán thẻ quà tặng của một số nhà cung cấp cho dịch vụ đó. Tôi có thể có chi phí mua cho nhà cung cấp của mình, dịch vụ được chuyển cho khách hàng của tôi chỉ khi khách hàng đổi thẻ. Do đó, thẻ quà tặng có ngày hết hạn, tôi muốn thực hiện một ưu tiên cho 'chi phí' đó mà không cần thêm chi phí cho thời gian thẻ quà tặng có hiệu lực, nếu thẻ quà tặng hết hạn, 'chi phí' đó không nên nhập vào tài khoản hệ thống.

Tôi biết rằng tôi có thể có 2 bảng bằng nhau được gọi là tiền tố và khai báo xác nhận nhưng không đúng, vì vậy tôi có trong cùng một bảng, 2 ngày, không thể thực hiện được, nhưng tôi muốn ràng buộc hoặc một cái gì đó để luôn luôn yêu cầu.

Có một chiến lược khả thi khác:

Payment_date NGÀY KHÔNG NULL is_prevision_date BOOL KHÔNG NULL

Vì vậy, trong trường hợp này, nếu ngày là giá trị bool thịnh hành sẽ là 1, nếu không sẽ là 0. Không có giá trị null, tất cả đều tốt. ngoại trừ việc tôi muốn tùy chọn lưu trữ giá trị CẢ khi lần đầu tiên tôi có ngày ưu tiên và THEN (giả sử hai ngày sau) có ngày xác nhận cho chi phí đó, trong trường hợp với chiến lược 2 tôi sẽ không có tùy chọn đó.

Tôi đang làm mọi thứ sai trong thiết kế cơ sở dữ liệu? : D

Câu trả lời:


10

Một phiên bản của câu trả lời của JD Schmidt, nhưng không có sự lúng túng của một cột phụ:

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

Nếu bạn đang sử dụng SQL Server, bạn có thể tránh việc sử dụng trình kích hoạt bằng cách sử dụng cột được tính toán bền vững trong bảng của mình:

CREATE TABLE Test_Constraint
(
    A DateTime Null,
    B DateTime Null,
    A_and_B AS (CASE WHEN A IS Null AND B IS Null THEN Null ELSE Convert(Binary(1), 1) END) PERSISTED Not Null 
);

Câu lệnh tình huống trong cột được tính A_and_B sẽ trả về giá trị null nếu cả hai cột A và B đều rỗng, nhưng ràng buộc Not Null trên cột được tính toán sau đó sẽ gây ra lỗi ngăn chặn chèn. Nếu không, nó trả về 1.

Vì cột được tính vẫn tồn tại, nên nó sẽ được lưu trữ vật lý trong bảng. Việc chuyển đổi thành nhị phân giảm thiểu tác động của điều này, làm cho cột trở thành kiểu dữ liệu nhị phân có độ dài 1.


1
Trong SQL-Server, bạn cũng có thể làm điều này với một CHECKràng buộc. Không cần cột kiên trì.
ypercubeᵀᴹ

1
Tuyệt vời, có vẻ như sạch hơn một chút. CREATE TABLE Test_Constraint2 ( A DateTime Null, B DateTime Null, CONSTRAINT A_or_B_Not_Null CHECK (CASE WHEN A IS Null AND B IS Null THEN 0 ELSE 1 END = 1) )
Shane Estelle

câu trả lời chính xác! Cái này phù hợp hơn cái kia nhưng vì tôi đang sử dụng MySQL, CHECK CLAUSE được phân tích cú pháp nhưng bị bỏ qua trên MySQL nên tôi đánh dấu câu trả lời khác là câu trả lời được chấp nhận. +1
Bart Calix đến

1

Tôi tìm thấy một bài viết trông giống như ở đây

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//
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

cảm ơn, tôi đang sử dụng MySQL và điều này hoạt động hoàn toàn tốt với nó. đặc biệt vì ném một giá trị null vào lỗi cột không null.
Bart Calix đến
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.