宮水の日記

宮水の日記

主に書評や資格取得について記事を書いています。

「達人に学ぶSQL徹底指南書」 を読みました

達人に学ぶSQL徹底指南書 を読みました。

対象読者

  • 実務でのSQLプログラミングの経験が半年から1年くらいある方
  • レベルによらず、「SQLとは何なのか」知りたいと思っている方々

この本で学べること

  • CASE式、ウィンドウ関数、外部結合、相関サブクエリ、HAVING句、EXISTS述語などのSQLの道具を取り上げて、それらの便利な使い方をサンプルケースを通じて学んでいく。
  • SQLの原理となっている仕組みや、この言語を作った人々が何を考えて現在の形にしたのかというバックグラウンドを学ぶ。

本の概要

1. CASE式のススメ
  • CASE式を使えば、異なる条件の集計を1つのSQLで行える。例えば、県名と人口のテーブルを、「四国」「九州」などで括って集計できる。条件の異なるUPDATEを一度にかけられる。CASE式の中で集約関数(SUM、MAX、COUNTなど)を使うことができ、複数のSQL文を一つにまとめられ、可読性もパフォーマンスも向上する。
  • CASE"文"ではなく、CASE"式"であるがゆえに、実行時には評価されて一つの値に定まる。「1+1」や「a + b」などと一緒。式だから、SELECT句にもGROUP BY句にもWHERE句にもORDER BY句にも書くことができる。(※ 式と文の違いを調べてみたら、例えば「a = 1 + 2」が文で、「1+2」が式っぽいです。)
2. 必ずわかるウィンドウ関数
  • ウィンドウとは「範囲」という意味。ざっくりいうとウィンドウ関数は手続き型でいうfor文やwhile文に似ている。

1. PARTITION BY句によって、レコードの集合のカット(カットとは、母集合のレコードから操作したいレコードを集めて部分集合を作ること)
2. ORDER BY句でレコードを順序付け
3. フレーム句で、カレントレコードを中心に処理を行っていく
f:id:kattyan53:20211010224226p:plain

3. 自己結合の使い方

自己結合を使うと、

  • 重複順列・順列・組み合わせ
  • 重複行の削除
  • 部分的に不一致なキーの検索(同じ家族レコードだけど、住所が違う)

などをしたいときに応用が効く。

4. 3値論理とNULL
  • NULLには「未知」と「適用不能」の2種類がある。NULLは値でも変数でもない。
5. EXISTS述語の使い方
  • SQLに置ける述語とは、戻り値が真理値(true, false, SQLの世界ではunknownも)になる関数のこと。
  • EXISTS / NOT EXISTSを応用すれば、テーブルに存在しないデータを検索できる。
6. HAVING句の力
  • HAVING句はCASE式や自己結合といった他の武器と組み合わせると真価を発揮する
  • 探したいデータがあるときは、線と資格ではなく円(ベン図)を書く
  • 歯抜けのデータを探せる
  • 最頻値を探せる
  • NULLを含まないデータを抽出できる
7. ウィンドウ関数で行間比較を行う
  • 行間の比較は、昔は相関サブクエリを使っていたが、今はパフォーマンスや可読性の観点からウィンドウ関数が使われている。
  • 以下のようなテーブルで、前年より売上が上がったのか、下がったのか、変わらなかったのかみたいなデータを抽出できる。

f:id:kattyan53:20211011223912p:plain

8. 外部結合の使い方
  • 本来、SQLは検索のためのクエリであって、表の再形成には向いてない。
  • この章では、外部結合やCASE式を駆使していろんなテーブルの整形を行う。
9. SQLで集合演算
  • 和(UNION), 交差(INTERSECT), 差(EXCEPT)は最近標準に入った。
  • 除算(DIVIDE BY)はまだ実装されていないので、自前で作る必要がある。
  • 和(UNION)を応用して、2つのテーブルが等しいか否か調べたりできる。
10. SQLで数列を扱う
  • SQLで数列や順序集合を扱う方法について
11. SQLを速くするぞ

SQLを早くするテクニックについて学びます。

  • 暗黙裡にソートが使われる関数を使わないようにする
  • GROUPBY句とORDERBY句でインデックスを使う
  • 中間テーブルをなくし、HAVING句を活用する
  • 早い段階でレコード数が絞れるなら絞る
12. SQLプログラミング作法

全ての言語に共通するような話

  • わかりやすいカラム名をつける、インデント、スペース、大文字と小文字、カンマの位置

