熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Oracle >> 正文

Oracle數據庫中違反唯一約束的處理

2013-11-13 22:11:46  來源: Oracle 

  根據NULL的定義NULL表示的是未知因此兩個NULL比較的結果既不相等也不不等結果仍然是未知根據這個定義多個NULL值的存在應該不違反唯一約束

  實際上Oracle也是如此實現的



  SQL> CREATE TABLE T (ID NUMBER);

  表已創建

  SQL> ALTER TABLE T ADD UNIQUE (ID);

  表已更改

  SQL> INSERT INTO T VALUES ();

  已創建

  SQL> INSERT INTO T VALUES ();

  INSERT INTO T VALUES ()

  *第 行出現錯誤:

  ORA: 違反唯一約束條件 (YANGTKSYS_C)

  SQL> INSERT INTO T VALUES (NULL);

  已創建

  SQL> INSERT INTO T VALUES (NULL);

  已創建

  SQL> INSERT INTO T VALUES (NULL);

  已創建

  但是當唯一約束為復合字段時則情況發生了變化根據Oracle文檔的描述對於復合字段的唯一約束不為空字段的值是不能重復的也就是說如果兩個字段構成了一個唯一約束其中一個字段為空那麼另一個字段的值不能出現重復



  SQL> DROP TABLE T PURGE;

  表已刪除

  SQL> CREATE TABLE T (ID NUMBER ID NUMBER);

  表已創建

  SQL> ALTER TABLE T ADD UNIQUE (ID ID);

  表已更改

  SQL> INSERT INTO T VALUES ( );

  已創建

  SQL> INSERT INTO T VALUES ( NULL);

  已創建

  SQL> INSERT INTO T VALUES ( NULL);

  已創建

  SQL> INSERT INTO T VALUES ( NULL);

  INSERT INTO T VALUES ( NULL)

  *第 行出現錯誤:

  ORA: 違反唯一約束條件 (YANGTKSYS_C)

  SQL> INSERT INTO T VALUES (NULL NULL);

  已創建

  SQL> INSERT INTO T VALUES (NULL NULL);

  已創建

  SQL> INSERT INTO T VALUES (NULL NULL);

  已創建

  對於全部為NULL的情況仍然和單字段唯一約束一樣不會造成重復但是對於部分為NULL的情況就如上面例子所示只要其中不為NULL的部分發生了重復Oracle就認為約束發生了重復

  而這似乎和NULL的定義有所沖突第一次看concept的時候一直沒有搞明白Oracle為什麼這麼實現不過這次再看concept的時候已經想明白了

  由於Oracle的唯一約束是依賴索引實現的而Oracle的BTREE索引又是不存儲NULL值的所以鍵值全部為NULL的記錄不會記錄在索引中因此也就不會違反唯一約束了而對於部分為NULL的記錄索引是要記錄數值的因此一旦鍵值中非NULL部分發生了沖突Oracle就認為違反了的唯一約束

  Oracle在這裡還是選擇了自己的方便的方法來實現而沒有完全真正的根據NULL的定義去實現唯一約束


From:http://tw.wingwit.com/Article/program/Oracle/201311/18438.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.