Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swapping two DB rows without violating constraints

I have a table regionkey:

areaid  -- primary key, int
region  -- char(4)
locale  -- char(4)

The entire rest of the database is foreign-keyed to areaid. In this table there is an index on (region, locale) with a unique constraint.

The problem is that I have two records:

101   MICH   DETR
102   ILLI   CHIC

And I need to swap the (region,locale) fields between them, so that I wind up with:

101   ILLI   CHIC
102   MICH   DETR

The naive approach won't work because it violates the unique index on region and locale:

update regionkey
     set region='ILLI', locale='CHIC' where areaid = 101; -- FAILS
update regionkey
     set region='MICH', locale='DETR' where areaid = 102;

How can I do this? Is there an atomic way to make the swap? Suggestions?

like image 469
Clinton Pierce Avatar asked Nov 19 '09 19:11

Clinton Pierce


1 Answers

You can't defer constraint checks in SQL Server over multiple statements (unless you DISABLE) so you have to avoid the conflict or do it in one statement

update
    regionkey 
set
    region= CASE areaid WHEN 101 THEN 'ILLI' ELSE 'MICH' END, 
    locale= CASE areaid WHEN 101 THEN 'CHIC' ELSE 'DETR' END
where
    areaid IN (101, 102); 

or, more conventionally (in a transaction this one)

update regionkey 
     set region='AAAA', locale='BBBB' where areaid = 101;
update regionkey 
     set region='MICH', locale='DETR' where areaid = 102;
update regionkey 
     set region='ILLI', locale='CHIC' where areaid = 101;

Edit: Why not swap keys not values? It usually achieves the sane result unless areaid has some meaning

update
    regionkey 
set
    areaid = 203 - areaid 
where
    areaid IN (101, 102); 
like image 191
gbn Avatar answered Oct 10 '22 10:10

gbn