我怎么能约束多列,以防止重复,但忽略空价值?
-
21-08-2019 - |
题
这里有一个小的实验我跑在一个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)--例如,有一个特殊的价值为"未知的",并编列的不可为空。但是我不能找出如何得到使用的情况(1).
换句话说,我怎么能得到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); -- 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
解决方案 2
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);
一个功能性指数!基本上我只是需要确保所有组,我想忽略(即接受)得到翻译成所有空。丑陋的,但不是屁股很丑。作为所希望的。
想出的帮助下解决的另一个问题: 如何限制一个数据库表,以便只有一个排可以具有特别价值在一个专栏?
所以去那里,给托尼*安德鲁斯分。:)
其他提示
尝试基于函数的索引:
在沙箱创建唯一索引sandbox_idx(CASE WHEN一个IS NULL NULL THEN当B是NULL ELSE THEN NULL一个|| '' || B端侧);
有其他方法对皮肤这只猫,但是这是其中之一。
我不是一个Oracle家伙,但这里的一个想法,应该工作,如果你可以包括在甲骨文的索引计算列。
一个附加列添加到表中(和你的独特的索引),计算如下:它是NULL,如果a和b为非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或所以在新闻组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将从未接受两个(1,null)的双如果列唯一索引。
一个对1和空的,被认为是“可转位”对。一对的两个空值不能被索引,这就是为什么它可以让你喜欢你插入许多空,空对。
(1,空)获取索引,因为1可以被索引。下一次你试图插入(1,空)再次,1是由指数回升和独特的约束被违反。
(NULL,NULL)未索引,因为没有要被索引的值。这就是为什么它不违反唯一约束。