2012-02-14 2 views
10

내 SQL 스키마는 MySQL은 다음과 같은 문장이 중복의 결과로 반복 될 수있다중지 MySQL은 UNIQUE 제약 조건에서 여러 널 (null)을 견뎌

CREATE TABLE Foo (
`bar` INT NULL , 
`name` VARCHAR (59) NOT NULL , 
UNIQUE (`name`, `bar`) 
) ENGINE = INNODB; 

입니다.

UNIQUE (`name`, `bar`) 

을 가지고에도 불구하고

INSERT INTO Foo (`bar`, `name`) VALUES (NULL, 'abc'); 

는 왜 이런 일이 용납이며 어떻게 중지합니까?

+2

은 주 그것을 확인 키, 두 필드에서 nulls 허용하지 않습니다. 또는 필드를 null이 아니게 만드십시오. mysql 문서 : http://dev.mysql.com/doc/refman/5.1/en/create-index.html "모든 엔진에 대해 UNIQUE 인덱스는 null을 포함 할 수있는 열에 대해 여러 개의 null 값을 허용합니다". –

+0

'NULL'은 값이 아닙니다. @MarcB가 말했듯이, 당신은 이것을 위해'NULL'을 허용하지 않아야합니다. – JNK

+0

버그 인 것 같습니다 : http://bugs.mysql.com/bug.php?id=8173. (적어도 버그 리포트의 일부 사람들은 그렇게 생각합니다.) –

답변

12

경고 :이 답변은 구식입니다. MySQL 5.1부터는 BDB가 지원되지 않습니다.

MySQL Engine Type에 따라 다릅니다. BDBUNIQUE을 사용하는 복수 NULL 값을 허용하지 않지만 MyISAMInnoDBUNIQUE과 함께 여러 NULL을 허용합니다.

2

일반적으로 스토리지 엔진에 따라 NULL은 고유 값으로 보일 수도 있고 그렇지 않을 수도 있습니다. 고유 한 값으로 NULL을 인식하지 못하는 스토리지 엔진을 사용해야합니다 (예 : InnoDB 또는 MyISAM.

스토리지 엔진이 고유 키에 널 (null) 처리하기로 결정 방법을 변경할 수있는 방법이 없기 때문에 당신이 NULL으로 인식 할 수있는 당신이 "null 값을"만들 수있는이 같은 99999999, 주위를 얻을 수 있습니다.

+4

-1 마법의 해답을 제안합니다. 진짜 대답은'NULL'을 이해하고 적절하게 사용하는 것입니다. – JNK

+0

OP는 'NULL'이 참으로 마법의 가치라고 생각하기 때문에 -1을주지 않을 것입니다. 개념을 잘 모르는 것이 바람직하지 않기 때문에 +1이 아닙니다. –

0

BDB는 UNIQUE를 사용하는 다중 NULL 값을 허용하지 않습니다. 그러나 MySQL은 BDB 엔진 (http://dev.mysql.com/doc/relnotes/mysql/5.1/en/news-5-1-12.html)을 삭제합니다. 그래서 지금

: 모든 엔진에 대한 http://dev.mysql.com/doc/refman/5.5/en/create-index.html

는 UNIQUE 인덱스는 NULL을 포함 할 수있는 컬럼에 대해 여러 NULL 값을 허용합니다. UNIQUE 인덱스의 열에 접두사 값을 지정하면 열 값이 접두사 내에서 고유해야합니다.

1

업데이트 : @ greenoldman에서 제안한 아이디어를 대신 아래 의견에 사용해야합니다. nullable 필드가 NULL인지 여부에 따라 값을 설정하고 고유 제한 조건의 부울 필드를 고유성을 정의하는 다른 필드와 결합하려면 트리거가있는 부울 필드를 만듭니다. 당신이 고유 제한 조건을 적용뿐만 아니라, 따라서 null로 그것을 필요로 열에 외래 키가 필요해야하는 경우


나는이 문제를 해결하는 방법을 발견했다. 내 솔루션은 this에서 파생되었으며 약간의 여유 공간이 필요합니다. 이것은 숫자 ID 필드가있는 예입니다.

기본 개념은 트리거를 사용하여 외부 키가 복제 된 nullable 필드의 값을 갖는 다른 nullableable 필드를 만들어야한다는 것입니다. 그런 다음 고유 제한 조건이 Null 허용 가능 복제 필드에 적용됩니다.

ALTER TABLE `my_table` ADD `uniq_foo` int(10) UNSIGNED NOT NULL DEFAULT '0'; 

그런 다음 당신은 그냥이 같은 몇 가지 트리거를 정의 할 수 있습니다 :이 유사 0의 기본값 nullable이 아닌 필드를 정의 할 필요가 이렇게하려면

DROP TRIGGER IF EXISTS `my_table_before_insert`; 
DELIMITER ;; 
CREATE TRIGGER `my_table_before_insert` BEFORE INSERT ON `my_table` 
FOR EACH ROW 
BEGIN 
    SET NEW.uniq_foo = IFNULL(NEW.foo_id, 0); 
END;; 
DELIMITER ; 

DROP TRIGGER IF EXISTS `my_table_before_update`; 
DELIMITER ;; 
CREATE TRIGGER `my_table_before_update` BEFORE UPDATE ON `my_table` 
FOR EACH ROW 
BEGIN 
    SET NEW.uniq_foo = IFNULL(NEW.foo_id, 0); 
END;; 
DELIMITER ; 
+0

대단히 고마워요! 개념은 훌륭하지만 사용하기에는 실행이 너무 약합니다. 그러나이 치료법은 치료법이 있습니다.이 여분의 열은 null에 대해서는 "0", not-null에 대해서는 "1"(또는 그 반대도 중요하지 않습니다) 인'TINYINT (1)'(의미 - 불량)이어야합니다. nullable 필드. 고유 색인은 ** 추가 열 **을 사용해야합니다. 그게 전부입니다 - 마법의 가치 때문에 갈등을 겪을 가능성은 없습니다. 왜냐하면 마법의 가치가 없기 때문입니다. – greenoldman

+0

@greenoldman 좋은 아이디어! FWIW, 나는 매우 크고 활동적인 데이터 세트로이 기술을 프로덕션에서 사용하는 데 어려움을 겪지는 않았지만 여전히 당신의 아이디어를 더 좋아합니다. –

관련 문제