はじめに
SQLの入門書は数え切れないほどあります。SELECT の書き方、JOIN の種類、正規化の理論。しかし、それらを一通り習得した後に立ちはだかるのが「で、この道具で何をどう分析するのか」という壁です。
本書『SQLではじめるデータ分析』は、まさにその壁の向こう側を扱った一冊です。原題は SQL for Data Analysis。構文の解説書ではなく、分析という営みをSQLでどう組み立てるかを主題にしています。
著者のCathy Tanimuraさんは20年以上データ分析に携わってきた実務家で、金融からB2Bソフトウェア、消費者向けサービスまで幅広い領域を経験しています。本書の「はじめに」には、SQLを学び始めた当時は参考資料が乏しく、多くの人がその場しのぎで技術を身につけていたという回想が綴られています。分析実務のノウハウが個人や小さなチームの中に閉じ込められがちな状況を変えたい、というのが執筆の動機だと述べられています。
その動機どおり、本書は「先輩が隣で教えてくれる分析テクニック集」に近い読み心地でした。
書誌情報
| 項目 | 内容 |
|---|---|
| 書名 | SQLではじめるデータ分析 ―クエリで行う前処理、時系列解析、コホート分析、テキスト分析、異常検知 |
| 原書 | SQL for Data Analysis (O'Reilly, 2021) |
| 著者 | Cathy Tanimura |
| 監訳 | 大橋 真也、嶋田 健志 |
| 訳者 | 木下 哲也 |
| 出版社 | オライリー・ジャパン |
| 発行 | 2023年1月24日 |
| ISBN | 978-4-8144-0020-1 |
前提とするDBはPostgreSQLです。原書はPostgreSQL 12.3ベースですが、日本語版の動作確認にはPostgreSQL 15が使われています。サンプルコードとデータセットはGitHubで公開されています。
全体の構成
全9章、大きく3つのブロックに分けて読むと見通しが良くなります。
| 章 | テーマ | ブロック |
|---|---|---|
| 1章 | SQLによる分析 | 土台 |
| 2章 | 分析用のデータの前処理を行う | 土台 |
| 3章 | 時系列解析 | 分析手法 |
| 4章 | コホート分析 | 分析手法 |
| 5章 | テキスト分析 | 分析手法 |
| 6章 | 異常検知 | 分析手法 |
| 7章 | 実験分析 | 分析手法 |
| 8章 | 分析用に複雑なデータセットを作成する | 設計と運用 |
| 9章 | まとめ | 設計と運用 |
1〜2章で分析の前提を固め、3〜7章で個別の分析手法を扱い、8〜9章でクエリの設計・保守・組み合わせに戻ってくる、という構成です。
各章は独立性が高く、必要な章から読み始めても支障はありません。ただし2章のプロファイリングと8章のクエリ設計は、他章を読む前後で必ず通しておく価値があります。
1章:SQLによる分析
導入章ですが、ここが本書の姿勢を最もよく表しています。
SQL / R / Python をどう使い分けるか
「SQLとR/Python、どちらを使うべきか」という定番の問いに対して、本書は明快な判断軸を示しています。
最大の違いとして挙げられているのは コードが実行される場所 です。SQLはデータベースサーバ上で動作し、サーバの計算リソースをそのまま使えます。一方でR/Pythonは手元のマシンで実行されることが多く、リソースはローカルの範囲に制限されがちです。大規模データであれば、リソースの潤沢なデータベース側で処理するほうが理にかなっている、という整理です。
構造の面でも違いがあります。リレーショナルデータベースは常に行と列の構造を前提とするため、SQLはその上でクエリを書きます。R/Pythonは変数・リスト・辞書と柔軟ですが、その分だけ習得コストが上がります。ループの扱いも異なり、SQLの集約は追加のコードなしにデータ集合を暗黙的にループします。この性質は強力ですが、ピボット/アンピボットのようにフィールドをループしたい処理では文が長くなる、という副作用も正直に書かれています。
SQLの弱点も明示されています。データがデータベースに存在していなければならないこと、そして統計的有意性の計算のような高度な統計処理は単体では実行できないことです。
判断軸として提示されているのは、データの所在、データ量、分析結果の用途(レポート/可視化/統計分析)、更新の必要性と頻度、そしてチームの既存標準、という5つの問いでした。「最強の言語」を主張するのではなく、仕事に最適な道具を選ぶための材料を並べる。この姿勢が全編にわたって一貫しています。
行ストアと列ストア
分析用途では列ストアが有利になる理由も、分析ワークフローの文脈の中で説明されます。ソースシステム → ETL → データウェアハウス → クエリ・分析、という流れの中でSQLがどこを担うかが図示されており、アーキテクチャ視点でも読みやすい章でした。
2章:分析用のデータの前処理を行う
個人的に、本書で最も再読することになりそうな章です。
プロファイリングという習慣
新しいデータセットに触れるとき、いきなり分析を始めるのではなく、まずプロファイリングを行う。これが本書の一貫した推奨です。スキーマとテーブルの配置を調べ、テーブル名から主題を把握し、列名からテーブル間の関係をイメージし、データディクショナリと実データのサンプルを突き合わせ、履歴がどう表現されているかを確認する。
最後の項目は見落としがちですが重要です。本番DBのレプリカには顧客住所や注文状態の過去の値が残っていないことがある一方、適切に設計されたデータウェアハウスには日次スナップショットが存在する。この差は分析結果を大きく左右します。
プロファイリングはTukeyの探索的データ分析(EDA)に連なる考え方だと位置づけられており、分布・度数・ビニング・n分位といった具体的なテクニックが続きます。
データ品質とクリーニング
重複の検出と GROUP BY / DISTINCT による排除、CASE 式によるクリーニング、型変換とキャスト、nullの扱い(coalesce、nullif、nvl)、欠損データへの対処が順に扱われます。
整形:ピボットとアンピボット
出力先(BIツール、可視化、統計処理、機械学習)によって必要な形が変わるという前提から、CASE 式によるピボット、UNION によるアンピボットが解説されます。ここで1章の「SQLはフィールドをループできない」という指摘が効いてきて、なぜピボット処理のSQLは冗長になりがちなのかが腑に落ちます。
3章:時系列解析
米国小売売上高のデータセットを題材に、時系列を扱うための道具立てが揃います。
日付・時刻の操作
タイムゾーン変換、フォーマット変換、日付計算、時間計算、異なるソースの結合。地味ですが、実務で最も事故が起きやすい領域です。
移動窓
移動平均をはじめとする移動窓の計算では、3つの設計要素が整理されています。ウィンドウのサイズ(大きいほど平滑化されるが短期の重要な変化への感度を失い、小さいほど感度は上がるがノイズが残る)、集約関数の選択(平均だけでなく合計・回数・最小・最大も使える)、パーティション化の方法(PARTITION BY で何を単位に窓を切るか)です。このトレードオフの言語化は、そのまま指標設計のレビュー観点になります。
DAU / WAU / MAU の使い分けに関するコラムも実践的でした。MAUは30日ウィンドウであるため、ユーザが29日間使っていなくても数値が下がらず、解約の兆候検出には向かない。一方DAUはキャパシティプランニングに向く。WAUはその中間で、短期変動への感度が高い分だけ早く警告を出せる、という整理です。
期間比較
YoY / MoM / DoD の計算には lag 関数を使います。lead は逆方向、あるいは ORDER BY を降順にすれば同じ効果が得られる、といった細かい実装の勘所も押さえられています。
-- 前月比の計算イメージ
SELECT
sales_month,
sales,
lag(sales) OVER (ORDER BY sales_month) AS prev_month_sales,
sales / lag(sales) OVER (ORDER BY sales_month) - 1 AS mom_growth
FROM retail_sales;
季節性の分析では、前年同月比や複数期間との比較まで踏み込みます。
4章:コホート分析
本書の中核といえる章です。SQLでのコホート分析をここまで丁寧に解説した日本語の資料は、そう多くないはずです。
コホート分析の3要素
- コホートのグループ化 — 多くは開始日ベース(初回購入日、契約日、就学日など)
- コホートを観測する時系列データ
- 行動を測定する集約指標
コホートとセグメントの違い
しばしば混同される二つの用語が明確に区別されています。
- コホート — 共通の開始日を持ち、時間とともに追跡するグループ
- セグメント — 開始日に関係なく、ある時点で共通の特性を共有するグループ
この区別は指標定義のレビューでそのまま使えます。
サバイバーシップバイアス
時系列がエンティティの存続期間全体をカバーしていないと、初期コホートに生存バイアスが生じる、という警告が繰り返されます。解約した顧客がデータセットから消えていると、残った顧客だけが観測され、古いコホートのほうが優秀に見えてしまう。分析基盤の設計時点で意識しておくべき論点です。
扱われる4種類の分析
リテンション(基本のリテンション曲線、時系列の調整、疎なコホートへの対応)、サバイバーシップ、リターンシップ(リピート購買行動)、累積計算の4つが扱われ、さらにコホート視点でのクロスセクション分析にも触れられています。
コホート分析の位置づけについての記述も誠実でした。因果関係を示すものではなく、顧客を理解し、後で検証可能な仮説を導き出すための手段である、と明確に線を引いています。
5章:テキスト分析
UFO目撃情報のデータセットという、やや意表を突く題材で進みます。
SQLが向いている場合/向いていない場合
向いている場合は、データがすでにDB内にあるとき、最終的な目標が定量化であるとき(特定のフレーズを含むチケット件数を数えるなど)、テキストフィールドのクリーニングと構造化を行うとき、そして何を探しているかが事前にわかっているときです。
向いていない場合は、人間が読んだほうが速い規模のデータ、低遅延の全文検索(ElasticsearchやSplunkの領域)、そしてセンチメント分析・品詞タグ付け・言語生成といったNLPタスクです。
ここで印象的だったのは、SQLによるテキスト分析がルールベースであることを明示している点です。ルールベースは人間が読んで理解でき、検証もできるという長所がある一方、状況が増えるほど長大化・複雑化し、保守が難しくなる。最初は4〜5行だった CASE 式が、アプリケーションの変更に伴って50行、100行へと膨れ上がった経験が語られていました。
この「短所も含めた道具の性格」を語る姿勢は、設計判断を扱う技術書として信頼できると感じた部分です。
正規表現
著者自身が長年正規表現を避けていた、という告白から入るのが良い導入になっています。POSIXの比較演算子(~)と正規表現関数の2通りの使い方が示され、簡単なものから始めて必要に応じて複雑にしていく、コメントを残す、という現実的なアドバイスが添えられています。
LIKE / ILIKE、IN / NOT IN、正規表現の使い分け、そして連結・整形による新しいテキストの生成まで扱われます。
6章:異常検知
地震データセット(earthquakes)を題材にした章です。
異常の2つの原因
異常はおおむね、実際に起きた極端な事象か、データの収集・処理過程で生じたエラーのどちらかから生じる、という切り分けから始まります。検出手順は原因によらず似ていますが、対処法は根本原因で決まる。だから原因の切り分けが重要だ、という主張です。手入力によるタイプミス、書式や検証ルールの変更、ロギング方法の変更、フィルタリングの誤り、多重ロードによる重複。心当たりのある話が並びます。
指標の変化を診断するときは、まず最近ロギングを変更していないか確認するようになった、という一文は多くのエンジニアが頷くところではないでしょうか。
検出のテクニック
ソートによる発見、パーセンタイルと標準偏差、グラフ化による視覚的な発見の3つが順に示されます。
異常の種類と対応
異常は個々の値だけでなく、回数や頻度のパターン、あるいはデータの不在としても現れます。「100ドルを使う顧客」は珍しくなくても、「48時間にわたって毎時間100ドルを使う同一顧客」はほぼ確実に異常である、という例が分かりやすいです。
対応の選択肢としては、調査・除去・代替値での置換・リスケーリングが提示されます。
異常=悪ではない、という点も強調されています。例外的に優良な顧客や、キャンペーンの好調、顧客行動の良い変化を検出するためにも同じテクニックが使える、という視点は有用でした。
7章:実験分析
架空のモバイルゲーム会社のデータセット(ユーザ、行動、課金、バリアント割り当ての4テーブル)を使ってA/Bテストの分析を扱います。
SQLの守備範囲
実験のコホートデータと行動データはすでにDBにあることが多く、成功指標のクエリも既存のものを流用できるため、SQLとの相性は良い。実験ごとに WHERE 句を差し替えるだけで同じクエリを回せるため、レポートの自動化にも向いています。
一方で、統計的有意性を求められないという決定的な制約があります。本書の提案は、SQLで要約統計量を算出し、オンラインの計算機や他ツールで有意性を判定するという役割分担でした。
相関と因果
XとYの関係には5つのパターンがあるという整理が挿入されています。XがYの原因である、YがXの原因である(傘は雨の原因ではない)、両者に共通の原因がある(アイスの売上とエアコン使用は気温で説明される)、両者の間にフィードバックループがある、そして単なる偶然。
指標を扱う人間が定期的に読み返すべきリストだと思います。
実験の種類
二値の結果にはカイ二乗検定(分割表で表現)、連続的な結果にはt検定。さらに、バリアント割り当ての偏り、外れ値、タイムボックス、反復暴露実験といった「実験が壊れるパターン」と、その修復方法が扱われます。
実験できない場合の代替分析
倫理的制約、規制上の要件、実務上の困難、あるいは「変更はすでに実施済み」という状況では、ランダム化実験ができません。その場合の擬似実験的アプローチとして次の3つが紹介されます。
- 事前/事後分析 — 変更の前後で同一・類似の母集団を比較する。前後の測定期間を同じ長さに揃え、1週間・2週間・3週間と複数の窓で結果が一致するかを確認すると信頼性が上がる
- 自然実験分析
- 閾値付近の母集団の分析
障害、フォームの不具合、災害といった意図しない変更も分析対象になりうる、という指摘が現実的でした。
8章:分析用に複雑なデータセットを作成する
設計・保守を扱う章で、アーキテクチャに関心のあるエンジニアには最も刺さる部分だと思います。
ロジックをどこに置くか
SQLクエリの中にすべてのロジックを抱えるか、ETL/ELTに移すか。判断基準として挙げられているのは性能と可視性の2点です。
性能:ETLはバックグラウンドで実行され、結果をテーブルに書き込みます。実行に30秒かかろうと1時間かかろうとエンドユーザには影響しません。利用者は JOIN や複雑なロジックなしに結果テーブルを直接参照できるため、クエリ時間が短くなります。
可視性:SQLクエリは個人のPC上やレポートコードの中に埋もれがちで、他の人が探すことすら難しい。ロジックをETLに移してGitHubなどのリポジトリで管理すれば、発見・レビュー・再利用が容易になり、変更履歴も残ります。
具体例として挙げられていた日次スナップショットテーブルは説得力がありました。個々のエンティティ単位・長期間のクエリは重くなりがちで、しかも現在の状態のような属性はソーステーブルで上書きされてしまう。正確な履歴を残す唯一の方法が日次スナップショットである場合がある、というのは基盤設計の要点です。
一方でETL化のデメリットも書かれています。元テーブルに新しいデータが到着していても、ジョブが実行されるまで最新の結果は得られません。
「ロジックの置き場所」という問題設定は、アプリケーション設計におけるレイヤ責務の議論とほぼ同型です。分析基盤でも同じ判断が求められるのだと再認識しました。
コードの整理
コメント、大文字化、インデント、丸括弧といった書式の作法から、コードの保存方法まで。地味ですが、SQLは長大化しやすいだけに効いてきます。
計算の整理
SQL句の評価順序の理解、サブクエリ、一時テーブル、共通テーブル式(CTE)、grouping sets が扱われます。
CTEについては長所と短所の両方が整理されています。
長所は、同じサブクエリを何度も定義せずに済むこと(DBが同じクエリを繰り返し実行せずに済み、更新漏れによる不整合も防げる)、特別なDB権限が不要なこと、ネストしたサブクエリの氾濫を避けてコードを整理できることです。
短所は、使用箇所から離れた先頭で定義するため長いクエリでは可読性が下がること、そして中間結果の確認が難しいこと(サブクエリなら該当部分だけ選択実行できますが、CTEでは周囲をコメントアウトする必要があります)。
WITH first_term AS (
SELECT id_bioguide, min(term_start) AS first_term
FROM legislators_terms
GROUP BY 1
)
SELECT
date_part('year', age(b.term_start, a.first_term)) AS periods,
count(DISTINCT a.id_bioguide) AS cohort_retained
FROM first_term a
JOIN legislators_terms b ON a.id_bioguide = b.id_bioguide
GROUP BY 1;
サイズとプライバシー
-
%やmodを使ったサンプリング - 次元削減
- PIIとデータプライバシー
PIIの節は、扱いの重さに見合った分量が割かれています。GDPR、CCPA、オーストラリアのプライバシー原則、ブラジルのLGPDといった規制が列挙され、氏名・住所・メール・生年月日だけでなく、心拍数や血圧などの健康指標、GPS座標もPIIに含まれると説明されます。
自宅と子どもの学校のGPS座標があれば家族の誰かを一意に特定でき、オフィスの座標が加われば個人が特定できる、という例は具体的で怖さが伝わります。
ベストプラクティスは3つです。集約する(ただしユーザ数が1になる属性の組み合わせは個人と結びつくため外れ値として除外する)、一意性を保つランダムな代替値に置換する(row_number を使う場合、匿名化とみなせるだけのランダム性を ORDER BY にどう持たせるかが課題になる)、ハッシュ化する(同じ入力は常に同じ出力になるため、一意性を保ちながら値を隠蔽できる)。
9章:まとめ
これまでのテクニックを組み合わせる応用編です。
ファネル分析は時系列解析とコホート分析の要素を併せ持ちます。手順間のリテンションを測りますが、この文脈では「コンバージョン」と呼ばれます。離脱の多い手順が最適化の手がかりになり、完了率の変化は外部要因の検出にも使えます。続いて解約・中断・離脱の定義(定義そのものが分析設計であるという扱い)、そしてバスケット分析(string_agg で顧客ごとの購入商品リストを作りグループ化する方法から、自己結合による商品ペアの抽出まで)が扱われます。
参考資料(書籍・ブログ・データセット)の紹介も充実しています。
最終節の主張が、本書全体を要約しています。優れた分析は最新技術の習得だけでは生まれない。適切な問いを立て、データと対象領域を時間をかけて理解し、適切な手法を適用し、最後に意思決定を支援する形で結果を伝えること。この4つが揃って初めて成立する、と締めくくられます。
読んで良かった点
1. トレードオフを必ず両面から書く
本書の最大の美点は、あらゆる技法について「向いていない場合」を必ず書くことです。SQLは統計的有意性を計算できない。テキスト分析のルールベースは保守が困難になる。CTEには可読性と中間結果確認のトレードオフがある。ロジックをETLに移すとデータの鮮度が落ちる。
「この方法が最善」ではなく「この方法はここまで有効で、ここからは別の道具」と書く。設計判断を扱う技術書として、最も信頼できる書き方だと思います。
2. 指標定義の言語化が丁寧
DAU / WAU / MAUの使い分け、コホートとセグメントの区別、サバイバーシップバイアス、相関と因果の5パターン。これらはSQLの話ではなく指標設計の話です。実装より前段の議論が充実しているため、レビューや仕様策定の場でそのまま使えます。
3. 実務の失敗から書かれている
本番DBに直接クエリを投げてサイトを落とした話、CASE 式が100行に膨れた話、指標の変化を追う前にロギング変更を確認するようになった話。教科書的な整理ではなく、実際に踏んだ地雷から書かれている感触があります。
注意点
PostgreSQL前提です。 date_trunc、string_agg、age、POSIX正規表現演算子など方言に依存する記述が多く、他のDBでは読み替えが必要です。本書自身も date_trunc 非対応のDBでは extract や trunc を検討するよう補足していますが、MySQLやBigQuery、Snowflakeが主戦場なら翻訳作業が発生します。
SQL入門書ではありません。 JOIN、GROUP BY、サブクエリ、ウィンドウ関数の基本構文は既知の前提で進みます。ウィンドウ関数に不慣れな場合は、3章の前に補強しておくと読みやすいはずです。
統計の詳細は扱いません。 カイ二乗検定やt検定は「SQLでどう集計するか」の観点で扱われ、統計理論そのものは外部資料に委ねられています。
原書は2021年刊行です。 生成AIやモダンデータスタックの最新動向は含まれていません。ただし本書が扱うのは時系列・コホート・異常検知といった分析の基本設計であり、この部分は陳腐化しにくい領域です。
こんな人におすすめ
- SQLの基本構文は書けるが、分析クエリの設計になると手が止まる
- リテンションやコホートの定義をチームで議論する立場にある
- 分析ロジックをアプリケーション側・SQL側・ETL側のどこに置くか判断する必要がある
- データ基盤の設計にあたり、PIIの扱いを整理したい
- ウィンドウ関数を「知っている」から「使いこなす」に進めたい
逆に、SQLをこれから学ぶ段階の方や、機械学習パイプラインの構築を目的としている方には、本書は最適な入り口ではないと思います。
おわりに
本書を読み終えて残ったのは、SQLの新しい関数の知識よりも、分析における設計判断の型でした。
ウィンドウサイズと感度のトレードオフ、コホートとセグメントの区別、ロジックの置き場所の判断、PIIを出力に含めないための3つの手段。これらはSQLに固有の話ではなく、データを扱うシステムを設計するときに繰り返し現れる論点です。
その意味で本書は「SQLの本」であると同時に、「データ分析というドメインの設計原則を、SQLという具体を通して語った本」だと感じました。ソフトウェア設計に関心のあるエンジニアが読んでも、得るものは少なくないはずです。
手元に置いて、分析要件が降ってきたときに該当章を開く。そういう付き合い方をする一冊になりそうです。