1つのテーブルに複数の主キーを含めることはできますか?


回答:


559

テーブルは、2つ以上の列から作成された主キーである複合主キーを持つことができます。例えば:

CREATE TABLE userdata (
  userid INT,
  userdataid INT,
  info char(200),
  primary key (userid, userdataid)
);

更新: 複合主キーの詳細な説明へのリンクがあります。


2
この例では、一意の行を識別/検索するには、useridとuserdataidの両方が必要です。OPの意図が何かはわかりませんが、キーのセットの1つを使用して行を一意に識別できるかどうかを確認するためにここに来ました。たとえば、両方を必要とせずに、ユーザー名またはユーザーIDのいずれかで一意のユーザーを識別したいとします。私はRBの一意のインデックスの答えがそこにトリックを行うと思います。
Burrito 2017

1
@Benitok RB。の回答で述べたように、Unique Indexesを使用して探していることを実行できます(同じテーブルの他の一意のインデックス付き列から独立した一意のインデックス付き列)。使用される正確な言語構文の詳細については、SQLのマニュアルの特定の種類を参照してください。
4AM

195

主キーは1つしか持てませんが、主キーには複数の列を含めることができます。

テーブルに一意のインデックスを設定することもできます。これは、一意の値を適用し、それらの値のクエリを高速化するという点で、主キーのように機能します。


39

テーブルは複数の候補キーを持つことができます。各候補キーは、UNIQUEである列または列のセットであり、まとめてNOT NULLになります。したがって、任意の候補キーのすべての列に値を指定するだけで、条件を満たす行が1つあるか、まったく行がないかを判断できます。

候補キーは、リレーショナルデータモデルの基本的な概念です。

1つのテーブルに複数のキーが存在する場合、候補キーの1つを主キーとして指定するのが一般的です。また、テーブルへの外部キーが他の候補キーではなく主キーを参照するようにすることも一般的な方法です。

これらの方法をお勧めしますが、リレーショナルモデルには、候補キーの中から主キーを選択する必要があるものはありません。


5
同意した。論理モデルでは、すべてのキーが同じです(どれも「プライマリ」ではありません)。物理実装のどのキーがPRIMARY KEYの指定を取得するかの選択は、アービトレイとベンダー/製品によって異なります。
2008年

3
データベースデザイナーに依存していると思います。
Walter Mitty

これが必要なユースケースに遭遇しました。Entity Frameworkによって作成/管理されるテーブルがあります-現在、収集できる限り、非主キーの一意の複合制約をサポートしていません。ただし、複合主キーはサポートしています。データは、複合キーをまったくサポートしていないリモートデータベースシステムにもリンクされます。私はEFで複合PKを作成しましたが、他のシステムが一意に識別するために使用できるnull不可のGUID列も追加しました。
Chris Nevill、2014年

2
クリス、私はリレーショナルモデルは主キーを必要としないと述べました。いくつかのツールがそれらを必要とするかどうかについては何も言わなかった。しかし、私はあなたの要点を理解します。
Walter Mitty、2014年

PKを最小限にする、つまり各レコードを一意に識別するために使用する列の数を最小限にする必要があると思います。
ゲイリー、

14

これは、メインの質問と@Kalmiの質問の両方に対する回答です

複数の自動生成列があることのポイントは何ですか?

以下のコードには複合主キーがあります。その列の1つは自動インクリメントされます。これはMyISAMでのみ機能します。InnoDBはエラー「ERROR 1075(42000):Incorrect table definition; only can be only one auto column and must be defined as a key "」を生成します。

