Sql 在不违反约束的情况下交换两个DB行

Sql 在不违反约束的情况下交换两个DB行,sql,sql-server,tsql,atomic,Sql,Sql Server,Tsql,Atomic,我有一个表regionkey: areaid -- primary key, int region -- char(4) locale -- char(4) 数据库的整个其余部分都以外键输入到areaid。此表中有一个索引(区域、语言环境)具有唯一约束 问题是我有两个记录: 101 MICH DETR 102 ILLI CHIC 我需要在它们之间交换(region,locale)字段,以便最终得到: 101 ILLI CHIC 102 MICH DETR

我有一个表
regionkey

areaid  -- primary key, int
region  -- char(4)
locale  -- char(4)
数据库的整个其余部分都以外键输入到areaid。此表中有一个索引(区域、语言环境)具有唯一约束

问题是我有两个记录:

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;

我该怎么做?有没有一种原子方法可以进行交换?建议?

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

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); 
或者,更传统地说(在一项交易中)

编辑:为什么不交换键而不是值?除非areaid有某种意义,否则它通常会达到正常的结果

update
    regionkey 
set
    areaid = 203 - areaid 
where
    areaid IN (101, 102); 

您是否尝试过将其包装到事务中的简单操作


我知道您可以设置约束,使其仅在事务结束时强制执行约束,但我不确定您的约束是否是这样设置的。

对于大型记录集来说,一个建议可能不是最安全的,就是将两个区域和区域设置的记录都设置为“”,然后执行两条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
正如我所说的,这可能不是最安全的方法,但对于一个小数据集来说应该是可以的

UPDATE:Larry正确地指出,第一个UPDATE语句将违反UNIQUE约束。在第一次更新中使用此选项:

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

这样一来,每个中间区域和区域设置都是(或应该是)唯一的。

这可能太疯狂了。你认为他应该把它包装在一个事务中吗?不管怎样,一次插入就是一次隐式事务,只比我,@gbn;-)快一点第一个在第一个逗号附近出现语法错误。我考虑过第二种选择,但由于可能会同时发生多起这种情况,如果没有大量的黑客攻击,我不能指望“AAAA”和“BBBB”是唯一的。第一种解决方案(带“END”)效果很好。您在编辑上比我快了几秒钟。SQL Server中没有“延迟约束”,除非您显式使用DISABLE,这是一个DDL语句。同样的问题-初始更新将违反区域、语言环境的唯一性。
UPDATE
    regionkey
SET
    region = areaid,
    locale = areaid
WHERE
    areaid in (101,102)