# 機能設計書 24-inner_join

## 概要

本ドキュメントは、dplyrパッケージにおける`inner_join`関数の機能設計を定義する。`inner_join`は、2つのデータフレームを内部結合し、両方のテーブルに一致するキーを持つ行のみを保持するMutating Join関数である。

### 本機能の処理概要

`inner_join`関数は、SQLの INNER JOIN に相当する操作を実行する。左側のデータフレーム（x）と右側のデータフレーム（y）の両方に一致するキーが存在する行のみを結果に含める。どちらか一方にしか存在しない行は結果から除外される。最も制限的な結合タイプであり、データの整合性が高いことを前提とした分析に適している。

**業務上の目的・背景**：両方のデータソースに存在するレコードのみを分析対象としたい場合に使用する。例えば、注文データと出荷データの両方に存在する取引のみを分析する、アクティブな顧客のみの購買履歴を抽出する、などのケースである。`inner_join`は、データの欠損を許容せず、完全に紐づくデータのみを対象とした厳密な分析を行う際の標準的な手法として設計されている。

**機能の利用シーン**：
- 両テーブルに存在するレコードのみを対象とした分析
- データ品質の検証（マッチしないレコードの特定の逆操作）
- 厳密なリレーションシップを持つデータの結合
- NAを結果に含めたくない場合の結合処理

**主要な処理内容**：
1. 結合キーの特定（by引数の解析またはcommon columnsの自動検出）
2. キー列の型の共通化（型が異なる場合のキャスト処理）
3. vctrs::vec_locate_matchesによるマッチング処理
4. マッチした行のみで結果データフレームを構築
5. 重複列名への接尾辞付与

**関連システム・外部連携**：vctrパッケージのvec_locate_matches関数を使用してマッチング処理を実行。rlangパッケージによるNSE処理、tibbleパッケージとの相互運用性を提供。

**権限による制御**：特になし。Rの通常のオブジェクト操作権限に依存する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはRライブラリであり、UIは存在しない |

## 機能種別

データ変換 / 結合処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| x | data.frame / tibble | Yes | 左側テーブル | data.frameまたはその拡張型 |
| y | data.frame / tibble | Yes | 右側テーブル | data.frameまたはその拡張型 |
| by | join_by / character / NULL | No | 結合キーの指定 | join_by()、文字ベクトル、またはNULL |
| copy | logical | No | 異なるソース間でのコピー許可 | TRUE/FALSE（デフォルト: FALSE） |
| suffix | character(2) | No | 重複列名への接尾辞 | 長さ2の文字ベクトル（デフォルト: c(".x", ".y")） |
| keep | logical / NULL | No | 両テーブルのキー列を保持するか | TRUE/FALSE/NULL |
| na_matches | character | No | NAの一致方法 | "na"（デフォルト）または"never" |
| multiple | character | No | 複数マッチの処理方法 | "all", "any", "first", "last" |
| unmatched | character / character(2) | No | 非マッチ行の処理 | "drop"または"error"、inner joinでは長さ2も可 |
| relationship | character / NULL | No | 期待される関係性 | "one-to-one", "one-to-many", "many-to-one", "many-to-many", NULL |

### 入力データソース

R環境内のdata.frame、tibble、またはdbplyr/dtplyrによるリモートテーブル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | data.frame / tibble | xと同じ型で、両テーブルにマッチした行のみを含む |

### 出力先

R環境内のオブジェクトとして返却

## 処理フロー

### 処理シーケンス

