プログラマのための SQL 第 2 版

ちょっと読んだのでメモ.

プログラマのためのSQL 第2版

プログラマのためのSQL 第2版

プログラミングのこつ

複雑な表現を扱うためには,LOGIC GEM のような,ディシジョンテーブル生成ツールを使うことをおすすめします.

1.1 スキーマとテーブルの生成

私は,データベース関連の雑誌で連載しているコラムの中で,キーワードは大文字,テーブル名は頭だけ大文字,カラム名は小文字という習慣を紹介しました.

  • わりとその場の気分でいろいろ書いてしまっていた
  • この規則は好きなので実践する
    • ちょっと Ruby 的だし

3.5 NULL との変換

3.5.2 COALESCE() 関数

  • 集計関数の使用例
    • SUM は NULL が対象でも 0 (スカラ) になる
    • COALESCE 使ってないですよ ?

3.6 ベンダー数学関数

3.6.1 数論演算子

負数の MOD の結果がベンダーによって異なるので注意する.

6.5 NULL と論理

注意するのはこの 4 ケースかな.

  • AND
    • UNK AND TRUE IS UNK
    • UNK AND FALSE IS FALSE
  • OR
    • UNK OR TRUE IS TRUE
    • UNK OR FALSE IS UNK
  • なんでこうなるのか分からん
    • TODO これが 3 値論理というもの ?
  • ドモルガンの法則とかを適用するとこれでよいことになるんだと思う
6.5.1 サブクエリーの中の NULL

そして,次のように展開できます.

直前の SQL がタイポ ?
サブクエリの FROM が Table2 じゃないと,その次のように展開できないです.

SELECT col1
  FROM Table2
 WHERE NOT (col1 = ANY (SELECT col1 FROM Table1));

6.9 NULL に関する設計のアドバイス

すべての基本テーブルのカラムで,できるだけ NOT NULL 制約を書いておくことをおすすめします.
NULL は SQL を知らない人を混乱させますし,NULL にはコストがかかります.
NULL は通常のカラム内ではなく,行のどこかに余分なビットを持つことで実装されています.

  • 意味上の NULL と実装の NULL をきちんと考えないと駄目だよね,ということを思い出した
  • NULL の実装のしかた,本当 ?
    • TODO MySQL のソースでも調べる ?

7.2 サブクエリー式と定数

どんな形のテーブルでも,VALUES() 式を使って構築することができます

  • VALUES 式のリファレンス,ちゃんと読んだことが無かった
    • TODO リファレンスを読む
  • 行というかテーブルを生成するものだったのか

9.1 DEETE FROM 文

カラム (というより疑似カラム) ROWID は,行の記憶内での物理的な位置に基づいています.
ユーザセッションが終了すると変化するかもしれませんが,セッションの最中は変わりません.
データの物理的な場所に直接行くことができますので,Oracle では最も速い物理的なアクセス方法です.

  • ROWID はポインタ
  • 同じセッション内でなら,同じテーブルの ROWID は変わらない
    • サブクエリの中でも
9.1.5 参照整合性のない複数のテーブルからの削除

まず検索条件に基づいて,消すべき製品の一時テーブルを作成します.
そして,このテーブルを創刊テーブルとしてサブクエリー内で使い,それぞれのテーブルから行を削除します

この使い方は目から鱗

第 11 章 評価述語

SQL-92 で追加された IS 述語.

12.5 パターンマッチ述語

grep マダー !?

13.1 BETWEEN 述語

  • 上界と下界は条件に含まれる
  • インデックスを使えるので速いときもある

14.1 IN 述語の最適化

この章,かなり具体例で書かれてるので引用は適当

多くの SQL エンジンは,サブクエリーを伴う IN に対して,最初にサブクエリーの結果を一時的な作業テーブルとして構築し,そのテーブルを左から右にスキャンすることで行います.

IN を効率化するテクニック (BK?)
  • ORDER BY 句を持ったビューを作る
    • XXX SQL 標準では,ビューは ORDER BY を持てない
  • IN 述語を結合操作で置き換える
    • XXX 重複行を取り除くため,ソートが必要な場合がある

14.2 OR を IN 述語で置き換える

-- OR で書いたもの
SELECT -
  FROM QualityControlReport
 WHERE test_1 = 'passed'
    OR test_2 = 'passed'
    OR test_3 = 'passed'
    OR test_4 = 'passed';

-- IN で書き換え
SELECT -
  FROM QualityControlReport
 WHERE 'passed' IN (test_1, test_2, test_3, test_4);
  • オプティマイザが 1 つの単位として扱ってくれる可能性があるとか
    • なんか駄目な臭いがする

14.3 NULL と IN 述語

NULL は,サブクエリーを使った NOT IN 述語では,いくつかの問題を引き起こします.

  • 結果が UNK になってしまうことが原因

第 15 章 EXISTS 述語

ここも引用は適当.
おれはこの述語をちゃんと理解してない.

プログラマが使える 3 つのオプションがあります.
1. EXISTS (SELECT - FROM ...)
 - 一般的に,実際のカラムを選ぶより,効率がよいでしょう
 - オプティマイザがカラムを決定する
  - インデックスがあるならインデックスのポインタを見るだけ

2. EXISTS (SELECT  FROM ...)
 - 特定のカラムを SQL コンパイラに指定してやったほうがよい場合もあるかもしれません
  - どっちやねんw

3. EXISTS (SELECT  FROM ...)
 - Oracle やその他のいくつかの製品では,SELECT 句に定数を書いたほうがよいようです
  - 行へのポインタが得られれば,実際の行を読む必要がないということを,実装に指摘するからです

述語が何をするものかを理解して,SQL コンパイラの判断を理解して,オプティマイザを理解して,ようやっと有用なクエリが書ける,ということかな.

15.1 EXISTS と NULL

NULL との比較で,述語のテストが UNKNOWN になり,そのために Gloria Clamour が見つからないのがおわかりになると思います.

  • NULL 怖い
  • 行を返すならいいのかな

第 16 章 限定されたサブクエリー述語

  • 集合の記号とクエリを対応付けながら読まないと意味がなさげなので,スキップした
    • TODOO メモ紙片手に読む

第 17 章 SELECT 文

  • SELECT 文について,本当じゃないけど,論理的には正しい SQL エンジンの動きかた
    • 羽生さんの本にもこれらしいことは書いてあったような気がする
17.1.4 ORDER BY 句

多くの方が思っているのとは異なり,ORDER BY 句は SELECT 文の一部ではありません.
それは,CURSOR 定義の一部です.

  • そしてまた NULL が問題になる...

GROUP BY,ORDER BY または DISTINCT の文脈においては,"x=y" が UNKNOWN であり,双方が NULL だったとしても,
NULL 値は同一視または他の NULL 値と重複しているものとする.

17.2 外部結合

DB2 の初期バージョンなどの製品では,面倒くさい UNION を使う必要がありました

えー