「データベース:: テーブルのキーって何なのよ?」の続きです。
データベース理論は数理科学の一分野だろうし、みずからそう標榜しています。しかしその割には曖昧だよなー、と僕は感じます。「定義や主張を論理式で書く」とか「命題とメタ命題を区別する」とか「構文論と意味論を区別する」とか、正確さ・明晰性の向上のためにやるべき事を(専門的論文以外では)あまりやってない印象です。通常の解説では、ハッキリした定義もないままに、曖昧な自然言語による印象や連想や雰囲気に頼った議論をしています。それじゃ、正確なコミュニケーションにはなりません。
「データベース:: テーブルのキーって何なのよ?」を読んでもらえれば分かると思いますが、正確・明晰な記述のためには、述語論理をけっこうヘビーに使います/使うべきでしょう。なので、論理を勉強した人にとっては、データベースは、論理を実践的に応用する練習素材としてうってつけだと思います。
この記事では、「データベース:: テーブルのキーって何なのよ?」で定義したテーブル構造をもとに、データベースの数理モデルであるデータベース構造を定義します。また、正確な議論のために、幾つか用語・記法も導入します。
ところどころに補足を入れています。飛ばしてもかまいません。圏論/型理論の予備知識があるなら、補足も読むと理解が深まるでしょう。$`\require{color}
\newcommand{\Keyword}[1]{ \textcolor{green}{\text{#1}} }
\newcommand{\For}{\Keyword{For }}
\newcommand{\Define}{\Keyword{Define }}
\newcommand{\Imp}{ \Rightarrow }
%\newcommand{\In}{ \text{ in } }
\newcommand{\mrm}[1]{\mathrm{#1}}
%\newcommand{\cat}[1]{\mathcal{#1}}
\newcommand{\hyp}{\text{-}}
\newcommand{\Iff}{\Leftrightarrow}
\newcommand{\Doms}{\mathscr{D}}
\newcommand{\u}[1]{\underline{#1}}
\newcommand{\bs}[1]{\boldsymbol{#1}}
`$
内容:
シリーズ・ハブ記事:
関数とその域・像
集合 $`X`$ の要素を引数として、集合 $`Y`$ の要素である値を返す関数〈写像〉を、
$`\quad f:X \to Y`$
と表します。集合 $`X`$ を関数〈写像〉の域〈domain〉と呼び、$`\mrm{dom}(f)`$ と書くのですが、「データベース:: テーブルのキーって何なのよ?」で述べたように、データベース用語の「ドメイン」とかぶって〈コンフリクトして〉しまいます。
データベース分野では、$`\mrm{dom}`$ や $`\mrm{Dom}`$ が、関数〈写像〉の域とは違う意味で使われることがあるようです。そこで、関数の域のほうを $`\u{f}`$ と下線で書くことにします。例えば、テーブルスキーマ $`S:C \to \Doms`$ は関数なので、$`\u{S} = C`$ となります。また、タプル $`t\in \mrm{Tuple}(S)`$ も関数 $`t:C \to \bigcup S`$ なので、$`\u{t} = \u{S} = C`$ となります。
関数 $`f`$ を、域も添えて $`f = (\u{f}, f)`$ とも書きます。これは冗長な書き方ですが、冗長にすると分かりやすくなることは多いので遠慮せずに使います。例えば、テーブルスキーマは $`S = (C, S)`$ と書いたほうが、カラム名集合 $`C`$ を明示することになり分かりやすいでしょう。
関数 $`f:X \to Y`$ と部分集合 $`A\subseteq X`$ に対して、像〈image | 像集合〉をしばしば $`f(A)`$ と書きます。これは混乱を招くことがあるので、$`f_*(A)`$ と書くことにします。$`f_*`$ は $`f`$ とは違った関数です。
$`\quad f:X \to Y\\
\quad f_*:\mrm{Pow}(X) \to \mrm{Pow}(Y)
`$
ここで、$`\mrm{Pow}(X)`$ は $`X`$ のベキ集合〈powerset〉です。$`f = (X, f)`$ ですが、$`f_* = (\mrm{Pow}(X), f_*)`$ です。
テーブルスキーマ $`(C, S)`$ があるとき、部分集合 $`X\subseteq C`$ に対する射影関数 $`\pi_X`$ はタプルを引数とする関数ですから $`\pi_X = (\mrm{Tuple}(S), \pi_X)`$ です。テーブルインスタンスを射影する関数は $`\pi_X`$ とは別物で、
$`\quad (\pi_X)_* = (\mrm{Pow}(\mrm{Tuple}(S)), (\pi_X)_*)`$
です。さらに、テーブルクラスを射影する関数は、
$`\quad ( (\pi_X)_*)_* = (\mrm{Pow}(\mrm{Pow}(\mrm{Tuple}(S))), ( (\pi_X)_*)_* )`$
です。区別していましたか?
圏論の言葉を使って言えば、下付きアスタリスクは関手の略記です。
ベキ集合を構成する操作 $`X\mapsto \mrm{Pow}(X)`$ は、部分集合に像集合を対応させる関数を考えると、関手に仕立てることができます。
- 集合 $`X`$ に対して、$`\mrm{Pow}(X)`$ を対応させる。
- 関数 $`f:X\to Y`$ に対して、
$`\mrm{Pow}(f) := \lambda\, A\in \mrm{Pow}(X).\, \{\ y\in Y\mid \exists x\in X. f(x) = y \}`$
を対応させる。
こう定義すると、
$`\quad \mrm{Pow}: {\bf Set} \to {\bf Set}`$
という共変関手になります。
文脈から明らかな共変関手の射パートは下付きアスタリスクで示す習慣があります。
$`\quad f_* := \mrm{Pow}(f)`$
[/補足]
テーブル構造
テーブル構造は次の構成素からなるのでした。
- $`\Doms`$ : ドメイン〈ASPDT | Application Specific Primitive Data-Type〉の集合。$`\Doms`$ に所属するドメインは有限個。
- $`C`$ : カラム名の集合。有限集合。
- $`S`$ : テーブルスキーマ。関数 $`S:C \to \Doms`$
- $`\Gamma`$ : テーブルクラス。$`\mrm{Pow}(\mrm{Tuple}(S))`$ の部分集合。
$`\Doms`$ は前もって決めておいて共通に使うので、毎回言及はしないことにして、テーブル構造は $`(C, S, \Gamma)`$ と書きます。テーブル構造を一文字で表したいときは、ボールド体の小文字を使うことにします。次のようにです。
$`\quad \bs{t} = (C, S, \Gamma)\\
\quad \bs{t}' = (C', S', \Gamma')\\
\quad \bs{s} = (B, R, \Delta)\\
\quad \bs{t}_1 = (C_1, S_1, \Gamma_1)
`$
テーブル構造 $`\bs{t}`$ から、各構成素を取り出すには、次の書き方を使います。
$`\For \bs{t} = (C, S, \Gamma)\\
\quad \mrm{Column}(\bs{t}) := C\\
\quad \mrm{Schema}(\bs{t}) := S\\
\quad \mrm{Class}(\bs{t}) := \Gamma
`$
テーブル構造に対して、その超キーの集合と候補キーの集合は決まるので、次のように書きます(「データベース:: テーブルのキーって何なのよ?」参照)。
$`\For \bs{t} = (C, S, \Gamma)\\
\quad \mrm{SKey}(\bs{t}) := \{ X\in \mrm{Pow}(C) \mid \text{isSuperkey}_{(C, S, \Gamma)}(X) \}\\
\quad \mrm{CKey}(\bs{t}) := \{ X\in \mrm{Pow}(C) \mid \text{isCandidateKey}_{(C, S, \Gamma)}(X) \}
`$
定義から、
$`\quad \mrm{SKey}(\bs{t}) \subseteq \mrm{Pow}(C)\\
\quad \mrm{CKey}(\bs{t}) \subseteq \mrm{Pow}(C)\\
\quad \mrm{CKey}(\bs{t}) \subseteq \mrm{SKey}(\bs{t})
`$
です。$`C`$ が超キーであることから:
$`\quad C \in \mrm{SKey}(\bs{t})\\
\quad \mrm{SKey}(\bs{t}) \ne \emptyset
`$
超キーがあれば、少なくとも1つの候補キー(それ以上小さくできない超キー)を含むので、
$`\quad \mrm{CKey}(\bs{t}) \ne \emptyset
`$
主キーは、テーブル構造 $`(C, S, \Gamma)`$ から自動的に決まるものではなくて、誰かの決定により決まります。主キーを特定したテーブル構造を $`(C, S, \Gamma, K)`$ と書きます。主キー付きの構造から主キーを取り出すには次のようにします。
$`\For \bs{t} = (C, S, \Gamma, K)\\
\quad \mrm{PKey}(\bs{t}) = K \in \mrm{CKey}(\bs{t})
`$
現実には、主キーを決定する事はとても重要ですが、抽象化したレベルでは恣意的に選ぶ行為に意味はない*1ので、主キーは使わない定式化が望ましいでしょう。
集合圏 $`{\bf Set}`$ と有限集合の圏 $`{\bf FinSet}`$、 集合の指数(集合の累乗) $`B^A = \mrm{Map}(A, B)`$ や、ファミリー〈集合族〉からのシグマ型・パイ型の構成を知っていれば、短い記述が可能です。
- カラム名の集合 $`C`$ は有限集合である。 → $`C \in |{\bf FinSet}|`$
- ドメインの集合 $`\Doms`$ は“集合の集合” で、それ自体は有限集合である。 → $`\Doms \subseteq |{\bf Set}| \land \Doms \in |{\bf FinSet}|`$
- カラム名の集合 $`C`$ と、ドメインの集合 $`\Doms`$ から作られる、すべてのテーブルスキーマ達 → $`\Doms^C = \mrm{Map}(C, \Doms)`$
- テーブルスキーマ $`S = (C, S)`$ のすべてのタプルからなる集合 → $`\prod_{c\in C} S(c)`$
- テーブルスキーマ $`S = (C, S)`$ のすべてのテーブルインスタンスからなる集合 → $`\mrm{Pow}(\prod_{c\in C} S(c))`$
- テーブルスキーマ $`S = (C, S)`$ のすべてのテーブルクラスからなる集合 → $`\mrm{Pow}(\mrm{Pow}(\prod_{c\in C} S(c)))`$
[/補足]
射影関数
射影関数はよく使うので、ここで整理しておきましょう。
射影関数は、テーブルスキーマ $`S`$ とカラム名の部分集合 $`X\subseteq \u{S} = C`$ から決まる関数 $`\pi^S_X`$ です。上付き添字のテーブルスキーマ $`S`$ は、文脈から明らかなら省略します。射影関数の域はすべてのタプルの集合なので $`\pi_X = (\mrm{Tuple}(S), \pi_X)`$ です。すべてのタプルの集合は頻繁に出てくるので、短い記法を準備しておきます。
$`\quad \widehat{S} := \mrm{Tuple}(S)\\
\quad \widehat{S}[X] := \mrm{Tuple}(S, X) = \mrm{Tuple}(S|_X)
`$
次が成立しています。
$`\quad \widehat{S}[\u{S}] := \mrm{Tuple}(S, \u{S}) = \mrm{Tuple}(S, C) = \mrm{Tuple}(S) = \widehat{S}`$
この短い記法を使うと:
$`\quad \pi_X = \pi^S_X : \widehat{S} \to \widehat{S}[X]`$
これは、タプルレベルの(タプルからタプルへの)関数ですが、インスタンスレベル(テーブルインスタンスからテーブルインスタンスへの)関数に持ち上げると:
$`\quad (\pi_X)_* = (\pi^S_X)_* : \mrm{Pow}(\widehat{S}) \to \mrm{Pow}(\widehat{S}[X])`$
$`(\pi_X)_*`$ はよく使うので、下付きアスタリスクを付ける代わりにパイの大文字で書いてもいいとしましょう。
$`\quad \Pi_X = \Pi^S_X : \mrm{Pow}(\widehat{S}) \to \mrm{Pow}(\widehat{S}[X])`$
$`\mrm{Pow}(\widehat{S}[X])`$ の要素は、テーブルスキーマ $`S|_X : X \to \Doms`$ のテーブルインスタンスと言ってかまいません。したがって、$`\Pi_X`$ はテーブルインスタンスを引数に受け取ってテーブルインスタンスを返す関数です。
データベースの話では、シグマ型・パイ型を表立って使う気はないのですが、補足説明ではシグマ型・パイ型を使うことがあります。大文字パイを、インスタンスレベルの射影関数の意味で使ってしまったので、パイ型と混乱のリスクがあります。
パイ型の記号は、(よく見れば)大文字パイとは違う記号を使っています。
- インスタンスレベルの射影関数: $`\Pi`$ (大文字パイ)
- パイ型の型構成子: $`\prod`$ (総積記号)
見た目の違いは僅かですが、文脈から区別は付くでしょう。
[/注意]
射影関数をもう少し一般化しておきます。$`S = (C, S)`$ で $`Y \subseteq X \subseteq C`$ だとします。このとき、次のような射影関数を定義できます。
$`\quad \pi_{X, Y} = \pi^S_{X, Y} : \widehat{S}[X] \to \widehat{S}[Y]`$
$`t \in \widehat{S}[X] = \mrm{Tuple}(S|_X)`$ のとき、タプル $`t`$ は $`X`$ のぶんだけの成分値を持ちます。$`Y \subseteq X`$ だったので、さらに成分を $`Y`$ のぶんに制限することができます。タプルの成分を減らす(一部の成分値を捨ててしまう)ことが射影でした。
以下の図式は可換になります。「図式が可換」とは、図の二頂点(2つの集合を表す)を結ぶ関数が等しいことです。
$`\xymatrix @C+1pc{
\widehat{S} \ar[r]^{\pi_X} \ar[dr]_{\pi_Y}
& \widehat{S}[X] \ar[d]^{\pi_{X , Y}}
\\
{}
& \widehat{S}[Y]
}
`$
「図式が可換」であることを論理式で書くならば:
$`\quad \forall t\in \widehat{S}.\, \pi_Y(t) = \pi_{X, Y}(\pi_X(t))`$
次のスキーマを事例にしましょう。
$`\quad S = (\text{姓}: {\bf String}, \text{名}: {\bf String}, \text{生年月日}: {\bf Date})\\
\quad C = \{\text{姓}, \text{名}, \text{生年月日}\}\\
\quad X = \{\text{姓}, \text{名}\}\\
\quad Y = \{\text{姓}\}
`$
このとき:
- $`\pi_X`$ : タプル $`t = (t_\text{姓},t_\text{名}, t_\text{生年月日})`$ からタプル $`(t_\text{姓},t_\text{名})`$ を取り出す。
- $`\pi_Y`$ : タプル $`t = (t_\text{姓},t_\text{名}, t_\text{生年月日})`$ からタプル $`(t_\text{姓})`$ を取り出す。
- $`\pi_{X, Y}`$ : タプル $`s = (S_\text{姓},s_\text{名})`$ からタプル $`(s_\text{姓})`$ を取り出す。
最初に定義した射影関数 $`\pi_X`$ も $`\pi_X = \pi_{C, X}`$ と書けるので、すべての射影関数は2つの下付き添字を持っていると考えましょう。恒等関数〈恒等写像 | identity {function | map}〉は特別な射影関数です。
$`\quad \pi_{X, X} = \mathrm{id}_{\widehat{S}[X]} : \widehat{S}[X] \to \widehat{S}[X]`$
特に、
$`\quad \pi_{C, C} = \mathrm{id}_{\widehat{S}} : \widehat{S} \to \widehat{S}`$
射影関数 $`\pi_{X, \emptyset}`$ は、空タプルだけを要素とする単元集合〈singleton set〉への唯一の関数です。
$`\quad \pi_{X, \emptyset} : \widehat{S}[X] \to \widehat{S}[\emptyset] = \{()\}`$
特に、
$`\quad \pi_{C, \emptyset} : \widehat{S} \to \{()\}`$
これは、テーブルスキーマ $`S`$ のすべてのタプルを空タプルに移す〈写す〉関数です。
データベース構造
データベース〈関係データベース〉とは、幾つかのテーブルを寄せ集めたものだと言われています。となると、データベースの数理モデルである“データベース構造”は、幾つかのテーブル構造を寄せ集めればいいのでしょうか? そうもいきません。次の点を考慮する必要があります。
- テーブルのあいだの参照がある。
- それぞれのテーブルごとには妥当なテーブルインスタンス達が、データベース全体のインスタンスとして妥当とは限らない。
とはいえ、まずは幾つかのテーブル構造の寄せ集めを作ります。$`I`$ をテーブル名の集合とします。カラム名の集合のときと同じく(「データベース:: テーブルのキーって何なのよ?」参照)、テーブル名が何かは一切規定しません。$`I`$ は有限集合だとは仮定します。
- 理論的な話では、番号の集合 $`I = \{1, 2, \cdots, N\}`$ で十分。
- 現実的な例では、それらしい名前達の集合にする。例えば、
$`I = \{\text{学生},\text{教員},\text{履修},\text{教材} \}`$ 。
各 $`i\in I`$ に対して、テーブル構造 $`\bs{t}_i`$ が決まっているとします。データベース構造の基盤部分は、次のように書けます。
$`\quad (\bs{t}_i)_{i\in I}`$
これは結局、$`(I \ni i \mapsto \bs{t}_i)`$ という関数なのですが*2、単一のテーブル構造と、テーブル構造を値とする関数を同じ書き方〈オーバーロード | 記号の乱用〉をします。使える文字種・フォントが底をついてきたので。
- 約束: ボールド体の小文字を、ひとつのテーブル構造を表すためにも、テーブル名にテーブル構造を対応させる関数を表すためにも使う。どちらを表すかは文脈による。
記述を簡潔にするために、次のような記法の約束もします。
$`\For (I \ni i \mapsto \bs{t}_i) \\
\quad C_i := \mrm{Column}(\bs{t}_i ) \\
\quad S_i := \mrm{Schema}(\bs{t}_i ) \\
\quad \Gamma_i := \mrm{Class}(\bs{t}_i )
`$
$`\mrm{SKey}(\bs{t}_i ) , \mrm{CKey}(\bs{t}_i ) `$ には、特に略記を用意しません。
ここで、「テーブル」という言葉が曖昧になってしまう理由、「テーブル名」が何を名指すか分からなくなってしまう理由を説明しましょう。
テーブル名 $`i\in I`$ に対して「テーブル $`i`$」と言ったときに、次の可能性があるでしょう。
- 「テーブル $`i`$」が、テーブル構造 $`\bs{t}_i`$ を指す。
- 「テーブル $`i`$」が、カラム名集合 $`C_i`$ を指す。
- 「テーブル $`i`$」が、テーブルスキーマ $`S_i`$ を指す。
- 「テーブル $`i`$」が、テーブルクラス $`\Gamma_i`$ を指す。
他に、テーブルインスタンス(例えば、特定時点でのテーブル状態)を名指すこともあるでしょう。こうなると、文脈から判断するのは困難なので、明示的に区別できる記法を使ったほうが良いと思います。
$`(I \ni i \mapsto \bs{t}_i )`$ は関数です。その域〈domain〉は有限集合 $`I`$ です。では、余域〈codomain〉は何でしょうか? 値 $`\bs{t}_i`$ はテーブル構造ですから、「すべてのテーブル構造からなる集合」が余域と言えるでしょう。
しかし、「すべてのテーブル構造からなる集合」なんて存在するのでしょうか? -- 大丈夫、存在します。ただし、小さな集合〈small set〉ではありません。
通常の集合を小さな集合と呼び、通常の集合とは認められない集合(例えば「すべての集合からなる集合」)を小さくない集合と呼びます。小さくない集合も扱えるようなうまい枠組みがあります*3。その枠組みのなかでは、「すべてのテーブル構造からなる“小さくない集合”」を構成できます。
ドメインの集合 $`\Doms`$ は固定するとして、すべてのテーブルスキーマからなる“小さくない集合”は:
$`\quad {\bf Schema} := \sum_{C \in |{\bf FinSet}|} \mrm{Map}(C, \Doms)`$
すべてのテーブルスキーマに対して、それぞれの“すべてのテーブルクラス”を寄せ集めた“小さくない集合”は:
$`\quad \sum_{S \in {\bf Schema}} \mrm{Pow}(\mrm{Pow}(\widehat{S}) )`$
この“小さくない集合”の要素は、どれかのテーブルスキーマと、そのテーブルスキーマの特定のテーブルクラスのペア $`(S, \Gamma)`$ です。それってテーブル構造。つまり、上記の“小さくない集合”が「すべてのテーブル構造からなる“小さくない集合”」です。
$`\quad \bs{t}`$ のプロファイル(域と余域)をちゃんと書けば:
$`\quad \bs{t} : I \to \sum_{S \in {\bf Schema}} \mrm{Pow}(\mrm{Pow}(\widehat{S}) )`$
記事本文(補足ではない部分)では、小さくない集合を出したくないので、$`(I\in i \mapsto \bs{t}_i)`$ の形を使います。
[/補足]
データベースインスタンス
テーブル名 $`i\in I`$ で指定されるテーブル構造 $`\bs{t}_i`$ の特定時点 $`\tau`$ の状態は、特定のテーブルインスタンス $`T_i(\tau) \in \mrm{Pow}(\widehat{S_i})`$ となります(テーブルも 't' 、タイムも 't' で、しょうがないのでギリシャ文字小文字を引っ張り出してきましたよ)。テーブル $`i`$ の状態が、時点 $`\tau`$ で正常、あるいは妥当であるとは次が成立することです。
$`\quad T_i(\tau) \in \Gamma_i\; \text{ where }\Gamma_i \subseteq \mrm{Pow}(\widehat{S})`$
なぜなら、テーブル $`i`$ のテーブルクラス $`\Gamma_i`$ は、正常あるいは妥当なテーブルインスタンスの集合だからです。
データベース内のすべてのテーブルにおいて、状態(その時点のテーブルインスタンス)が妥当なことは次のように書けます。
$`\quad \forall i \in I.\, T_i(\tau) \in \Gamma_i`$
これは、データベース全体としての状態(その時点のすべてのテーブルインスタンス達)が正常・妥当なことを意味するでしょうか? 否〈いな〉ですね。複数のテーブルのあいだに何らかの相互関連/相互依存性があるかも知れません。それぞれのテーブルが勝手気ままな(単独では正常な)状態を取ったとき、データベース全体の妥当性は失われる可能性があります。したがって、正常・妥当なデータベース状態の集合を定義する必要があります。
まず、テーブルごとに勝手気ままな状態の全体は次のように書けます。
$`\quad \prod_{i \in I} \Gamma_i`$
$`I = \{1, 2, \cdots, N\}`$ のときなら、次のように書けます。
$`\quad \Gamma_1 \times \Gamma_2 \times \cdots\times \Gamma_N`$
この集合の要素は、$`i`$ ごとにテーブルクラス $`\Gamma_i`$ の要素(つまりテーブルインスタンス)を選んだタプルですから、次のように書けます。
$`\quad (T_1, T_2, \cdots, T_N) \in \Gamma_1 \times \Gamma_2 \times \cdots\times \Gamma_N`$
勝手気ままなタプルのなかには、データベース全体の妥当性にそぐわないモノもあるでしょう。正常・妥当な“テーブルインスタンスのタプル”(テーブルインスタンスを成分とするタプル*4)の集合 $`\bs{\Psi}`$ は、次の部分集合です。
$`\quad \bs{\Psi} \subseteq \Gamma_1 \times \Gamma_2 \times \cdots\times \Gamma_N`$
一般的には:
$`\quad \bs{\Psi} \subseteq \prod_{i \in I} \Gamma_i`$
$`\prod_{i \in I} \Gamma_i`$ の要素をデータベースインスタンス〈database instance〉と呼び、$`\bs{\Psi}`$ の要素を妥当なデータベースインスタンス〈valid database instance〉と呼ぶことにします。言い方を変えれば、$`\bs{\Psi}`$ は、妥当なデータベースインスタンスの集合です。妥当でない〈不適切な | 異常な〉データベースインスタンスは $`\bs{\Psi}`$ の要素ではありません。
データベース構造の構成素としては、$`I`$ でインデックスされたテーブル構造の集まり $`(I\ni i\mapsto \bs{t}_i)`$ 以外に、このデータベースの妥当なデータベースインスタンスの集合 $`\bs{\Psi}`$ も必要です。
データベース構造の構成素としての $`\bs{\Psi}`$ を(そのデータベースの)データベースクラス〈database class〉と呼びましょう。大事なことは:
- データベースクラス $`\bs{\Psi}`$ は、各テーブルのテーブルクラスの総直積 $`\prod_{i \in I} \Gamma_i`$ とは限らない。
データベースクラス $`\bs{\Psi}`$ は、「データベース状態が正常である」と判断するときの基準を与えます。どのようにして $`\bs{\Psi}`$ を定義・記述するか? 与えられたデータベース状態〈データベースインスタンス〉が $`\bs{\Psi}`$ の要素であることをどうやって判定するか? などが主要な問題意識になります。
そしてそれから
データベース構造〈database structure〉の定義はまだ終わっていません。先に触れたように、関係データベースは、テーブルのあいだの参照(外部キー)メカニズムを持っています。システムが組み込みで持っているメカニズムを、数理モデルに取り込まないわけにはいかないので、参照はデータベース構造の一部になります。
参照のメカニズムを取り込んで、データベース構造の定義を完了させるのは次の機会にします。
*1:主キーの選び方に関する白熱した議論をたまに見かけます。そういう議論をしている人には怒られるでしょう。
*2:次の3つの書き方は、構文が違うだけで同じ意味です: $`(\bs{t}_i)_{i\in I},\, (I \ni i \mapsto \bs{t}_i),\, \lambda\, i\in I. \bs{t}_i`$
*3:グロタンディーク宇宙の系列です。
*4:日本語の「の」の曖昧性で、正確な表現が難しい。この場合、テーブルインスタンスに所属するタプル $`t \in T`$ ではなくて、テーブルインスタンス達 $`T_1, T_2, \cdots, T_N`$ を成分として作ったタプル $`(T_1, T_2, \cdots, T_N)`$ の意味です。日本語だけではく、数式表現も参照してもらえれば、誤解しにくいとは思いますが。