DISTINCTで重複排除
同じ会社名が 400 回出てくる
取引先を選ぶドロップダウンを作りたくて、請求書の表から会社名を取り出したとします。返ってきたのは 400 行。請求書の枚数だけ同じ会社名が並んでいて、一覧としては使えません。
欲しいのは行ではなく、値の種類です。そういうときに DISTINCT を書きます。
SQL クエリ
SELECT DISTINCT company_name
FROM invoices
ORDER BY company_name;同じ値の行はまとめられ、会社名が 1 つずつ返ります。DISTINCT は SELECT の直後に 1 回だけ書きます。列ごとに付けるものではありません。
1 つの会社が何枚も請求書を持つのは、表の作りとして正しい姿です。だからこの重複は直すべき汚れではなく、取り出し方の側で畳むものだと考えます。
列を 1 つ足しただけで、重複が戻ってくる
DISTINCT は「並べた列の組み合わせ」で重複を判定するからです。
SQL クエリ
SELECT DISTINCT company_name, staff_name
FROM invoices;これは会社名を一意にしません。会社名と担当者名のペアが一意になるので、担当者が 5 人いる会社は 5 行出ます。「なぜか重複が消えない」と相談されるクエリは、たいてい余計な列が混ざっています。一意にしたい列だけを並べるのが安全です。
延べ数とユニーク数は、別の指標
DISTINCT は集計関数の括弧の中にも書けます。
SQL クエリ
SELECT
COUNT(*) AS page_views,
COUNT(DISTINCT visitor_id) AS visitors
FROM access_logs;COUNT(*) は行数、つまり閲覧の延べ回数です。COUNT(DISTINCT visitor_id) は訪問した人数です。1 人が 10 回見れば、前者は 10、後者は 1 になります。どちらも正しい数字ですが、意味はまったく違います。数字を報告する前に、聞かれているのがどちらなのかを確かめてください。
この 2 つを並べて出すと、1 人あたり何回見ているかもその場で分かります。差が開いているほど、少数の人が繰り返し訪れている形です。重複がどれくらいあるかを確かめたいときも、この 2 つの差を見るのがいちばん早い方法です。
現場の話
DISTINCTは重複を見つけるために、内部で並べ替えや突き合わせをしています。行数が多いほど重くなるので、先にWHEREで範囲を絞ってから使います。なおDISTINCTは NULL どうしを同じ値として扱うので、NULL は何行あっても 1 行にまとまります。
テーブル構造
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT NOT NULL,
product VARCHAR(50) NOT NULL,
amount INT NOT NULL
);
INSERT INTO orders (id, user_id, product, amount) VALUES
(1, 101, 'ノートPC', 128000),
(2, 102, 'マウス', 2980),
(3, 101, 'キーボード', 6800),
(4, 103, 'マウス', 2980),
(5, 101, '小説A', 1800),
(6, 104, '小説B', 2200),
(7, 102, 'コーヒー豆', 1500),
(8, 103, '紅茶葉', 1200);期待される出力
| user_unique_count |
|---|
| 4 |