テキストファイル(id,value)の読み込み → パース → DB(Oracle) にInsert (重複idの時は、 Updateでvalue加算)  
という処理のバッチを作るのですが、効率的な処理の方法を教えてください。  
１回の処理件数 → １万件は超えないものと想定

**想定している手順**

  * テキストファイル(id,valueが書かれている)読み込み
  * 読み込みループの中、SQL文字列を作っていく
  * Merge?
  * Update or Insert?

という処理を考えています。  
以下のSQLふぐあいをおこします。

```

    MERGE INTO USERS
    USING DUAL
    ON (id='001')
    WHEN MATCHED THEN
        UPDATE SET no='002' ,from_date = TO_DATE('20-07-01 00:00:00', 'YY-MM-DD HH24:MI:SS')
    WHEN NOT MATCHED THEN
    INSERT USERS (id,no,from_date) VALUES ('02','t002',TO_DATE('20-07-01 00:00:00', 'YY-MM-DD HH24:MI:SS'));
    
```
CC BY-SA 4.0
2020-07-18T05:35:09.527
68689
2020-07-24T05:20:04.443
2020-07-24T05:01:02.443
19110
41060
question
java sql oracle
テキストファイルを元に OracleDB へ登録するバッチの良い作り方を教えてください
javaからテキストファイルを読み込み、JDBCを呼び出す一連の流れはできる前提で回答します。

難しく考えずにトランザクションを増やさなければ効率的な処理をすることができます。  
高々1万件ならば、1回のトランザクションがDBに負荷を掛け過ぎるリスクは無視できるでしょう。

**OK:** つまりこの疑似コードは効率的です。(try-catch-finallyやrollbackは省略)

```

    // 最初にコネクションを作成してオートコミットしない
    Connection conn = DriverManager.getConnection();
    conn.setAutoCommit(false); 
    
    BufferedReader br = new BufferedReader(new FileReader(new File(hoge)));
    String line = br.readLine();
    while(line != null) {
        String sql = myParser(line);  //独自のパーサでmerge文を作る
        Statement statement = conn.createStatement();
        statement.executeUpdate(sql);
        statement.close();
        line = br.readLine();
    }
    conn.commit();  //最後にトランザクションが終了
    conn.close();
    
```

**NG:** この疑似コードは効率的ではありません。

```

    BufferedReader br = new BufferedReader(new FileReader(new File(hoge)));
    String line = br.readLine();
    while(line != null) {
        String sql = myParser(line);  //独自のパーサでmerge文を作る
        // 1行ごとにトランザクションを作って自動コミットする
        Connection conn = DriverManager.getConnection();
        Statement statement = conn.createStatement();
        statement.close();
        conn.close();
        statement.executeUpdate(sql);
        line = br.readLine();
    }
    
```

**insert all:** 効率的なデータ処理を求めるならば[insert
all](https://qiita.com/mkoba_6/items/dcd53aa10b08b8d81211)の使用も検討すると良いでしょう。

```

    insert all
    into hoge values(1, 'fuga')
    into hoge values(2, 'piyo')
    select * from dual; -- 最後のselect文は省略不可
    
```

**merge?:**
insert/updateとmerge文のどちらを使うべきかについては、毎回sql作成時にselectしてinsert文とupdate文の条件分岐をするよりも[merge文](https://www.atmarkit.co.jp/ait/articles/0505/24/news104.html)の方が効率的です。

* * *

編集後のSQLは`ORA-00926: missing VALUES keyword`エラーが発生しています。  
※最新の編集でSQL文が消えていたのでロールバックしました。

エラーの原因は`WHEN NOT MATCHED THEN`以下のINSERTに`USERS`テーブル名が書かれていることです。  
[Merge文](https://www.shift-the-oracle.com/sql/merge.html)ではテーブル名を省略します。

INSERTの行を下記のように書き直してみてください。

修正前: `INSERT USERS (id,no,from_date) VALUES ('02','t002',TO_DATE('20-07-01
00:00:00', 'YY-MM-DD HH24:MI:SS'));`  
修正後: `INSERT (id,no,from_date) VALUES ('02','t002',TO_DATE('20-07-01
00:00:00', 'YY-MM-DD HH24:MI:SS'));`

[SQL Fiddle](http://sqlfiddle.com/#!4/63a59e/1)
CC BY-SA 4.0
2020-07-18T06:55:32.740
68692
2020-07-24T05:20:04.443
2020-07-24T05:20:04.443
9820
9820
68689
answer