2010-04-07 39 views
2

SQL Server初學者問題:如何在SQL Server中定義一個「複雜」的ComputedColumn?

我想在SQL Server(2008)中引入一個計算列。在SQL Server Management Studio的表設計器中,我可以做到這一點,但設計人員只給我提供一個編輯單元來定義此列的表達式。由於我的計算列將會相當複雜(取決於幾個數據庫字段和一些個案差異),我希望有一個更舒適和可維護的方法來輸入列定義(包括格式化換行符等)。

我見過有一個選項可以在SQL Server中定義函數(標量值或表值函數)。定義這樣一個函數並將該函數用作列規範可能更好嗎?什麼樣的函數(標量值,表值)?

爲了使一個簡單的例子:

我有兩個數據庫列:

DateTime1 (smalldatetime, NULL) 
DateTime2 (smalldatetime, NULL) 

現在我要定義一個計算列「狀態」,它可以有四個可能的值。在虛擬語言:

if (DateTime1 IS NULL and DateTime2 IS NULL) 
    set Status = 0 
else if (DateTime1 IS NULL and DateTime2 IS NOT NULL) 
    set Status = 1 
else if (DateTime1 IS NOT NULL and DateTime2 IS NULL) 
    set Status = 2 
else 
    set Status = 3 

理想情況下,我想有一個函數GetStatus()可以訪問錶行的,我想計算的「狀態」的值不同的列值,然後只定義計算列規格爲GetStatus(),不帶參數。

這可能嗎?或者使用「複雜」計算列定義的最佳方法是什麼?

感謝您提前提示!

回答

8

您可以在一個ALTER TABLE語句來做到這一點:

alter table my_table_name 
    add Status as 
    case 
     when (DateTime1 IS NULL and DateTime2 IS NULL) then 0 
     when (DateTime1 IS NULL and DateTime2 IS NOT NULL) then 1 
     when (DateTime1 IS NOT NULL and DateTime2 IS NULL) then 2 
     else 3 
    end 

編輯,以修復啞複製和粘貼語法錯誤

+0

謝謝,工作正常!但是當我想稍後改變公式時,我會做些什麼,比如說,添加一個額外的案例?我是否需要刪除表中的「狀態」列並再次運行這樣的「alter table」腳本? – Slauma 2010-04-07 21:51:38

+0

是的 - 你將不得不放棄它,並重新創建它 – Ray 2010-04-07 21:56:50

0

您可以在插入或更新時使用觸發器來確保列值。

+1

但是「觸發器」不是「計算列」,不是嗎? (也許我應該用粗體寫出「SQL Server初學者問題」。) – Slauma 2010-04-07 21:39:20

+1

沒有辦法 - 觸發和計算列是兩個完全不同的概念 - 觸發器在這裏不會幫助你。 – 2010-04-08 07:13:16

10

您可以隨時還可以使用用戶定義的函數本 - 包裝你的「複雜」的代碼爲UDF,並用它來定義計算列:

CREATE FUNCTION dbo.GetStatus(@DateTime1 DATETIME, @DateTime2 DATETIME) 
RETURNS INT 
AS BEGIN 
    DECLARE @Result INT 

    IF (@DateTime1 IS NULL AND @DateTime2 IS NULL) 
     SET @Result = 0 
    ELSE IF (@DateTime1 IS NULL AND @DateTime2 IS NOT NULL) 
     SET @Result = 1 
    ELSE IF (@DateTime1 IS NOT NULL AND @DateTime2 IS NULL) 
     SET @Result = 2 
    ELSE 
     SET @Result = 3 

    RETURN @Result 
END 

,然後你定義計算列如:

ALTER TABLE dbo.YourTable 
    ADD Status AS dbo.GetStatus(DateTime1, DateTime2) 
+0

感謝您的回覆!但我總是需要我的數據庫字段(計算列值依賴)作爲函數的輸入參數,是嗎?是不是可以直接在函數中使用行的字段(如對象的成員)?例如:使用參數'@ DateTime1'可以使用類似'dbo.MyTable.DateTime1'的東西嗎? – Slauma 2010-04-08 11:35:22

+0

@Slauma:是的,您可以讀出函數內部行的值 - 但您仍然需要傳入某些內容以識別正在處理的列。另外,如果您在函數內部進行表訪問,您將無法生成計算結果列** PERSISTED **,在某些情況下這是一個理想的功能 – 2010-04-08 12:21:25

+1

事實上,可以將計算列堅持對我的目的很重要(需要快速查詢和列索引)。我已經開始關注Ray的提議,但很有必要了解用戶定義的函數以後可以定義一個計算列。 – Slauma 2010-04-08 15:22:29