CSV を読み込んで DB に登録している処理で、今は単純に INSERT を行っているのだが、それだとキーが重複したときに
Caused by: java.sql.BatchUpdateException: バッチ 0 INSERT INTO t_user_summary (user_id,user_name,user_address1,user_address2,user_phone_number,anniversary,note) VALUES (('1'::int8),('MASA SHIMURA'),('岩国市黄金町黄金1928-11'),(''),('090-0000-1111(携帯)'),('19650824'),('誕生日(2回目)'))はアボートしました: ERROR: 重複したキー値は一意制約"t_user_summary_pkey"違反となります詳細: キー (user_id, anniversary)=(1, 19650824) はすでに存在します。 このバッチの他のエラーは getNextException を呼び出すことで確認できます。
このように更新に失敗する。(このケースは、user_id が '1' で anniversary が '19650824' のデータがすでに存在している)
そこで、まず存在チェックを行って、存在していれば UPDATE、存在していなければ INSERT を行うようにしたい。
そのために、SELECT 処理を埋め込みたいが、Spring Batch の Chunk 方式の場合、どこにその処理を入れればきれいなのか?と Gemini に気いてみたら「SQL 直せばいいだけです」と言われた。
そうなん?いやあ、俺も、SQL をきちんと(専門書を買うなどして)一から勉強したことなくて・・・。長年の経験から相当複雑な SQL も組めるけど、あるステートメントのオプションなんかは知らないものもちょこちょこある。
Gemini が示した SQL の、
INSERT INTO t_user_summary (user_id,user_name,user_address1,user_address2,user_phone_number,anniversary,note) VALUES (:user_id,:user_name,:user_address1,:user_address2,:user_phone_number,:anniversary,:note)ON CONFLICT (user_id, anniversary) DO UPDATE SETuser_name = EXCLUDED.user_name,user_address1 = EXCLUDED.user_address1,user_address2 = EXCLUDED.user_address2,user_phone_number = EXCLUDED.user_phone_number,anniversary = EXCLUDED.anniversary,note = EXCLUDED.note
ON CONFLICT () DO もそうだし、EXCLUDED も何?って感じ(笑)
ON CONFLICT () DO は「キー重複時の動きを指定する PostgreSQL 独自の句(オプション)」なんじゃね(SQLite でも書き方は違うが使える)。EXCLUDED は「INSERT に失敗したデータが一時的に保管されている DB」を表すんだそうな。
もう、各 RDBMS 独自の構文になってくるとわけわからん(笑)。なもんで、この業界には「Oracle しか使えん」っていう Oracle 独自構文にどっぷり浸かって抜け出せない Oracle じいさんがたくさん存在してるけどな(笑)
というわけで、ItemWriter 内の SQL を上記に置き換え。
test01=> SELECT user_id, anniversary, note FROM t_user_summary WHEREuser_id=1 AND anniversary='19650824';user_id | anniversary | note---------+-------------+--------1 | 19650824 | 誕生日(1 行)
が、
test01=> SELECT user_id, anniversary, note FROM t_user_summary WHEREuser_id=1 AND anniversary='19650824';user_id | anniversary | note---------+-------------+------------------1 | 19650824 | 誕生日(2回目)(1 行)
と、ちゃんと更新されていてバッチグー(死語)であった。

コメントする