คอลัมน์ nullable สองคอลัมน์จำเป็นต้องมีค่า


10

คำถามที่ไม่มีคำอธิบาย:

อย่างไรก็ตามมีข้อ จำกัด ของค่า Null 2 ​​ค่าที่ต้องมีค่า 1 เสมอหรือไม่ ตัวอย่างเช่นสองคอลัมน์วันที่ทั้งเป็นโมฆะ แต่มีอย่างน้อย 1 ที่ต้องมีค่า

คำอธิบายปัญหา:

สมมติว่าฉันมีตารางที่เรียกว่าค่าใช้จ่าย

และมี 2 วัน:

prevision_expense_expiration_date DATE NULLABLE ค่าใช้จ่าย _payment_date DATE NULLABLE

ตรรกะของคอลัมน์ 2 คอลัมน์ดังต่อไปนี้:

ฉันซื้อของบางอย่างและฉันรู้ว่าฉันต้องจ่ายเงินสำหรับบางวันเช่นค่าโทรศัพท์ ฉันจะป้อนสิ่งนี้เป็นค่าใช้จ่ายโดยมี costs_payment_date วันนี้เป็นวันที่ควรจะจ่าย แต่ไม่ใช่วันที่จ่ายจริงเช่นวันหมดอายุของใบแจ้งหนี้

ในสถานการณ์อื่น ๆ ฉันขายบัตรของขวัญของผู้ให้บริการบางรายเพื่อให้บริการ ฉันอาจมีค่าใช้จ่ายในการซื้อให้กับผู้ให้บริการของฉันบริการโอนไปยังลูกค้าของฉันเฉพาะในกรณีที่ลูกค้าแลกบัตร ดังนั้นบัตรของขวัญจึงมีวันหมดอายุฉันต้องการทำเช่นนั้นสำหรับ 'ค่าใช้จ่าย' โดยไม่ต้องใส่เป็นค่าใช้จ่ายสำหรับเวลาที่บัตรของขวัญนั้นถูกต้องหากบัตรของขวัญหมดอายุ 'ค่าใช้จ่าย' นั้นไม่ควรเข้าบัญชี ระบบ.

ฉันรู้ว่าฉันสามารถมี 2 ตารางเท่า ๆ กันที่เรียกว่า prevision_expense และ confirm_expense แต่ฟังดูไม่ถูกต้องดังนั้นฉันมีตารางเดียวกัน 2 วันที่ว่างเปล่า แต่ฉันต้องการ จำกัด หรือบางสิ่งเพื่อให้เป็นสิ่งที่จำเป็นเสมอ

มีอีกกลยุทธ์ที่เป็นไปได้:

payment_date DATE NOT NULL is_prevision_date BOOL NOT NULL

ดังนั้นในกรณีนี้ถ้าวันที่มีค่าเป็นบูนิกเป็น 1 มิฉะนั้นจะเป็น 0 ไม่มีค่า Null ทั้งหมดเป็นสิ่งที่ดี ยกเว้นว่าฉันต้องการตัวเลือกในการเก็บค่าทั้งสองเมื่อครั้งแรกที่ฉันมีวันที่แล้วและจากนั้น (ให้บอกว่าสองวันต่อมา) มีวันที่ยืนยันสำหรับค่าใช้จ่ายนั้นในกรณีที่มีกลยุทธ์ 2 ฉันจะไม่มีตัวเลือกนั้น

ฉันทำทุกอย่างผิดปกติในการออกแบบฐานข้อมูลหรือไม่? : D

คำตอบ:


10

รุ่นของคำตอบของ JD Schmidt แต่ไม่มีความอึดอัดใจของคอลัมน์เพิ่มเติม:

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

หากคุณใช้ SQL Server คุณสามารถหลีกเลี่ยงการใช้ทริกเกอร์โดยใช้คอลัมน์ที่คำนวณแล้วในตารางของคุณ:

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 
);

คำสั่ง case ในคอลัมน์ที่คำนวณ A_and_B จะส่งคืนค่า null ถ้าทั้งคอลัมน์ A และ B เป็น null แต่ข้อ จำกัด Not Null ในคอลัมน์ที่คำนวณแล้วจะทำให้เกิดข้อผิดพลาดในการป้องกันการแทรก มิฉะนั้นจะส่งคืน 1

เนื่องจากคอลัมน์ที่คำนวณนั้นยังคงอยู่มันจะถูกเก็บไว้ในตาราง การแปลงเป็นไบนารีจะลดผลกระทบของสิ่งนี้ทำให้คอลัมน์เป็นประเภทข้อมูลไบนารีที่มีความยาว 1


1
ใน SQL-Server คุณสามารถทำได้ด้วยCHECKข้อ จำกัด เช่นกัน ไม่จำเป็นต้องมีคอลัมน์ที่คงอยู่
ypercubeᵀᴹ

1
เยี่ยมมากมันดูค่อนข้างสะอาดกว่า 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) )
เชนเอสเทล

คำตอบที่ดี! อันนี้เหมาะกว่าอีกอันหนึ่ง แต่เนื่องจากฉันใช้ MySQL CHECK CLAUSE จึงถูกแยกวิเคราะห์ แต่ไม่สนใจใน MySQL ดังนั้นฉันจึงทำเครื่องหมายคำตอบอื่น ๆ ว่าเป็นคำตอบที่ยอมรับ +1
Bart Calixto

1

ฉันพบบทความที่มีลักษณะเหมือนกันที่นี่

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

ขอบคุณฉันใช้ MySQL และมันทำงานได้อย่างสมบูรณ์แบบกับมัน พิเศษเนื่องจากการโยนค่า Null บนข้อผิดพลาดของคอลัมน์ Null ไม่ใช่
Bart Calixto
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.