SQL独特の作法

  • SQLの世界はコメント推奨
  • PostgreSQLOracleMySQLなど方言が強いので、いつか移行するかもしれないことを視野に入れて標準語で書くようにする。
13. RDB 近現代史
  • RDBは従来の階層型DBを置き換えた破壊的イノベーション。エンジニアが扱うものとされていたデータベースをエンドユーザーが扱えるものにしようとした。
  • RDBは、非循環グラフ(例えば、組織図)やネットワーク構造(例えば、SNS)を表すのが苦手。
  • 近年NoSQLの製品群が登場しているが、RDBの補完的関係として共存する可能性が高い。
14. なぜ"関係"モデルという名前なのか?(なぜ表モデルではないのか)

簡単にいうと、関係モデルは数学の集合論を基礎に作られたので、使われる用語も集合論の用語を流用している。関係と表は、以下のような違いがある。

  • 関係には重複する組みは存在してはならないが、表には存在しても良い。
  • 関係の組は上から下へ順序付けられていないが、表の行は上から下へ順序付けられている。
  • 関係の属性は左から右へ順序付けられていないが、表の列は左から右へ順序付けられている。
  • 関係のすべての属性値は分割不可能だが、表の列の値は分割可能である。
15. 関係に始まり関係に終わる
  • SQLが持っている面白い性質の一つ、「閉包性」について。
  • 演算時の入力と出力が共に関係になる、関係の世界が閉じていることを保証する性質のこと。
  • 関係が閉包性を満たすおかげで、これらの演算の出力を、別の演算の入力にすることが可能になる。
16. アドレス、この巨大な怪物
  • SQLでは、ポインタが隠蔽されている。そうすることで、人間が認識しやすい有意味な世界を作り上げようとした。
17. 順序をめぐる冒険
  • ウィンドウ関数の登場は、なぜこんなに遅かったのか。
  • SQLには、「行は順序を持つべきではない」という思想があったから。
18. GROUP BY とPARTITION BY
  • どちらもほぼ似たような動きをする
  • PARTITION BYは数学でいう「類」の概念に由来して付けられた
  • GROUP BYは個々の要素を集合に振り分ける機能を持つ
19. 手続き型から宣言型・集合指向へ頭を切り替える7箇条

① if文やcase文はcase式で置き換える。
② ループはGROUP BY 句とウィンドウ関数で置き換える
③ テーブルの行に順序はない
④ テーブルを集合とみなそう
⑤ EXISTS述語と「量化」の概念を理解しよう
⑥ HAVING句の真価を学ぶ
⑦ 四角では無く、円を描く

20. 神のいない論理
  • 3値論理の歴史について
21. SQL再帰集合
  • 集合の中に集合を含むような入れ子の集合を再帰集合という。
  • よくわからなかった。
22. NULL撲滅委員会
  • NULLでは無く、コードを割り当てる(0:未知, 9:適応不能など)
  • 数値の場合は0で代替する
  • 日付の場合、最大値・最小値で代替する
23. SQLにおける存在の階層
  • SQLでは、集約すると元のテーブルの列名をそのまま参照できなくなる。
  • 例えばage列はメンバー一人一人の年齢の情報を保持しているが、年齢というのが一個人にまつわる属性であって、チーム全体の属性ではないから。1人の人間について「年齢は?」とたずねることはできても、複数の人間の集まった集団に対して「年齢は?」とたずねることはできない。

感想

率直にいうと、DBエンジニア向けの本だったので結構難しかったです。説明はありますが、たくさん数学用語が出てきたり、ソフトウェアエンジニアがあまり使わないようなデータの取得のケースを取り扱っていたからです。難しい箇所に関しては、「こういうSQLを使ったら、こういうテーブルからこんなデータを抽出できたり、こんなテーブルの再成形ができるんだな」くらいの感想で読んじゃいました。

しかしながら、今まで抱いていたSQLへのイメージがかなり変わりました。特に「テーブルには順序がない」「ループがない」「ポインタが隠蔽されている」など、言われてみないと気づかないような、今まで意識したことがない事柄を学ぶことができました。

また、SQLの歴史も初めて知りました。データの持ち方にもいろんな種類があって、それぞれに利点や欠点があるので、RDBMSだけでなくそのサービスにあったものを検討してみるのもいいと思いました。

一見簡単な構文しか持っていないように見えて、実は奥が深いですね!

ここまでお読みいただきありがとうございました!