1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2024-06-12

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

必要なライブラリ

  1. SQLite JDBCライブラリ
  2. OpenCSVライブラリ(CSVファイルの読み書きに使用)

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

Maven依存関係

org.xerial sqlite-jdbc 3.34.0
<!-- OpenCSV Library -->
<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>5.5.2</version>
</dependency>

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

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メソッドを使用して、TableATableBの差分を抽出し、結果を指定されたCSVファイルに書き込みます。

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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?