对 Oracle DB 中表上的行子集强制唯一性

Posted

技术标签:

【中文标题】对 Oracle DB 中表上的行子集强制唯一性【英文标题】:Enforce Uniqueness on a Subset of Rows on Table in Oracle DB 【发布时间】:2017-06-28 17:04:13 【问题描述】:

对于具有两列 MAKE 和 MODEL 的表 CARS,我想强制要求对于某些特定的 MAKE 值,它们的 MODEL 值必须是唯一的(假设这是一个 Oracle 数据库)。

例如,我想为福特强制重复,但不是丰田。 'F150' MODEL 和 'Ford' MAKE 我不想超过一排。但是,'Rav4' MODEL 和 'Toyota' MAKE 有两排是可以的。 'F150' MODEL 和 'Ford' MAKE 排成一排,'F150' MODEL 和'Toyota' MAKE 排成另一排也是可以的。

我一直在研究各种带有触发器、约束或索引的策略,但我还没有找到任何可以给我所需的控制级别的东西。

谢谢!

【问题讨论】:

【参考方案1】:

只有在 make='Ford' 时,您才可以创建一个唯一的基于函数的索引来强制 (make,model) 对的唯一性:

create table cars (make varchar2(255) not null, model varchar2(255) not null);

create unique index ford_index on cars (
  case make 
  when 'Ford' then make
  else null
  end,
  case make 
  when 'Ford' then model
  else null
  end  );


insert into cars (make, model) values ('Ford', 'F150');
insert into cars (make, model) values ('Ford', 'Fiesta');
insert into cars (make, model) values ('Toyota', 'Camry');
insert into cars (make, model) values ('Toyota', 'Camry');
insert into cars (make, model) values ('Ford', 'F150'); --- FAILS with unique constraint violation

仅当 make='Ford' 时,ford_index 索引(品牌、型号) - 其他所有内容都被排除在索引之外,因此不受唯一性约束。

【讨论】:

但是,如果有 28 个必须强制执行唯一性的制造,而其他 36 个不需要唯一性的制造,您会怎么写?如果需要唯一性的品牌列表随时间发生变化,将如何维护? @mathguy - 我可能会为每个需要模型唯一性的品牌创建一个索引。由于我们谈论的是汽车制造商,我预计制造商的数量会相当低。 谢谢!我没有想过在这种情况下使用案例陈述。这当然是我见过的最好的方式。对我来说不幸的是,我必须将其添加到已经有重复项的现有表中(以防止将来出现重复),但似乎没有任何索引等效于您可以在约束中提供的 'DEFFERED NOVALIDATE' 选项。【参考方案2】:

创建一个物化视图,在提交时快速刷新。 MV 定义可能只是select make, model from <your_table> where make in (select make from <small_table>)<small_table> 将列出您想要强制执行此唯一性的品牌。然后在物化视图的(make, model)上创建一个唯一索引。

每当尝试使用 make 'Ford' 进行复制时,都会在提交时刷新 MV。 MV中的更改会被拒绝,进而导致原来的COMMIT失效。

【讨论】:

把create语句加到你的帖子就好了。 @miracle173 - 创建物化视图语句很简单。更重要的是,必须先创建 MV 日志。 快速刷新的 mviews 不能有选择列表子查询。 @eaolson - 这是正确的,与我发布的内容无关。 “选择列表子查询”是在查询的SELECT 子句中 的子查询。我的解决方案中没有这样的东西。 @eaolson 这是manual 我找不到这个限制

以上是关于对 Oracle DB 中表上的行子集强制唯一性的主要内容,如果未能解决你的问题,请参考以下文章

如何确定Oracle数据库表中重复的记录

如何对 SQLAlchemy 中的整个列强制执行唯一性约束?

如何根据选定的列而不是Oracle中表的所有列获取不同的行

如何根据所选列而不是Oracle中表的所有列获取不同的行

获取所有数据库中表的行数

在 python 的 berkeley db 中表达多列?