PostgreSQL入門!EXISTSとNOT EXISTSの使い方を初心者向けに徹底解説
生徒
「データベースから『注文履歴があるお客さんだけ』を抜き出したいんですけど、どうすればいいですか?」
先生
「そんな時は、PostgreSQLの『EXISTS(イグジスト)』という命令を使うのが便利ですよ。これは『データが存在するかどうか』を確認する魔法の言葉なんです。」
生徒
「存在するかどうか…難しそうですね。私、パソコンもあまり詳しくないのですが…。」
先生
「大丈夫です!名簿と注文表を照らし合わせる作業をイメージすれば、初心者の方でもすぐにマスターできますよ。」
1. データベースとSQLの基本をおさらい
まずは、基本から確認しましょう。データベースとは、パソコンの中に作られた「整理整頓された情報の箱」のことです。PostgreSQL(ポストグレスキューエル)は、その箱を管理するためのソフトウェアの一つです。
そして、SQL(エスキューエル)は、その箱に向かって「このデータを見せて!」「この情報を消して!」と命令するための専用の言葉です。プログラミングと聞くと身構えてしまうかもしれませんが、SQLは英語の文章に近いので、慣れると意外と読みやすいのが特徴です。
今回学習する「EXISTS」も、「~が存在する」という意味の英単語そのままの役割を持っています。
2. EXISTS(イグジスト)とは?「存在チェック」の仕組み
「EXISTS」は、サブクエリ(命令の中に入れ子にする別の命令)と一緒に使われます。ある条件に当てはまるデータが「一件でも見つかればOK!」という仕組みです。
例えば、「果物リスト」と「在庫リスト」があったとします。果物リストの中から、在庫リストに名前が載っているものだけを表示したい場合にEXISTSを使います。
ここで大事なのは、EXISTSは「中身が何か」ではなく「そこにデータがあるかないか」だけを気にしているという点です。探しているものが見つかった瞬間に「あったよ!」と返事をしてくれる、とても効率の良い命令なのです。
3. 実際にやってみよう!EXISTSを使った基本の検索
それでは、具体的な例を見てみましょう。「顧客(users)」テーブルと「注文(orders)」テーブルを使って、「一度でも注文をしたことがあるお客さん」だけを探してみます。
まずは、準備したデータ(テーブルの中身)を確認しましょう。
[users テーブル]
id | name | city
---+----------+-------
1 | 田中太郎 | 東京
2 | 佐藤花子 | 大阪
3 | 鈴木一郎 | 名古屋
4 | 高橋愛美 | 福岡
[orders テーブル]
order_id | user_id | amount
---------+---------+-------
101 | 1 | 5000
102 | 1 | 3000
103 | 3 | 12000
このデータを見ると、田中さん(ID:1)と鈴木さん(ID:3)は注文していますが、佐藤さん(ID:2)と高橋さん(ID:4)はまだ注文していませんね。
SELECT name
FROM users u
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.user_id = u.id
);
実行結果は以下のようになります。
name
----------
田中太郎
鈴木一郎
解説:このSQLでは、usersテーブルの各行に対して、「その人のIDがordersテーブルにあるかな?」とチェックしています。存在した人だけが結果に表示されました。
4. NOT EXISTSで「存在しないもの」を探す
次に、「NOT EXISTS」を使ってみましょう。これはEXISTSの逆で、「データが見つからなかった場合だけ表示する」という命令です。
先ほどの例で言うと、「まだ一度も注文をしていないお客さん」を探すのに最適です。
SELECT name
FROM users u
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.user_id = u.id
);
実行結果を見てみましょう。
name
----------
佐藤花子
高橋愛美
このように、注文履歴がない佐藤さんと高橋さんだけを抽出できました。キャンペーンの案内を「まだ買い物をしていない人だけ」に送りたい時などに非常に役立ちます。
5. サブクエリ(副問合せ)とは?
これまでの説明で「サブクエリ」という言葉が出てきました。これは、大きなSQL文の中に入っている「小さなSQL文」のことです。
カッコ ( ) で囲まれている部分がそれにあたります。パソコンに「まずこのカッコの中の結果を調べて、その結果を使って全体の答えを出してね」とお願いしているわけです。
EXISTSの中のサブクエリで SELECT 1 と書いているのを見て、「1って何?」と思ったかもしれません。これは「データがあるかないかだけ知りたいから、中身の列名は何でもいいよ(とりあえず1を返して)」という意味でよく使われる書き方です。
6. CTE(WITH句)を使って複雑な処理をスッキリさせる
SQLを書いていると、だんだん命令が長くなって、自分でも何を書いていたか分からなくなることがあります。そんな時に便利なのが「CTE(Common Table Expression)」、通称「WITH句」です。
CTEは、一時的に「使い捨ての表」に名前をつけて保存しておくようなイメージです。
例として、「10,000円以上の高額注文をしたことがあるお客さん」を探してみましょう。
[users テーブル]
id | name | city
---+----------+-------
1 | 田中太郎 | 東京
2 | 佐藤花子 | 大阪
3 | 鈴木一郎 | 名古屋
[orders テーブル]
order_id | user_id | amount
---------+---------+-------
101 | 1 | 5000
102 | 3 | 15000
WITH expensive_orders AS (
SELECT user_id
FROM orders
WHERE amount >= 10000
)
SELECT name
FROM users u
WHERE EXISTS (
SELECT 1
FROM expensive_orders eo
WHERE eo.user_id = u.id
);
実行結果は以下の通りです。
name
----------
鈴木一郎
解説:最初に WITH expensive_orders AS (...) の部分で、「1万円以上の注文リスト」という仮の表を作っています。その後のメインの処理で、その仮の表を使ってEXISTSでチェックしています。
7. EXISTSとINの違いとは?どちらを使えばいい?
「特定のデータがあるか探す」方法には、他にも IN という命令があります。初心者の方はどちらを使えばいいか迷うかもしれません。
大きな違いは「動きの速さ」と「NULL(空っぽのデータ)への対応」です。
- EXISTS: 「見つかったら即終了」するので、大量のデータがある時に速いことが多いです。また、データが空っぽ(NULL)でもエラーになりにくいのが特徴です。
- IN: 小さなリストの中から探す時は分かりやすいですが、リストが巨大になると動作が重くなることがあります。
基本的には、今回学んだ EXISTS を使いこなせるようになると、よりプロフェッショナルなデータベース操作が可能になります。
8. 実践編:複数の条件を組み合わせてみよう
最後に応用編です。EXISTSの中に、さらに細かい条件を入れてみましょう。「東京に住んでいる人で、かつ5,000円以上の注文をしたことがある人」を探します。
[users テーブル]
id | name | city
---+----------+-------
1 | 田中太郎 | 東京
2 | 佐藤花子 | 大阪
3 | 鈴木一郎 | 東京
[orders テーブル]
order_id | user_id | amount
---------+---------+-------
101 | 1 | 8000
102 | 3 | 3000
SELECT name
FROM users u
WHERE city = '東京'
AND EXISTS (
SELECT 1
FROM orders o
WHERE o.user_id = u.id
AND o.amount >= 5000
);
実行結果:
name
----------
田中太郎
鈴木さんも東京住まいですが、注文金額が3,000円だったので、この結果には出てきません。このように、AND(かつ)を使って条件を絞り込むことができます。
9. パソコン操作に慣れていなくても大丈夫な理由
ここまで読んで、「やっぱり難しそう…」と感じた方もいるかもしれません。でも安心してください。SQLは「型」が決まっています。
最初は意味がわからなくても、お手本のコードをコピーして、テーブル名や列名だけを自分のものに書き換えるだけで動かすことができます。これを繰り返すうちに、自然と「WHERE EXISTSはセットなんだな」と指が覚えていきます。
料理のレシピと同じです。最初はレシピ通りに作り、慣れてきたら自分流にアレンジ(条件を追加)していけば良いのです。
10. EXISTSを使いこなすためのヒント
EXISTSを使う時のコツは、主役(メインのSELECT)となる表と、脇役(サブクエリ)となる表をしっかり分けることです。
「誰の」情報を出したいのか?(これが主役)
「どんな条件」を別の表から探したいのか?(これが脇役)
この2つを整理するだけで、SQLはぐっと書きやすくなります。PostgreSQLには他にも便利な機能がたくさんありますが、このEXISTSとNOT EXISTSを覚えるだけで、データの分析能力は劇的にアップします。