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)