하나는 값을 가져야하는 두 개의 널 입력 가능 열


10

설명이없는 질문 :

어쨌든 항상 1을 필요로하는 2 개의 null 값을 제한해야합니까? 예를 들어 두 개의 날짜 열이 모두 null이지만 값이 필요한 1 개 이상이어야 합니다.

문제 설명:

Expense라는 테이블이 있다고 가정 해 봅시다.

그리고 2 개의 날짜가 있습니다 :

prevision_expense_expiration_date DATE NULLABLE cost_payment_date DATE NULLABLE

이 두 열의 논리는 다음과 같습니다.

나는 물건을 사서 전화 청구서와 같은 날짜에 돈을 지불해야한다는 것을 안다. 나는 이것을 cost_payment_date와 함께 비용으로 입력 할 것입니다. 이 날짜는 인보이스 만료 날짜와 같이 지불해야하는 실제 날짜이지만 실제 지불 날짜는 아닙니다.

다른 상황에서는 서비스 제공 업체의 기프트 카드를 판매합니다. 나는 할 수있다 , 서비스 내 클라이언트로 옮겨진 내 공급자에게 구매의 비용이 단지 클라이언트가 카드를 사용할 경우. 기프트 카드 유효 기간이 있으므로 기프트 카드 유효 기간에 대한 비용을 기프트 카드가 만료 된 경우 계정에 입력하면 안되는 비용으로 삽입하지 않고 해당 '비용'에 대한 사전 준비를하고 싶습니다. 체계.

나는 prevision_expense와 confirm_expense라는 두 개의 동등한 테이블을 가질 수 있지만 올바른 소리가 들리지 않으므로 같은 테이블, 2 개의 날짜, 널 입력 가능을 갖지만 항상 하나가 필요하도록 제한하거나 무언가를 원합니다.

또 다른 가능한 전략이 있습니다.

payment_date DATE NOT NULL is_prevision_date BOOL NOT NULL

따라서이 경우 날짜가 프리비 안일 경우 bool 값은 1이되고 그렇지 않으면 0이됩니다. null 값이 없으면 모두 좋습니다. 처음에 사전 준비 날짜가 있고 THEN (이틀 후에 말하겠습니다)이 해당 비용에 대해 확인 된 날짜를 가질 때 BOTH 값을 저장하는 옵션을 원합니다.이 경우 전략 2의 경우 해당 옵션이 없습니다.

데이터베이스 디자인에서 모든 것을 잘못하고 있습니까? :디

답변:


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

계산 열 A_and_B의 case 문은 열 A와 B가 모두 null 인 경우 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) )
Shane Estelle

좋은 답변입니다! 이것은 다른 것보다 더 적합하지만 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.