6

我有一张桌子regionkey

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

数据库的整个其余部分都外键为 areaid。在此表中, (region, locale) 上有一个具有唯一约束的索引。

问题是我有两条记录:

101   MICH   DETR
102   ILLI   CHIC

我需要在它们之间交换 (region,locale) 字段,这样我就可以得到:

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;

我怎样才能做到这一点?有没有一种原子方式来进行交换?建议?

4

4 回答 4

9

您不能将 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); 
于 2009-11-19T19:53:25.793 回答
1

最好的办法是进行三个更新。将第一条记录更新为一组临时值,更新第二条记录,然后将第一条记录重新更新为所需的值。

于 2009-11-19T19:53:08.753 回答
0

您是否尝试过将其包装在事务中的简单行为?

我了解您可以设置约束以使其仅在事务结束时强制执行约束,但我不确定您的约束是否以这种方式设置。

于 2009-11-19T19:53:43.123 回答
0

一个建议,对于大型记录集可能不是最安全的,将两个记录都设置为 ' ' 对于区域和语言环境,然后执行两个更新语句,每个记录一个,如下所示:

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

就像我说的,这可能不是最安全的方法,但对于小型数据集应该没问题。

UPDATE:Larry 正确地指出第一个 UPDATE 语句将违反 UNIQUE 约束。将其用于第一个更新:

UPDATE
    regionkey
SET
    region = areaid,
    locale = areaid
WHERE
    areaid in (101,102)

这样,每个中间区域和语言环境都是(或应该是)唯一的。

于 2009-11-19T19:55:37.957 回答