勉強日記

チラ裏

理論から学ぶデータベース実践入門 ch8 SELECTを攻略する (2/2)

gihyo.jp


リレーショナルではない操作

リレーショナルな操作のおさらい

  • SELECTによるリレーショナルな操作
リレーションの演算 SELECTによる表現
制限 基本形: WHERE句
射影 基本形: select list
直積 基本形: FROM句, JOIN句
結合 基本形: FROM句, JOIN句
基本形: FROM句, JOIN句
UNION
NOT EXISTSサブクエリ, MINUS
属性名変更 基本形: select list
拡張 基本形: select list
  • IN, ANY, EXISTSサブクエリはJOINとDISTINCTを用いて書けることが知られている
  • 他のはリレーショナルな演算でない
    • FROM句のサブクエリで集約を行っている場合など

ソート

  • ORDER BY句による結果セットの並べ替えはリレーショナルモデル上の演算ではない
    • 何しろ集合の要素に順序はない
  • ORDER BYはカーソルの操作である (SQL標準より)
    • SELECT自身のではない
  • アプリケーション開発上有用だが、リレーショナルモデルから逸脱する危険な要素であるため要注意

明示的に定義されていないカラム

  • ROWID、ROWNUMなど
  • やはり順序絡みなのでリレーショナルモデルを逸脱する。要注意

ストアドファンクション(ユーザ定義関数)

  • ストアドファンクションのロジックは手続き型で記述される
  • ストアドファンクションがSELECTに含まれると、手続き型の処理になる
  • オプティマイザ困惑
  • SQLは宣言型プログラミング言語である
    • 手続き型ロジックを持ち込むと破綻する

コラム: 集約とGROUP BY

  • GROUP BYは数学的には「要約」(Summarizatoin)だよ、という話
    • リレーションからリレーションを求める
      • 閉包である
    • cf. 「集約」(Aggregate)はリレーションからスカラを求める
      • 閉包でない
  • 要約は拡張の一種
    • リレーションの演算以外の何らかの方法で集計を行い、新たに属性を追加している
  • 学生の人数を学科ごとに集計する例
SELECT department
     , COUNT(*)
  FROM students
 GROUP BY department;
  • 同等の結果を得るサブクエリ
SELECT department
     , (SELECT COUNT(*)
          FROM students
         WHERE department = t1.department
       ) AS COUNT
  FROM (SELECT DISTINCT
               department
          FROM students
       ) AS t1;
  • 見出し列
SELECT DISTINCT
       department
  FROM students
  • これに集計結果の列を追加している(拡張)
SELECT COUNT(*)
  FROM students
 WHERE department = t1.department

リレーショナルではない操作の扱い方

  • アプリケーション開発ではリレーショナルではない操作も必要
    • 例: ソート
  • 大事なのは、リレーショナルな操作とそうでない操作とを明確に区別すること
  • 指針
    • リレーショナルモデルの範疇でできることをリレーショナルではない操作で実装しない
      • オプティマイザによる最適化はリレーショナルモデルの範疇で最大の威力を発揮するため
    • リレーショナルモデルの範疇でうまく記述できないと思ったら、DB設計を見直す
      • 見直しができない場合、泥沼に足を踏み入れることになる
    • リレーショナルではない操作がどうしても必要な場合は、リレーショナルな操作に関するロジックを必ず先に行う
      • 【補】リレーショナルな操作の入力はリレーション
        • 先にリレーショナルではない操作を行ってしまうと、後にリレーショナルな操作を続けられない

インデントでSQLを読みやすくする

  • MySQL Workbenchとかでやると良いよ