SQLのEXISTS文を活用した柔軟なデータ分析方法


## はじめに  
SQLの`EXISTS`文は、「データが存在するかどうか」を判定するための非常に強力な機能です。ただし、多くの方が`WHERE`句でのみ使えると誤解しがちです。本記事では、`EXISTS`文が実際にはさまざまな場面で使えることを、具体例とその出力結果を交えながら解説します。  


## `EXISTS`文の基本構文  
まずは基本構文を確認しましょう。  

```sql
SELECT 列名
FROM テーブル名
WHERE EXISTS (
  サブクエリ
);
```

`EXISTS`文の中に記述されたサブクエリが結果を返す場合、その条件が`TRUE`と評価されます。これを利用して、柔軟なデータ操作や分析が可能です。  


## `EXISTS`の活用場面と出力例



### 1. **WHERE句での存在確認**
最も基本的な使い方として、`WHERE`句でデータの存在を確認します。  
**例:** 注文が存在する顧客を抽出する。  

```sql
SELECT customer_id, customer_name
FROM customers c
WHERE EXISTS (
  SELECT 1
  FROM orders o
  WHERE o.customer_id = c.customer_id
);
```

**出力例:**  
| customer_id | customer_name |
|-------------|---------------|
| 101         | 山田 太郎     |
| 102         | 田中 花子     |


### 2. **SELECT句での条件評価**
`EXISTS`文を`SELECT`句内で使用すると、存在確認の結果（`TRUE`または`FALSE`）を直接出力できます。  
**例:** 各顧客の注文有無を列として表示する。  

```sql
SELECT 
    customer_id,
    customer_name,
    EXISTS (
        SELECT 1
        FROM orders o
        WHERE o.customer_id = c.customer_id
    ) AS has_orders
FROM customers c;
```

**出力例:**  
| customer_id | customer_name | has_orders |
|-------------|---------------|------------|
| 101         | 山田 太郎     | TRUE       |
| 102         | 田中 花子     | TRUE       |
| 103         | 鈴木 次郎     | FALSE      |



### 3. **CASE文での条件分岐**
`EXISTS`文は`CASE`文と組み合わせることで、条件に応じた値を設定できます。  
**例:** 注文が存在する顧客に「Active」、それ以外に「Inactive」を割り当てる。  

```sql
SELECT 
    customer_id,
    customer_name,
    CASE 
        WHEN EXISTS (
            SELECT 1
            FROM orders o
            WHERE o.customer_id = c.customer_id
        ) THEN 'Active'
        ELSE 'Inactive'
    END AS customer_status
FROM customers c;
```

**出力例:**  
| customer_id | customer_name | customer_status |
|-------------|---------------|-----------------|
| 101         | 山田 太郎     | Active          |
| 102         | 田中 花子     | Active          |
| 103         | 鈴木 次郎     | Inactive        |


### 4. **HAVING句での条件付き集計**
`EXISTS`を`HAVING`句内で使用すると、グループ化したデータに条件を課すことができます。  
**例:** 商品マスターに存在する商品のみ注文数を集計。  

```sql
SELECT 
    product_id,
    COUNT(*) AS order_count
FROM orders o
GROUP BY product_id
HAVING EXISTS (
    SELECT 1
    FROM product_master pm
    WHERE pm.product_id = o.product_id
);
```

**出力例:**  
| product_id | order_count |
|------------|-------------|
| 501        | 20          |
| 502        | 35          |


### 5. **INSERT文での条件付き挿入**
`EXISTS`を`INSERT`文に組み込むことで、特定条件を満たす場合のみデータを挿入できます。  
**例:** 顧客が存在する場合のみ注文を挿入する。  

```sql
INSERT INTO orders (order_id, customer_id, order_date)
SELECT 
    new_order_id, 
    new_customer_id, 
    CURRENT_DATE
FROM temp_orders t
WHERE EXISTS (
    SELECT 1
    FROM customers c
    WHERE c.customer_id = t.new_customer_id
);
```

**挿入前の`orders`テーブル:**  
| order_id | customer_id | order_date |
|----------|-------------|------------|
| 1        | 101         | 2024-11-01|

**挿入後の`orders`テーブル:**  
| order_id | customer_id | order_date |
|----------|-------------|------------|
| 1        | 101         | 2024-11-01|
| 2        | 102         | 2024-11-24|


### 6. **UPDATE文での条件付き更新**
`EXISTS`を`UPDATE`文に使うことで、条件に合致するデータのみを更新します。  
**例:** 注文が存在する顧客のステータスを「アクティブ」に更新する。  

```sql
UPDATE customers c
SET status = 'Active'
WHERE EXISTS (
    SELECT 1
    FROM orders o
    WHERE o.customer_id = c.customer_id
);
```

**更新前の`customers`テーブル:**  
| customer_id | customer_name | status      |
|-------------|---------------|-------------|
| 101         | 山田 太郎     | Inactive    |
| 102         | 田中 花子     | Inactive    |

**更新後の`customers`テーブル:**  
| customer_id | customer_name | status      |
|-------------|---------------|-------------|
| 101         | 山田 太郎     | Active      |
| 102         | 田中 花子     | Active      |



### 7. **DELETE文での条件付き削除**
`EXISTS`を`DELETE`文で使用すると、条件を満たすレコードのみ削除可能です。  
**例:** 商品マスターに存在しない商品を削除する。  

```sql
DELETE FROM products p
WHERE NOT EXISTS (
    SELECT 1
    FROM product_master pm
    WHERE pm.product_id = p.product_id
);
```

**削除前の`products`テーブル:**  
| product_id | product_name  |
|------------|---------------|
| 501        | 商品A         |
| 503        | 商品C         |

**削除後の`products`テーブル:**  
| product_id | product_name  |
|------------|---------------|
| 501        | 商品A         |


## まとめ  
SQLの`EXISTS`文は、**WHERE句以外でも幅広く活用可能**です。特に、条件付きの`SELECT`、`CASE`文、`INSERT`、`UPDATE`、`DELETE`などでその真価を発揮します。さらに、`EXISTS`は`IN`よりもパフォーマンスに優れる場合が多いため、大規模データを扱うシステムでの利用を検討する価値があります。