0

我有一個包含錯誤數據的表,並且想要防止在修復數據時發現插入了新的錯誤數據,並找出在哪個過程或哪個地方使用這個語句發生。 我首先對不應該重複的列進行UQ約束,但是這使我陷入另一個問題:我只需要在所有列都有值時應用唯一性,如果有空值,我需要在這些列上重複記錄。事情是這樣的:使用現有的重複值在基於函數的索引上創建唯一約束

CREATE TABLE MYTAB (COL1 NUMBER, COL2 NUMBER, COL3 NUMBER, COL4 NUMBER); --EXAMPLE TABLE. I NEED NO DUPS OVER (COL1, COL3, COL4) 
INSERT INTO MYTAB VALUES (1, 1, 1, 1); --OK 
INSERT INTO MYTAB VALUES (1, 2, 1, 1); -- NOOK 
INSERT INTO MYTAB VALUES (1, 3, NULL, NULL); --OK 
INSERT INTO MYTAB VALUES (1, 4, NULL, NULL); --OK 

如果我創建這樣一個約束:

ALTER TABLE MYTAB 
ADD CONSTRAINT U_CONSTRAINT UNIQUE (COL1, COL3, COL4) NOVALIDATE; 

末插入會崩潰。

我試着

CREATE UNIQUE INDEX FN_UIX_MYTAB 
    ON MYTAB (CASE WHEN COL2 IS NOT NULL THEN COL1 ELSE null END, 
       CASE WHEN COL2 IS NOT NULL THEN COL3 ELSE null END 
       CASE WHEN COL2 IS NOT NULL THEN COL4 ELSE null END) ; 

但創建崩潰,因爲表中有重複的數據。我將需要創建此索引而不驗證現有數據,這意味着索引將僅應用於插入的新記錄。

我也試過用:

CREATE INDEX FN_IX_MYTAB 
    ON MYTAB (CASE WHEN COL2 IS NOT NULL THEN COL1 ELSE null END, 
       CASE WHEN COL2 IS NOT NULL THEN COL3 ELSE null END, 
       CASE WHEN COL2 IS NOT NULL THEN COL4 ELSE null END) ; 
ALTER TABLE MYTAB 
ADD CONSTRAINT FN_UIX_MYTAB UNIQUE (COL1, COL3, COL4) USING INDEX FN_IX_MYTAB NOVALIDATE; 

但是這給了我錯誤:

ORA-14196: Specified index cannot be used to enforce the constraint. 

有沒有辦法做我已經解釋了,或者我應該防止錯誤插入另一種方式,當我尋找問題的根源?任何建議也將受到讚賞。

+1

如果這是一個臨時解決方法,直到您清理您的表,也許使用觸發器來防止新的重複,然後刪除並添加適當的約束。 – OldProgrammer

+0

你的問題陳述不太合理。您想要在col1,col3,col4上創建唯一索引,但是您希望允許(1,...,NULL,NULL)被複制。這不是UNIQUE在這三列中的含義 - 問題不是「破壞獨特性的舊數據」。即使你首先創建表格,然後添加這個唯一的約束,然後你第一次填充表格,你將無法添加示例中的所有行,完全出於這個原因。這與預先存在的數據有什麼關係? – mathguy

+0

@mathguy我想只有當這3列有價值時才應用UNIQUE。正如OldProgrammer指出的那樣,這是一個臨時解決方法,我只需要找到問題的根源並找到一個乾淨的解決方案。 – EAmez

回答

0

以下是一種可能的方法。創建物化視圖,刷新提交(如果情況允許,最好快速刷新;在這種情況下,他們應該)。該MV會是這樣的

create materialized view mymv 
refresh fast on commit 
as 
select col1, col3, col4 
from mytab 
where col1 is not null and col3 is not null and col4 is not null 
; 

然後把上的MV(COL1,COL3,COL4)的唯一約束。

+0

但是,視圖中的約束不會阻止插入「錯誤」的數據。 此外,我試過你的解決方案,但不起作用,因爲MyTab沒有PK,因爲使每個記錄唯一的列是有時需要爲空的列。是的,我知道這是一個奇怪的場景......但是這是很久以前其他人做出來的方式:( – EAmez

+1

缺少PK確實是一個問題,但是否則,MV **中的約束將會** 「錯誤的」數據被插入,對於這種場景,這是一種非常常見的策略,我並沒有發明它!它的工作原理是這樣的:你試圖插入「錯誤」的數據,在提交時,必須刷新MV。 MV拒絕新的行,從而使整個交易無效。 – mathguy