2010-04-06 110 views
4

我有一個表ab和c列,如果c爲假,那麼我只想允許插入,如果列a和b是唯一的,但如果c是真的,那麼a和b不會需要是獨一無二的。結合UNIQUE和CHECK約束

示例: 表中只能有一個(foo,bar,false),但對於可以有多少(foo,bar,true)沒有限制。

我嘗試了一些像CONSTRAINT blah UNIQUE(a,b)和CHECK(C是TRUE)但我找不出正確的語法。

+1

哪個數據庫? mysql,oracle,postgres,ms sql等... – Unreason 2010-04-06 18:23:22

+1

...什麼版本? – gbn 2010-04-06 18:59:29

回答

1

您可以隨時在插入前創建一個檢查所需條件的觸發器。

5

唯一約束適用於所有行,並且無法指定僅某些行。

檢查約束僅用於單行內的驗證。

達到你的要求,唯一的方法就是做任何以下內容:

1)建立所有刀片由由一個存儲過程。你可以在這裏驗證你的所有邏輯。然而,流氓程序/用戶可以避免使用它並擊敗你的邏輯。

2)創建一個觸發器,驗證您的邏輯並導致無效的插入/更新失敗。應該寫成一次處理一組行

3)創建一個檢查約束,調用用戶定義的函數來進行驗證檢查。這被認爲是不好的做法,應該避免,因爲它們非常慢,並且可能會失敗多行更新。

我建議選項#2觸發器,因爲這正是觸發器的設計目的。

9
  1. 創建返回a和b帶有過濾器WHERE C = false索引視圖,然後創建視圖的唯一索引。這是一個普遍的做法

  2. 如果您有SQL Server 2008中,然後create a unique filtered index代替

  3. 存儲過程

  4. 觸發(之前或之後)

+0

不知道過濾索引 – devio 2010-04-06 19:23:14

0

可以使用表約束(取決於SQL引擎 - 不清楚你正在使用哪一個),以確保沒有太多的特定類型的元組。

在火鳥2.1:

fb> CREATE TABLE so2587151 (
    > a VARCHAR(16) NOT NULL, 
    > b VARCHAR(16) NOT NULL, 
    > c VARCHAR(1) NOT NULL CHECK (c in ('T', 'F')), 
    > CONSTRAINT so2587151_only_one_false CHECK ( -- begin CONSTRAINT 
    >  NOT EXISTS ( SELECT a, b, COUNT('x') 
    >      FROM so2587151 
    >      WHERE c = 'F' 
    >     GROUP BY 1, 2 
    >     HAVING COUNT('x') >= 1 ) 
    > )            -- end CONSTRAINT 
    >); 
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'T'); 
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'T'); 
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'F'); 
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'F'); 
Error: Operation violates CHECK constraint on view or table 
-Operation violates CHECK constraint SO2587151_ONLY_ONE_FALSE on view or table SO2587151 
-At trigger 'CHECK_15' 
fb> SELECT * FROM so2587151; 
A | B | C 
============== 
foo | bar | T 
foo | bar | T 
foo | bar | F 

你可以從約束違反錯誤信息看,這是在引擎蓋下Firebird的觸發機制方面實現。