主キー

 テーブルにおいて必要な行を特定するために欠かせない主キーの設定方法、主キーに適した列の考え方等について説明します。

主キーとは

 主キーは、テーブルに記録された行(レコード)のうち、ただ1つを特定する(「一意に識別する」とも言います)ことができるように設定するものです。具体的にはテーブルの列(フィールド)からいずれかを選んで主キーとして設定します。主キーとして設定された列には一定の制約(他の行と重複する値を記録することができない、Nullとすることができない)がかかりますが、これにより、主キーとなっている列の値さえ特定できれば行をただ1つに特定できる、という状態が保証されます。
 主キーは必ず設定しなければならないというものではありませんが、複数のテーブルを連携させていく場合には特に欠かせないものであり、データベースを構築する際の重要な基礎となります。主キーの設定は、テーブルにおけるさまざまな設定の中で最も重要なものといえます。

1つの行を特定することの必要性

 たいていのテーブルでは1つ1つの行の内容がそれぞれ異なったものとなり、どの行が何を指しているのか自然と識別できますが、列の設定の仕方と実際のデータの内容によっては全く同内容の行になってしまうことも考えられます。
 例として次のようなテーブルがあるものとします。

顧客テーブル
氏名住所
山田 敏子○○市△△1−1
伊藤 瞬□□市**6−12
吉川 真治××町☆☆2
山田 敏子○○市△△1−1
吉澤 美由紀○○市▽▽3−8

たまたま同姓同名で住所も同じ人物が記録されており、2つの行がそれぞれどちらの人を指しているのかは全く識別できません。しかし苗字も名前も住所も同じ人物というのはあり得ないことではありませんし、それをそのままテーブルに記録すること自体は別に異状でもなければ不可能でもありません。例えばこのテーブルが専ら地域(市町村)ごとの顧客人数を把握するためだけに利用されるのであれば、人物が2人いるということが記録されているだけでも十分に機能していると捉えることができます。
 しかし、この2人を区別して記録することが必要となる場合があります。これらの個人を対象とした販売やサポートといった出来事を記録していこうとする場合、仮に同姓同名、同住所であってもそれらのどちらかを確実に識別できるようにデータを整理しておかなくてはなりません。
 識別できるようにする方法として、まず1つは生年月日でも血液型でも何でもいいので本人について得られる情報を記録する列を増やしていくということが考えられます。どこまで突き詰めても同じという人間は現実には考えにくいですので、どんどん列を増やしていけばどこかで違いが生じることでしょう。
 もう1つは、個人を識別する番号や記号を新たに作り出してしまうという方法があります。顧客番号といった番号や記号を定めて、他の人と重複しない番号を1人に1つ割り当てるようにし、認証が必要であればそれを記載したカードを発行するなどしておけば個人を識別することが可能です。これだと列を1つだけ増やすだけで済みますし、限られた何人かの人々を識別するためだけに情報を収集する手間も必要ありません。
 現実的な解決法は後者が基本となります。具体的には個人を識別するためのコードを設定し、また、もしもの混乱を避けるために別の新たな列を用いて備考や特徴を記していく、という方法が一般的です。

顧客テーブル
顧客番号氏名住所備考
1山田 敏子○○市△△1−1昭和29年生まれ
2伊藤 瞬□□市**6−12
3吉川 真治××町☆☆2
4山田 敏子○○市△△1−1昭和60年生まれ
5吉澤 美由紀○○市▽▽3−8

主キーの設定

 行を1つに特定できるような列を設定することは常に必要とは限りませんが、実際にはとても重要で、ほとんどの業務において欠かせないこととなります。
 しかし、「値が重複してはならない」というルールを守ることを、データを入力する人間に任せていてはそのうちミスが起き、区別のつかないデータが発生する恐れがあります。そこで、重複してはならない列を「主キー」として設定して制約を設けることにより行の識別を確実なものにすることができます。

 実際に主キーを設定してみます。テーブルデザインの画面で、主キーとする列の名前を選んだ上で、ウインドウ上部の「主キー」をクリックします。すると列名の左側にカギのマークが出ます。これだけで主キーの設定は完了です。


 主キーとなった列では他の行と重複する値を記録することができず、また、Nullとすることもできません。いずれかに該当する場合、行の内容を確定しようとした際に(その行から別の行に移ろうとしたとき等に)エラーとなります。
 右の画像は主キー(顧客番号)として重複する値(5)を記録しようとした際のエラーです。


複合キー

 主キーはテーブルごとに1つしか設けられません。しかし、複数の列からなる主キー(複合キーといいます)、というものは設定できます。
 次の例はある学校のクラス名簿を想定したものです。

