Значение поля должно быть уникальным, если оно не равно NULL - PullRequest
10 голосов
/ 18 декабря 2008

Я использую SQL Server 2005.

У меня есть поле, которое должно содержать либо уникальное значение, либо значение NULL. Я думаю, что я должен применять это либо с CHECK CONSTRAINT, либо с TRIGGER for INSERT, UPDATE.

Есть ли преимущество в использовании здесь ограничения перед триггером (или наоборот)? Как может выглядеть такое ограничение / триггер?

Или есть другой, более подходящий вариант, который я не рассматривал?

Ответы [ 7 ]

6 голосов
/ 18 декабря 2008

Я создаю представление с индексом, который игнорирует нулевые значения в предложении where ... т.е. если вы вставляете нуль в таблицу, представлению все равно, но если вы вставляете ненулевое значение, представление будет применять ограничение.

create view dbo.UniqueAssetTag with schemabinding
as
select asset_tag
from dbo.equipment
where asset_tag is not null

GO

create unique clustered index ix_UniqueAssetTag
on UniqueAssetTag(asset_tag)

GO

Так что теперь в моей таблице оборудования есть столбец asset_tag, который допускает несколько нулевых значений, но только уникальные ненулевые значения.

Примечание: Если вы используете mssql 2000, вам нужно будет " SET ARITHABORT ON " непосредственно перед выполнением любой вставки, обновления или удаления таблицы. Уверен, что это не требуется на MSSQL 2005 и выше.

4 голосов
/ 18 декабря 2008

Вот альтернативный способ сделать это с ограничением. Чтобы применить это ограничение, вам понадобится функция, которая подсчитывает количество вхождений значения поля. В вашем ограничении просто убедитесь, что этот максимум равен 1.

Ограничение:

   field is null or dbo.fn_count_maximum_of_field(field) < 2

РЕДАКТИРОВАТЬ Я не могу вспомнить прямо сейчас - и не могу проверить это также - выполняется ли проверка ограничения до вставки / обновления или после. Я думаю, что после вставки / обновления отката при сбое. Если окажется, что я ошибаюсь, то 2 выше должно быть 1.

Табличная функция возвращает int и использует следующий select для ее получения

   declare @retVal int

   select @retVal = max(occurrences)
   from ( 
        select field, count(*) as occurrences
        from dbo.tbl
        where field = @field
        group by field
   ) tmp

Это должно быть достаточно быстро, если ваш столбец (неуникальный) индекс для него.

3 голосов
/ 17 ноября 2009

Это можно сделать, создав вычисляемый столбец и поместив уникальный индекс в этот столбец.

ALTER TABLE MYTABLE 
ADD COL2 AS (CASE WHEN COL1 IS NULL THEN CAST(ID AS NVARCHAR(255)) ELSE COL1 END)

CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2)   

Предполагается, что ID - это PK вашей таблицы, а COL1 - это столбец "уникальный или пустой".

В вычисляемом столбце (COL2) будет использоваться значение PK, если ваш «уникальный» столбец равен нулю.

В следующем примере все еще существует вероятность коллизий между столбцом ID и COL1:

ID     COL1    COL2
1     [NULL]    1
2        1      1

Чтобы обойти это, я обычно создаю другой вычисляемый столбец, в котором хранится значение, полученное в COL2, из столбца ID или столбца COL1:

 ALTER TABLE MYTABLE 
 ADD COL3 AS (CASE WHEN COL1 IS NULL THEN 1 ELSE 0 END)

Индекс должен быть изменен на:

CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2, COL3)   

Теперь индекс находится в обоих вычисляемых столбцах COL2 и COL3, поэтому проблем нет:

ID     COL1    COL2   COL3
1     [NULL]    1       1
2        1      1       0
2 голосов
/ 18 декабря 2008

Есть ли первичный ключ в этой таблице, может быть, столбец Identity? Вы можете создать уникальный ключ, который является составной частью поля, для которого вы вводите уникальность в сочетании с первичным ключом.

Здесь обсуждается именно этот вопрос: http://blog.sqlauthority.com/2008/09/07/sql-server-explanation-about-usage-of-unique-index-and-unique-constraint/

К вашему сведению - в SQL Server 2008 представлены отфильтрованные индексы, которые позволят вам подойти к этому немного по-другому.

2 голосов
/ 18 декабря 2008

В Oracle уникальный ключ разрешит несколько NULL.

В SQL Server 2005 хорошим подходом является выполнение вставок через представление и отключение прямых вставок в таблицу.

Вот пример кода.

0 голосов
/ 18 декабря 2008

Ограничение намного легче, чем триггер, даже если уникальное ограничение фактически является индексом.

Однако вам разрешено использовать только одно значение NULL в уникальном ограничении / индексе. Таким образом, вам придется использовать триггер для обнаружения дубликатов.

От MS * было запрошено игнорировать NULLS , но в SQL 2008 отфильтрованы индексы (как уже упоминалось, пока я набираю это)

0 голосов
/ 18 декабря 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...