当前位置: 首页 > 面试题库 >

具有唯一约束的原子多行更新

钱飞翼
2023-03-14
问题内容

我有一张标签列表,按标签顺序显示。为了确保没有两行可以具有相同的等级,它们的值是唯一的:

create table label (
  id_label serial not null,
  rank integer not null,
  title text not null,
  constraint pri primary key (id_label),
  constraint unq unique (rank)
)

不管是PostgreSQL还是MySQL,它们都表现出相同的行为。查询可能看起来像select title from label order by rank。假设该表包含:

id_label rank title
1        10   Cow
2        20   Apple
3        45   Horse
4        60   Beer

现在,假设我想重新排序两个标签,例如Apple在Cow之前排名。最简单的方法是交换其等级值:

update label
set rank = case when rank = 20 then 10 else 20 end
where id_label in (1,2)

没有。也不:

update label
set rank = case when rank = 20 then rank - 10 else rank + 10 end
where id_label in (1,2)

甚至没有:

update label
set rank = 30 - rank
where id_label in (1,2)

每次,唯一约束都会在第一行更新时触发,并中止该操作。如果我可以将支票推迟到帐单末尾,那将是可以的。这在PostgreSQL和MySQL上都发生。

使用ACID安全的解决方法是:

  1. 开始交易
  2. 选择表中第一,第二条记录和最高(最大)等级(副手可能需要并集)
  3. 将第一条记录更新为等级=最大值+ 1
  4. 将第二条记录更新为第一名
  5. 将第一条记录更新为第二名
  6. 犯罪

那真是丑陋。更糟糕的是删除约束,更新然后重新创建约束。将此类特权授予操作角色会带来麻烦。所以我的问题是:是否有一种我忽略了的简单技术可以解决此问题,或者我是SOL?


问题答案:

在PostgreSQL中,这只能通过9.0版以“不错”的方式解决,因为您可以定义唯一的约束以在那里可以延期。

使用PostgreSQL 9.0,您只需执行以下操作:

create table label (
  id_label serial not null,
  rank integer not null,
  title text not null,
  constraint pri primary key (id_label)
);
alter table label add constraint unique_rank unique (rank) 
      deferrable initially immediate;

然后更新就这样简单:

begin;
set constraints unique_rank DEFERRED;
update rank
   set rank = case when rank = 20 then 10 else 20 end
   where id_label in (1,2);
commit;

编辑:
如果您不想麻烦地将约束设置为在事务内延迟,则只需将约束定义为即可initially deferred



 类似资料:
  • 我的桌子有两个独特的列: 我想写保存或更新方法 My jooq code: 但我遇到了异常: “错误:没有唯一或排除约束匹配ON CONFLICT规范” 请帮助。

  • 我对Postgres Unique约束有问题,该约束包含多个可能包含空值的列。 让我们假设这种情况: Insert将插入('foo',bar')一次和('foo',NULL)两次(尽管直觉告诉它应该插入一次)。 在这种情况下,解决方案非常简单。我可以添加唯一的索引 但是当有更多的列和不同的类型(不仅仅是文本)时,问题就开始了。假设我们有10列,其中9列可以有值。也许我可以用大量的限制来解决它,但这

  • 问题内容: 我正在将SEAM 2 / Hibernate与PostgreSQL 9数据库一起使用。我有下表 我想添加一个约束,以确保每个新条目都具有active_band_user和active_band_date的唯一组合。 每秒可能有许多次尝试插入,因此我需要尽可能地提高效率,是否可以在实体映射中使用SEAM /hibernate注释? 提前致谢 问题答案: 没有Hibernate注释在插入/

  • 我想用插页。。请务必更新。。对两列具有唯一约束的表的语法。这可能吗? mytable对col1和col2有单独的唯一约束。 我可以写: 然而,这不起作用: 错误:冲突时,更新是否需要推理规范或约束名称 这也不起作用: 错误:不存在与冲突规范匹配的唯一或排除约束 这种语法似乎是为两列上的单一复合唯一约束而设计的,而不是两个约束。 如果违反了其中一个唯一约束,有没有办法进行条件更新?这个问题是如何在博

  • 问题内容: 假设我们有这些表: 是否有可能在上创建唯一约束,使得对于最多一个引用中的所有行,其值都为??陈述另一种方法,我可以创建一个唯一约束,以便上述表的连接没有重复项吗?我没有考虑- 我可以找到的每个数据库的语法似乎都与每个约束都限制在一个表上- 但这可能是我缺乏想象力的原因。(当然,去规范化以包含on是一种解决方案。) 问题答案: 您可以尝试以下方法。您必须在Parent中创建一个冗余的UN

  • 我有这样布局的模型: 这里的场景是我永远不希望用户删除数据。相反,删除只会隐藏记录。但是,我仍然希望所有非软删除的记录都遵循唯一的键约束。基本上,我希望有尽可能多的重复的已删除记录,但只有一个唯一的未删除记录可以存在。所以我本来想包括“已删除”字段(由django安全删除库提供),但问题是Django的唯一检查因“psycopg2”而失败。完整性错误:重复的键值违反了 ['field2', 'fi