クラス名簿
クラス番号出席番号氏名
11藤井 美優
12平本 和之
13大西 遥
14長澤 麻友
21秋元 大樹
22益岡 泰三
23照井 桃子

この学校ではクラス番号と出席番号で生徒を識別しています。各クラスには複数の生徒がいますので、同じクラスの行は複数あります。また、各クラスの出席番号は1番から始めるようになっていますので、出席番号が1番である行も複数(クラスの数だけ)ありますし2番以下の生徒も同様です。つまりクラス番号も出席番号も単独では主キーにはなりえません。しかし、クラス番号と出席番号がどちらも同じという生徒はありえませんので、どちらも同じとなる行が複数あることはありません。この場合、クラス番号と出席番号の2つの列の全体を主キーとすることが考えられ、実際にそう設定することができます。

 具体的にはテーブルデザインの画面で複数の列名を選択した上で「主キー」をクリックします。すると複数の列名にわたりカギのマークが表示されます。これは、1つのテーブルに主キーが2つあるのではなく、1つの主キーが2つの列からなることを表します。


 複数の列からなる主キーを設定した場合、個々の列の値については重複が許されますが、それらの列が全体として重複することは許されません。また、いずれの列の値もNullにすることができません。右の画像は主キー({クラス番号,出席番号})として重複する値({2,3})を記録しようとした際のエラーです。


 複合キーについては少々注意が必要です。次のテーブルは、1行ごとに1台の自動車を記録しているテーブルです。

自動車テーブル
ナンバー車台番号車種所有者
横浜300お77-77XYZ753QQ-77PP45678マークX杉山 真季
湘南500し12-34ZZAA123-98BBYY77RX-7関本 陽一
世田谷500へ99-9999999AB11C-8888デミオ小泉 遥人
品川300ん11-11AB11C999-11111ヴィッツ斉藤 薫

 一般に自動車のナンバーは重複しませんし、車台番号も重複しませんので、どちらか一方だけでも特定できれば1台の自動車を特定できる、つまり行を1つに特定することができます。そこで、2つとも(個別の)主キーにしたいと考えてその2列を選んで主キーとして設定すると、実際には1つの複合キーとみなされてしまいます。


 その結果、ナンバーも車台番号も両方とも同じという行が複数存在することは許されないものの、ナンバーが同じ行が複数あっても許されますし、車台番号が同じという行が複数あることも許されてしまいます。つまり本来意図したような制約になりません。右の画像では重複するナンバー(品川300ん11-11)の記録が許容されてしまっていまるのがわかります。なまじ本来の意図どおりに番号が入力されている限り、ミスであることが露呈しにくいので注意が必要です。


 もし、値が重複してはいけないという制約を列ごとに設けたい場合は、主キーとは別にインデックスという機能を利用する必要があります。

