2009-09-20 52 views
1

好的我知道我可以在應用程序層做到這一點,這可能是最簡單的事情,但只是爲了確保沒有錯誤流入數據庫,我有一個嚴重的問題如何在多個列上實現雙向唯一索引

我有兩列X和Y,每個存儲兩個整數(A或B在任何列中)。是否有可能有一個唯一索引的約束,使得在任何情況下,我們應該有

  1. X列A和第Y列爲B
  2. X列與B和y列有一個

我會給出一個場景

我有兩個用戶,userA有id 678498和userB有id 679879.兩個用戶都打一個2人遊戲,這需要這個session的新記錄存儲在一個表中(tbl_chalenger)。要做到這一點,我有一個列「主機」和「挑戰者」的表。

我添加了一個獨特的約束,以tbl_challenger作爲

UNIQUE KEY `UNIQUE_PARTICIPANTS` (`host`,`challenger`) 

品牌用戶主機或挑戰者基本上依賴誰開始遊戲。因此,如果用戶A啓動遊戲,我們有一個查詢,如下所示

INSERT INTO `tbl_challenger` VALUES(678498 , 679879); 

這將創建一個新的記錄,不過不幸的是,如果在同一時間用戶B嘗試啓動遊戲與用戶A,我們得到

INSERT INTO `tbl_challenger` VALUES(679879, 678498); 

這創建了一個新的不需要的行,相同的參與者。這與UNIQUE鍵約束無關。

所以我的問題是,如何有一個約束是雙向的?這樣的「主機挑戰者」以及「挑戰者 - 主機」不能有相同的數據對

回答

8

在MySQL中,我可以的唯一途徑想到的是添加一些實用工具列的像

CREATE TABLE tbl_challenger (
    host int, 
    challenger int, 
    u0 int, u1 int 
); 

,並添加了幾個觸發該設置u0u1到最小和最大的兩個:

CREATE TRIGGER uinsert BEFORE INSERT ON tbl_challenger 
FOR EACH ROW SET NEW.u0 = LEAST(NEW.host,NEW.challenger), 
    NEW.u1 = GREATEST(NEW.host,NEW.challenger); 
CREATE TRIGGER uupdate BEFORE UPDATE ON tbl_challenger 
FOR EACH ROW SET NEW.u0 = LEAST(NEW.host,NEW.challenger), 
    NEW.u1 = GREATEST(NEW.host,NEW.challenger); 

那麼你就(u0,u1)

CREATE UNIQUE INDEX uniqueness ON tbl_challenger(u0,u1); 

添加唯一索引,而現在你會得到嘗試插入重複對不分先後順序的錯誤。

在一個體面的RDBMS像PostgreSQL你將能夠在表達式中使用索引:

CREATE UNIQUE INDEX uniqueness ON tbl_challenger 
    (LEAST(host,challenger), GREATEST(host,challenger)); 

所以,纔開關爲時已晚;-)

+0

很酷,我會試試這個,並在幾分鐘內回報! – stone 2009-09-21 10:35:46

+0

當然,慢慢來;-) – 2009-09-21 10:51:09

+0

完美的作品!是的,只是使用MySQL,因爲它是一個僅使用MySQL的應用程序的擴展,沒有時間爲其他DBMS編寫一個全新的抽象層,但是當我獲得更多時間時,肯定會查看。非常感謝黑客 – stone 2009-09-21 10:53:47

1

我不認爲你可以做到這一點「開箱即用」,就像使用UNIQUE索引或類似的東西一樣。

儘管如此,您可能可以在插入和更新之前使用觸發器實施這種檢查。

我不能使用觸發器工作了相當一段時間,這是不是在MySQL,所以我不能給你任何例子,但這裏的手冊的相關頁面:12.1.19. CREATE TRIGGER Syntax

作爲一個旁註:像你說的那樣,這種約束通常是在應用程序端實現的。

+0

感謝指針,觸發器正常工作!謝謝! – stone 2009-09-21 10:55:02

+0

不客氣,玩的開心 ! – 2009-09-21 10:57:57