今回はPostgreSQLのDISTINCTを使い、取得結果の重複を取り除く方法を学習しました。1列を取得する場合と複数列を取得する場合について、取得したデータの意味を整理します。
所要時間は15分ほどです。
それでは、さっそく始めていきましょう!
今日のテーマと到達目標
DISTINCTを使ったSQLを書き、どの列の値をもとに重複を判定するかを説明することが目標です。
用語の定義
| 用語 | 意味 |
|---|---|
| DISTINCT | 選択した列の値の組み合わせが同じ行を、取得結果では1行にまとめる指定 |
| 重複 | 今回のデータでは、選択したすべての列の値が一致していること |
| 結果セット | SELECTの実行で返される行と列の集まり |
| ORDER BY | 結果の行を並べる基準と方向を指定する部分 |
今回は値がすべて入力済みの商品データを使います。
演習用の商品を追加する
取得元のTableはproductsです。1行は商品1種類を表します。product_idは商品を識別する番号、product_nameは商品名、price_yenは円単位の価格です。
最初にSELECT * FROM products;で、登録済みの商品が3件であることを確認しました。その後、100円の商品を1件追加しました。
INSERT INTO products (product_id, product_name, price_yen)
VALUES (4, 'pan', 100);
実行時にはINSERT 0 1と表示されました。続けて全列を取得し、次の4行を確認しました。
| product_id | product_name | price_yen |
|---|---|---|
| 1 | onigiri | 100 |
| 2 | bento | 500 |
| 3 | ame | 50 |
| 4 | pan | 100 |
このINSERTは演習時に実行済みです。同じ環境で繰り返す場合は、まず登録済みのデータを確認します。
DISTINCTなしで価格を取得する
SELECT price_yen
FROM products
ORDER BY price_yen;
実際の実行結果は次のとおりです。
price_yen
-----------
50
100
100
500
(4 行)
4商品それぞれの価格が返るため、100が2回表示されています。ORDER BY price_yenは昇順で並べる指定です。
DISTINCTありで価格を取得する
SELECT DISTINCT price_yen
FROM products
ORDER BY price_yen;
実行結果は次の3行でした。
price_yen
-----------
50
100
500
(3 行)
選択している列はprice_yenだけなので、同じ価格の100は結果で1行にまとまります。結果の3行は商品の件数ではなく、登録されている価格の種類を表しています。
複数列を取得するとどうなるか
次は、商品名と価格の2列を取得し、DISTINCTを指定するSQLを自分で書きました。実行前の予想は「4行」です。
SELECT DISTINCT product_name, price_yen
FROM products
ORDER BY price_yen;
実際の結果も4行でした。
product_name | price_yen
--------------+-----------
ame | 50
onigiri | 100
pan | 100
bento | 500
(4 行)
onigiriとpanは価格が同じでも商品名が異なります。商品名と価格の組み合わせは異なるため、両方の行が残ります。
なお、この画面ではonigiri、panの順でしたが、価格だけで並べているため、同じ100円の2行の間の順序までは保証されません。
重複を判定する列を整理する
| 選択した列 | 重複の判定に使う値 | 今回の行数 |
|---|---|---|
| price_yen | 価格 | 3行 |
| product_name, price_yen | 商品名と価格の組み合わせ | 4行 |
DISTINCTは、選択した列全体を対象にします。今回の2列の例では、価格だけが同じでも1行にはまとまりません。
確認問題と回答
同じ100円なのに、なぜ2行とも残るのか
「DISTINCTで1行にまとめられるのは、取得した列すべての値が一致するときだから」と回答しました。今回のデータでは、商品名が異なることが理由です。
結果が3行になったら商品が削除されたのか
「削除されていない」と回答しました。
SELECT DISTINCTは取得結果の重複を取り除く指定です。元のproductsに記録された商品を削除する操作ではありません。
合格条件と学習記録
| 確認項目 | 確認できた内容 |
|---|---|
| DISTINCTの有無による違いを確認できる | 価格の取得結果が4行から3行になったことを確認 |
| 複数列のSQLを自分で書ける | 商品名と価格を取得するSQLを書き、予想も実行結果も4行 |
| 重複の判定対象を説明できる | 選択した列すべての値が一致するときにまとまると回答 |
| 元データの削除と区別できる | 商品は削除されていないと回答 |
共有されたSQLはエラーなく実行でき、確認問題にも正しく回答できました。
まとめ
| 指定 | 結果 |
|---|---|
| SELECT price_yen | 商品ごとの価格を取得する |
| SELECT DISTINCT price_yen | 重複を除いた価格を取得する |
| SELECT DISTINCT product_name, price_yen | 重複を除いた商品名と価格の組み合わせを取得する |
DISTINCTを使うときは、どの列を選択しているかを確認します。選択した列が変わると、重複を判定する対象も変わります。