我有一张表regionkey
:
areaid -- primary key, int
region -- char(4)
locale -- char(4)
数据库的其余部分都是外键到areaid。在此表中,有一个具有唯一约束的(区域,区域设置)索引。
问题是我有两条记录:
101 MICH DETR
102 ILLI CHIC
我需要在它们之间交换(区域,区域设置)字段,以便最终结束:
101 ILLI CHIC
102 MICH DETR
天真的方法不起作用,因为它违反了区域和区域设置的唯一索引:
update regionkey
set region='ILLI', locale='CHIC' where areaid = 101; -- FAILS
update regionkey
set region='MICH', locale='DETR' where areaid = 102;
我该怎么做?有一种原子方式来进行交换吗?建议?
答案 0 :(得分:8)
您不能在SQL Server中推迟多个语句中的约束检查(除非您禁用),因此您必须避免冲突或在一个语句中执行此操作
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);
或者,更常规地(在这个交易中)
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;
编辑:为什么不交换键而不是值?除非areaid具有某种含义,否则它通常会达到理智的结果
update
regionkey
set
areaid = 203 - areaid
where
areaid IN (101, 102);
答案 1 :(得分:1)
最好的赌注是进行三次更新。将第一个记录更新为临时值集,更新第二个记录,然后将第一个记录重新更新为您想要的值。
答案 2 :(得分:0)
您是否尝试过在事务中包装它的简单行为?
我知道您可以设置约束以允许它仅在事务结束时强制执行约束,但我不确定您的约束是否以这种方式设置。
答案 3 :(得分:0)
对于大型唱片集而言可能不是最安全的一个建议是将两个记录设置为''对于区域和& locale,然后执行两个update语句,每个记录一个,如下所示:
UPDATE
regionkey
SET
region = ' ',
locale = ' '
WHERE
areaid in (101,102)
UPDATE
regionkey
SET
region = 'ILLI',
locale = 'CHIC'
WHERE
areaid = 101
UPDATE
regionkey
SET
region = 'MICH',
locale = 'DETR'
WHERE
areaid = 102
就像我说的那样,这可能不是最安全的方法,但对于一个小数据集应该没问题。
更新:Larry正确地指出第一个UPDATE语句将违反UNIQUE约束。使用此代替第一个更新:
UPDATE
regionkey
SET
region = areaid,
locale = areaid
WHERE
areaid in (101,102)
这样每个中间区域和区域设置都是(或应该是)唯一的。