2つのCSVファイルを取り込み差分を抽出する



カラム名を動的に取り込み、CSVファイルをSQLiteに格納する方法を以下に示します。ここでは、CSVの最初の行をカラム名として使用します。

### 必要なライブラリ
1. SQLite JDBCライブラリ
2. OpenCSVライブラリ（CSVファイルの読み書きに使用）

### ステップ1: 必要なライブラリを追加

Maven依存関係

<dependencies>
    <!-- SQLite JDBC Driver -->
    <dependency>
        <groupId>org.xerial</groupId>
        <artifactId>sqlite-jdbc</artifactId>
        <version>3.34.0</version>
    </dependency>

    <!-- OpenCSV Library -->
    <dependency>
        <groupId>com.opencsv</groupId>
        <artifactId>opencsv</artifactId>
        <version>5.5.2</version>
    </dependency>
</dependencies>



### ステップ2: カラム名を動的に取り込み、CSVファイルをSQLiteに格納する

```java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.File;
import java.util.Arrays;
import java.util.List;

import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.CSVWriter;
import com.opencsv.exceptions.CsvValidationException;

public class CsvToSQLite {
    private static final String DB_URL = "jdbc:sqlite:example.db";

    public static void main(String[] args) {
        try (Connection conn = DriverManager.getConnection(DB_URL)) {
            if (conn != null) {
                // CSVファイルを読み込み、TableAに挿入
                importCsvToTable(conn, "path/to/csv_A/", "TableA");
                // CSVファイルを読み込み、TableBに挿入
                importCsvToTable(conn, "path/to/csv_B/", "TableB");

                // 差分を抽出し、CSVに出力
                exportDiffToCsv(conn, "TableA", "TableB", "diffA.csv");
                exportDiffToCsv(conn, "TableB", "TableA", "diffB.csv");
            }
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
    }

    private static void importCsvToTable(Connection conn, String csvDirPath, String tableName) {
        File folder = new File(csvDirPath);
        File[] listOfFiles = folder.listFiles((dir, name) -> name.endsWith(".csv"));

        if (listOfFiles == null) {
            System.out.println("No CSV files found in the directory: " + csvDirPath);
            return;
        }

        for (File file : listOfFiles) {
            try (CSVReader csvReader = new CSVReaderBuilder(new FileReader(file))
                    .withSkipLines(0) // コメント行を処理するためにスキップしない
                    .build()) {
                // 最初の行をカラム名として取得
                String[] headers = csvReader.readNext();
                if (headers == null) {
                    continue;
                }

                // コメント行をスキップ
                while (headers[0].startsWith("#")) {
                    headers = csvReader.readNext();
                    if (headers == null) {
                        break;
                    }
                }

                // テーブル作成
                createTable(conn, tableName, headers);

                // データ挿入
                String[] row;
                while ((row = csvReader.readNext()) != null) {
                    if (row[0].startsWith("#")) {
                        continue;
                    }
                    insertRow(conn, tableName, headers, row);
                }
            } catch (IOException | CsvValidationException | SQLException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    private static void createTable(Connection conn, String tableName, String[] headers) throws SQLException {
        try (Statement stmt = conn.createStatement()) {
            String columns = String.join(" TEXT, ", headers) + " TEXT";
            String createTableSQL = String.format("CREATE TABLE IF NOT EXISTS %s (%s)", tableName, columns);
            stmt.execute(createTableSQL);
        }
    }

    private static void insertRow(Connection conn, String tableName, String[] headers, String[] row) throws SQLException {
        String columns = String.join(", ", headers);
        String placeholders = String.join(", ", Arrays.asList(row).stream().map(col -> "?").toArray(String[]::new));

        String insertSQL = String.format("INSERT INTO %s (%s) VALUES (%s)", tableName, columns, placeholders);
        try (java.sql.PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
            for (int i = 0; i < row.length; i++) {
                pstmt.setString(i + 1, row[i]);
            }
            pstmt.executeUpdate();
        }
    }

    private static void exportDiffToCsv(Connection conn, String tableA, String tableB, String outputCsvPath) {
        String sql = String.format("SELECT * FROM %s EXCEPT SELECT * FROM %s", tableA, tableB);

        try (CSVWriter writer = new CSVWriter(new FileWriter(outputCsvPath));
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {

            writer.writeAll(rs, true);
        } catch (SQLException | IOException e) {
            System.out.println(e.getMessage());
        }
    }
}
```

### 説明

1. **カラム名の動的取得**:
   最初の行をカラム名として読み込み、`headers`配列に格納します。コメント行が最初にある場合は無視します。

2. **テーブルの作成**:
   `createTable`メソッドを使い、動的に取得したカラム名でテーブルを作成します。

3. **データの挿入**:
   `insertRow`メソッドを使い、動的に取得したカラム名に基づいてデータを挿入します。

4. **CSVファイルの読み込み**:
   指定されたディレクトリ内のすべてのCSVファイルを読み込み、対応するテーブルにデータを挿入します。

5. **差分の抽出とCSVへのエクスポート**:
   `exportDiffToCsv`メソッドを使用して、`TableA`と`TableB`の差分を抽出し、結果を指定されたCSVファイルに書き込みます。

このスクリプトを使用することで、CSVファイルのカラム名を動的に取り込み、適切なテーブルを作成し、データを挿入することができます。カラム名やテーブル構造は実際のデータに応じて調整してください。