2014-07-17 34 views
0

我有一張表,我想防止插入重複的行。如何創建即使列爲NULL也可以工作的UNIQUE約束條件

CREATE TABLE blah(id INTEGER PRIMARY KEY ASC, a INTEGER, b INTEGER, c, d, e, f, 
    UNIQUE (a,b,c,d,e,f) ON CONFLICT IGNORE); 

現在我插入一些記錄:

INSERT INTO event2 (a,b,c,d) 
    VALUES (1,1405451500,"Y",100), 
      (1,1405451555,"Z",115); 

現在,如果我重新運行上面的命令,我希望它不插入任何東西,因爲新行完全匹配的是已經存在。相反,我看到插入了兩個新行。

SQLite documentation,看來SQLite不強制UNIQUE約束如果一個或多個列的是NULL。如果有一些方法可以使用其他機制來實現這個目標?在上述情況下,cd,ef列可能爲空。或者,我可以使用空字符串而不是NULL,但閱讀其他答案似乎表明null不應與空字符串混淆,因爲它們表示單獨的東西。

+1

您的表格結構沒有意義。主鍵應該是自動唯一的。您的初始插入應該失敗,因爲'id'被聲明爲主鍵。 –

+0

@GordonLinoff好抓。固定。 – Michael

回答

0

您可以使用BEFORE INSERT觸發器來檢查數據的正確性。

要知道,這並不全表每次插入之前掃描,所以對於更大的表會造成插入很慢!

爲了加快速度(並避免全表掃描),您應該使用CREATE INDEX,其中包括觸發器中已檢查的所有列。

這裏是你如何用你的例子做:

CREATE TRIGGER event2uniqTrigger 
     BEFORE INSERT ON event2 
     WHEN ( 
    SELECT count(*) 
     FROM event2 t 
    WHERE (CASE 
        WHEN new.a IS NULL THEN t.a IS NULL 
        ELSE t.a = new.a 
      END) 
      AND 
      (CASE 
        WHEN new.b IS NULL THEN t.b IS NULL 
        ELSE t.b = new.b 
      END) 
      AND 
      (CASE 
        WHEN new.c IS NULL THEN t.c IS NULL 
        ELSE t.c = new.c 
      END) 
      AND 
      (CASE 
        WHEN new.d IS NULL THEN t.d IS NULL 
        ELSE t.d = new.d 
      END) 
      AND 
      (CASE 
        WHEN new.e IS NULL THEN t.e IS NULL 
        ELSE t.e = new.e 
      END) 
      AND 
      (CASE 
        WHEN new.f IS NULL THEN t.f IS NULL 
        ELSE t.f = new.f 
      END) 
    ) > 0 
BEGIN 
    SELECT RAISE (FAIL, 'inserted value not unique'); 
END; 

和索引:

CREATE INDEX event2idx ON event2 (a, b, c, d, e, f); 

您可能還需要創建另一個觸發BEFORE UPDATE。它看起來就像上面的那個,除了BEFORE UPDATE部分。