2015-03-13 64 views
1

我正在使用Oracle數據庫,並且需要創建一個如下所示的表。如何在兩列上獨立制定唯一約束順序

MAP(Point_One, Poin_Two, Connection_weight). 

該表代表關於圖的數據。我想創建一個表格,其中有一個約束可以防止插入已經存在的連接。

例如,表中已包含此連接:

Point_One | Point_Two | Connection_weight 
----------------------------------------- 
p_no1  | p_no2  | 10 

和約束將阻止該連接的多次插入,即使我嘗試在不同的順序添加點。 (例如:(p_no2,p_no1,10))

一個簡單的UNIQUE(Point_One,Point_Two)約束是不夠的。你有什麼建議嗎?

回答

5

您可以創建一個基於函數的索引

CREATE UNIQUE INDEX idx_unique_edge 
    ON map(greatest(point_one, point_two), 
      least(point_one, point_two)); 

我假設的point_onepoint_two數據類型是與Oracle greatestleast功能兼容。如果沒有,你需要一個你自己的函數來爲你的複雜數據類型選擇「最大」和「最小」的點。

+0

這是非常好的想法 – Martina 2015-03-13 20:18:23

0

您可以通過使用觸發器輕鬆實現預期的結果。

create table map (point_one number, point_two number, connection_weight number) 
/
create or replace trigger tr_map before insert on map 
for each row 
declare 
c number; 
    begin 
    select count(1) into c from map where (point_one=:new.point_one and point_two=:new.point_two) 
    or 
    (point_one=:new.point_two and point_two=:new.point_one); 
    if c>0 then 
    raise_application_error(-20000,'Connection line already exists'); 
    end if; 
end; 
/

SQL> insert into map values(1,2,10);

1 row created。 SQL> insert into map values(2,1,10); SQL> insert into map values(2,1,10); 插入到圖值(2,1,10)中的第1行 * ERROR: ORA-21000:錯誤編號參數-100 RAISE_APPLICATION_ERROR超出 範圍 ORA-06512的:在「C## MINA.TR_MAP 「,第10行 ORA-04088:執行觸發器'C## MINA.TR_MAP'時出錯

我仍然在考慮CHECK約束,但是我沒有決定是否可能與否。

+0

只要你只使用INSERT ... VALUES語句進行單行插入,它就可以工作。只要你想做一個基於集合的'INSERT ... SELECT',你就會得到一個變異的表格異常。通常,在表上定義的行級觸發器(在這種情況下爲'map')不能直接查詢該表。所以這個行級觸發器一般不允許查詢'map'。您可以通過創建行級觸發器和語句級觸發器以及包含集合但開始變得相當複雜的包來解決該問題。 – 2015-03-13 20:24:59

+0

在Oracle 11.2中,您可以創建一個複合觸發器。但通常通過觸發強制約束是一個壞主意 – 2015-03-14 06:10:37