Я хочу иметь уникальное ограничение для столбца, который я собираюсь заполнить GUID. Тем не менее, мои данные содержат нулевые значения для этих столбцов. Как создать ограничение, которое допускает множественные нулевые значения?
Вот пример сценария . Рассмотрим эту схему:
CREATE TABLE People (
Id INT CONSTRAINT PK_MyTable PRIMARY KEY IDENTITY,
Name NVARCHAR(250) NOT NULL,
LibraryCardId UNIQUEIDENTIFIER NULL,
CONSTRAINT UQ_People_LibraryCardId UNIQUE (LibraryCardId)
)
Тогда посмотрите этот код для того, что я пытаюсь достичь:
-- This works fine:
INSERT INTO People (Name, LibraryCardId)
VALUES ('John Doe', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA');
-- This also works fine, obviously:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Marie Doe', 'BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB');
-- This would *correctly* fail:
--INSERT INTO People (Name, LibraryCardId)
--VALUES ('John Doe the Second', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA');
-- This works fine this one first time:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Richard Roe', NULL);
-- THE PROBLEM: This fails even though I'd like to be able to do this:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Marcus Roe', NULL);
Окончательное утверждение завершается ошибкой с сообщением:
Нарушение ограничения UNIQUE KEY 'UQ_People_LibraryCardId'. Невозможно вставить дубликат ключа в объект 'dbo.People'.
Как я могу изменить мою схему и / или ограничение уникальности, чтобы оно допускало множественные NULL
значения, в то же время проверяя уникальность реальных данных?
sql-server
tsql
Стюарт
источник
источник
null
это не ценность, а отсутствие ценности. Согласно стандарту SQL,null
не считается равнымnull
. Так почему множественное числоnull
должно быть нарушением уникальности?Ответы:
SQL Server 2008 +
Вы можете создать уникальный индекс, который принимает несколько NULL с
WHERE
предложением. Смотрите ответ ниже .До SQL Server 2008
Вы не можете создать УНИКАЛЬНОЕ ограничение и разрешить NULL. Вам нужно установить значение по умолчанию NEWID ().
Обновите существующие значения до NEWID (), где NULL, перед созданием ограничения UNIQUE.
источник
То, что вы ищете, действительно является частью стандартов ANSI SQL: 92, SQL: 1999 и SQL: 2003, то есть ограничение UNIQUE должно запрещать повторяющиеся значения, отличные от NULL, но принимать несколько значений NULL.
Однако в мире Microsoft SQL Server допускается использование одного NULL, а нескольких NULL - нет ...
В SQL Server 2008 вы можете определить уникальный фильтрованный индекс на основе предиката, который исключает NULL:
В более ранних версиях вы можете прибегнуть к VIEWS с предикатом NOT NULL, чтобы применить ограничение.
источник
SQL Server 2008 и выше
Просто отфильтруйте уникальный индекс:
В более низких версиях материализованное представление все еще не требуется
Для SQL Server 2005 и более ранних версий вы можете сделать это без представления. Я только что добавил уникальное ограничение, как вы просите, к одной из моих таблиц. Учитывая, что мне нужна уникальность в столбце
SamAccountName
, но я хочу разрешить несколько значений NULL, я использовал материализованный столбец, а не материализованное представление:Вы просто должны поместить что-то в вычисляемый столбец, который будет гарантированно уникальным по всей таблице, когда фактический желаемый уникальный столбец равен NULL. В данном случае
PartyID
это столбец идентификаторов, и числовое значение никогда не будет совпадать ни с однимSamAccountName
, поэтому для меня это сработало. Вы можете попробовать свой собственный метод - убедитесь, что вы понимаете область своих данных, чтобы не было возможности пересечения с реальными данными. Это может быть так же просто, как добавить символ дифференцирования, например так:Даже если когда
PartyID
-нибудь станет нечисловым и может совпадать сSamAccountName
, теперь это не будет иметь значения.Обратите внимание, что наличие индекса, включающего вычисляемый столбец, неявно приводит к тому, что каждый результат выражения сохраняется на диск вместе с другими данными в таблице, что ДОЛЖНО занимать дополнительное место на диске.
Обратите внимание, что если вы не хотите индексировать, вы все равно можете сохранить ЦП, предварительно рассчитав выражение на диске, добавив ключевое слово
PERSISTED
в конец определения выражения столбца.В SQL Server 2008 и выше обязательно используйте фильтрованное решение, если это возможно!
полемика
Обратите внимание, что некоторые специалисты по базам данных будут рассматривать это как случай «суррогатных NULL», которые определенно имеют проблемы (в основном из-за проблем, связанных с попыткой определить, является ли что-то реальным или суррогатным значением для отсутствующих данных ; также могут быть проблемы с числом ненулевых суррогатных значений, умножающихся как сумасшедшие).
Тем не менее, я считаю, что этот случай отличается. Вычисляемый столбец, который я добавляю, никогда не будет использоваться для определения чего-либо. Он не имеет смысла сам по себе и не кодирует информацию, которая не найдена отдельно в других, правильно определенных столбцах. Он никогда не должен быть выбран или использован.
Итак, моя история такова, что это не суррогатный NULL, и я придерживаюсь его! Поскольку на самом деле мы не хотим, чтобы значение, отличное от
UNIQUE
NULL, использовалось не для того, чтобы обмануть индекс, чтобы игнорировать NULL, в нашем сценарии использования нет проблем, возникающих при обычном создании суррогатного NULL.Несмотря на все сказанное, у меня нет проблем с использованием индексированного представления вместо этого, но это вызывает некоторые проблемы, такие как требование использования
SCHEMABINDING
. Получайте удовольствие, добавляя новый столбец в вашу базовую таблицу (вам как минимум придется отбросить индекс, а затем отбросить представление или изменить представление, чтобы оно не было привязано к схеме). См. Полный (длинный) список требований для создания индексированного представления в SQL Server (2005) (также более поздние версии), (2000) .Обновить
Если ваш столбец числовой, может возникнуть проблема обеспечения того, чтобы использование уникального ограничения
Coalesce
не приводило к коллизиям. В этом случае есть несколько вариантов. Можно было бы использовать отрицательное число, чтобы поместить «суррогатные значения NULL» только в отрицательный диапазон, а «реальные значения» только в положительный диапазон. В качестве альтернативы можно использовать следующий шаблон. В таблицеIssue
(гдеIssueID
находитсяPRIMARY KEY
) может быть или не бытьTicketID
, но если она есть, она должна быть уникальной.Если IssueID 1 имеет тикет 123,
UNIQUE
ограничение будет на значениях (123, NULL). Если IssueID 2 не имеет билета, он будет включен (NULL, 2). Некоторые рассуждения покажут, что это ограничение не может быть продублировано для какой-либо строки в таблице, и, тем не менее, допускает несколько значений NULL.источник
Для людей, которые используют Microsoft SQL Server Manager и хотят создать уникальный, но обнуляемый индекс, вы можете создать свой уникальный индекс, как обычно, затем в свойствах индекса для нового индекса выберите «Фильтр» на левой панели и введите ваш фильтр (который является вашим предложением where). Следует читать что-то вроде этого:
Это работает с MSSQL 2012
источник
Когда я применил уникальный индекс ниже:
каждое ненулевое обновление и вставка завершались неудачно с ошибкой ниже:
Я нашел это на MSDN
Чтобы заставить это работать правильно, я сделал это
Я считаю, что можно установить эту опцию в коде, используя
но я не проверял это
источник
Создайте представление, которое выбирает только не
NULL
столбцы, и создайтеUNIQUE INDEX
представление:Обратите внимание, что вам нужно выполнять
INSERT
«иUPDATE
» в представлении вместо таблицы.Вы можете сделать это с помощью
INSTEAD OF
триггера:источник
Это можно сделать и в дизайнере
Щелкните правой кнопкой мыши на Index> Properties, чтобы открыть это окно.
источник
Можно создать уникальное ограничение для кластеризованного индексированного представления
Вы можете создать вид следующим образом:
и уникальное ограничение, подобное этому:
источник
Может быть, рассмотреть "
INSTEAD OF
" триггер и сделать проверку самостоятельно? С некластеризованным (неуникальным) индексом для столбца для включения поиска.источник
Как указывалось ранее, SQL Server не реализует стандарт ANSI, когда дело доходит до
UNIQUE CONSTRAINT
. Существует билет на Microsoft Connect для этого с 2007 года , как там и предложил здесь лучшие варианты , как сегодня должны использовать фильтрованную индекс , как указано в другом ответе или вычисляемого столбца, например:источник
Вы можете создать ВМЕСТО триггер для проверки определенных условий и ошибок, если они выполняются. Создание индекса может быть дорогостоящим для больших таблиц.
Вот пример:
источник
Вы не можете сделать это с
UNIQUE
ограничением, но вы можете сделать это в триггере.источник
источник
этот код, если вы делаете регистрационную форму с textBox и используете вставку, а ваш textBox пуст и нажимаете кнопку отправки.
источник