「主キー制約と一意キー制約の違いは何ですか?」
これはおそらく、データベース開発者にとって最も頻繁に尋ねられる就職の面接の質問です。この記事では、それに答えようとします。
まず、プライマリキーと一意のキー、およびそれらの類似点を確認します。
主キー
主キーは、テーブル内の各レコードを一意に識別するために使用されます。各テーブルには、少なくとも1つの主キーが必要です。 SQL Serverで主キーを定義するには、列の名前の後に「主キー」というキーワードを使用するだけです。
一意キー
一意キー制約のある列には、一意の値のみを含めることができます。これは、一意キーが列内に重複する値を格納することを禁止している結果です。
一意のキーを定義するには、フィールドの名前に「一意」を追加する必要があります。テーブルに一意キーを含めることは必須ではないことに注意してください。
プライマリキーと一意のキーの作成例
次のスクリプトは、「Cars」という1つのテーブルを含む「Test」データベースを作成します。
このテーブルには、「ID」という名前の主キー列と「NumberPlate」という名前の一意のキー列があります。
CREATE DATABASE TEST GO USE TEST GO CREATE TABLE Cars ( ID int PRIMARY KEY, Name varchar(255) NOT NULL, NumberPlate varchar(255) UNIQUE, Model int );
次に、「Cars」テーブルにいくつかのダミーレコードを追加しましょう。次のスクリプトを実行します。
INSERT INTO Cars VALUES (1, 'Toyota', 'ABC 123', 199), (2, 'Toyota', 'ABC 345', 207), (3, 'Toyota', 'ABC 758', 205), (4, 'Toyota', 'ABC 741', 306), (5, 'Toyota', 'ABC 356', 124)
違いについて説明する前に、まずプライマリキーと一意のキーの類似点を見てみましょう。
プライマリキーと一意のキーの類似点
- 主キーまたは一意のキーを持つ列に重複する値を含めることはできません。
ID値が2の新しいレコード(すでに存在している)を「Cars」テーブルに追加してみましょう。次のスクリプトを実行します。
INSERT INTO Cars VALUES (2, 'Toyota', 'ABC 345', 356)
上記のスクリプトを実行すると、次のエラーが表示されます。
このエラーは、このステートメントが主キーの制約に違反しており、重複する値を主キーの列に挿入できないことを明確に示しています。
同様に、次のクエリを使用して、一意のキー制約を使用して「NumberPlate」列に重複する値を挿入してみましょう。
INSERT INTO Cars VALUES (6, 'Toyota', 'ABC 345', 356)
今回は、一意キー制約のある「NumberPlate」列に値「ABC345」がすでに存在するため、一意キー制約の違反があることがわかります。エラーメッセージは次のようになります:
- 主キーと一意の列はどちらも重複する値を受け入れないため、テーブル内のレコードを一意に識別するために使用できます。これは、主キー列または一意キー列の値ごとに、1つのレコードのみが返されることを意味します。
プライマリキーと一意のキーの違い
主キーと一意のキーの類似点を理解したので、それらの違いを見てみましょう。
- テーブルには主キーを1つだけ含めることができますが、一意のキーは複数持つことができます。
次の例は、これをよりよく理解するのに役立ちます。
以前に作成した「テスト」データベース内に、2つの主キーを使用して新しい「Cars2」テーブルを作成しましょう。これを行うには、次のスクリプトを実行します。
CREATE TABLE Cars2 ( ID int PRIMARY KEY, Name varchar(255) NOT NULL, NumberPlate varchar(255) UNIQUE, Model int PRIMARY KEY );
上記のスクリプトでは、ID列とモデル列に主キー制約を設定しています。ただし、テーブル内の1つの列のみが主キー制約を持つことができるため、次のエラーが表示されます。
このエラーメッセージは、テーブルに複数の主キー制約を設定できないことを明確に示しています。
次に、「Cars2」テーブルに複数の一意キー制約を追加しましょう。次のスクリプトを見てください:
CREATE TABLE Cars2 ( ID int PRIMARY KEY, Name varchar(255) NOT NULL, NumberPlate varchar(255) UNIQUE, Model int UNIQUE );
これにより、「NumberPlate」列と「Model」列に一意のキー制約を追加できます。テーブルには一意のキー制約を持つ複数の列を含めることができるため、上記のスクリプトを実行するときにエラーメッセージは表示されません。
- 主キー列にnull値を含めることはできませんが、一意キー列に1つのnull値を含めることができます。
これを実際に見てみましょう。まず、「Cars」テーブルの主キー列にnull値のレコードを追加しましょう。以下のスクリプトを見てください:
INSERT INTO Cars VALUES ( null, 'Toyota', 'ABC 345', 356)
このスクリプトは、ID列に値としてnullを挿入していることがわかります。実行すると、出力メッセージウィンドウに次のエラーが表示されます。
このエラーは、主キー列でnull値が許可されていないため、null値を挿入できないことを示しています。
次に、「NumberPlate」の一意のキー列にnull値を追加してみましょう。これを行うには、次のスクリプトを実行します。
INSERT INTO Cars VALUES ( 6, 'Toyota',null, 356)
これにより、ID値が6でnull値の新しいレコードが「Cars」テーブルに追加されます。具体的には、null値が「NumberPlate」列に割り当てられます。一意キー列はデフォルトでnull値を受け入れることができるため、上記のスクリプトはエラーなしで実行されることがわかります。
null値が実際に「NumberPlate」列に挿入されているかどうかを確認するには、次のスクリプトを使用して「Cars」テーブルからすべてのレコードを選択する必要があります。
SELECT * FROM Cars
上記の結果セットでは、主キー列「ID」がそうではないことがはっきりとわかります。 null値は含まれません。一方、一意キー制約のある「NumberPlate」列には、挿入したばかりのnull値が含まれています。 2番目のnull値は最初のnull値と重複するため、一意のキー列に複数のnull値を追加することはできません。重複は許可されていません。
- デフォルトでは、一意のクラスター化インデックスが主キー列に作成されます。一方、一意の非クラスター化インデックスは、一意のキー列に作成されます。
「Cars」テーブルのインデックスを表示するには、次のスクリプトを実行します。
USE TEST GO sp_help Cars
出力には、次の図に示すように、インデックスを含む「Cars」テーブルの詳細が表示されます。
上の図から、「NumberPlate」列にはクラスター化されていない一意のインデックスがあり、ID列にはクラスター化された一意のインデックスがあることがわかります。
結論
いくつかの基本的な類似点にもかかわらず、プライマリキーと一意のキーには大きな違いがあります。テーブルごとに持つことができる主キーは1つだけですが、複数の一意のキーを持つことができます。同様に、主キー列はnull値を受け入れませんが、一意のキー列にはそれぞれ1つのnull値を含めることができます。そして最後に、主キー列には一意のクラスター化インデックスがあり、一意のキー列には一意の非クラスター化インデックスがあります。