6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

「今月のKPI、過去最高ですね!素晴らしい!」

会議で上司から褒められたあの瞬間。プレゼン資料に映し出された右肩上がりのグラフ。チームメンバーからの拍手。

でも、その翌日。

「ちょっといい?このSQL見せて」

先輩エンジニアに声をかけられた瞬間、私の人生で最も恥ずかしい経験が始まりました。

KPIが20%も上振れしていた。 過去最高どころか、平均以下。昨日褒められたのは、すべて NULLを理解していなかった 自分のミスによる幻想でした。

image.png

この記事では、NULLを甘く見て痛い目に遭った実体験をお伝えします。

事故の始まり:月次報告の準備

「今月のアクティブ率を集計してくれ」

月末の金曜日。上司から依頼されました。

「来週の経営会議で使うから、今月のユーザーアクティブ率を出してくれる?」

アクティブ率の定義:月内にログインしたユーザー数 / 全登録ユーザー数

すぐにSQLを書きました。

SELECT 
    COUNT(DISTINCT u.user_id) as total_users,
    COUNT(DISTINCT l.user_id) as active_users,
    ROUND(COUNT(DISTINCT l.user_id) * 100.0 / COUNT(DISTINCT u.user_id), 2) as active_rate
FROM 
    users u
LEFT JOIN 
    login_logs l 
    ON u.user_id = l.user_id 
    AND l.login_date >= '2024-11-01' 
    AND l.login_date < '2024-12-01';

結果:アクティブ率76.5%

「先月は65%くらいだったから、かなり改善してる!」

グラフを作成して上司に報告。週末を迎えました。

会議での報告「過去最高です!」

月曜の朝、経営会議。

「今月のユーザーアクティブ率ですが、76.5%で過去最高を記録しました」

自信満々でプレゼン。上司が満足そうに頷き、「素晴らしい!」とチームメンバーからも拍手。

その夜は、気分良く帰宅しました。

翌日の悪夢

「ちょっといい?このSQL見せて」

火曜日の午後。先輩エンジニアが近づいてきました。

「昨日の報告、見たよ。ちょっとそのSQL見せてもらっていい?」

何も疑わず、画面を見せました。先輩が私のSQLを見て、10秒ほどの沈黙。

「...あ」

「これ、LEFT JOINしてるよね。ログインしてないユーザーの場合、l.user_id は?」

「え...NULL...です...ね...」

血の気が引きました。

COUNT()の使い方が間違っていた

先輩が説明してくれました。

「COUNT(DISTINCT l.user_id) は、NULLを除外してカウントする。だから、ログインしたユーザーは正しい。でも、users テーブルの user_id にNULLが入ってたら?」

「え、それはないはず...あ、でも最近、退会ユーザーの仕様変更で...」

思い出しました。先月、一部のレコードで user_id を NULL に更新する処理を入れていました。

「正しい全登録ユーザー数は、COUNT(*) で取得すべきだったんだ」

-- 正しいSQL
SELECT 
    COUNT(*) as total_users,  -- これが正しい
    COUNT(DISTINCT l.user_id) as active_users,
    ...

先輩が修正したSQLを実行。

アクティブ率:58.3%

報告した数字より 18.2ポイント も低い。過去最高どころか、過去3ヶ月で最低でした。

「上司に報告、どうする?」

「...上司に、報告しないと...」

立ち上がる足が震えました。昨日あれだけ褒められたのに。

「あの...昨日の数字なんですが...」

訂正報告の会議

「昨日の数字、間違っていました」

翌日、再び経営会議。今度は謝罪のためです。

「昨日報告した数字ですが、集計ミスがありました。正しいアクティブ率は 58.3% です。昨日の報告値より約18ポイント低くなります」

スクリーンの修正後のグラフ。右肩上がりだったトレンドが、横ばいに。

会議室に重い沈黙が流れました。

「SQLのCOUNT関数の使い方を誤っていました。NULLの扱いを正しく理解していなかったことが原因です。申し訳ございませんでした」

