NULL列に一意のインデックスを作成する方法は?
-
08-07-2019 - |
質問
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)
より良いアイデアはありますか?
解決
一意の目的に違反しているため、それができないことを確認してください。
ただし、この人は適切な回避策を持っているようです: 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 。 (Simonはこれをコメントとして追加しましたが、コメントは簡単に見落とされるため、独自の回答に値すると考えました。)
別のオプションは一意性をチェックするトリガーですが、これはパフォーマンスに影響を与える可能性があります。
計算された列のトリックは、「ヌルバスター」として広く知られています。私のメモは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)
)
厳密に言えば、同じ値(およびこれにはNULLを含む)が複数回明らかに一意制約に違反しているため、一意のNULL可能列(または列のセット)は一度だけNULL(またはNULLのレコード)になります。 / p>
ただし、「一意の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" inside" 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の行にuniqnull値が関連付けられていない場合(つまり、the_entity_incorrectにNULLを挿入する場合)、the_relationに行を追加しません。
uniqnullの値は、すべてのthe_relationに対して一意であり、the_entityの各値には、主キーと外部キーがこれを強制するため、最大で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に対応する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
;
「左外部結合」演算子は、the_entityのすべての行が結果に表示されるようにし、一致する列がthe_relationに存在しない場合はuniqnull列にNULLを入れます。
十分に正規化されたデータベース(および対応する非正規化ビューと手順)を設計するのに数日(または数週間または数ヶ月)費やした労力は、数年(または数十年)の痛みと無駄なリソースを節約します。