在不违反约束的情况下交换两个数据库行

发布于 2024-08-12 01:30:31 字数 654 浏览 2 评论 0原文

我有一个表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;

如何我可以这样做吗?有没有一种原子方法来进行交换?建议?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

迷离° 2024-08-19 01:30:31

您不能在 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); 

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); 
陪你到最终 2024-08-19 01:30:31

最好的选择是进行三项更新。将第一条记录更新为临时值集,更新第二条记录,然后将第一条记录重新更新为所需的值。

BEst bet is to make three updates. Update the first record to a temp set of values, update the second record and then reupdate the first record to the values you want.

青衫负雪 2024-08-19 01:30:31

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

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

Have you tried the simple act of wrapping it in a transaction?

I understand you can set up constraints to allow it to only enforce the constraint at the end of a transaction but I am unsure if your constraints are set up that way.

聽兲甴掵 2024-08-19 01:30:31

一项建议(对于大型记录集可能不是最安全的)是将区域和地区的两条记录都设置为“ ”。 locale,然后执行两个更新语句,每个记录一个,如下所示:

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)

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

One suggestion, which may not be the safest for large record sets, would be to set both records to ' ' for both region & locale, and then execute two update statements, one for each record, like so:

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

Like I said, this is probably not the safest way to go, but for a small data set it should be OK.

UPDATE: Larry correctly pointed out that the first UPDATE statement will violate the UNIQUE constraint. Use this instead for the first UPDATE:

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

This way each intermediate region and locale is (or should be) unique.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文