# 機能設計書 84-Export-DbaDiagnosticQuery

## 概要

本ドキュメントは、dbatools PowerShellモジュールのExport-DbaDiagnosticQuery関数の機能設計を定義する。この関数は、Invoke-DbaDiagnosticQueryの結果をCSVまたはExcelファイルに変換・エクスポートする機能を提供する。

### 本機能の処理概要

Export-DbaDiagnosticQuery は、Glenn Berryの診断クエリ（Invoke-DbaDiagnosticQuery）の実行結果を、分析やレポート作成のためにCSVまたはExcelファイルとして出力するコマンドレットである。実行プランは.sqlplanファイル、クエリテキストは.sqlファイルとして自動的に抽出・保存される。

**業務上の目的・背景**：Glenn Berryの診断クエリは、SQL Serverのパフォーマンス分析とトラブルシューティングに広く使用されている標準的なツールである。これらのクエリ結果をファイルベースで保存することで、ベンダーとの共有、コンプライアンス文書化、経時的なパフォーマンス傾向分析、PowerShellオブジェクトよりも従来のファイル形式を好むチームとの連携が可能になる。Excel出力は複数のクエリ結果を1つのワークブックに統合し、CSV出力はクエリごとに個別ファイルを生成する。

**機能の利用シーン**：
- パフォーマンス問題の診断結果をベンダーサポートに提供
- 定期的な健全性チェック結果のアーカイブ
- コンプライアンス監査用のサーバー状態ドキュメント作成
- 複数サーバーの診断結果を比較分析
- 実行プランの詳細分析のためのSSMS用ファイル生成
- 非技術者向けのExcelレポート作成

**主要な処理内容**：
1. Invoke-DbaDiagnosticQueryからの結果オブジェクト受け取り
2. 実行プラン列の検出と.sqlplanファイルへの抽出
3. クエリテキスト列の検出と.sqlファイルへの抽出
4. 結果データのCSVまたはExcelファイルへの出力
5. 生成されたファイルオブジェクトの返却

**関連システム・外部連携**：
- Invoke-DbaDiagnosticQuery からの結果オブジェクト入力
- ImportExcel モジュール（Excel出力時）
- SQL Server Management Studio（.sqlplan/.sqlファイルの表示用）

**権限による制御**：
- 出力先ディレクトリへの書き込み権限が必要
- Excel出力時はImportExcelモジュールがインストールされている必要がある

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 167 | 診断クエリ | 補助機能 | 診断クエリのエクスポート |

## 機能種別

データエクスポート / レポート出力

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| InputObject | object[] | Yes | Invoke-DbaDiagnosticQueryの結果オブジェクト | パイプライン入力対応 |
| ConvertTo | string | No | 出力形式（Excel/Csv） | デフォルト: Csv |
| Path | System.IO.FileInfo | No | 出力ディレクトリパス | デフォルト: dbatools設定パス |
| Suffix | string | No | ファイル名に付加するサフィックス | デフォルト: タイムスタンプ |
| NoPlanExport | switch | No | 実行プランの抽出を抑制 | - |
| NoQueryExport | switch | No | クエリテキストの抽出を抑制 | - |
| EnableException | switch | No | 例外処理の有効化 | - |

### 入力データソース

- パイプライン入力: Invoke-DbaDiagnosticQuery の出力を直接受け取り
- 変数経由: 事前に取得した診断クエリ結果を変数で渡す

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| System.IO.FileInfo | FileInfo | 生成されたファイルのファイル情報オブジェクト |

出力されるファイルの種類：
- CSVファイル: 各診断クエリの結果データ
- Excelファイル: ワークシートとして統合された結果データ
- .sqlplanファイル: 実行プラン（NoPlanExport未指定時）
- .sqlファイル: クエリテキスト（NoQueryExport未指定時）

### 出力先

- ファイルシステム: 指定されたPathディレクトリ
- PowerShellパイプライン: System.IO.FileInfoオブジェクト

## 処理フロー

### 処理シーケンス

