前提
- SQLに苦手意識があり、where句とかgroup byとかはとりあえずわかるところからのスタート(havingの理解が怪しいレベル)。
- Rのtidyverseは大体理解しているので、関数プログラミング的な考え方は問題ない
- リレーショナルDBで、クエリの書き方を習得した。正規化など基本的な部分もやった。DBの運用や構築はあまりやっていない
- クエリを自ら試す際の環境構築は https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess のdocker-composeを参考にした
- 以下の本をやった: ミック氏の本多め
- スッキリわかるSQL入門 第3版
- データサイエンス100本ノック構造化データ加工編ガイドブック
- 達人に学ぶSQL徹底指南書 第2版
- ウィンドウ関数が加筆されている(参考: https://mickmack.hatenablog.com/entry/2018/10/11/132452)
- SQLパズル 第2版
- https://mickindex.sakura.ne.jp/database/db_support_sqlpuzzle.html にサンプルデータと簡易な解説がある。
- 全部やったので、SQLクエリの実装に関しては中級以上と自負して良いと思う
- プログラマのためのSQL 第4版
- SQLパズル終わる頃には大体理解できる素地はついている
- 達人に学ぶDB設計 徹底指南書
- リレーショナルデータベース入門
- かなり数学的な記述で読みにくいが、特にisolation levelあたりは丁寧でよい
感想
- https://github.com/knknkn1162/sql_recipies/tree/main この辺でまとめている。
- 実装、メモとして情報を残すにあたりjupyter notebookを使うのが便利だった
- SQLは関数プログラミングに近いが、命令が限定的なので通常のプログラミング言語ともまた違う考え方が必要
- 集合ベースの言語。自分的には価値観が広がって非常に良かった。
- ただ普通のプログラミング言語とは違って命令セットが貧弱なので、やや縛りプレイで実装している感はある
- CSVなどファイルベースで、それほどサイズが大きくない場合はRかPowerShellかなぁ。group byやより複雑な実装を必要とする場合はRでそれ以外だったらPowerShellでも十分。ただ、インタプリタなのでどちらも速度は遅め。
- ただ普通のプログラミング言語とは違って命令セットが貧弱なので、やや縛りプレイで実装している感はある
- SQLやっぱり難しいよね..?
- 少なくとも非エンジニアが相関サブクエリをササッとかけるとは思えない。かといってテーブル設計もやはり非エンジニアにとっては難しい
- 集合ベースの言語。自分的には価値観が広がって非常に良かった。
- 複雑な要件に対しては相関サブクエリを書く必要がある。相関サブクエリを制するものは(高度な)SQLを制する。
- ウィンドウ関数で一部は代替できる(全てではない)。実装は相関サブクエリよりも簡単になりがちなので逃げずにマスターはしておきたい。
- 考え方のコツは外側のスコープのテーブルを1つ固定した状態で、相関サブクエリ内のスコープのテーブルの結果を考えれば良い
- 基本的なクエリ(select .. from where .. group by .. having ..など)を理解して、達人に学ぶSQL徹底指南書 第2版を頑張って読もう。(これが読めないとSQLパズルは無理)。
- SQLパズルは難しいが、最初の3問~10問くらいを乗り越えさえすれば、その後は割とスムーズに進められる。写経はせず自身で考えて行く方が良いと思う
- case式自体は式として使える(文ではない)。応用範囲こそ広いものの、所詮は
X^n -> X^n
の写像なのでやってることはシンプル。
- where句の中にサブクエリを書く他に、selectやhavingでサブクエリを書くのにも慣れておこう。こちらも応用範囲は広い
- 期間に関連するSQLクエリは難しくなりがち
- ウィンドウ関数でできればベスト
- 3つの同じテーブルを使って自己結合or相関サブクエリを実装する必要がある場合が多い
- 外側の2つのテーブル(
from tb as tb1, tb as tb2
)をそれぞれ開始、終了と見て、サブクエリ内のテーブル(tb as tb3とする)を開始~終了の間で動く変数と考えると実装しやすい(select * from tb as tb1, tb as tb2 where ... and not exists (select * from tb as tb3 where tb3.date between tb1.date and tb2.date) ...
みたいな感じ)
- 外側の2つのテーブル(