深く頭を下げました。

会議後、上司から個別に呼ばれました。

「ミスは誰にでもある。でも、KPIはチーム全体の評価に直結するから、今後は必ずレビューを入れること。それと...SQLの基礎、ちゃんと勉強した方がいいよ。なんとなくで書いてたでしょ?」

図星でした。何も言い返せませんでした。

なぜこんなことに?

デスクに戻って考えました。

  • COUNT(col) と COUNT(*) の違いを知らなかった
  • NULLがどう扱われるか理解していなかった
  • 「なんとなく動くSQL」を書いていた

一番の問題は、SQLの基礎知識が欠けていた ことでした。

真因:基礎知識の欠如

後日、先輩が教えてくれました。

JOINでNULLが増える

「LEFT JOINは、左側のテーブルの全レコードを保持する。右側にマッチするデータがない場合、右側のカラムはすべてNULLになる」

言われてみれば当たり前。でも、意識したことがありませんでした。特に集計関数と組み合わせた場合、NULLの扱いを理解していないと今回のような事故が起きます。

COALESCEで"0扱い"にしていた

「君のSQL、よくCOALESCEでNULLを0に変換してるよね」

過去のコードを見返すと、確かにそうでした。

「購入履歴なし(NULL) と 購入金額0円 は、意味が違うよね。COALESCEで一律0にすると、その違いが消えちゃう」

平均購入額を計算するとき、この違いは大きな影響を与えます。意識せずにCOALESCEを使っていた 自分は、その違いを理解していませんでした。

NULLの三値論理

先輩から渡された本で初めて知りました。NULLの三値論理。

SQLの世界では、TRUE と FALSE だけでなく、UNKNOWN という第三の状態が存在する。NULLとの比較結果は UNKNOWN になり、WHERE句では除外される。

知らなかったでは済まされない。これは SQLの基本中の基本 でした。

基礎を学び直す決意

「もう二度とこんな恥はかきたくない」

もう二度と、こんな恥はかきたくない。

ネットで調べてコピペする仕事の仕方は終わりにする。体系的に学ぶため、先輩に勧められた OSS-DB技術者認定試験 に挑戦することにしました。

OSS-DB技術者認定試験への挑戦

OSS-DBは PostgreSQL の技術力と知識を認定する資格です。

image.png

Silver の出題範囲を見ると、今回のミスの原因がそのまま載っていました。

  • SQL全般:SELECT、集計関数、NULL の扱い
  • データベース設計:正規化、制約
  • 運用管理:バックアップ
  • パフォーマンス:インデックス、EXPLAIN

「これだ」と思い、勉強を開始。NULLの章では「COUNT(col) と COUNT(*) の違い」「NULLを含む計算」など、知らなかったことだらけでした。

2ヶ月後、OSS-DB Silver に合格しました。

学び直した結果

試験勉強を通じて得られたもの:

  • 自信を持ってSQLを書ける - 「なんとなく」ではなく「理解して」書けるように
  • 同じミスをしない - NULL、集計、JOINの挙動を理解
  • 信頼の回復 - 半年後の報告では、レビュー済みで正確な数値を提出。「前より信頼できる」と言葉をもらいました。

まとめ

NULLを甘く見た代償

  • KPIが20%上振れして会議で褒められる
  • 翌日に間違いが発覚して謝罪
  • チームからの信頼を失う

基礎知識の大切さ

  • 断片的な知識では不十分
  • 体系的に学ぶことの価値
  • SQLの基本(NULL、COUNT、COALESCE)の理解

SQLの基礎に不安がある方は、OSS-DB試験での学習をおすすめします。試験合格が目的ではなく、学び直しのガイドとして活用するだけでも、実務で大きな違いを生むはずです。

詳細は公式サイトをご確認ください:

※試験内容や受験料は変更される可能性がありますので、最新情報は公式サイトでご確認ください。

参考リンク

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?