Ответ 1
Довольно уверен, что вы не можете этого сделать, поскольку это нарушает цель уникальности.
Однако у этого человека, похоже, есть приличная работа: http://sqlservercodebook.blogspot.com/2008/04/multiple-null-values-in-unique-index-in.html
Я использую SQL Server 2005. Я хочу, чтобы значения в столбце были уникальными, позволяя NULLS.
Мое текущее решение включает в себя уникальный индекс для такого вида:
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)
Любые лучшие идеи?
Довольно уверен, что вы не можете этого сделать, поскольку это нарушает цель уникальности.
Однако у этого человека, похоже, есть приличная работа: http://sqlservercodebook.blogspot.com/2008/04/multiple-null-values-in-unique-index-in.html
Используя SQL Server 2008, вы можете создать отфильтрованный индекс: http://msdn.microsoft.com/en-us/library/cc280372.aspx. (Я вижу, что Саймон добавил это как комментарий, но считал, что заслужил его собственный ответ, поскольку комментарий легко пропущен)
Другая опция - это триггер для проверки уникальности, но это может повлиять на производительность.
Вычисленный трюк столбца широко известен как "нульбастер"; мои заметки кредитуют Стив Касс:
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)
)
Строго говоря, уникальный нулевой столбец (или набор столбцов) может быть 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 с строкой в__определении, нам нужно также добавить строку в ссылку.
Для строк в объекте не были сопоставлены значения uniqnull (т.е. для тех, которые мы бы поместили в NULL в in_entity_incorrect), мы просто не добавляем строку в ссылку.
Обратите внимание, что значения для uniqnull будут уникальными для всех параметров, а также заметят, что для каждого значения в__определении в переменной может быть не более одного значения, так как первичный и внешний ключи на ней обеспечивают это.
Затем, если значение 5 для uniqnull должно быть связано с id_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, если в этой_реляции нет соответствующих столбцов.
Помните, что любые усилия, потраченные на несколько дней (или недель или месяцев) на разработку хорошо нормированной базы данных (и соответствующие денормализующие представления и процедуры), сэкономят вам годы (или десятилетия) боли и потраченные впустую ресурсы.