2013-11-02 105 views
7

假設我在表中有3列 - A,B和C.我想確保如果向列A中插入一些值(比如說x),我不能插入對於所有元組,B或C等於x的元組(即值x)對列A應保持唯一。在多個列中唯一的SQL Oracle約束值

請注意,對於其他元組,可以在A中重複x。

我知道SQL中的UNIQUE子句,但這只是爲了確保一個值只出現在特定列中一次。由於Oracle中的CHECK語句不允許子查詢,所以我無法弄清楚如何實現這個。

EDIT(添加詳細信息)

主鍵是EMPLOYEE_NUMBER,而有問題的3列LandlineNo,MobileNo和VOIP。因此,假設這是一個條目:

Employee_Number = 1, LandlineNo = x, MobileNo = y, VOIP = z 

那麼這個輸入另一元組將不被允許 -

Employee_Number = 2, LandlineNo = a, MobileNo = x, VOIP = c 

在另一方面,這一個就可以了(是的,2名員工可以有相同數目的相同類型的)

Employee_Number = 2, LandlineNo = x, MobileNo = b, VOIP = c 
+0

你能擴大與好壞行一個例子你的問題?表格的結構和主鍵是什麼? –

+3

你是否堅持使用這款餐桌設計?你要求的是保證每個數字都是某種類型的。所以爲什麼不有一個表「數字」,主要關鍵是數字(或者如果你喜歡這個數字加一個唯一的數字約束),然後你有一個列類型。因此每個數字都是唯一的並且有一個類型。然後在你的員工表中,你只有三個外鍵給該號碼錶(即三個號碼或三個ID)。 –

+0

您正在使用哪個版本的Oracle? – Sebas

回答

2
CREATE MATERIALIZED VIEW mv_my 
BUILD IMMEDIATE 
REFRESH FAST ON COMMIT AS 
SELECT DISTINCT 
    CASE 
     WHEN t2.Employee_Number IS NOT NULL THEN 1 
     WHEN t3.Employee_Number IS NOT NULL THEN 1 
     WHEN t4.Employee_Number IS NOT NULL THEN 1 
     ELSE 0 
    END AS wrong 
FROM table t1 
    LEFT JOIN table t2 ON t2.MobileNo = t1.LandlineNo AND t2.Employee_Number != t1.Employee_Number 
    LEFT JOIN table t3 ON t3.VOIP = t1.LandlineNo AND t3.Employee_Number != t1.Employee_Number 
    LEFT JOIN table t4 ON t4.VOIP = t1.MobileNo AND t4.Employee_Number != t1.Employee_Number 
/

ALTER TABLE mv_my ADD CHECK(wrong = 0) 
/

它可能或根據您的Oracle版本可能無法正常工作(doc

1
create table table1(
    a varchar2(20) not null, 
    b varchar2(20) not null, 
    c varchar2(20) not null 
) 
/
create table ctrs (
    val varchar2(20) unique, 
    ctr_a int, 
    ctr_b int, 
    ctr_c int, 
    check(ctr_a*ctr_b+ctr_a*ctr_c+ctr_b*ctr_c=0) 
) 
/
create trigger table1_trg 
before insert or update or delete on table1 
for each row 
begin 
    if deleting then 
     update ctrs set ctr_a = ctr_a - 1 where val = :old.a; 
     update ctrs set ctr_b = ctr_b - 1 where val = :old.b; 
     update ctrs set ctr_c = ctr_c - 1 where val = :old.c; 
    elsif inserting then 
     merge into ctrs using (
     select :new.a as x from dual union all 
     select :new.b as x from dual union all 
     select :new.c as x from dual 
    ) 
     on (val = x) 
     when not matched then 
     insert (val, ctr_a, ctr_b, ctr_c) values (x, 0, 0, 0); 
     update ctrs set ctr_a = ctr_a + 1 where val = :new.a; 
     update ctrs set ctr_b = ctr_b + 1 where val = :new.b; 
     update ctrs set ctr_c = ctr_c + 1 where val = :new.c; 
    else 
     update ctrs set ctr_a = ctr_a - 1 where val = :old.a; 
     update ctrs set ctr_b = ctr_b - 1 where val = :old.b; 
     update ctrs set ctr_c = ctr_c - 1 where val = :old.c; 
     merge into ctrs using (
     select :new.a as x from dual union all 
     select :new.b as x from dual union all 
     select :new.c as x from dual 
    ) 
     on (val = x) 
     when not matched then 
     insert (val, ctr_a, ctr_b, ctr_c) values (x, 0, 0, 0); 
     update ctrs set ctr_a = ctr_a + 1 where val = :new.a; 
     update ctrs set ctr_b = ctr_b + 1 where val = :new.b; 
     update ctrs set ctr_c = ctr_c + 1 where val = :new.c; 
    end if; 
end; 
/

fiddle