【SQL実践|実務向け】現場のDBAが教える!COUNT関数の「NULL」と「重複」を正しく扱うための基本と応用

1. 導入: なぜCOUNT関数の挙動を正しく理解すべきか

DB運用において、テーブル内の件数を取得するCOUNT関数は最も頻繁に使われる関数の一つです。しかし、「とりあえずCOUNT()でいいや」と考えていると、意図しない集計結果を招くことがあります。特に、カラム指定とCOUNT()の違いや、NULLの扱いを正しく理解することは、データ分析やバッチ処理の正確性を担保する上で極めて重要です。本稿では、実務で迷わないCOUNT関数の使い分けを解説します。

2. 基礎知識: COUNT関数が扱う「行数」の定義

COUNT関数には、主に3つの異なる挙動があります。

COUNT(カラム名): 指定したカラムに「値が存在する(NULLではない)」行数だけをカウントします。
COUNT(): カラムの値に関わらず、テーブルの「行そのもの」の数をカウントします。
COUNT(DISTINCT カラム名): 指定したカラム内の「重複しない値」の数をカウントします(NULLは除外)。

初心者が陥りやすいのは、COUNT(カラム名)でNULLが含まれている場合に想定より少ない件数が返されるという現象です。この仕様を正しく把握しておく必要があります。

3. 実装/解決策: シチュエーション別クエリの使い分け

現場では、「全件数」を知りたいのか、「有効なデータ数」を知りたいのかによって使い分けます。

・全行数を知りたい場合: 迷わず COUNT() を使用します。
・特定カラムに値が入っている行だけを知りたい場合: COUNT(カラム名) を使用します。
・カテゴリ分けされたユニークな件数を知りたい場合: COUNT(DISTINCT カラム名) を使用します。

4. サンプルプログラム: 実務を想定した動作確認

以下のSQLを環境に合わせて実行し、それぞれの結果の違いを確認してください。

— 実務を想定したテストテーブルの準備
CREATE TABLE pointnote (classname VARCHAR(10), name VARCHAR(10), point INT);

INSERT INTO pointnote VALUES (‘A’, ‘Yamada’, 72), (‘A’, ‘Suzuki’, 82), (‘B’, ‘Togawa’, 76),
(‘A’, ‘Honda’, 90), (‘B’, NULL, 68), (‘B’, ‘Nishi’, 82), (‘A’, ‘Suzuki’, NULL);

— 1. カラム指定のCOUNT: NULLを除外してカウントする
— nameカラムのNULL行はカウントされません
SELECT COUNT(name) AS name_count FROM pointnote;

— 2. 全行数のカウント: NULLを含めてテーブルの行数を取得
SELECT COUNT() AS total_rows FROM pointnote;

— 3. 重複を除外したカウント: ‘Suzuki’が2回登場しても1件として扱う
SELECT COUNT(DISTINCT name) AS unique_name_count FROM pointnote;

5. 応用・注意点: 現場での落とし穴

最後に、DBAの視点から現場で役立つ注意点を2つ伝えます。

NULLの扱いに注意: 前述の通り、COUNT(カラム名)はNULLを無視します。もし「NULLを含めた件数」が必要な場面でCOUNT(カラム名)を使うと、バグの原因になります。その場合はIFNULL()関数などで補完するか、COUNT()を使用してください。

パフォーマンスへの影響: 大規模なテーブルでCOUNT(DISTINCT カラム名)を多用すると、一時テーブルの作成やソート処理が発生し、パフォーマンスが急激に低下することがあります。数百万件を超えるテーブルに対して頻繁に実行する場合は、インデックスの設計見直しや、別途集計用テーブルの作成を検討してください。

適切な関数選択を行うことで、より正確で高速なクエリ設計を目指しましょう。

コメント

タイトルとURLをコピーしました