하나의 열에 고유(여러 열) 및 null
간단한 카테고리 테이블이 있습니다.범주에는 상위 범주가 있을 수 있습니다(par_cat
column) 또는 null(기본 범주이고 부모 범주가 동일한 경우에는 이름이나 URL이 같은 범주가 2개 이상 없어야 합니다.
이 테이블의 코드:
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) unsigned NOT NULL,
`par_cat` int(10) unsigned DEFAULT NULL,
`lang` varchar(2) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'pl',
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`url` varchar(120) COLLATE utf8_unicode_ci NOT NULL,
`active` tinyint(3) unsigned NOT NULL DEFAULT '1',
`accepted` tinyint(3) unsigned NOT NULL DEFAULT '1',
`priority` int(10) unsigned NOT NULL DEFAULT '1000',
`entries` int(10) unsigned NOT NULL DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ;
ALTER TABLE `categories`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `categories_name_par_cat_unique` (`name`,`par_cat`),
ADD UNIQUE KEY `categories_url_par_cat_unique` (`url`,`par_cat`),
ADD KEY `categories_par_cat_foreign` (`par_cat`);
ALTER TABLE `categories`
MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=3;
ALTER TABLE `categories`ADD CONSTRAINT `categories_par_cat_foreign`
FOREIGN KEY (`par_cat`) REFERENCES `categories` (`id`);
문제는 제가 고유한 키를 가지고 있어도 작동하지 않는다는 것입니다.데이터베이스에 다음을 포함하는 2개의 카테고리를 삽입하려고 하면par_cat
로 설정.null
그리고 동일한 이름과 url, 이 두 카테고리는 문제없이 데이터베이스에 삽입될 수 있습니다(그리고 그렇게 해서는 안 됩니다).그러나 이 범주에 대해 선택하면 다른 범주에서par_cat
(예를 들어, ID가 1인 카테고리가 존재한다고 가정할 경우), 첫 번째 레코드만 삽입됩니다(이는 원하는 동작입니다).
질문 - 이 사건을 어떻게 처리해야 합니까?나는 다음을 읽었습니다.
UNIQUE 인덱스는 인덱스의 모든 값이 서로 달라야 하는 제약 조건을 만듭니다.기존 행과 일치하는 키 값으로 새 행을 추가하려고 하면 오류가 발생합니다.이 제약 조건은 BDB 스토리지 엔진을 제외한 NULL 값에는 적용되지 않습니다.다른 엔진의 경우 UNICEF 인덱스는 NULL을 포함할 수 있는 열에 대해 여러 NULL 값을 허용합니다. UNICEF 인덱스의 열에 대한 접두사 값을 지정하는 경우 열 값은 접두사 내에서 고유해야 합니다.
그러나 여러 열에 고유한 항목이 있는 경우에는 그렇지 않을 것으로 예상했습니다(단,par_cat
null일 수 있습니다.name
그리고.url
null일 수 없습니다.왜냐면par_cat
에 대한 언급.id
같은 테이블이지만 일부 범주에는 허용해야 할 상위 범주가 없습니다.null
가치.
SQL 표준에서 정의한 대로 작동합니다.NULL은 알 수 없음을 의미합니다.par_cat = NULL 및 name = 'X'의 두 레코드가 있는 경우 두 NULL은 동일한 값을 가지는 것으로 간주되지 않습니다.따라서 고유한 키 제약 조건을 위반하지 않습니다.(음, NULL은 여전히 동일한 값을 의미할 수 있지만 이 규칙을 적용하면 고유한 인덱스와 NULL 필드를 사용하는 작업이 거의 불가능합니다. NULL은 1, 2 또는 다른 값을 의미할 수도 있기 때문입니다.그래서 그들은 제 생각처럼 잘 정의했습니다.)
MySQL은 인덱스를 가질 수 있는 기능 인덱스를 지원하지 않기 때문에ISNULL(par_cat,-1), name
, 제약 조건이 작동하도록 하려면 par_cat를 "부모 없음"에 대해 0 또는 -1 또는 그 밖에 없는 NOT NULL 열로 만드는 것이 유일한 옵션입니다.
이것은 2014년에 요청된 것으로 알고 있습니다.그러나 MySQL: https://bugs.mysql.com/bug.php?id=8173 및 https://bugs.mysql.com/bug.php?id=17825 에서 요청하는 경우가 많습니다.사람들은 MySQL에서 관심을 끌기 위해 영향을 클릭할 수 있습니다.
MySQL 5.7 이후로 이제 다음과 같은 해결 방법을 사용할 수 있습니다.
ALTER TABLE categories
ADD generated_par_cat INT UNSIGNED AS (ifNull(par_cat, 0)) NOT NULL,
ADD UNIQUE INDEX categories_name_generated_par_cat (name, generated_par_cat),
ADD UNIQUE INDEX categories_url_generated_par_cat (url, generated_par_cat);
generated_par_cat은 가상으로 생성된 열이므로 저장 공간이 없습니다.사용자가 삽입(또는 업데이트)하면 고유 인덱스로 인해 generated_par_cat 값이 즉시 생성됩니다. 이는 매우 빠른 작업입니다.
혹시 라라벨에서 오실 때를 대비해서요
이 버전은 가상 칼럼에서 해결할 수 있는 Laravel의 마이그레이션 버전입니다.UNIQUE
열 중 하나가 다음과 같은 경우 발행NULL
값어치가 있는
$table->integer('generated_par_cat')->virtualAs('ifNull(par_cat, 0)');
$table->unique(['name', 'generated_par_cat'], 'name_par_cat_unique');
언급URL : https://stackoverflow.com/questions/25844786/unique-multiple-columns-and-null-in-one-column
'programing' 카테고리의 다른 글
이 "SQL 문 무시됨" 오류를 수정하려면 어떻게 해야 합니까? (0) | 2023.11.05 |
---|---|
도커 컨테이너를 중지하거나 다시 시작할 수 없습니다. (0) | 2023.11.05 |
앱이 설치되지 않은 것처럼 보여도 [INSTALL_FAILED_UPDATE_INCOMPATIC] 실패 (0) | 2023.11.05 |
MySQL 5.0의 int와 integer의 차이점은 무엇입니까? (0) | 2023.11.05 |
C의 동일한 디렉토리에 있는 다른 파일에서 함수 호출 (0) | 2023.11.05 |