2008-10-04 4 views
11

MySQL에서 NULL이 아닌 제약 조건을 생성하여 fieldA와 fieldB를 둘 다 NULL로 지정할 수없는 가장 좋은 방법은 무엇입니까? 다른 필드가 NULL이 아닌 값을 가지고있는 한, 어느 것이 든 자체적으로 NULL인지 상관하지 않습니다. 둘 다 NULL이 아닌 값을 가지고 있다면 더 좋습니다.MySQL에서 또는 null이 아닌 제약 조건

내가 SQL 서버에서 비슷한 짓을했는지

답변

4

MySQL 5.5는 SIGNAL을 도입 했으므로 Bill Karwin의 대답에서 추가 열은 필요하지 않습니다. Bill은 업데이트를위한 트리거가 필요하다고 지적하여이를 포함 시켰습니다.

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

, 나는 그것이 MySQL을 직접 작동하는지 모르겠지만, :

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

가 적어도 나는 그 구문 믿습니다.

그러나 테이블간에 check 제약 조건을 만들 수는 없으므로 하나의 테이블에서만 열을 확인할 수 있습니다.

4

이 같은 제약 조건에 대한 표준 구문이지만, MySQL은 행복하게 제약 조건을 무시 이후

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

표준 SQL 구문이므로 다른 SQL 기반 데이터베이스에서도 사용할 수 있습니다. (PostgreSQL에서는 확실히 작동합니다.) – Neall

+0

MySQL 설명서에 "CHECK 절은 모든 저장소 엔진에서 구문 분석되지만 무시됩니다." 나는 그것을 시도하고 그것은 사실입니다. –

+0

InnoDB 테이블의 경우에도 무시됩니까? 그거 끔찍해. – Neall

7

@Sklivvz : MySQL의 5.0.51a와 함께 테스트, 나는 그것이 CHECK 제약 조건을 구문 분석하지만 실행하지 않는 것을 발견 그것. (NULL, NULL)을 오류없이 삽입 할 수 있습니다. MyISAM과 InnoDB를 모두 테스트했습니다. SHOW CREATE TABLE을 사용하면 테이블을 정의 할 때 오류가 없더라도 CHECK 제약 조건이 테이블 정의에 없다는 것을 알 수 있습니다.

"CHECK 절은 모든 저장소 엔진에서 구문 분석되지만 무시됩니다."라는 MySQL manual과 일치합니다.

그래서 MySQL의 경우 트리거를 사용하여이 규칙을 적용해야합니다. 유일한 문제는 MySQL 트리거가 오류를 발생 시키거나 INSERT 작업을 중단 할 수 없다는 것입니다. 트리거에서 오류를 유발할 수있는 한 가지 방법은 NOT NULL 열을 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 

이전에 비슷한 트리거가 필요합니다.

+0

빌, 이에 대한 답변을 고쳤습니다. – Sklivvz

+0

'NOT NULL' 칼럼을 사용하여 에러를 강제하는 대신, 'SET NEW.FieldA = 1/0'과 같이 할 수 있습니다. 0으로 나누기 오류가 발생합니다 . 매우 유용한 * 오류 메시지는 아니지만 최소한 특수 열을 추가 할 필요는 없습니다. MySQL이 적절한'CHECK' 제약 조건을 지원하거나 최소한 트리거로부터 에러를 던질 수있는 더 좋은 방법을 원합니다. : – friedo

+0

@friedo : OP의 질문은 특별한 null이 아닌 조건을 적용하는 것에 관한 것이므로 null 위반 오류 메시지가 적절할 것이라고 생각했습니다 .MySQL 트리거에서 수행 할 수있는 또 다른 트릭은 트리거의 정수 변수를 선언하고 문자열을 할당하면 사용하는 문자열을 포함하는 오류 메시지가 발생합니다. :) –

7

이 질문에 대한 대답은 아니지만 몇 가지 추가 정보가 있습니다.

여러 열을 다루는 모두가 null 또는 하나가 null가 아닌 경우 확인, 나는 일반적으로 COALESCE() 사용 - 목록이 증가하는 경우는, 간단한 읽기 쉽게 유지 보수의 :

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 

이 사용할 수 있습니다 너의 방아쇠.