2012-08-09 88 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