関係代数理論は、リレーショナルデータベースの設計において非常に重要な理論であり、ここを基礎にして正規化等をようやく正しく議論できる。正直コードを書かずに理論を追っていくだけの勉強は私にとってはあまり得意なものではなかったので、後回しになってしまったのだが、いつまでも感覚でやっていくわけにはいかないので、ここで時間をかけて勉強をしてみた。
今回使用したのはサイエンス社・増永良文先生著の、「リレーショナルデータベース入門 第3版」である。正直初学者にはハードルがかなり高かったのだが、AIを用いながら理解を進めていった。今回全ての説明を行うことはしないが、個人的につまづいて理解に時間が掛かった部分を解説していこうと思う。
論理式の読み方
これは全てのパートに共通するのだが、論理式に慣れていないと、そこでアレルギーを起こす方が多いのではないだろうか。∃とか∀とか、30代以降の人は2chのアスキーアートで見慣れたような文字である。
私がまず躓いたのは射影の演算である。
定義 3.6:射影演算
リレーションを
R(A_1, A_2, \ldots, A_n)とする。
また、属性集合をX = \{ A_{i_1}, A_{i_2}, \ldots, A_{i_k} \} \quad (1 \le i_1 < i_2 < \cdots < i_k \le n)とする。
このとき、$R$ の $X$ 上の射影を
R[X]または
R[A_{i_1}, A_{i_2}, \ldots, A_{i_k}]と表し、次のように定義する。
\begin{aligned} R[A_{i_1}, A_{i_2}, \ldots, A_{i_k}] = \{\, u \mid\;& u \in \operatorname{dom}(A_{i_1}) \times \operatorname{dom}(A_{i_2}) \times \cdots \times \operatorname{dom}(A_{i_k}) \\ &\land (\exists t \in R) ( t[A_{i_1}] = u[A_{i_1}] \land t[A_{i_2}] = u[A_{i_2}] \land \cdots \land t[A_{i_k}] = u[A_{i_k}] ) \,\}. \end{aligned}ここで、$\exists$ は存在作用素である。
これが読めなかった。
特に、
(\exists t \in R) ( t[A_{i_1}] = u[A_{i_1}] \land t[A_{i_2}] = u[A_{i_2}] \land \cdots \land t[A_{i_k}] = u[A_{i_k}] )
が当たり前のことを書いているように見えてしまい、何のために存在しているかわからなかったのである。
これを一旦読み解いていこうと思う。この後出てくる式のほとんどに応用が利くものとなる。慣れてしまえば割とスムーズではある。
まず一つのコツとして、具体的なタプルを思い浮かべるというものがある。具体無しで抽象はやはり理解できないのである。
「内容なき思考は空虚であり、概念なき直観は盲目である」(カント)
次のテーブルを思い浮かべる。これが関係Rであるとしよう。nameとageは元々この2パターンずつしか存在しないものとする。
| id | name | age |
|---|---|---|
| 1 | Alice | 20 |
| 2 | Bob | 25 |
ここで、nameとage列で射影しようと思う。
先に結果を出すと、こうなる。
| name | age |
|---|---|
| Alice | 20 |
| Bob | 25 |
ここで、式の中のtとuが、何に相当するかを見てみよう。
tはRの中の各タプルである。つまり、これらである。
t = (1, Alice, 20)
t = (2, Bob, 25)
ではuというのは何なのか?定義に従うと、この4つなのである。
u = (Alice,20)
u = (Bob,25)
u = (Alice,25)
u = (Bob,20)
何故かというと、uの定義は、下記を満たすuであったためである。
u \in
\operatorname{dom}(A_{i_1})
\times
\operatorname{dom}(A_{i_2})
\times
\cdots
\times
\operatorname{dom}(A_{i_k}) \\
私が冒頭でnameとageは元々この2パターンずつしか存在しないものとする。 としたので、nameドメインとageドメインは2パターンずつ、であり、uの定義から、uはドメインの構成要素の直積になるので、2×2で4パターンである。
ここを正しく読めていないと、後半部分がわけわからなくなってしまう。
そして後半部分
(\exists t \in R) ( t[A_{i_1}] = u[A_{i_1}] \land t[A_{i_2}] = u[A_{i_2}] \land \cdots \land t[A_{i_k}] = u[A_{i_k}] )
これであるが、何を示しているかというと、
u = (Alice,20)
u = (Bob,25)
u = (Alice,25)
u = (Bob,20)
から、「Rに存在しているタプルに対応するタプル絞り込む」をやっているのである。
一つ一つ見てみよう。
u = (Alice,20) → t = (1, Alice, 20)と一致するので残す
u = (Bob,25) → t = (1, Bob, 25)と一致するので残す
u = (Alice,25) → このような組み合わせはRでは存在しないので消える
u = (Bob,20) → このような組み合わせはRでは存在しないので消える
なので、結局最終結果としては、
u = (Alice,20)
u = (Bob,25)
この2つという形である。
ポイントとしては、andを表す⋀の左右で、
左側で全母集団を出す→右側で条件で絞り込む とやるとわかりやすいかもしれない。
そして、tというのは、こういった式では大体の場合は、元のリレーションRの中のタプルであり、このタプルとの照合を何かしら行っている、と理解すればよい。伝わったであろうか。
こういった形で、具体的なタプルを実際に自分で作ると、書いていることが少しずつ読めてくるので、是非試してみてほしい。
終わりに
すみません、今日は力尽きてしまったので、また次回以降、下記を取り上げていきます。
自然結合
商演算
リレーショナル完備
多値従属性と関数従属性
アームストロングの公理系