1. ホーム
  2. sql

[解決済み] SQL/DB2 SQLSTATE=23505 UPDATE文の実行時にエラーが発生する

2022-02-14 16:55:01

質問

以下のDB2ステートメントを実行すると、SQLSTATE=23505エラーが発生します。

update SEOURLKEYWORD 
set URLKEYWORD = REPLACE(URLKEYWORD, '/', '-') 
where STOREENT_ID = 10701 
and URLKEYWORD like '%/%';

ざっと調べたところ、SQLステート23505エラーは以下のように定義されています。

インデックス空間内のインデックスがテーブルの列を制限しているため、2 つの行がそれらの列に重複した値を含むことができないため、挿入または更新された値は無効です。

私が見ているエラーの全容は

私が見ている完全なエラーは、次のとおりです。

DB2 データベースのエラーです。ERROR [23505] [IBM][DB2/LINUXX8664] SQL0803N INSERT文、UPDATE文、またはDELETE文による外部キー更新の1つ以上の値は、主キー、一意制約、または2"で識別される一意インデックスがインデックスキーに重複した値を持っていないテーブルquot;WSCOMUSR.SEOURLKEYWORDを制約しているので有効ではありません。 SQLSTATE=23505 1 0

2'で識別されるインデックスが何を意味するのか分かりませんが、重要である可能性があります。

SEOURLKEYWORDテーブルのカラムのプロパティは以下のとおりです。

この情報を理解した上で、一意性を強制されるのは主キー列であるSEOURLKEYWORD_IDのみです。 このことから、私が実行しようとしている更新文は、すでにテーブルに存在するSEOURLKEYWORD_IDを持つ行を挿入しようとしているように聞こえます。

更新しようとする行に対して select * ステートメントを実行すると、次のようになります。

select * from SEOURLKEYWORD 
where storeent_id = 10701 
and lower(URLKEYWORD) like '%/%';

UPDATE文の実行が、どうしてここでエラーになるのか理解できません。 この文が見るべき行は4行だけで、主キーを手動で更新したわけでは全くありません。 既存の行を削除する前に、更新されたカラム値で重複した行を再挿入しているように思えますが、どうでしょうか?

この4行のURLKEYWORD列を更新しようとすると、なぜこのエラーが発生するのでしょうか? どうすればこの問題を解決できますか?

重要:この質問を書いた時点で、問題は上のテーブルの4行のうち最後のSEOURLKEYWORD_ID = 3074457345616973668に絞られました。 他の3行は問題なく更新できるのですが、4行目がエラーになるのですが、その理由がわかりません。 select * from SEOURLKEYWORD where SEOURLKEYWORD_ID = 3074457345616973668;を実行すると、1行だけ表示されます。

どうすればいいですか?

エラーはかなりはっきりしています。テーブルにユニークなインデックス/制約があります。例えば、次のような2つの行があるとします。

<テーブル STOREENT_ID URLKEYWORD 10701 A/B 10701 A-B

で置き換えた場合、最初のバージョンは 'A-B' の一意制約に違反することになります。 (STOREENT_ID, URLKEYWORD) または (URLKEYWORD) (他のカラムも同様に一意制約/インデックスに含まれる可能性があることに注意してください)。

更新しないことで、こうした状況を回避することができます。一意制約がどのカラムにかかるのか分かりませんが、仮にのみ URLKEYWORD . では。

update SEOURLKEYWORD 
    set URLKEYWORD = REPLACE(URLKEYWORD, '/', '-') 
where STOREENT_ID = 10701 and
      URLKEYWORD like '%/%' and
      not exists (select 1 from SEOURLKEYWORD s2 where replace(s2.urlkeyword, '/', '-') = REPLACE(SEOURLKEYWORD.URLKEYWORD, '/', '-') 
                 );

注意 replace() は両方のカラムに必要だからです。

A-B/C
A/B-C

これらは、両方の値で置換された後にのみ衝突します。