主キーに適した列

 ここで少し振り返ってみましょう。Accessの機能としてはどんな列でも主キーとして設定することは出来ます(ただし、データ型がOLEオブジェクト型等となっている列はできません)。しかし、行を確実に識別するという役割を持たせる以上、主キーに適した列、適していない列というのは自ずと存在します。主キーが必要であるにもかかわらずそれに適した列が存在しない場合は新たに作り出してしまう必要があります。
 一般に、主キーとなる列に求められる性質を挙げてみます。

  • 値が重複しないこと…最も重要な性質です。たまたま今のところ値が重複していないからそれでよい、というものではありません。例えば人物を記録するテーブルに生年月日という列があって、たまたま生年月日が同じ人物がいないからといって生年月日を主キーとしてしまうと、新たに記録しようとする人物の生年月日と既存の人物の生年月日が重複してしまい、新たな人物を記録できなくなることが考えられます。将来にわたって重複する値が存在し得ない、ということが重要です。生年月日だけでなく、氏名や住所を主キーにしても同じ結果となる可能性がありますので、これらは主キーには向いていません。
  • 値がNullとならないこと…つまり、値が確実に存在し入手することが出来るものであることが求められます(なければ適当な記号や番号を自ら作り出すしかありません)。例えば人物を記録するテーブルにおいて連絡先メールアドレスを主キーにすることは適当でしょうか。ネット上でのコミュニティでは問題ないかもしれません。しかし、一般にはメールアドレスを持たない人も大勢いるので必ずしも適当とはいえません。また、日本国民には一人ひとりに住民票コードという番号が割り当てられており、これは主キーとするのに打ってつけ、と考えられますが、住民票コードは高度なプライバシー情報にあたり(官公庁でない限り)収集が禁止されていますので、現実的には主キーとすることができません。
  • 値の変更がない(少ない)こと…主キーとして設定した値はさまざまな形で参照・引用されることが考えられます(社員番号が社員証に記載されるなど)ので、主キーは変更がないものが望ましいとされます。また、Accessの内部においても、あるテーブルで主キーとなっている列の値を他のテーブルから参照している(外部キーといいます。以降で説明します)場合、主キーを変更すると、他のテーブルの値もすべて変更しないと矛盾が生じてしまいますので、やはり変更がないものがよいとされます。しかし、後で見るように参照整合性(連鎖更新)の設定を行うことにより、主キーの値を変更すると同時に外部キーの値を変更するようにでき、少なくともAccess内部(テーブル上のデータ)の不整合は防ぐことが出来ます。
  • 形式が整っており簡潔であること…Accessの機能としては漢字・ひらがな・英数字が混合した主キーだろうと長短にばらつきがある主キーだろうと問題はありませんが、利用する人間が混乱しますので、必ず整数にするとか「1桁目が半角英字で2から8桁までは半角数字」とするなどルールを決めるのが一般的です。外部キーとして他のテーブルから参照する場合などに面倒になりやすいので、主キーの値は簡潔なものにすべきといえます。このほか、4列も5列もあるような複合キーを主キーにしている場合もやはり参照するのが面倒になりますので、主キーとするためだけに新たな列を増やすことにでなってでもシンプルな主キーを設定することが好ましいとされます。ただし、新たな列の濫造になるのも考えものですので、これはそれほど強い要求ではありません。

 さて、上記のような基準から判断すると、世の中に自然に存在している情報の多くは主キーにできませんし、可能性があるものでもたいていは向いてません。
 例えば、人名はともかく国名や都道府県名は決して重複しないと考えられるので、国テーブルや都道府県テーブルを作って利用する場合にはそのまま主キーにしても良さそうなものですが、実際は国コードや都道府県コードが設けられ主キーとされます。ひとつの理由として、上記のように主キーの値は簡潔であるべきという理由がありますし、また、並べ替えの基準となる列(ソートキー)があった方が便利であり、主キーをその並べ替えの基準としても利用したい(実際に都道府県テーブルを作る場合、北海道のコードは1、青森のコードは2といったように、たいてい北から順にコードが割り振られます)、ということが挙げられます。
 結局のところ、名前などで一意に識別できる場合であっても適当な記号や番号をコードとして設定し、その列を設けて主キーとするのが無難で一般的な方法といえます。また、上記の複合キーの例(クラス、出席番号)のようにルールがきちんと整理されていて複雑なものでなければ複合キーになっていても特に問題はありません。

外部キー

 あるテーブルで主キーになっている列の値を、別のテーブルにも記録することによって、2つ(以上)のテーブルのデータにつながりをもたせることができます。
 例としては、次のようなものがあります。

メーカーテーブル
メーカーコードメーカー名
1篠山飲料
2山本フーズ
3東亜ビバレッジ

商品テーブル
商品コードメーカーコード商品名
A000011100%ドリアンジュース
A000021ホット専用冬のコーラ
A000032半生茶
A000042ミラクルエナジードレイン
A000053水素水コーヒー
A000063荒川深層水
A000073はちみつメロン

 メーカーテーブルにはメーカー企業の情報が1行ごとに記録されており、メーカーコードが主キーとなります。
 一方で商品テーブルでは商品コードが主キーとなりますが、このテーブルにもメーカーコードという列があります。この値からメーカーテーブルを参照することにより、商品のメーカーの情報を知ることが出来ます。
 このように、あるテーブルでの主キー(この場合はメーカーテーブルのメーカーコード)となっている値を記録している、別のテーブルの列(この場合は商品テーブルのメーカーコード)を外部キーといいます。
 ただし、この(後述するリレーションシップの設定を行っていない)段階では、単にこれらの列の名称と値を一致させていることをもって、両方のテーブルにつながりがあるものと人間が解釈しているに過ぎません。Excelのようにセルを参照したり、何か設定を行うことでつながりを持たせているわけではないので、どちらかの値が変更され一致しなくなってしまっただけで、このつながりは失われてしまいます。
 しかし、リレーションシップという設定を行うことにより、テーブルどうし、列どうしのつながりを具体的に定義づけることができます。両方の列で一致しない値は記録できない、といった一定の制約を課すことにより、テーブル間の不整合を回避し、連動を確実なものにすることができるのです。