```
1. 引数の検証
   └─ check_dots_empty0: 不正な追加引数のチェック
2. データソースの同期
   └─ auto_copy: 異なるソースの場合のコピー処理
3. join_mutate関数への委譲（type="inner"）
   ├─ na_matchesの検証
   ├─ keepの検証
   ├─ by引数の解析（join_by_commonまたはas_join_by）
   ├─ join_cols: 出力列の決定
   ├─ join_cast_common: キー列の型統一
   ├─ join_rows: マッチング処理（非マッチ行は除外）
   └─ 結果の構築（マッチした行のみ）
4. dplyr_reconstruct: 出力型の復元
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[check_dots_empty0]
    B --> C[auto_copy: yをxのソースにコピー]
    C --> D[join_mutate呼び出し type=inner]
    D --> E[na_matches/keep検証]
    E --> F{by指定あり?}
    F -->|No| G[join_by_common: 共通列検出]
    F -->|Yes| H[as_join_by: by解析]
    G --> I[join_cols: 出力列計算]
    H --> I
    I --> J[join_cast_common: 型統一]
    J --> K[join_rows: マッチング 非マッチは除外]
    K --> L{マッチあり?}
    L -->|Yes| M[結果データフレーム構築]
    L -->|No| N[空のデータフレーム]
    M --> O[dplyr_reconstruct]
    N --> O
    O --> P[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-24-01 | マッチ行のみ | 両テーブルに一致する行のみを結果に含める | 常に適用 |
| BR-24-02 | 非マッチ除外 | xまたはyに一致しない行は結果から除外 | 常に適用 |
| BR-24-03 | 行順序 | xの行順序を維持 | 常に適用 |
| BR-24-04 | unmatched双方向 | inner joinではx,y両方の非マッチをチェック可能 | unmatched指定時 |
| BR-24-05 | 多対多警告 | 等価結合で多対多関係を検出時に警告 | relationship=NULL時 |

### 計算ロジック

- **マッチング**: vctrs::vec_locate_matchesを使用
- **非マッチ行**: standardise_join_no_matchでno_match="drop"が設定され、除外される
- **結果行数**: マッチした組み合わせの数（最大でnrow(x) * nrow(y)、通常は小さい）

## データベース操作仕様

### 操作別データベース影響一覧

本機能はインメモリ処理のため、データベース操作は発生しない。ただし、dbplyrバックエンドと連携した場合、SQLのINNER JOINクエリが生成される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| dplyr_error_join | 結合エラー | キー列の型が互換性なし | 同じ型に変換するか結合キーを見直す |
| dplyr_error_join_matches_nothing | 非マッチエラー | unmatched="error"でxに非マッチ行あり | 非マッチ行を確認するかunmatched="drop"に変更 |
| dplyr_error_join_matches_remaining | 非マッチエラー | unmatched="error"でyに非マッチ行あり | 非マッチ行を確認するかunmatched="drop"に変更 |
| dplyr_error_join_relationship | 関係性エラー | relationship指定に違反 | データの関係性を確認 |

### リトライ仕様

該当なし（同期処理）

## トランザクション仕様

該当なし（インメモリ処理）

## パフォーマンス要件

- 計算量: O(n + m) ～ O(n * m)（nはxの行数、mはyの行数、マッチングパターンに依存）
- メモリ使用量: 結果行数分のメモリを消費（outer joinより少ない傾向）

## セキュリティ考慮事項

特になし。入力データの機密性は呼び出し側の責任で管理する。

## 備考

- 最も制限的な結合タイプであり、データが失われる可能性がある点に注意
- unmatched引数でinner joinでは長さ2のベクトルを指定し、xとyを個別に制御可能
- na_matches="never"を使用するとNA同士はマッチしない

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | join.R | `R/join.R` | Inner joinの説明（8-16行目） |

**読解のコツ**: inner_joinの特徴は「unmatched rows in either input are not included in the result」。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | join.R | `R/join.R` | inner_join関数本体（251-293行目） |

**主要処理フロー**:
1. **251-261行目**: inner_joinジェネリック関数定義
2. **265-277行目**: inner_join.data.frameメソッドのパラメータ定義
3. **278行目**: check_dots_empty0
4. **279行目**: auto_copy
5. **280-292行目**: join_mutate呼び出し - type="inner"を指定

#### Step 3: unmatched引数の特殊処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | join-rows.R | `R/join-rows.R` | check_unmatched関数（317-349行目） |
| 3-2 | join-rows.R | `R/join-rows.R` | standardise_join_no_match関数（370-384行目） |

**主要処理フロー**:
- **321行目**: inner joinでは`n_unmatched == 2L`を許可
- **324行目**: inner joinのunmatchedは長さ1または2
- **374行目**: inner joinでは非マッチ行を"drop"

### プログラム呼び出し階層図

```
inner_join(x, y, by, copy, suffix, keep, na_matches, multiple, unmatched, relationship)
    │
    ├─ check_dots_empty0(...)
    │
    ├─ auto_copy(x, y, copy)
    │
    └─ join_mutate(x, y, by, type="inner", ...)
           │
           ├─ join_cols(x_names, y_names, by, suffix, keep)
           │
           ├─ join_cast_common(x_key, y_key, vars)
           │
           ├─ join_rows(x_key, y_key, type="inner", ...)
           │      ├─ check_unmatched() - inner joinは長さ2許可
           │      ├─ standardise_join_no_match() - "drop"設定
           │      └─ dplyr_locate_matches(...)
           │
           └─ dplyr_reconstruct(out, x)
```

### データフロー図

```
[入力]                      [処理]                           [出力]

x (data.frame) ──┐
                 ├─▶ join_rows(type="inner") ─▶ マッチング
y (data.frame) ──┤           │
                 │           ├─▶ マッチした行のみ抽出
                 │           └─▶ 非マッチ行は除外
                 │
                 └─▶ vec_slice() ─▶ 結合結果 (data.frame)
                                        │
                                        └─▶ 両テーブルにマッチした行のみ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| join.R | `R/join.R` | ソース | inner_join関数の定義 |
| join-rows.R | `R/join-rows.R` | ソース | join_rows、check_unmatched関数の定義 |
| join-cols.R | `R/join-cols.R` | ソース | join_cols関数の定義 |
| join-by.R | `R/join-by.R` | ソース | join_by関数の定義 |