```
1. 前処理（begin）
   ├─ Excel出力時: ImportExcelモジュールのロード確認
   └─ 出力ディレクトリの存在確認・作成

2. 各結果オブジェクトの処理（process）
   ├─ 結果データの抽出
   ├─ ファイル名の構築
   ├─ 実行プラン列の検出と.sqlplanファイル出力
   ├─ クエリテキスト列の検出と.sqlファイル出力
   └─ CSV/Excelへの結果出力

3. ファイル情報の返却
   └─ Get-ChildItemで生成ファイル情報を取得・出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{ConvertTo=Excel?}
    B -->|Yes| C[ImportExcelモジュール確認]
    C --> D{ロード成功?}
    D -->|No| E[エラー終了]
    D -->|Yes| F[ディレクトリ確認/作成]
    B -->|No| F
    F --> G[結果オブジェクトループ]
    G --> H{Result null?}
    H -->|Yes| I[警告出力、次へ]
    H -->|No| J[ファイル名構築]
    J --> K{実行プラン列あり?}
    K -->|Yes| L{NoPlanExport?}
    L -->|No| M[.sqlplanファイル出力]
    L -->|Yes| N[プラン列除外]
    M --> N
    K -->|No| O{クエリテキスト列あり?}
    N --> O
    O -->|Yes| P{NoQueryExport?}
    P -->|No| Q[.sqlファイル出力]
    P -->|Yes| R[テキスト列除外]
    Q --> R
    O -->|No| S{ConvertTo判定}
    R --> S
    S -->|Excel| T[Export-Excel実行]
    S -->|Csv| U[Export-Csv実行]
    T --> V[ファイル情報出力]
    U --> V
    I --> W{次の結果?}
    V --> W
    W -->|Yes| G
    W -->|No| X[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | Excel依存確認 | Excel出力時はImportExcelモジュールが必須 | ConvertTo=Excel |
| BR-002 | ディレクトリ自動作成 | 出力先が存在しない場合は自動作成 | 常時 |
| BR-003 | プラン列自動検出 | 複数の列名パターンで実行プラン列を検出 | 常時 |
| BR-004 | クエリ列自動検出 | 複数の列名パターンでクエリテキスト列を検出 | 常時 |
| BR-005 | データベース固有ファイル | DatabaseSpecific結果は別ファイル名パターン | DatabaseSpecific=true |

### 計算ロジック

ファイル名パターン:
- CSV（通常）: `{SqlInstance}-DQ-{Number}-{QueryName}-{Suffix}.csv`
- CSV（DB固有）: `{SqlInstance}-{DbName}-DQ-{Number}-{QueryName}-{Suffix}.csv`
- Excel（通常）: `{SqlInstance}-DQ-{Suffix}.xlsx`
- Excel（DB固有）: `{SqlInstance}-DQ-{DbName}-{Suffix}.xlsx`
- 実行プラン: `{SqlInstance}-DQ-{Number}-{QueryName}-{PlanNr}-{Suffix}.sqlplan`
- クエリテキスト: `{SqlInstance}-DQ-{Number}-{QueryName}-{SqlNr}-{Suffix}.sql`

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

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

本機能はデータベースへの直接アクセスを行わない。Invoke-DbaDiagnosticQueryの結果オブジェクトを処理するのみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ModuleError | 依存エラー | ImportExcelモジュール未インストール（Excel出力時） | モジュールをインストール |
| PathError | パスエラー | Pathがファイルパス（ディレクトリでない） | ディレクトリパスを指定 |
| ResultEmpty | データエラー | 結果オブジェクトが空 | 入力データを確認 |

### リトライ仕様

自動リトライは実装されていない。空の結果はスキップして次の結果オブジェクトの処理を続行する。

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

ファイル出力操作のため、トランザクション制御は不要。各ファイルは独立して出力される。

## パフォーマンス要件

- 大量の診断クエリ結果を処理する場合、I/O負荷が発生
- Excel出力は内部でファイルを開閉するため、CSVよりも遅い場合がある
- 実行プランが多数ある場合、ファイル数が増加

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

- 診断結果にはサーバー構成情報が含まれるため、出力ファイルの取り扱いに注意
- 実行プランには潜在的に機密性のあるクエリ構造が含まれる
- 出力先ディレクトリのアクセス制御を適切に設定する必要がある

## 備考

- ImportExcelモジュールはhttps://github.com/dfinke/ImportExcelから入手可能
- .sqlplanファイルはSSMSで直接開いてプラン分析が可能
- Suffixのデフォルトはタイムスタンプ形式（yyyyMMddHHmmssms）

---

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

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

### 推奨読解順序

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

入力として受け取る診断クエリ結果オブジェクトの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Export-DbaDiagnosticQuery.ps1 | `public/Export-DbaDiagnosticQuery.ps1` | 127-132行目で入力オブジェクトから各プロパティを抽出 |

**読解のコツ**: InputObjectは Invoke-DbaDiagnosticQuery からの結果で、Result, Name, SqlInstance, Database, Number, DatabaseSpecific などのプロパティを持つ。

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

コマンドの入口となるパラメータ定義と前処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Export-DbaDiagnosticQuery.ps1 | `public/Export-DbaDiagnosticQuery.ps1` | 88-100行目のparam()ブロック |
| 2-2 | Export-DbaDiagnosticQuery.ps1 | `public/Export-DbaDiagnosticQuery.ps1` | 102-123行目のbeginブロック |

**主要処理フロー**:
1. **103-112行目**: Excel出力時のImportExcelモジュール確認
2. **115-122行目**: 出力ディレクトリの存在確認と作成

#### Step 3: 実行プラン抽出処理を理解する

実行プラン列の検出と.sqlplanファイルへの出力を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Export-DbaDiagnosticQuery.ps1 | `public/Export-DbaDiagnosticQuery.ps1` | 144-163行目のプラン抽出処理 |

**主要処理フロー**:
- **144行目**: 実行プラン列名の候補リスト定義
- **145行目**: 列名候補とのマッチング確認
- **147行目**: マッチした列名の取得
- **148-159行目**: 各プランを個別ファイルに出力
- **162行目**: 出力後、プラン列を結果から除外

#### Step 4: クエリテキスト抽出処理を理解する

クエリテキスト列の検出と.sqlファイルへの出力を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Export-DbaDiagnosticQuery.ps1 | `public/Export-DbaDiagnosticQuery.ps1` | 165-187行目のクエリ抽出処理 |

**主要処理フロー**:
- **165行目**: クエリテキスト列名の候補リスト定義
- **166行目**: 列名候補とのマッチング確認
- **169-183行目**: 各クエリを個別ファイルに出力
- **186行目**: 出力後、テキスト列を結果から除外

#### Step 5: 結果データの出力処理を理解する

CSV/Excel形式での結果出力を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Export-DbaDiagnosticQuery.ps1 | `public/Export-DbaDiagnosticQuery.ps1` | 189-212行目の出力処理 |

**主要処理フロー**:
- **189行目**: switch文でConvertToの値を判定
- **190-199行目**: Excel出力（DatabaseSpecificでファイル名分岐）
- **201-210行目**: CSV出力（DatabaseSpecificでファイル名分岐）

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

```
Export-DbaDiagnosticQuery
    │
    ├─ Import-Module ImportExcel（Excel出力時）
    │      └─ ImportExcelモジュールのロード
    │
    ├─ New-Item -ItemType Directory
    │      └─ 出力ディレクトリの作成
    │
    ├─ Remove-InvalidFileNameChars
    │      └─ ファイル名の無効文字除去
    │
    ├─ Out-File
    │      └─ .sqlplan/.sqlファイルの出力
    │
    ├─ Export-Excel（Excel出力時）
    │      └─ Excelワークブックへの出力
    │
    ├─ Export-Csv（CSV出力時）
    │      └─ CSVファイルへの出力
    │
    └─ Get-ChildItem
           └─ 出力ファイル情報の取得
