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

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 行)

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

トラックバック(0)

このブログ記事を参照しているブログ一覧: Table に存在していれば Update に切り替える SQL

このブログ記事に対するトラックバックURL: https://blog.netandfield.com/mt/mt-tb.cgi/7283

コメントする

このブログ記事について

このページは、shinodaが2026年8月 4日 01:45に書いたブログ記事です。

ひとつ前のブログ記事は「はじめて美川町のでかまるくんを観た」です。

次のブログ記事は「ファイルダウンロードで、成否により処理を振り分けたい」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら