Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oracle 如何约束多个列以防止重复,但忽略空值?_Oracle_Null_Nullable_Constraints_Unique Index - Fatal编程技术网

Oracle 如何约束多个列以防止重复,但忽略空值?

Oracle 如何约束多个列以防止重复,但忽略空值?,oracle,null,nullable,constraints,unique-index,Oracle,Null,Nullable,Constraints,Unique Index,下面是我在Oracle数据库(10g)中运行的一个小实验。除了(Oracle的)实现便利性之外,我不明白为什么一些插入被接受而另一些被拒绝 create table sandbox(a number(10,0), b number(10,0)); create unique index sandbox_idx on sandbox(a,b); insert into sandbox values (1,1); -- accepted insert into sandbox values (1,

下面是我在Oracle数据库(10g)中运行的一个小实验。除了(Oracle的)实现便利性之外,我不明白为什么一些插入被接受而另一些被拒绝

create table sandbox(a number(10,0), b number(10,0));
create unique index sandbox_idx on sandbox(a,b);

insert into sandbox values (1,1); -- accepted
insert into sandbox values (1,2); -- accepted
insert into sandbox values (1,1); -- rejected

insert into sandbox values (1,null); -- accepted
insert into sandbox values (2,null); -- accepted
insert into sandbox values (1,null); -- rejected

insert into sandbox values (null,1); -- accepted
insert into sandbox values (null,2); -- accepted
insert into sandbox values (null,1); -- rejected

insert into sandbox values (null,null); -- accepted
insert into sandbox values (null,null); -- accepted
假设偶尔有一些行的某些列值未知是有意义的,我可以考虑两种可能的用例来防止重复:
1.我想拒绝重复项,但在任何受约束列的值未知时接受。
2.我希望拒绝重复项,即使在受约束列的值未知的情况下也是如此

显然Oracle实现了一些不同的功能:
3.拒绝重复项,但仅在所有受约束的列值未知时接受

我可以想办法利用Oracle的实现来访问用例(2)——例如,为“unknown”指定一个特殊值,并使列不可为null。但我不知道如何进入用例(1)

换句话说,我怎样才能让甲骨文这样做

create table sandbox(a number(10,0), b number(10,0));
create unique index sandbox_idx on sandbox(a,b);

insert into sandbox values (1,1); -- accepted
insert into sandbox values (1,2); -- accepted
insert into sandbox values (1,1); -- rejected

insert into sandbox values (1,null); -- accepted
insert into sandbox values (2,null); -- accepted
insert into sandbox values (1,null); -- accepted

insert into sandbox values (null,1); -- accepted
insert into sandbox values (null,2); -- accepted
insert into sandbox values (null,1); -- accepted

insert into sandbox values (null,null); -- accepted
insert into sandbox values (null,null); -- accepted
我想你可以

不过,为了记录在案,我留下一段话来解释,如果在两列上有一个简单的唯一索引,Oracle为什么会这样做:

如果列是唯一索引的,Oracle将永远不会接受两(1,null)对

一对1和一对空,被认为是“可转位”对。一对两个空值不能被索引,这就是为什么它允许您插入任意多的空值对

(1,null)被索引,因为1可以被索引。下次再次尝试插入(1,null)时,索引将拾取1,并且违反了唯一约束


(null,null)没有索引,因为没有要索引的值。这就是它不违反唯一约束的原因。

尝试基于函数的索引:

在沙盒上创建唯一索引沙盒_idx(a为NULL时为NULL,b为NULL时为NULL,其他情况下为a | |','| | b END)

还有其他方法可以剥这只猫的皮,但这是其中之一

create unique index sandbox_idx on sandbox
 (case when a is null or b is null then null else a end,
  case when a is null or b is null then null else b end);
功能索引!基本上,我只需要确保我想要忽略的所有元组(ie-accept)都被转换为所有空值。丑,但不丑。工作正常

借助于另一个问题的解决方案:


因此,去那里,也给托尼·安德鲁斯分数。:)

我不是一个喜欢Oracle的人,但是如果您可以在Oracle的索引中包含一个计算列,那么这里有一个想法应该是可行的

向表(和唯一索引)添加一个额外的列,该列的计算如下:如果a和b都不为NULL,则为NULL,否则为表的主键。我之所以称这个附加的专栏为“nullbuster”,原因很明显

alter table sandbox add nullbuster as 
  case when a is null or b is null then pk else null end;
create unique index sandbox_idx on sandbox(a,b,pk);
大约在2002年左右,我在Usenet组microsoft.public.sqlserver.programming中多次给出了这个示例。如果你在groups.google.com上搜索“nullbuster”这个词,你可以找到这些讨论。使用Oracle这一事实应该无关紧要

p.S.在SQL Server中,此解决方案几乎被筛选索引所取代:

create unique index sandbox_idx on sandbox(a,b)
(where a is not null and b is not null);
您引用的线程表明Oracle不提供此选项。它是否也不具备索引视图的可能性,这是另一种选择

create view sandbox_for_unique as
select a, b from sandbox
where a is not null and b is not null;

create index sandbox_for_unique_idx on sandbox_for_unique(a,b);

这只是在Oracle中实现基于函数的索引的一个原因。它允许企业根据自己的业务规则定制索引。这是一个很好的答案,尽管对我的应用程序来说有点过于巴洛克风格。为了回答您的问题,Oracle没有筛选索引,但您的“索引视图”似乎被Oracle中的物化视图所覆盖,这些视图可以被索引,并且通常用于引用完整性。我一点也不觉得这很难看。IMHO比公认的答案要干净得多,它可以将两列混合在一起,甚至可能不是相同的数据类型,以创建一些弗兰肯斯坦的唯一键(不是说如果你没有向我展示多列的正确语法,我就不会使用它)。一个好问题的完美示例(加上我需要回答的问题!)