主キーってどうやって決めるの?

# 初めに
基本情報技術者試験の勉強をしていると、必ず出てくるのがデータベースです。勉強すれば試験問題を解くことはできても、実際にデータベースを設計するとなると疑問点が出てきます。この記事では、データベースにおける「主キー」についてまとめます。

# 正規化の試験問題における主キー
LPI-Japan OSS-DBのサイトに載っている正規化の説明から一部流用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149438/26f4dbe1-870e-c181-65be-c1a679e991e4.png)
[第4回　データベースの正規化 oss-db.jp](https://oss-db.jp/dojo/dojo_info_04)

第3正規形を実施する際は「主キー以外の項目について項目同士で依存関係を持つもの(推移的関数従属)」を探します。
- 仕入先(主キー)  -> 代表者名(非キー属性) -> 代表者連絡先(非キー属性)

この場合、「代表者名/代表者連絡先」をテーブルとして独立させます。試験問題ならこれで終了ですが、自身がデータベースの設計をするときはどうでしょう。そもそも「代表者名」が主キーになる可能性はあるでしょうか?上記サイトでは説明が省かれていましたが、第2正規形時点では以下のようなテーブル構成だったと考えられます。

**商品テーブル**
| 商品名 | 一個あたりの金額 | 備考 |
|:-:|:-:|:-:|

**入荷テーブル**
| 商品名 | 仕入先 | 入荷日 | 入荷数 |
|:-:|:-:|:-:|:-:|

**仕入先テーブル**
| 仕入先 | 住所 | 代表者名 | 代表者連絡先 |
|:-:|:-:|:-:|:-:|

仮に「代表者名」が初めから主キーであったら第2正規形/第3正規形のどちらでしょうか?

# そもそも主キーってどうやって決めるの?

https://atmarkit.itmedia.co.jp/ait/articles/1703/01/news180.html

- [スーパーキー | Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%BC%E3%83%91%E3%83%BC%E3%82%AD%E3%83%BC)
- [候補キー | Wikipedia](https://ja.wikipedia.org/wiki/%E5%80%99%E8%A3%9C%E3%82%AD%E3%83%BC)
- [主キー | Wikipedia](https://ja.wikipedia.org/wiki/%E4%B8%BB%E3%82%AD%E3%83%BC)

---

主キーを特定するには「スーパーキー」から「候補キー」を取り出し、そこから「主キー」となるものを選定しているようです。どのキーもテーブルから行を一意に特定できるキーになりますが、違いが幾つかあります。

- スーパーキー
    - 一意に識別できるすべての組み合わせを指す。
    - すべてなので一意に特定するために不要な属性も含まれる。
- 候補キー
    - スーパーキーの中から行を一意に特定できる最低限の組み合わせを指す。
    - 候補キーはテーブルによっては1つ以上存在する可能性がある。
- 主キー
    - 候補キーの中から、識別子として最も適切なものと選んだ1つの候補キーを指す。

「候補キー」から「主キー」を選ぶ際の基準は設計者に委ねられているように読めます。ただ、一定の基準はあり

- 候補キーの中でNOT NULL制約かつ一意制約である(主キー制約)
- 候補キーの中でできるだけデータ量が少なく、簡潔な項目である
- 候補キーの中で更新がかからない項目である

等があげられます。

# 主キーの決め方
初めの説明時点で「仕入先」「商品名」「入荷日」がなぜ主キーで、「代表者名」が主キーではないのか。それは初めの状態を「1つのテーブル」とみなすと分かりやすいかもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149438/26f4dbe1-870e-c181-65be-c1a679e991e4.png)
[第4回　データベースの正規化 oss-db.jp](https://oss-db.jp/dojo/dojo_info_04)
上記のテーブルでは、一つの属性で一意に行を特定することはできません。そのため、人工キーを利用しない場合、既存のキーを組み合わせた複合主キーとなります。

- 「仕入先」は「住所」「代表者氏名」を特定できる
- 「代表者名」は「代表者連絡先」を特定できる
- 「商品名」は「1個当たりの金額」「備考」を特定できる
- 「仕入先/商品名/入荷日」は「入荷数」を特定できる

「代表者名」は「代表者連絡先」を特定できますが、「代表者名」は「仕入先」から特定できます。そのため複合主キーとしては「仕入先/商品名/入荷日」があれば、行を一意に特定できます。したがって **この時点では「代表者名」は主キーとしては不適当です。**

# 注意
ただし、実際にデータベースを設計する際はさらに考慮が必要です。例えば第3正規化を実行したことにより「仕入先」「代表者氏名」「商品名」は主キーになりますが、要件によっては
- 属性のデータが重複する
- 属性のデータが変更される

等が発生します。そのため「人工キー」を作成し、これを主キーとすることがあります。複合主キーに関しても検索時の指定が煩雑になりやすいため、「人工キー」を作成する場合があります。

例
- 「仕入先コード」は「仕入先」「住所」「代表者コード」を特定できる
- 「商品コード」は「商品名」「1個当たりの金額」「備考」を特定できる
- 「代表者コード」は「代表者名」「代表者連絡先」を特定できる
- 「入荷コード」は「仕入先コード」「商品コード」「入荷日」「入荷数」を特定できる


# 余談：主キーではなくて候補キー?
https://atmarkit.itmedia.co.jp/ait/articles/1703/01/news181.html

主キーの性質上、候補キーと比べて設計者の判断にゆだねられている部分が大きいです。そのため正規化の説明によっては主キーでなく候補キーに言い換えたり、両方を併記しているパターンが存在します。

# 参考
- [第4回　データベースの正規化 | oss-db.jp](https://oss-db.jp/dojo/dojo_info_04)
- [さまざまな種類の「キー」を理解する：「データベーススペシャリスト試験」戦略的学習のススメ（7）| @it](https://atmarkit.itmedia.co.jp/ait/articles/1703/01/news180.html)
- [「関数従属性」を理解する：「データベーススペシャリスト試験」戦略的学習のススメ（8）| @it](https://atmarkit.itmedia.co.jp/ait/articles/1703/01/news181.html)
- [スーパーキー | Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%BC%E3%83%91%E3%83%BC%E3%82%AD%E3%83%BC)
- [候補キー | Wikipedia](https://ja.wikipedia.org/wiki/%E5%80%99%E8%A3%9C%E3%82%AD%E3%83%BC)
- [主キー | Wikipedia](https://ja.wikipedia.org/wiki/%E4%B8%BB%E3%82%AD%E3%83%BC)