```

### データフロー図

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

Invoke-DbaDiagnosticQuery
        │
        ▼
InputObject ──────▶ プロパティ抽出
(Result,Name,          │
SqlInstance等)         ▼
                 ┌─────┴─────┐
                 │ プラン列? │
                 └─────┬─────┘
                   Yes─┤─No
                     │ │
           .sqlplan ◀┘ │
                       ▼
                 ┌─────┴─────┐
                 │ クエリ列? │
                 └─────┬─────┘
                   Yes─┤─No
                     │ │
              .sql ◀─┘ │
                       ▼
                 ┌─────┴─────┐
                 │ ConvertTo │
                 └─────┬─────┘
                Excel──┤──Csv
                  │    │    │
            .xlsx ◀    │    ▶ .csv
                       │
                       ▼
                Get-ChildItem
                       │
                       ▼
                FileInfo ──────▶ パイプライン出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Export-DbaDiagnosticQuery.ps1 | `public/Export-DbaDiagnosticQuery.ps1` | ソース | メイン関数定義 |
| Invoke-DbaDiagnosticQuery.ps1 | `public/Invoke-DbaDiagnosticQuery.ps1` | ソース | 診断クエリ実行（入力元） |
| Remove-InvalidFileNameChars.ps1 | `private/functions/Remove-InvalidFileNameChars.ps1` | ソース | ファイル名サニタイズ |
| Join-DbaPath.ps1 | `private/functions/Join-DbaPath.ps1` | ソース | パス結合ユーティリティ |
| Stop-Function.ps1 | `private/functions/Stop-Function.ps1` | ソース | エラーハンドリング関数 |
| Write-Message.ps1 | `private/functions/Write-Message.ps1` | ソース | メッセージ出力関数 |
