ど素人から毛を生やす。<延>

[MySQL]該当レコード群の最新○件のみをUPDATE(JOIN編)

Web > Other 2023年9月28日(最終更新:1年前)

2023年9月28日に作成されたページです。
情報が古かったり、僕が今以上のど素人だった頃の記事だったりする可能性があります。

どもです。
MySQLではUPDATE句でもORDER BYやLIMITを使用できるため、条件に合う最新○件のレコードを更新、という処理が可能です。

が、UPDATEにJOINを使用すると、Incorrect usage of UPDATE and ORDER BY エラーになってしまいます。
ORDER BYだけでなくLIMITも使用できません。

TABLE_ATABLE_B
id(int)id(int)
text(TEXT)
date(DATE)

TABLE_B.dateが指定より古いレコードのTABLE_A.textを更新する場合、どうすればここにORDER BYやLIMITを適用できるでしょうか。

TABLE_ATABLE_B
id(int)id(int)
text(TEXT)
date(DATE)
is_UPDATE(TINYINT)

TABLE_Bのテーブル定義を変更できるのであれば、更新フラグを設置すれば手っ取り早く解決できます。

TABLE_B単品であればORDER BYやLIMITが使用できるため、

UPDATE TABLE_B SET is_UPDATE = 1 WHERE TABLE_B.date < ○○ ORDER BY TABLE_B.date ASC LIMIT 500;

UPDATE TABLE_B AS tb INNER JOIN TABLE_A AS ta ON tb.id = ta.id SET ta.text = ☆☆ WHERE TABLE_B.is_UPDATE = 1;

①TABLE_Bのみを対象に、ORDER BYやLIMITで更新対象フラグを立てる。
②TABLE_A・TABLE_BをJOINし、更新対象フラグを条件にUPDATEする。
これなら②のUPDATEではORDER BYやLIMITを使用せずに済みます。

また、TABLE_A側に更新の条件がある場合は、TABLE_Bのフラグ列を2つに増やし、

TABLE_ATABLE_B
id(int)id(int)
text(TEXT)
date(DATE)
is_satisfy(TINYINT)
is_UPDATE(TINYINT)
UPDATE TABLE_B AS tb INNER JOIN TABLE_A AS ta ON tb.id = ta.id SET tb.is_satisfy = 1 WHERE TABLE_A.×× = ▽▽;

UPDATE TABLE_B SET is_UPDATE = 1 WHERE TABLE_B.date < ○○ AND TABLE_B.is_satisfy = 1 ORDER BY TABLE_B.date ASC LIMIT 500;

UPDATE TABLE_B AS tb INNER JOIN TABLE_A AS ta ON tb.id = ta.id SET ta.text = ☆☆ WHERE TABLE_B.is_UPDATE = 1;

①TABLE_A・TABLE_BをJOINし、ORDER BYやLIMITは無視して要件を満たすフラグを立てる。
②TABLE_Bの要件を満たすフラグを立てたレコードのみを対象に、ORDER BYやLIMITを使用し更新フラグを立てる。
③TABLE_A・TABLE_BをJOINし、更新フラグを元にTABLE_Aを更新。

これで更新できました。
JOINしたUPDATEではORDER BYやLIMITを使用できないので、SQLの発行を分割し、JOINなしでORDER BYやLIMITを使用する工夫が必要です。

この記事は役に立ちましたか?
  • _(:3」∠)_ 面白かった (0)
  • (・∀・) 参考になった (0)
  • (`・ω・´) 役に立った (0)