2NF, 3NFの定式化と3NFの定義における2NFの冗長性
データベースにおける関数従属性や正規形(例えば2NFや3NFなど)の解説資料は、数学的に曖昧なことが多い。
そこで本記事ではできるだけ曖昧さを減らすために、集合論の言葉を用いて関数従属性や2NF、3NFなどの概念を定式化する。
また、その定式化を用いて、よくある3NFの定義に冗長性があることを示す。
3NFの定義の冗長性について、ここで少しだけ説明する。
あるリレーションスキーマが3NFであるとは、次の(1)と(2)を満たすことと定義されることが多い。
(1) 2NFである(任意の非キー属性が任意のキー候補に完全関数従属する)
(2) 任意の非キー属性が任意の候補キーに非推移的に関数従属する
実は(1)は冗長である。本記事では、2NFと3NFなどの概念を定式化し、(1)が冗長であること、すなわち「(2)ならば(1)」であることを示す。
tl;dr
「(2)ならば(1)」であることについて。
「(2)ならば(1)」を示すために、その対偶「(1)でないならば(2)でない」を示す。
ここでは例を用いて「(1)でないならば(2)でない」こと、すなわち「2NFではないならば、ある非キー属性がある候補キーに推移的に関数従属する」ことをざっくりと説明する。
学生の所属する部活動に関するリレーションスキーマを考える。属性は学籍番号・学生氏名・部活動の3つとする。
このリレーションスキーマには、「{学籍番号}→{学生氏名}」いう関数従属性がある。
同姓同名の可能性を考え、「{学生氏名}→{学籍番号}」という関数従属性はないとする。
また兼部の可能性を考え、「{学籍番号}→{部活動}」という関数従属性もないとする。
このリレーションスキーマは2NFではない。
なぜなら、関数従属性「{学籍番号, 部活動}→{学生氏名}」は部分関数従属だからである。
({学籍番号, 部活動}はキー候補、学生氏名は非キー属性で、「{学籍番号}→{学生氏名}」という関数従属があることに注意)
「2NFでない」ことから「ある非キー属性がある候補キーに推移的に関数従属する」も言える。
この例でいうと、部分関数従属性「{学籍番号, 部活動}→{学生氏名}」は
「{学籍番号, 部活動}→{学籍番号}→{学生氏名}」
という推移的な関数従属と見れるからである。
一般に、候補キー→{非キー属性}という関数従属性は部分関数従属であれば推移的関数従属である。
この記事では、まずリレーションスキーマや関数従属性、2NF、3NFなどの概念を集合論の言葉を用いて定式化する。
そして「2NFではないならば、ある非キー属性がある候補キーに推移的に関数従属」こと、すなわち「3NFの定義の2NFであるという条件は冗長である」ことを証明する。
準備: 集合論
部分集合
集合
べき集合
集合
写像の制限
直積
極小元
極小元は複数存在する場合がある。
テーブル
データベースにおけるテーブルの例として、以下のテーブルを考える。
社員ID | 社員氏名 | 部署コード | 部署名 |
---|---|---|---|
1 | 社員A | 2 | 部署Y |
2 | 社員B | 2 | 部署Y |
3 | 社員C | 1 | 部署X |
テーブルには「社員ID」や「社員氏名」のような属性がある。属性全体の集合を
各属性には型がある。例えば、社員IDは整数型、社員氏名は文字列型である。
各属性
例えば、
テーブルには行がいくつかある。1行目を見ると、
タプルは写像
例えば、1行目のタプルは次で定義される写像
t(\text{社員ID})=1 t(\text{社員氏名})=\text{社員A} t(\text{部署コード})=2 t(\text{部署名})=\text{部署Y}
ここで、直積
テーブルはタプルの集まりである。つまり、テーブルは
以上の話を踏まえて、テーブルを定式化する。
―――――――――
定義1 (テーブル)
このとき、3つ組
タプル
タプル
ただし、
と定義される。
―――――――――
t(\text{社員ID})=1 t(\text{社員氏名})=\text{社員A} t(\text{部署コード})=2 t(\text{部署名})=\text{部署Y}
で確認する。
社員ID | 社員氏名 | 部署コード | 部署名 |
---|---|---|---|
1 | 社員A | 2 | 部署Y |
である。
よって、
社員ID | 社員氏名 |
---|---|
1 | 社員A |
リレーションスキーマ
すべての
例えば、以下のような「1つの部署コードに対応する部署名が複数ある」テーブルは普通現れない。
(以下のテーブルでは、部署コード4に対して、部署Wと部署Vの2種類が対応してしまっている)
社員ID | 社員氏名 | 部署コード | 部署名 |
---|---|---|---|
4 | 社員D | 3 | 部署Z |
5 | 社員E | 4 | 部署W |
6 | 社員F | 4 | 部署V |
ここで、あり得るテーブル全体の集合として、
テーブル
以上の話を踏まえて、リレーションスキーマを定義する。
―――――――――
定義2 (リレーションスキーマ)
―――――――――
テーブル(リレーション)が実際のデータなのに対して、リレーションスキーマはテーブルの設計に相当する。
関数従属性
テーブルに対する関数従属性の定義
「学生の所属する部活動と所属年数」のテーブルについて考える。
学籍番号 | 学生氏名 | 部活動 | 所属年数 |
---|---|---|---|
1 | 学生A | 部活動X | 1 |
1 | 学生A | 部活動Y | 2 |
2 | 学生B | 部活動X | 2 |
3 | 学生C | 部活動Y | 1 |
このテーブルでは、属性について以下のことが言える。
- 学籍番号が決まれば学生氏名が決まる
- 学籍番号と部活動が決まれば、所属年数が決まる
このような関係を関数従属性という。関数従属性は次のように定義される。
―――――――――
定義3 (テーブルに対する関数従属性)
すなわち、
「
と定義する。
―――――――――
「任意の
であるというのは、「ある関数
関数従属性の例をあげる。「学生の所属する部活動と所属年数」のテーブル
学籍番号 | 学生氏名 | 部活動 | 所属年数 |
---|---|---|---|
1 | 学生A | 部活動X | 1 |
1 | 学生A | 部活動Y | 2 |
2 | 学生B | 部活動X | 2 |
3 | 学生C | 部活動Y | 1 |
このテーブルにおいて、以下の関数従属性が成り立つ。
\{学籍番号\}\to_R\{学生氏名\} \{学籍番号, 部活動\}\to_R\{所属年数\}
また、
このテーブルでは同姓同名がいないため、
もし同姓同名がいたら、
このように、テーブルに対する関数従属性は、そのテーブルの状態によって成り立ったり成り立たなかったりする。
1つ極端な例を紹介する。
このとき、任意の
証明
(1)
「
以上から、
(2)
よって、「
(一般に「任意の
以上から、
つまり、テーブルのタプル数が0または1の場合は、すべての属性集合の間で関数従属性が成り立ち、もはや関数従属性の意味をなさない。
タプル数が0や1のように極端でなくても、タプル数が少ない場合には意図していない関数従属性が成り立ってしまうということがあり得る。
このように、ある特定のタイミングのインスタンス(テーブル)だけを見て関数従属性を考えると、そのテーブルの状態に大きく左右されてしまう。
そこで、リレーションスキーマのどんなインスタンスに対しても成り立つ関数従属性というものを考える。
リレーションスキーマに対する関数従属性の定義
―――――――――
定義4 (リレーションスキーマに対する関数従属性)
すなわち、
「任意の
と定義する。
誤解の恐れがなければ、
―――――――――
ここで、リレーションスキーマと関数従属性の例をあげる。
以下のテーブルをインスタンスに持つような「学生の所属する部活動と所属年数」のリレーションスキーマ
学籍番号 | 学生氏名 | 部活動 | 所属年数 |
---|---|---|---|
1 | 学生A | 部活動X | 1 |
1 | 学生A | 部活動Y | 2 |
2 | 学生B | 部活動X | 2 |
3 | 学生C | 部活動Y | 1 |
集合族
すなわち
次に、インスタンスの制約
このとき、
また、このリレーションスキーマについて、以下の関数従属性が成り立つ。
\{学籍番号\}\to_\mathcal{R}\{学生氏名\} \{学籍番号, 部活動\}\to_\mathcal{R} \{所属年数\}
図で書くと、関数従属性は以下のようになる。
その理由を説明する。インスタンス
学籍番号 | 学生氏名 | 部活動 | 所属年数 |
---|---|---|---|
1 | 学生A | 部活動X | 1 |
1 | 学生A | 部活動Y | 2 |
2 | 学生B | 部活動X | 2 |
3 | 学生C | 部活動Y | 1 |
このインスタンス
よって、
同様に、同姓同名が発生しているインスタンスを考えることで、
関数従属性の性質
(テーブル
-
ならばA\supseteq B A\to B -
ならばA\to B A\cup C \to B\cup C -
かつA\to B ならばB \to C A\to C
また、上記3つの系として以下の性質もよく使用する。
-
かつA\supseteq B ならばB \to C A \to C -
かつA\to B ならばB \supseteq C A \to C
完全関数従属
以下、関数従属性はリレーションスキーマに対する関数従属性のみを扱うことにする。
また
―――――――――
定義5 (完全関数従属性)
関数従属するが完全関数従属しない場合は部分関数従属するという。
―――――――――
完全関数従属の例をとりあげる。
先程の「学生の所属する部活動と所属年数」のリレーションスキーマを例にする。
{学籍番号, 部活動}→{所属年数}という関数従属は完全関数従属である。
一方、{学籍番号, 部活動}→{学生氏名}という関数従属は部分関数従属である。
なぜならば、{学籍番号}→{学生氏名}という関数従属が成り立つからである。
キー
―――――――――
定義6 (スーパーキー)
―――――――――
―――――――――
定義7 (キー候補)
―――――――――
スーパーキーとは、スーパーキーでの値が決まればすべての属性の値が決まる(タプルが一意に定まる)属性集合のことである。
キー候補は極小のスーパーキーである。
よって、
キー候補は複数存在する場合がある。
スーパーキー・キー候補の例をとりあげる。
先程の「学生の所属する部活動と所属年数」のリレーションスキーマを例にする。
{学籍番号, 部活動}はスーパーキーでキー候補である。また{学籍番号, 部活動}を含む属性の集合はスーパーキーである。
{学籍番号}はスーパーキーではない。なぜならば、(兼部の可能性から){学籍番号}→{部活動}が成り立たないので、{学籍番号}→{学籍番号, 学生氏名, 部活動, 所属年数}が成り立たないからである。
正規形
正規形の目的
現実世界では、テーブルの値を更新したいという要望がある。
例えば、以下のテーブルで、「学籍番号」が1のタプル(1行目と2行目)に対して「学生氏名」を更新したいという話があり得る。
学籍番号 | 学生氏名 | 部活動 | 所属年数 |
---|---|---|---|
1 | 学生A | 部活動X | 1 |
1 | 学生A | 部活動Y | 2 |
2 | 学生B | 部活動X | 2 |
3 | 学生C | 部活動Y | 1 |
この要望を定式化する。
リレーションスキーマ
このとき「
複数箇所を更新するのは嫌なので、更新箇所は1箇所(
もし、
逆に
以上から、
つまり、「
そういう状況を排除しようというのが、正規化である。正規化の段階として2NFや3NFなどがある。
2NFは、
キー属性・非キー属性
2NF・3NFの定義には非キー属性という概念が現れるのでここで定義する。
―――――――――
定義8 (キー属性・非キー属性)
キー属性でない属性を非キー属性という。
―――――――――
2NFや3NFでは、「非スーパーキー→{非キー属性}」という関数従属性を排除する。
「非スーパーキー→{キー属性}」という関数従属性は2NFや3NFでは排除しない(この記事では扱わないが、3NFより制約の強いBCNFで排除する)。
2NF
―――――――――
定義9 (2NF)
任意の非キー属性
―――――――――
2NFでないということは、ある非キー属性
すなわち、非スーパーキー
(
2NFでない例をあげる。
「学生の所属する部活動と所属年数」のリレーションスキーマは2NFではない。
なぜならば、非キー属性「学生氏名」はキー候補{学籍番号, 部活動}に部分関数従属しているからである。それは{学籍番号}→{学生氏名}という関数従属があることからわかる。
この2NFでないリレーションスキーマは、2NFである2つのリレーションスキーマに分解できる。
具体的には、キー候補に部分関数従属している非キー属性「学生氏名」をリレーションスキーマから外し、新しく「学籍番号・学生氏名」を持つリレーションスキーマを作成することで、次に示す2NFのリレーションスキーマが2つできる。(リレーションスキーマの分解について、この記事ではこれ以上深く触れないことにする。)
学生番号 | 学生氏名 |
---|---|
... | ... |
学生番号 | 部活動 | 所属年数 |
---|---|---|
... | ... | ... |
推移的関数従属性
次に3NFを定義するために推移的関数従属性を定義する。
―――――――――
定義10 (推移的関数従属性)
(1)
(2)
(3)
―――――――――
(1)の
推移的関数従属性の定義の意味について説明する。「推移的」という言葉から(1)を求めることは自然である。(2)と(3)を求める理由を説明する。
まず(3)
(3)がない場合、(
(文献によっては(3)がないが、(3)がないとこのように定義が壊れてしまう。)
次に(2)
例として、「学生の所属する部活動と所属年数」のリレーションスキーマに、自動採番(オートインクリメント)されるIDを属性として追加したリレーションスキーマを考える
IDはタプルを一意に識別できる属性である。
キー候補は{ID}と{学籍番号, 部活動}である。
{ID}と{学籍番号, 部活動}の間には双方向の関数従属性
{ID}→{学籍番号, 部活動}, {学籍番号, 部活動}→{ID}が成り立つ。
ここで、もし条件(2)がない場合、{学籍番号, 部活動}→{所属年数}が推移的関数従属となってしまう。
なぜならば、{学籍番号, 部活動}→{ID}→{所属年数}だからである。
関数従属性{学籍番号, 部活動}→{所属年数}を推移的関数従属と言わないようにするために(2)の条件がある。
もう1つ、(2)
(2)が成り立っていると、「
もし(2)が成り立たず
(2)は
3NF
推移的関数従属性を定義したので、3NFを定義する。
―――――――――
定義11 (3NF)
次の条件(1), (2)を満たすとき、リレーションスキーマ
(1)
(2) 任意の非キー属性
―――――――――
後で証明するが、「(2)ならば(1)」が成り立つので、(1)の2NFであることは冗長である。しかし、「3NFならば2NFである」ことをわかりやすくするためか、このように定義されることが多い。
(3NFの原論文[1]では、この記事の「(1)かつ(2)」のように3NFを冗長に定義している。なお、文献[3]のように2NFを前提としない3NFの定義が書かれている文献もある。)
3NFも「非スーパーキー→{非キー属性}」という関数従属性を排除しようとしている。
3NFでなく特に(2)を満たさない状況はどういうことかを説明する。
(2)を満たさないとき、ある非キー属性
すなわち、ある
K \to B \to \{x\} B \not\to K x \notin B
ここで、関数従属性
3NFであれば
このように、3NFでも「非スーパーキー→{非キー属性}」という関数従属性を排除しようとしている。
2NFでは、関数従属性「非スーパーキー→{非キー属性}」のうち、非スーパーキーがあるキー候補の真部分集合でない場合の関数従属性については排除しなかった。
3NFでは、非スーパーキーがあるキー候補の真部分集合でない場合も含めて、「非スーパーキー→{非キー属性}」という関数従属性を排除している。
ここで3NFでない例を上げる。
以下に示す「社員の所属する部署」のリレーションスキーマを考える。
以下の関数従属性が成り立っているとする。
- {社員ID}→{社員氏名}
- {社員ID}→{部署コード}→{部署名}
キー候補は{社員ID}のみである。
このリレーションスキーマは(2NFではあるが)3NFではない。
なぜならば、{社員ID}がキー候補、「部署名」は非キー属性で、{社員ID}→{部署名}が推移的関数従属だからである({社員ID}→{部署コード}→{部署名}という推移がある)。
もう1つ3NFでない例を上げる。
「学生の所属する部活動と所属年数」のリレーションスキーマは3NFではない。
先程見たとおり、このリレーションスキーマは2NFではないので、3NFではない。なお、「3NFの条件(2)を満たしていないから3NFでない」ということもできる。
なぜならば、キー候補{学籍番号, 部活動}と非キー属性「学生氏名」に対して、{学籍番号, 部活動}→{学生氏名}が推移的関数従属だからである({学籍番号, 部活動}→{学籍番号}→{学生氏名}という推移がある)。
推移的関数従属{学籍番号, 部活動}→{学生氏名}は部分関数従属でもあった。
実は、「キー候補→{非キー属性}」という関数従属性は、部分関数従属であれば推移的関数従属であることが言える。後ほど証明する。
3NFの定義における2NFの冗長性
3NFの定義を再掲する。
―――――――――
定義11 (3NF・再掲)
次の条件(1), (2)を満たすとき、リレーションスキーマ
(1)
(2) 任意の非キー属性
―――――――――
前に述べたが、(1)は冗長であり、「(1)かつ(2)」と(2)は同値である。すなわち「(2)ならば(1)」が成り立つ。
「(2)ならば(1)」を証明するために一つ補題を用意する。
―――――――――
補題12
このとき、関数従属性
―――――――――
証明
関数従属性
このとき、ある
K \to B \to \{x\} B \not\to K x \notin B
[
[
[
以上から、
補題12は「キー候補→{非キー属性}」という関数従属性において「部分関数従属するならば推移的関数従属する」という話である。
一般の関数従属性では「部分関数従属するならば推移的関数従属する」が成り立つとは限らない点に注意である。
部分関数従属するが推移的関数従属しない例
属性全体を
関数従属性
補題12の例として、3NFでない例であげたリレーションスキーマの関数従属性「{学籍番号, 部活動}→{学生氏名}」がある。
関数従属性「{学籍番号, 部活動}→{学生氏名}」は部分関数従属であり推移的関数従属という話をした。この話は補題12からも説明できる。
準備ができたので、3NFの定義における「(2)ならば(1)」を証明する。
―――――――――
定理13 (3NFの定義における2NFの冗長性)
次の(1), (2)について、「(2)ならば(1)」が成り立つ。
(1)
(2) 任意の非キー属性
―――――――――
証明
「(2)ならば(1)」の対偶「(1)でないならば(2)でない」ことを示す。
「(1)でないこと」と「(2)でないこと」は次のように書ける。
- (1)でない: ある非キー属性
と、あるキー候補x\in X が存在して、K\subseteq X が\{x\} に部分関数従属する。K - (2)でない: ある非キー属性
と、あるキー候補x\in X が存在して、K\subseteq X が\{x\} に推移的に関数従属する。K
このことと補題12から「(1)でないならば(2)でない」が成り立つ。
つまり、「(2)ならば(1)」が成り立つ。□
以上で、3NFの定義において、2NFである条件が冗長であることが示された。
参考文献
- [1] Codd, Edgar F. "Further normalization of the data base relational model.". Data base systems 6. 1972, p33-64.
- 2NFや3NFの原論文。
- 2NFや3NFの定義は、今でも[1]にある定義が用いられる場合が多く、本記事でもこの定義をもとにして話を進めた。
- 本記事の3NFと同様に、[1]の3NFの定義は「2NFでありさらに...」と冗長な定義になっている。
- なお、[1]の推移的関数従属性の定義は不正確なので、代わりに[3]の定義を採用した。
- [2] Armstrong, William Ward. "Dependency Structures of Data Base Relationships." IFIP congress. Vol. 74. 1974.
- アームストロングの公理の原論文。
- タプルを写像として表現したり、タプル
のサブタプルをt のように写像の制限を用いて表現したりするのは、この論文にも現れる。t|_A - この論文ではリレーションスキーマではなくテーブルに対して関数従属性を定義している。
- [3] Zaniolo, Carlo. "A new normal form for the design of relational database schemata." ACM Transactions on Database Systems (TODS) 7.3, 1982, p489-499.
- 推移的関数従属の定義で参考にした。
- この論文では3NFの定義に2NFを使用していない。そもそもこの論文に2NFが現れない。この論文で3NFの定義に2NFが不要なことを知った。
- この論文ではテーブルに対する関数従属性を定義して、リレーションスキーマに対する関数従属性を定義している(本記事とほぼ同じである)
- [4] 石川 佳治:データベース1・2(2019年度)
- 大学のデータベースの講義資料。
- リレーションスキーマやインスタンスなどの用語、関数従属性の定義などを参考にした。
- 関数従属性はリレーションスキーマに対して定義されている。
- [5] 集合論による関係データモデルの定式化 | Mathlog
- 昔、筆者が書いた記事。
- 本記事は記事[5]のリメイクのようなもの。
- 記事[5]と本記事の主な違い
- 記事[5]ではリレーションスキーマを定義せずテーブルで話を進めた。本記事ではリレーションスキーマを定義した。
- 記事[5]ではテーブルに対して2NFを定義した。2NFなどの正規形はテーブルに対してではなくリレーションスキーマに対して定義されるべきだと考え、本記事ではリレーションスキーマで2NFを定義するように変更した。
- 記事[5]では2NFは定義したが、3NFを定義してなかった。本記事では3NFも定義した。
-
を適当にとる。A_1\in \mathcal{K} が極小元でない場合は、A_1 の元で\mathcal{K} の真部分集合であるA_1 が存在する。A_2 が極小元でない場合は、A_2 の元で\mathcal{K} の真部分集合であるA_2 が存在する。A_3 が有限集合の場合、これを有限回繰り返すことで極小元が見つかる。 ↩︎\mathcal{K} -
タプルはレコードとも呼ばれる。 ↩︎
-
がA の極小元ならば\{A' \subseteq X \mid A'\to B\} を満たすので、A\to B という条件は冗長である。 ↩︎A\to B -
属性全体の集合
が無限集合のとき、キー候補が存在しない場合がある。例えば、X の連続関数全体のテーブルを唯一のインスタンスとして持つリレーションスキーマ\mathbb{R}\to \mathbb{R} \langle \mathbb{R}, (\mathbb{R})_{x\in \mathbb{R}}, \{\{f\colon \mathbb{R}\to \mathbb{R} \mid f \text{は連続関数}\}\}\rangle
にはキー候補が存在しない。キー候補が存在しないことを簡単に説明する。
このリレーションスキーマにおいて、 に対して、A\subseteq \mathbb{R} がスーパーキーであることと、A がA において稠密であることは同値である(例えば\mathbb{R} はスーパーキーである)。このことから、\mathbb{Q} がスーパーキーならばA に対してx_0\in A もスーパーキーである(A\setminus\{x_0\} であることに注意)。よって、スーパーキー全体の極小元であるキー候補は存在しない(もし、キー候補A \neq \emptyset が存在したらA に対してx_0\in A もスーパーキーなのでA\setminus\{x_0\} の極小性に矛盾する)。 ↩︎A
Discussion