2008-10-23 159 views
5

如何在表格中的兩個字段上有效創建唯一索引,如下所示: create table t(integer,b integer);如何在兩個字段上創建「雙面」唯一索引?

其中兩個不同數字的任何唯一組合不能在表中的同一行上出現超過一次。

如果一行存在使得a = 1且b = 2,則另一行不能存在,其中a = 2且b = 1或a = 1且b = 2。換句話說,兩個數字不能以任何順序一次出現超過一次。

我不知道這樣的約束被稱爲什麼,因此標題中的'雙面唯一索引'名稱。

更新:如果我在列(a,b)上有一個組合鍵,並且數據庫中存在一行(1,2),則可以在沒有錯誤的情況下插入另一行(2,1) 。我正在尋找的是被用來不止一次以任意順序 ...

回答

5

如何控制進入表格的內容,以便始終將最小數字存入第一列,並將最小數字存入第二列?只要「意味着」當然是相同的東西。在它進入數據庫之前做它可能會更便宜。

如果這是不可能的,你可以保存領域的信息,但有他們在數字順序複製成兩個等領域上,您將創建主鍵(僞代碼-ISH):

COLUMN A : 2 
COLUMN B : 1 

COLUMN A_PK : 1 (if new.a < new.b then new.a else new.b) 
COLUMN B_PK : 2 (if new.b > new.a then new.b else new.a) 

在應用程序中,這可以通過觸發器(如Ronald的響應)輕鬆完成,或者處理得更高。

+0

你的第一個答案對我來說是完美的。謝謝。 我希望能有一個更「自然」的解決方案,但我想這就是它。 – 2008-10-23 17:20:21

3

我想這隻能做到用一個方法,以防止同一對數從一個FOR INSERT觸發器(結合兩列上的唯一約束)。我的MySql語法不太流利(我的T-SQL更好),所以我想下面會包含一些錯誤:

編輯:清理了語法,因此它適用於MySQL。此外,請注意,您可能還想將其作爲BEFORE UPDATE觸發器(當然,使用不同的名稱)。另外,這種方法依賴於在兩個字段上有一個主鍵或其他唯一鍵(即,這個觸發器只檢查相反的東西是不存在的)。似乎沒有任何方法可以拋出一個錯誤從一個觸發器,所以我敢說這是一樣好。

CREATE TRIGGER tr_CheckDuplicates_insert 
BEFORE INSERT ON t 
FOR EACH ROW 
BEGIN 
    DECLARE rowCount INT; 
    SELECT COUNT(*) INTO rowCount 
        FROM t 
        WHERE a = NEW.b AND b = NEW.a; 

    IF rowCount > 0 THEN 
     -- Oops, we need a temporary variable here. Oh well. 
     -- Switch the values so that the key will cause the insert to fail. 
     SET rowCount = NEW.a, NEW.a = NEW.b, NEW.b = rowCount; 
    END IF; 
END; 
+0

修正了並在MySQL下進行了測試。如果有人知道是否有可能直接從觸發器中拋出一個錯誤來停止插入,那將會很方便知道...... – 2008-10-23 13:38:42

2

在Oracle中你可以使用一個基於函數的索引是這樣的:

create unique index mytab_idx on mytab (least(a,b), greatest(a,b)); 

我不知道MySQL的,但也許類似的東西是可能的嗎?例如,您可以在表中添加2個新列leastab和greatestab,並使用觸發器分別保留值分別爲最小值(a,b)和最大值(a,b),然後創建一個唯一索引,greatestab)。

相關問題