DROP TABLE IF EXISTS `test`.`animals`;
CREATE TABLE  `test`.`animals` (
  `grp` char(30) NOT NULL,
  `id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `name` char(30) NOT NULL,
  PRIMARY KEY (`grp`,`id`)
) ENGINE=MyISAM;

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Which returns:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+

2
これは、主キー定義で最初に自動インクリメント列を指定した場合に機能します。(たぶん、これは変更されたので、5.6でテストしました)
CTarczon

11

(これまでたくさん勉強してきました)

候補キー -テーブルの行を一意に識別するために必要な最小限の列の組み合わせ。
複合キー -2つ以上の列。

  • テーブルには複数の候補キーが存在できます。
    • 主キー - 私たちが選択した候補キーの1つのみ
    • 代替キー - 他のすべて候補キー
      • 主キーと代替キーの両方を複合キーにすることができます

ソース:
https//en.wikipedia.org/wiki/Superkey
https://en.wikipedia.org/wiki/Candidate_key
https://en.wikipedia.org/wiki/Primary_key
https://en.wikipedia.org / wiki / Compound_key


6

他の人が指摘したように、複数列の主キーを持つことが可能です。ただし、キーによって導入されない機能の依存関係がある場合は、関係の正規化を検討する必要があることに注意してください。

例:

Person(id, name, email, street, zip_code, area)

間の機能の依存関係が存在することができid -> name,email, street, zip_code and area しかし、多くの場合、zip_code関連付けられているareaので、間の内部機能dependecyありますzip_code -> area

したがって、別のテーブルに分割することを検討できます。

Person(id, name, email, street, zip_code)
Area(zip_code, name)

そのため、第3正規形と一致します。


6

「プライマリ」の意味合いと論理モデルに起因する潜在意識の関連付けのため、プライマリキーは非常に残念な表記法です。したがって、使用は避けます。代わりに、物理モデルのサロゲートキーと論理モデルの自然キーを参照します。

すべてのエンティティの論理モデルには、エンティティのキ​​ーを構成する「ビジネス属性」のセットが少なくとも1つあることが重要です。Boyce、Codd、Dateなどは、リレーショナルモデルでこれらを候補キーと呼びます。次に、これらのエンティティのテーブルを作成すると、それらの候補キーはそれらのテーブルの自然キーになります。ユーザーがテーブル内の行を一意に識別できるのは、これらの自然キーを介してのみです。代理キーは常にユーザーから非表示にする必要があるためです。これは、代理キーにビジネス上の意味がないためです。

ただし、テーブルの物理モデルは、多くの場合、代理キーがないと非効率になります。非クラスター化インデックスのカバーされていない列は、クラスター化インデックスへのキールックアップを通じてのみ(通常)見つけることができることを思い出してください(一時的にヒープとして実装されたテーブルは無視してください)。使用可能なNatural Keyが広い場合、これは(1)非クラスター化リーフノードの幅を広げ、非クラスター化インデックスのシークおよびスキャンに対するストレージ要件と読み取りアクセスを増加させます。(2)クラスター化インデックスからのファンアウトを減らし、インデックスの高さとインデックスサイズを増やし、クラスター化インデックスの読み取りとストレージの要件を増やします。(3)クラスタ化インデックスのキャッシュ要件を増やします。他のインデックスとデータをキャッシュから追い出します。

これは、「主キー」としてRDBMSに指定された小さなサロゲートキーが有益であることが証明される場所です。クラスタリングキーとして設定すると、非クラスタ化インデックスからクラスタ化インデックスへのキールックアップや、関連テーブルからの外部キールックアップに使用されるため、これらの欠点はすべてなくなります。クラスタ化インデックスのファンアウトは再び増加し、クラスタ化インデックスの高さとサイズを削減し、クラスタ化インデックスのキャッシュ負荷を削減し、任意のメカニズム(インデックススキャン、インデックスシーク、非クラスタ化キールックアップまたは外部キールックアップ)を介してデータにアクセスするときの読み取りを削減します。また、テーブルのクラスター化インデックスと非クラスター化インデックスの両方のストレージ要件を減らします。

これらの利点は、代理キーが小さく、クラスタリングキーの両方である場合にのみ発生することに注意してください。GUIDをクラスタリングキーとして使用すると、利用可能な最小のNaturalキーが使用された場合よりも状況が悪化することがよくあります。テーブルがヒープとして編成されている場合、8バイト(ヒープ)のRowIDがキールックアップに使用されます。これは、16バイトのGUIDよりも優れていますが、4バイトの整数よりもパフォーマンスが劣ります。

ビジネス上の制約のためにGUIDを使用する必要がある場合は、より良いクラスタリングキーを検索する価値があります。たとえば、小さなサイト識別子と4バイトの「site-sequence-number」が可能である場合、その設計は代理キーとしてのGUIDよりも優れたパフォーマンスを提供する可能性があります。

ヒープの結果(おそらくハッシュ結合)が優先ストレージになる場合、より広いクラスタリングキーのコストは、トレードオフ分析でバランスを取る必要があります。

この例を考えてみましょう::

ALTER TABLE Persons
ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)

タプル「(P_Id、LastName)」は一意性制約を必要とし、長いUnicode LastName + 4バイト整数である場合があります。(1)この制約を「ADD CONSTRAINT pk_PersonID UNIQUE NONCLUSTERED(P_Id 、LastName) "および(2)小さなサロゲートキーを個別にクラスター化インデックスの" 主キー "として宣言します。注目すべきは、AnitaがLastNameをこの制約に追加したいだけなので、カバードフィールドを作成することです。すべてのフィールドがカバーされているため、クラスター化インデックスでは不要です。

SQL Serverで主キーを非クラスター化として指定する機能は、「論理モデルからの」「優先自然キーまたは候補キー」という意味と物理からの「ストレージ内のルックアップキー」という意味が混同されているため、不幸な歴史的状況です。モデル。私の理解では、元々のSYBASE SQL Serverは、物理モデルからの「ストレージ内のルックアップキー」として、ヒープまたはクラスタ化インデックスにかかわらず、常に4バイトのRowIDを使用していました。


3
これを英語に翻訳してください!
Jasir

3

一部の人々は、「主キー」という用語を、何らかの自動メカニズムによって生成された値を取得する整数列を正確に意味するために使用します。たとえばAUTO_INCREMENT、MySQLまたはIDENTITYMicrosoft SQL Serverです。この意味で主キーを使用していますか?

その場合の答えは、使用しているデータベースのブランドによって異なります。MySQLでは、これを行うことはできず、エラーが発生します。

mysql> create table foo (
  id int primary key auto_increment, 
  id2 int auto_increment
);
ERROR 1075 (42000): Incorrect table definition; 
there can be only one auto column and it must be defined as a key

他のいくつかのブランドのデータベースでは、テーブルに複数の自動生成列を定義できます。


5
複数の自動生成列があることのポイントは何ですか?
TarnayKálmán

私はユースケースを考えていませんが、必要があれば、データベースのブランドによってはこれをサポートするものとサポートしないものがあります。私が言っているのはそれだけです。
ビルカーウィン

1
ケースは次のとおりです。ordersテーブルには、ID(自動インクリメント)と外部ID(ハッシュのような文字列)の両方があり、どちらも一意でなければならないので、理論的にはどちらも「プライマリ」であると言えます。もちろん、これはセカンダリユニークインデックスで実行できますが、それでも正当なケース(IMHO)です
Nir

2

2つの主キーを同時に持つことはできません。しかし、(複合キーでケースをめちゃくちゃにしていないと仮定すると)、1つの属性を一意にすることが必要になる場合があります。

CREATE t1(
c1 int NOT NULL,
c2 int NOT NULL UNIQUE,
...,
PRIMARY KEY (c1)
);

ただし、リレーショナルデータベースでは、「スーパーキー」はテーブルのタプルまたは行を一意に識別する属性のサブセットであることに注意してください。「キー」は「スーパーキー」であり、キーから任意の属性を削除して、そのキーを「スーパーキー」ではなくする(または単に「キー」が最小のスーパーキーになる)追加のプロパティがあります。さらにキーがある場合、それらのすべてが候補キーです。候補キーの1つを主キーとして選択します。そのため、1つのリレーションまたはテーブルの複数の主キーについて話し合うことは対立します。


ウィキペディアには「キー」の定義がありません。また、「キーから任意の属性を削除すると、そのキーは「スーパーキー」ではなくなります」というのは、スーパーキーから属性を削除してもスーパーキーである可能性があるため、私には何の意味もありませんでした。
Manohar Reddy Poreddy

@ManoharReddyPoreddyはい、その場合、属性のセットは「キー」ではなく「スーパーキー」です。つまり、属性のセットを「キー」にするか、セットを最小限にするか、またはセットから属性を削除して、結果のセットを「スーパーキー」にしない追加のプロパティを設定する必要があるということです。
Rusiru Adithya Samarasinghe

「キー」の実際の意味はCandidate_key(en.wikipedia.org/wiki/Candidate_key)です。
Manohar Reddy Poreddy

@ManoharReddyPoreddyはい私はすでに私の回答でそれを述べました。「より多くのキーがある場合、それらはすべて候補キーです」。とにかくあなたのレビューをありがとう。
Rusiru Adithya Samarasinghe

1.「より多くのキーがある場合、それらのすべてが候補キーです」と述べるとき、...そうでない場合、またはそうでない場合、それらは候補キーではありませんか?... 2. else-partはどこにありますか?...私たちはまったく同じページですか?
Manohar Reddy Poreddy

1

主キーは、レコードを一意に識別するキーであり、すべてのインデックスで使用されます。これが、1つしか持てない理由です。また、通常は子テーブルへの結合に使用されるキーですが、これは必須ではありません。PKの本当の目的は、何かがレコードを一意に識別できるようにし、データの変更が正しいレコードに影響し、インデックスを作成できるようにすることです。

ただし、1つの主キー(複合PK)に複数のフィールドを配置できます。これにより、結合が遅くなり(特に、文字列型フィールドが大きい場合)、インデックスが大きくなりますが、一部の子テーブルで結合を実行する必要がなくなる可能性があるため、パフォーマンスと設計に関しては、ケースベース。これを行う場合、各フィールド自体は一意ではありませんが、それらの組み合わせは一意です。複合キーの1つ以上のフィールドも一意である必要がある場合は、それに一意のインデックスが必要です。ただし、1つのフィールドが一意である場合、これがPKのより良い候補である可能性があります。

現在、時々、PKの候補者が複数います。この場合、PKとして1つを選択するか、代理キーを使用します(私は個人的にこのインスタンスの代理キーを好みます)。そして(これは重要です!)PKとして選択されなかった候補キーのそれぞれに一意のインデックスを追加します。データを一意にする必要がある場合は、PKであるかどうかに関係なく、一意のインデックスが必要です。これはデータの整合性の問題です。(これは、代理キーを使用する場合にも当てはまります。候補キーに一意のインデックスを作成するのを忘れているため、代理キーで問題が発生します。)

複数のサロゲートキー(必要な場合は通常はPK)が必要になる場合があります。この場合、必要なのはより多くのPKではなく、自動生成キーを持つより多くのフィールドです。ほとんどのDBではこれを許可していませんが、回避する方法はいくつかあります。最初に、2番目のフィールドが最初の自動生成キー(たとえば、Field1 * -1)に基づいて計算できるかどうか、または2番目の自動生成キーの必要性が実際に関連するテーブルの作成を意味するかどうかを検討します。関連するテーブルは、1対1の関係にあります。親テーブルから子テーブルにPKを追加し、新しい自動生成フィールドをテーブルに追加してから、このテーブルに適切なフィールドを追加することで、これを適用します。次に、2つのキーの1つをPKとして選択し、もう一方に一意のインデックスを配置します(自動生成フィールドはPKである必要はありません)。また、親テーブルにあるフィールドにFKを必ず追加してください。一般に、子テーブルに追加のフィールドがない場合は、2つの自動生成フィールドが必要であると考える理由を調べる必要があります。


0

良い技術的な答えは、私ができるよりも良い方法で与えられました。私はこのトピックにのみ追加できます:

許可されていない/受け入れられないものが必要な場合は、一歩戻るのがもっともです。

  1. それが受け入れられない理由の核心を理解します。
  2. ドキュメンテーション/ジャーナル記事/ウェブなどでさらに掘り下げます
  3. 現在の設計を分析/レビューし、主要な欠陥を指摘します。
  4. 新しい設計のすべてのステップを検討してテストします。
  5. 常に楽しみにして、適応型ソリューションを作成してください。

それが誰かを助けることを願っています。


1
特定の質問に対する答えではなく、一般的な(有用ではある)アドバイス。
Bradford Needham 2017年

-3

はい、SQLでは可能ですが、MsAccessで複数の主キーを設定することはできません。すると、他のデータベースについてはわかりません。

CREATE TABLE CHAPTER (
    BOOK_ISBN VARCHAR(50) NOT NULL,
    IDX INT NOT NULL,
    TITLE VARCHAR(100) NOT NULL,
    NUM_OF_PAGES INT,
    PRIMARY KEY (BOOK_ISBN, IDX)
);

SQLテーブルは1つのPKのみを持つことができます。
philipxy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.