目次
ふりかえり

筆者
本記事は、SQLの基本、実務使用例編になります。
SQLの基礎に関しましては、
【初学者必見!】SQLの超基礎編の記事をご覧くださいませ。

A子
本編に入ります!
INと EXISTSの違い

筆者
INと EXISTSの違いの一覧になります。
| 項目 | IN | EXISTS |
|---|---|---|
| 本質 | 値の比較(リストに含まれるか) | 存在の確認(1件でも存在するか) |
| 主な使い方 | 「この値は、あのリストに含まれているか?」を調べる | 「この条件のデータが存在するか?」を調べる |
| 処理対象 | 値(=値の集合) | 行の存在有無 |
| パフォーマンス面 | 小規模データ向き(リストと比較) | 大規模データに強い(途中で打ち切れる) |
| NULL の扱い | 注意が必要(NULLがあると結果が変わる) | NULLの影響を受けにくい |
| 結びつけ | 結びつけなくても動く(値比較なので) | 通常はメインクエリとの結びつきが必要 |

A子
INは値の比較をして、EXISTSは存在の確認をするんだね。

筆者
はい、そうです!
具体的にどんな感じで使用するのか、解説していきます。
実務レベルの使用例を見ていこう!

筆者
実際に、SQLを使用してデータを確認していきましょう。
SQLに関しては以下を使用して解説していきます。
create table文、select文、insert文、update文、delete文、
drop table文、につきましては、過去にアップロードした
【初学者必見!】SQLの超基礎編の記事をご覧くださいませ。

A子
目次の、「ふりかえり」のところにそれぞれの記事のリンクが
貼ってあるよ!
または、サイドバーのカテゴリーにSQLがあるから、そちらからでも
参照できます!
Oracle Live SQLを使用して、SQLの動きを確認していきます。
[事前準備]今回、実行するSQLの一覧
-- 申請管理情報テーブルの作成
create table 申請管理情報 (
STAFF_NO varchar2(10) not null, -- 職員番号 (Staff Number)
APPLI_NO varchar2(10) not null, -- 申請番号 (Application Number)
APPLI_DATE date, -- 申請年月日 (Application Date)
DEPARTMENT varchar2(10), -- 部署名(Department)
constraint PK_申請管理情報 primary key (STAFF_NO, APPLI_NO)
);
create table 申請内容の詳細 (
職員番号 varchar2(10) not null, -- 親テーブルの STAFF_NO に対応
申請番号 varchar2(10) not null, -- 親テーブルの APPLI_NO に対応
申請内容の詳細 varchar2(100), -- 申請の詳細内容を格納するカラム
constraint PK_申請内容の詳細 primary key (職員番号, 申請番号),
constraint FK_申請内容の詳細 foreign key (職員番号, 申請番号)
references 申請管理情報 (STAFF_NO, APPLI_NO)
);
insert into 申請管理情報 (STAFF_NO, APPLI_NO, APPLI_DATE, DEPARTMENT)
values ('1001', 'A001', TO_DATE('2024-02-25', 'YYYY-MM-DD'),'営業');
insert into 申請管理情報 (STAFF_NO, APPLI_NO, APPLI_DATE, DEPARTMENT)
values ('1001', 'A002', TO_DATE('2024-02-26', 'YYYY-MM-DD'),'営業');
insert into 申請管理情報 (STAFF_NO, APPLI_NO, APPLI_DATE, DEPARTMENT)
values ('1002', 'A003', TO_DATE('2024-02-27', 'YYYY-MM-DD'),'開発');
insert into 申請管理情報 (STAFF_NO, APPLI_NO, APPLI_DATE, DEPARTMENT)
values ('1002', 'a003', TO_DATE('2024-01-27', 'YYYY-MM-DD'),'開発');
insert into 申請管理情報 (STAFF_NO, APPLI_NO, APPLI_DATE, DEPARTMENT)
values ('1003', 'A004', TO_DATE('2024-02-28', 'YYYY-MM-DD'),'営業');
insert into 申請内容の詳細 (職員番号, 申請番号, 申請内容の詳細)
values ('1001', 'A001', 'レギュラーとハイオク間違えたので、もう一回入れに行きたいです。');
insert into 申請内容の詳細 (職員番号, 申請番号, 申請内容の詳細)
values ('1001', 'A002', 'ガソリン高いから、もっと補助してほしい');
insert into 申請内容の詳細 (職員番号, 申請番号, 申請内容の詳細)
values ('1002', 'A003', 'ハイオク満タンにしちゃった');
insert into 申請内容の詳細 (職員番号, 申請番号, 申請内容の詳細)
values ('1002', 'a003', 'レギュラー満タンにしちゃった');
使用例①:IN を使った例
select *
from 申請管理情報
where (STAFF_NO, APPLI_NO) in (
select 職員番号, 申請番号
from 申請内容の詳細
);

解説:
申請内容の詳細に登録されている(職員番号, 申請番号)のリストと、申請管理情報の(STAFF_NO, APPLI_NO)を 値として照合しています。- つまり「申請内容が書かれている申請だけ抽出する」イメージです。
使用例②:EXISTS を使った例
ログイン者の職員番号が '1001'、申請番号が 'A001' のときに、申請内容の詳細 にデータが存在するか確認する SQL
select 1
from dual
where exists (
select 1
from 申請内容の詳細
where 職員番号 = '1001'
and 申請番号 = 'A001'
);

解説:
| 部分 | 内容 |
|---|---|
select 1 from dual | Oracleでは1行返すためのダミー |
where exists (...) | 存在すれば 1 が返る(結果あり)、なければ何も返らない |
職員番号 = '1001' and 申請番号 = 'A001' | この2つの条件で該当するレコードがあるかを確認 |
間違ったSQL(文法エラー)
select *
from 申請内容の詳細
where (職員番号, 申請番号) exists (
select STAFF_NO, APPLI_NO
from 申請管理情報
where DEPARTMENT = '営業'
);

なぜエラーになるのか?
EXISTSは、左側に比較対象(列や値)を置けません!- 正しい使い方は、次のように単体で
WHERE EXISTS (サブクエリ)という形です。 - つまり、
EXISTSは「行の存在」を調べるだけで、値の比較はしません。
正しい EXISTS の書き方に直すとこうなります
select *
from 申請内容の詳細 d
where exists (
select 1
from 申請管理情報 m
where m.STAFF_NO = d.職員番号
and m.APPLI_NO = d.申請番号
and m.DEPARTMENT = '営業'
);

このSQLの動き
申請内容の詳細の1行ごとに、申請管理情報に「一致する職員番号・申請番号」で、かつ営業のデータがあるかどうかをチェック。- 存在すれば(=該当すれば)その行を返す。
IN と EXISTS の違いをここで整理
| 比較項目 | IN(正しい例) | EXISTS(正しい例) |
|---|---|---|
| 書き方 | where (列1, 列2) in (select ...) | where exists (select ... where 結び条件) |
| 使いどころ | 値で一致させたいとき | 存在確認をしたいとき |
| 間違いやすい書き方 | (列1, 列2) exists (...) ← ❌ | 正しくは exists (...) の中で列を比較 |
まとめ

筆者
EXISTS と IN の違いについて解説しました。
複雑に見えますが、値の比較をしたいのか、存在の有無を確認したいのかで使用を分けるケースが多いです。
次回もお楽しみに!










コメント