電気ウナギ的○○

About Home

Table に存在していれば Update に切り替える SQL

shinoda (2026年8月 4日 01:45)
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 SET
                user_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 WHERE
user_id=1 AND anniversary='19650824';
 user_id | anniversary |  note
---------+-------------+--------
       1 | 19650824    | 誕生日
(1 行)

が、

test01=> SELECT user_id, anniversary, note FROM t_user_summary WHERE
user_id=1 AND anniversary='19650824';
 user_id | anniversary |       note
---------+-------------+------------------
       1 | 19650824    | 誕生日(2回目)
(1 行)

と、ちゃんと更新されていてバッチグー(死語)であった。

電気ウナギ的○○

電気ウナギ的○○

About Back

コメント(0)

電気ウナギ的○○

電気ウナギ的○○

About Back

トラックバック(0)

トラックバックURL: https://blog.netandfield.com/mt/mt-tb.cgi/7283

電気ウナギ的○○

About This Site

電気ウナギ的○○
岩国在住。広島で働く超零細IT企業社長のいわゆる社長日記。
何か、酒と食い物のことばかり書いているようで・・・お察しのとおり、肥満体です:-)


2011/06/24
iPhone用サイト公開

Create with jQuery, jQTouch.


CLOSE