axjack's blog

axjack is said to be an abbreviation for An eXistent JApanese Cool Klutz.

update文

とある1レコードの値で本番のデータを全件更新してしまうというヤラカシをやってしまったので、次回は気をつける意を込めた記録です。 SQLcompile sql server onlineを使用します。

仕様

  • tbl1.val1をtbl2.val2へと更新する
  • 更新の条件
    • tbl1.idとtbl2.idを結合し、tbl2.val2 = 'foo'の時だけ更新する
    • tbl2.val2 <> 'foo'の時は更新しない

tbl1

f:id:axjack:20200417235435p:plain

tbl2

f:id:axjack:20200417235458p:plain

ということでこの場合、id = {10,30,80}が更新対象となります。

問題のコード(ヤラカシあり)

-- データ作成 ここから
create table tbl1  (
 id int primary key
  , val1 nvarchar(10) null
)
;

insert into tbl1 values
  (10,'a')
  ,(20,'b')
  ,(30,'c')
  ,(40,'d')
  ,(50,'e')
  ,(60,'f')
  ,(70,'g')
  ,(80,'h')
  ,(90,'i')
;

create table tbl2 (
 id int primary key
  , val2 nvarchar(10) null
  , constraint fk_id foreign key(id) references  tbl1
)
;

insert into tbl2 values
  (10,'foo')
  ,(30,'foo')
  ,(50,'baz')
  ,(60,'baz')
  ,(80,'foo')
;
-- データ作成 ここまで



--  一時テーブルに tbl1 のレコードを格納
select * into #t1 from tbl1
;


-- tbl1 更新前
select * from tbl1
;

-- 更新処理
update tbl1
set val1 = tbl2.val2
from #t1 
  inner join tbl2 
    on #t1.id = tbl2.id 
    and tbl2.val2 = 'foo'
;


-- tbl1 更新後
select * from tbl1
;

実行結果

上:更新前のtbl1, 下:更新後のtbl1なのですが、見ての通り残念な感じに更新されてしまいました。。

f:id:axjack:20200417234647p:plain

better なコード

★の箇所のように、updateで更新対象となるテーブルをinner join してあげるとinner join で抽出される結果通りに更新されます。

update tbl1
set val1 = tbl2.val2
from #t1 
  inner join tbl2 
    on #t1.id = tbl2.id 
    and tbl2.val2 = 'foo'
  inner join tbl1 on tbl1.id = #t1.id -- ★
;

better なコードの実行結果

仕様を満たした更新結果となりました。 f:id:axjack:20200417235104p:plain

まなび

更新対象のテーブルをちゃんとjoin しましょう。

axjack is said to be an abbreviation for An eXistent JApanese Cool Klutz.