104

SQL Server 2005 を使用しています。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)

より良いアイデアはありますか?

4

5 に答える 5

107

SQL Server 2008 を使用すると、フィルター処理されたインデックスを作成できます: http://msdn.microsoft.com/en-us/library/cc280372.aspx。(Simon がこれをコメントとして追加したように見えますが、コメントが見逃されやすいため、独自の回答に値すると考えました。)

もう 1 つのオプションは、一意性をチェックするためのトリガーですが、これはパフォーマンスに影響を与える可能性があります。

于 2010-07-07T02:50:14.447 に答える
75

計算された列のトリックは、「ヌルバスター」として広く知られています。私のメモはSteve 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)
)
于 2008-10-10T14:56:44.757 に答える
24

ユニークの目的に違反しているので、それができないことは間違いありません。

ただし、この人はディーセントワークを回避しているようです: http ://sqlservercodebook.blogspot.com/2008/04/multiple-null-values-in-unique-index-in.html

于 2008-10-10T14:17:17.193 に答える
-3

厳密に言えば、一意の null 許容列 (または列のセット) が NULL (または NULL のレコード) になるのは 1 回だけです。これは、同じ値 (およびこれには NULL を含む) が 2 回以上存在すると明らかに一意制約に違反するためです。

ただし、それは「一意の null 許容列」の概念が有効であることを意味するものではありません。リレーショナルデータベースに実際に実装するには、この種のデータベースは適切に機能するように正規化する必要があることを覚えておく必要があります.正規化には通常、エンティティ間の関係を確立するためにいくつかの(エンティティではない)余分なテーブルを追加する必要があります. .

「一意のnull許容列」を1つだけ考慮して基本的な例を考えてみましょう。それをより多くの列に拡張するのは簡単です。

次のようなテーブルで表される情報があるとします。

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

uniqnull を分離し、2 つ目のテーブルを追加して、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 にも行を追加する必要があります。

the_entity の行に一意の null 値が関連付けられていない場合 (つまり、the_entity_incorrect に NULL を入れる行の場合)、単に the_relation に行を追加しません。

uniqnull の値はすべての the_relation で一意であることに注意してください。また、the_entity の各値に対して、the_relation の値は最大で 1 つになることに注意してください。これは、主キーと外部キーがこれを強制するためです。

次に、uniqnull の値 5 を the_entity id 3 に関連付ける場合は、次のことを行う必要があります。

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

そして、the_entity の id 値 10 に対応する一意の null がない場合は、次のことのみを行います。

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
;

「左外部結合」演算子は、the_entity からのすべての行が結果に表示されることを保証し、一致する列が the_relation に存在しない場合、uniqnull 列に NULL を置きます。

適切に正規化されたデータベース (および対応する非正規化ビューと手順) を設計するために数日 (または数週間または数か月) を費やすことで、何年 (または何十年) もの労力と無駄なリソースを節約できます。

于 2015-02-24T05:33:08.527 に答える