2010-07-08 132 views
1

如何在列上放置CHECK約束以使其可接受值的範圍來自另一個表,而無需硬編碼?SQL Server - 對其值來自另一個表的列進行CHECK約束

下面是一個簡化的例子:

OneManyTable 
RoleID TaskID 
10  Val1 
10  Val2 
20  Val1 
20  Val2 


MetaDataTable 
pkID Class Value 
1  A  Val1 
2  A  Val2 
3  B  Val3 
4  B  Val4 

我希望把OneManyTable.TaskID列檢查約束,使得可接受的值來自另一表的列中,即,從其中MetadataTable.Value MetadataTable.class =「A 「

我已經嘗試過創建格式

TaskID in (Select Value FROM MetadataTable where class= 'A') 

的CHECK約束,但這是不支持的。另一方面('Val1','Val2')中的TaskID作爲SQL2k8中的檢查約束(不在SQL2000!中),但由於硬編碼不可接受。

如何實現我想要的,無論是通過CHECK約束還是其他一些我不知道的奇特機制?

PS。必須在數據庫方面,沒有任何人向我建議的客戶端檢查。

回答

4

這可能不是一個好習慣,但可以編寫一個用戶定義的函數,它接受您的TaskID作爲參數,並根據TaskID是否落在所提供的範圍內將其計算爲true或false在你的MetaDataTable中。

這將允許你獲得你正在尋找的功能 - CHECK約束實際上只是爲了限制列的範圍而設計的簡單函數,並且他們的行爲是按照這個設計的,所以這就是爲什麼你不能在SQL服務器的檢查約束中編寫子查詢。

然而,您可以在用戶定義函數中編寫SELECT語句並從CHECK約束中調用它。

+1

因此,我寫了我的udf並創建了dbo.udfValidateTaskIDRange(TaskID)= 1形式的約束。感謝您將我放在正確的軌道上,滿分。不知道你的'不是一個好的練習評論',雖然;如果所有的參考數據都在一張表中,那麼這是一個完美的練習:-)比不使用任何東西,並讓錯誤進入你的表。 – joedotnot 2010-07-08 06:12:40

+0

我們謹慎使用這個構造,它對我們來說工作得非常好。 – 2010-07-08 06:19:15

+0

@Joedotnot是的,如果使用得當,這種技術真的很有用 - 它只是很容易濫用/濫用,這就是爲什麼我寫道,這可能不是一個好習慣。只要你對你如何設計你的UDF很小心,那麼你將會保持良好狀態。 – Aaronontheweb 2010-07-08 16:31:50

2

針對來自另一個表的值的CHECK約束通常會被設計爲外鍵約束。這是設計用於鏈接表的值的機制。

CHECK約束實際上只設計定義

  • 最大或最小值
  • 範圍一組給定值

  • 枚舉所以我不認爲你可以做你想做的事情,因爲這是你試圖用來做這件事的錯誤特徵。