2012-08-09 163 views
1

我在SO上遇到此示例,它提供了一种通过忽略空值来创建唯一索引的解决方案。但是,我想扩展它,但我无法达成解决方案。Oracle:创建唯一索引,但忽略空值

我有一个表的3列的组合索引(表中还有其他10列)。这些列不是PK的一部分。在这3列中,2将始终保持某个值,而3可能为NULL。我有巨大的测试数据,并且有许多插入与2个具有相同值的列和第3列NULL。这些所有插入对PostgreSQL都适用,但是Oracle抱怨道。对于我的测试用例的工作,我认为我认为最简单的解决方案就是尝试Oracle独特的索引,它可以在PostgreSQL中工作。

正:我想以下类型的结构,不知道col1 + col2 + col3

create unique index tbl_idx on tbl (nvl2(col3, col1 + col2, col1 + col2 + col3)) 

我使用liquibase如何结合。指数以下列方式产生 -

<changeSet dbms="postgresql,oracle" author="abc" id="222"> 
    <createIndex indexName="Index_7" schemaName="ss" tableName="Users" unique="true"> 
     <column name="idOrganization"/> 
     <column name="strUsername"/> 
     <column name="strNotDeleted"/> 
    </createIndex> 
</changeSet> 

我使用liquibase创建我的测试数据,这里有两个INSERT语句

<insert schemaName="ss" tableName="Users"> 
    <column name="strUsername" value="user1" /> 
    <column name="idUser" valueNumeric="20741" /> 
    <column name="idOrganization" valueNumeric="4" /> 
    <column name="strFirstName" value="user" /> 
    <column name="strLastName" value="one" /> 
    <column name="strEmail" value="[email protected]" /> 
    <column name="strNotDeleted" /> 
</insert> 
<insert schemaName="ss" tableName="Users"> 
    <column name="strUsername" value="user1" /> 
    <column name="idUser" valueNumeric="20771" /> 
    <column name="idOrganization" valueNumeric="4" /> 
    <column name="strFirstName" value="user" /> 
    <column name="strLastName" value="one" /> 
    <column name="strEmail" value="[email protected]" /> 
    <column name="strNotDeleted" /> 
</insert> 

这2个刀片做工精细PostgreSQL的,甲骨文有错误但失败“违反Index_7约束”。

+0

我不确定我是否理解您正在尝试解决的问题。如果创建了最简单的可能唯一约束,“alter table table_name add constraint uk_table_name unique(col1,col2,col3)',那么您想要排除哪些行以及/或者哪些行包含了您想要禁止? – 2012-08-09 22:53:53

+0

@JustinCave:更新了我的问题,希望它能提供更好的图片。 – devang 2012-08-09 23:05:46

+0

“甲骨文抱怨”究竟意味着什么?是否有错误讯息?如果是这样,有什么错误? 'col1,col2,col3'上的一个简单的复合唯一索引将允许您插入无限数量的行,其中'col1'和'col2'完全相同,'col3 IS NULL'。这听起来像你说这就是你想要的,这不是你观察到的,所以它会帮助发布一个小的测试用例,显示你想要达到的目标以及你得到的错误。 – 2012-08-09 23:13:48

回答

8

如果目标仅仅是防止在strNotDeleted被设置为一个非NULL值重复,那么你需要一个这样

SQL> create table users(
    2 idOrganization number, 
    3 strUsername varchar2(100), 
    4 strNotDeleted varchar2(3) 
    5 ); 

Table created. 


SQL> create unique index idx_users 
    2  on users((case when strNotDeleted is not null 
    3      then idOrganization 
    4      else null 
    5     end), 
    6    (case when strNotDeleted is not null 
    7      then strUsername 
    8      else null 
    9     end)); 

Index created. 

一个基于函数的索引这可以让你在你的问题提了两行要插入

SQL> insert into users values(4, 'user', null); 

1 row created. 

SQL> insert into users values(4, 'user', null); 

1 row created. 

可以插入一排,其中strNotNull列设置为一个非NULL值

SQL> insert into users values(4, 'user', 'Yes'); 

1 row created. 

但是你再不能插​​入第二个这样的行

SQL> insert into users values(4, 'user', 'Yes'); 
insert into users values(4, 'user', 'Yes') 
* 
ERROR at line 1: 
ORA-00001: unique constraint (SCOTT.IDX_USERS) violated 

在幕后,一个Oracle B *树索引不会索引完全NULL条目。如果strNotDeleted不是NULL,则两个CASE语句确保该索引仅具有条目idOrganizationstrUsername。如果strNotDeletedNULL,则两个CASE语句评估为NULL,并且在索引中没有条目。从概念上讲,它与其他数据库中的部分索引类似,允许您在索引中指定WHERE子句,以便只索引“有趣”的行。

+0

简单的问题,让我明白。你创建索引的方法是否等同于为用户创建唯一索引idx_users(idOrganization,strUsername,strNotDeleted)? – devang 2012-08-10 02:23:06

+0

@gotuskar - 不,这是不同的。这三列上的直线组合索引将不允许第二个和第四个插入。 – 2012-08-10 02:32:56

+0

在create index语句中,为什么两个case都具有相同的检查,即'strNotDeleted不为空'。如果你可以请详细解释。 – devang 2012-08-10 03:33:32

0
SQL> create table users(
     idOrganization number, 
     strUsername varchar2(100), 
     strNotDeleted varchar2(3) 
    ) 
SQL>/

Table created. 

SQL> Create unique index idx_users 
    on users(
     (
      case when strNotDeleted is not null 
         then idOrganization 
         else null 
      end 
     ), 
      (
      case when strNotDeleted is not null 
         then strUsername 
         else null 
      end 
     ), 
     (
      case when strNotDeleted is not null 
         then strNotDeleted 
         else null 
      end 
     ) 
    ) 
SQL>/

Index created. 
+0

让我们试试这个 – krishnakanth 2014-12-16 10:35:41