2008-10-10 6 views
88

Я использую SQL Server 2005. Я хочу, чтобы значения в столбце были уникальными, а NULLS.Как создать уникальный индекс в столбце NULL?

Мое текущее решение включает в себя уникальный индекс на вид, как так:

CREATE VIEW vw_unq WITH SCHEMABINDING AS 
    SELECT Column1 
     FROM MyTable 
    WHERE Column1 IS NOT NULL 

CREATE UNIQUE CLUSTERED INDEX unq_idx ON vw_unq (Column1) 

Все лучшие идеи?

+14

нет шансов на использование sql 2008? вы можете создать отфильтрованный индекс, используя 'where' – 2010-03-13 03:21:02

+3

Вы не имели в виду _unique, позволяя NULLs_, вы, похоже, имели в виду _unique, но включали несколько NULLs_. В противном случае NULL индексируется как любое другое значение, а ограничение уникальности работает как ожидалось - просто не согласно стандартам SQL, как @pst, упомянутое в комментарии ниже. – Suncat2000 2012-02-09 14:28:26

ответ

26

Довольно уверен, что вы не можете этого сделать, поскольку это нарушает цель уникальности.

Однако, этот человек, похоже, достойной работы вокруг: http://sqlservercodebook.blogspot.com/2008/04/multiple-null-values-in-unique-index-in.html

+2

Кажется, что содержание ссылки, которую вы предоставили, было фактически (частично) скопировано без атрибуции отсюда: http://decipherinfosys.wordpress.com/2007/11/30/multiple-null-values-in-a-unique-index -in-sql-serverdb2-luw/ – 2010-02-25 09:58:39

+71

Я не согласен с тем, что он «нарушает цель uniques» - NULL является особым значением в SQL (по-разному похожим на NaN) и нуждается в соответствующем обращении. На самом деле это ошибка в SQL Server для оценки различных спецификаций SQL: вот ссылка для запроса «правильной реализации» на то, что она стоит: http://connect.microsoft.com/SQLServer/feedback/details/299229/изменить-уникально ограничение-на-Allow-множественные нулевые значения. – 2010-08-08 05:08:42

+2

для справки в 2008 году вы можете сделать CREATE UNIQUE INDEX foo ON dbo.bar (key) WHERE key NOT NULL; – niico 2017-05-03 16:06:15

68

Рассчитанная трюк столбец широко известен как «nullbuster»; мои примечания кредит Стив Kass:

CREATE TABLE dupNulls (
pk int identity(1,1) primary key, 
X int NULL, 
nullbuster as (case when X is null then pk else 0 end), 
CONSTRAINT dupNulls_uqX UNIQUE (X,nullbuster) 
) 
97

Использование SQL Server 2008, вы можете создать отфильтрованный индекс: http://msdn.microsoft.com/en-us/library/cc280372.aspx. (Я вижу, что Саймон добавил это как комментарий, но считал, что это заслуживает собственного ответа, так как комментарий легко пропущен)

Другой вариант - это триггер для проверки уникальности, но это может повлиять на производительность.

0

Строго говоря, уникальный столбец с нулевым значением (или набор столбцов) может быть NULL (или запись NULL) только один раз, поскольку одно и то же значение (и это включает в себя NULL) более одного раза явно нарушает уникальное ограничение.

Однако это не означает, что понятие «уникальные столбцы с нулевым значением» действительно; чтобы фактически реализовать его в любой реляционной базе данных, нам просто нужно иметь в виду, что такие базы данных должны быть нормализованы для правильной работы, а нормализация обычно включает в себя добавление нескольких (не-сущностей) дополнительных таблиц для установления отношений между объектами ,

Давайте рассмотрим базовый пример с учетом только одного «уникального столбца с нулевым значением», его легко расширить до большего количества таких столбцов.

Предположим, что мы информация представлена ​​в виде таблицы, как это:

create table the_entity_incorrect 
(
    id integer, 
    uniqnull integer null, /* we want this to be "unique and nullable" */ 
    primary key (id) 
); 

Мы можем сделать это, поместив uniqnull друг от друга и добавить вторую таблицу, чтобы установить связь между uniqnull ценностей и the_entity (вместо того uniqnull " внутри»the_entity):

create table the_entity 
(
    id integer, 
    primary key(id) 
); 

create table the_relation 
(
    the_entity_id integer not null, 
    uniqnull integer not null, 

    unique(the_entity_id), 
    unique(uniqnull), 
    /* primary key can be both or either of the_entity_id or uniqnull */ 
    primary key (the_entity_id, uniqnull), 
    foreign key (the_entity_id) references the_entity(id) 
); 

чтобы связать значение uniqnull строке в the_entity нам нужно добавить строку в the_relation.

Для строк в объекте не были присвоены значения uniqnull (т. Е. Для тех, которые мы бы поместили в NULL в the_entity_incorrect), мы просто не добавляем строку в the_relation.

Обратите внимание, что значения для uniqnull будут уникальными для всех the_relation, а также обратите внимание, что для каждого значения в_значении в переменной может быть не более одного значения, так как первичный и внешний ключи на нем обеспечивают это.

Затем, если значение 5 для uniqnull должен быть связан с the_entity идентификатором 3, нам нужно:

start transaction; 
insert into the_entity (id) values (3); 
insert into the_relation (the_entity_id, uniqnull) values (3, 5); 
commit; 

И, если значение ID 10 для the_entity не имеет uniqnull аналога, мы только делаем:

start transaction; 
insert into the_entity (id) values (10); 
commit; 

денормализовать эту информацию и получить данные таблицы как the_entity_incorrect будет выполнено, то необходимо:

select 
    id, uniqnull 
from 
    the_entity left outer join the_relation 
on 
    the_entity.id = the_relation.the_entity_id 
; 

Оператор «left external join» гарантирует, что в результате появятся все строки from_entity, поместив NULL в столбец uniqnull, если в the_relation нет соответствующих столбцов.

Помните, что любое усилие, потраченное на несколько дней (или недель или месяцев) на разработку хорошо нормированной базы данных (и соответствующих денормализующих представлений и процедур), сэкономит вам годы (или десятилетия) боли и потраченных впустую ресурсов.