2010年11月11日木曜日

Tutorial D でリレーショナル代数

Tutorial D で関係変数の定義と代入」 のつづき

データベース実践講義」 における “5.2 オリジナル演算子” (pp.92-99) の練習。

SQL の相関サブクエリ (2)」 で利用したデータベースと同じものを使う。

5093301582_c738e3bb96

Tutorial D での定義は以下通り。

削除するときはこちらより。

 

制限

特定の条件に一致するタプルを含む関係を返す。例えば、男性を取得するには、

persons where gender = 1

111-11-2010CropperCapture[1]

SQL の WHERE 句に相当し、同じキーワード where を使うので覚えやすい。

 

射影

特定の属性を含む関係を返す。人の名前と年齢を取得するには、

persons { name, age }

211-11-2010CropperCapture[2]

SQL の SELECT 句に相当する。こちらは位置も表現も異なる。

SQL との違いは、以下を評価するとハッキリとする。

persons { gender }

411-11-2010CropperCapture[4]

リレーショナル代数で 「関係」 が返されるわけだから、重複はない。 SQL では SELECT 句で DISTINCT を指定することに相当。

 

結合

「人」 と 「割当て」 を結合する。 SQL の自然結合に相当。

persons rename(id as p_id) join assignments

ただし、結合には同じ属性名が使われるので、結合前に属性名を変更するため rename 演算子を利用する。

ここでは assignments で 「人」 を示すための属性として p_id を利用しているので、上記では persons の属性 id を p_id に変更している。

311-11-2010CropperCapture[3]

次に 「人」 「割当て」 「グループ」 の 3 つを結合し、「人の名前、グループ名、日付」 を表示する。

(persons rename(id as p_id)
  join assignments
  join groups rename(id as g_id, name as g_name))
    {name, g_name, date}

複数の属性名を一気に変更する場合は、rename 演算子において prefix を利用する。

(persons rename(prefix "" as "p_") 
  join assignments
  join groups rename(prefix "" as "g_"))
    {p_name, g_name, date}

結合は、join { A, B, C … } のように書くことができる。

join { persons rename(prefix "" as "p_")
     , assignments
     , groups rename(prefix "" as "g_")}
  {p_name, g_name, date}

 

交わり

「人」 の属性 id と 「割当て」の属性 p_id の交わりを求める。

(persons rename(id as p_id)) {p_id} 
  intersect assignments {p_id}

1011-11-2010CropperCapture[10]

交わりは、属性が全て同じ関係の結合と見なせるので、join を使っても書ける。

(persons rename(id as p_id)) {p_id} 
  join assignments {p_id}

 

デカルト積

「人」の名前 と 「グループ」名 のすべての組み合わせを求めたい。

デカルト積は、共通属性がない関係の結合と見なせるので、結合したい関係の属性名が重ならないように rename 演算子を用いる。このとき、prefix を利用すると便利。

(persons rename(prefix "" as "p_")
  join groups rename(prefix "" as "g_"))
    {p_name, g_name}

1111-11-2010CropperCapture[11]

SQL では FROM 句にテーブル名を並べることに相当。

 

半結合

「グループ」 に 「割当て」 られている 「人」 を抽出したい。

persons semijoin assignments

911-11-2010CropperCapture[9]

データベース実践講義 (p94) によると、

(半結合についてこれまでに聞いたことがないかもしれないが、実がとても重要な演算子である)。定義は次の通り。 r と s の半結合は、 r と s の結合であり、結果は r の属性に射影される。

semijoin の代わりに matching と書くこともできる。こちらの方が言葉としては理解しやすいかな。

SQL では exists 述語を利用して記述できる。

 

「人」 と 「人」 の和。

 (persons where id = 1) union 
  relation {tuple {id 100, name "Gonzou", gender 1, age 100}}

1211-11-2010CropperCapture[12]

 

直和

共通のタプルがあった場合に、エラーが出力される和も用意されている。

(persons where id <= 3)
  d_union (persons where id >= 3)

この場合、「人」 の id が 3 の人が共通してるのでエラーとなる。

 

特定の 「人」 を取り除きたい場合。

persons { name } minus
  relation { tuple { name "Hanko" }
           , tuple { name "Jirou" }
           , tuple { name "Sadayo" }}

 

半差

先ほどの 「半結合」 とは対照的な 「半差」。 SQL では not exists 述語に相当する演算子。

persons rename(id as p_id) 
  semiminus assignments

111-11-2010CropperCapture[1][4]

差は、属性が全て共通している関係の半差と見なせる。

persons { name } semiminus
 relation { tuple { name "Hanko"}
          , tuple { name "Jirou"}
          , tuple {name "Sadayo" }}

 

その他

「商」 はどうやって書いたらいいんだろう。。 (+_+)

Tutorial D の拡張と要約 - 値の計算と集約」へつづく