2011-08-24 51 views
1

我的表中有一列叫做Value1。然後我有一個計算列,Value2,公式爲;是否有一種解決方法,允許在其公式中使用計算列

(CASE WHEN [Value1] > [Value2] THEN [Value1] ELSE [Value2] END) 

我無法保存此信息,因爲SQL Server在公式中的Value2計算列的自引用上很差。

還有什麼我可以做的嗎?

+0

遞歸讓我頭暈目眩。如果您輸入Value1 = 5,Value2將如何成爲5以外的任何其他值? –

回答

5

看起來好像你需要跟蹤不僅是現在的價值1,而且還有價值1曾經是什麼。您無法使用計算列做到這一點,因爲它只能對當前值作出反應,而不會對其本身或以前的值作出反應。

我建議一個INSTEAD OF TRIGGER而不是計算列。下面是一個簡單的例子:

USE tempdb; 
GO 

CREATE TABLE dbo.SparkyMark 
(
    [key] INT IDENTITY(1,1) PRIMARY KEY, 
    [string] VARCHAR(32), 
    Value1 INT, 
    Value2 INT 
); 
GO 

INSTEAD OF INSERT TRIGGER

CREATE TRIGGER dbo.SparkyMark_BeforeInsert 
ON dbo.SparkyMark 
INSTEAD OF INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    INSERT dbo.SparkyMark([string], Value1, Value2) 
     SELECT [string], Value1, Value1 FROM inserted; 
END 
GO 

INSTEAD OF UPDATE TRIGGER

CREATE TRIGGER dbo.SparkyMark_BeforeUpdate 
ON dbo.SparkyMark 
INSTEAD OF UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON; 

    UPDATE sm 
     SET [string] = i.[string], 
      Value1 = i.Value1, 
      Value2 = CASE WHEN sm.Value2 < i.Value1 THEN i.Value1 ELSE sm.Value2 END 
     FROM 
      dbo.SparkyMark AS sm 
     INNER JOIN 
      inserted AS i 
      ON sm.[key] = i.[key]; 
END 
GO 

現在讓我們插入一些記錄和證明,我們能夠保持值2而沒有插入或直接更新該列:

INSERT dbo.SparkyMark([string], Value1) SELECT 'foo', 3; 
INSERT dbo.SparkyMark([string], Value1) SELECT 'foo', 5; 

-- Value1 and Value2 are the same: 
SELECT * FROM dbo.SparkyMark ORDER BY [key]; 

-- they will still be the same because the new Value1 > old Value2: 
UPDATE dbo.SparkyMark SET Value1 = Value1 + 1; 
SELECT * FROM dbo.SparkyMark ORDER BY [key]; 

-- now they will be one less because the new Value1 < old Value2: 
UPDATE dbo.SparkyMark SET Value1 = Value1 - 1; 
SELECT * FROM dbo.SparkyMark ORDER BY [key]; 

-- in row 1 Value1 drops by 2 but Value2 stays the same: 
UPDATE dbo.SparkyMark SET Value1 = Value1 - 2 WHERE [key] = 1; 
SELECT * FROM dbo.SparkyMark ORDER BY [key]; 

-- and finally we get both values in both rows equal again: 
UPDATE dbo.SparkyMark SET Value1 = Value1 + 5; 
SELECT * FROM dbo.SparkyMark ORDER BY [key]; 

清理:當記錄被選中

DROP TRIGGER dbo.SparkyMark_BeforeInsert, dbo.SparkyMark_BeforeUpdate; 
DROP TABLE dbo.SparkyMark; 
GO 
+0

+1 @Aaron正在寫同樣的答案:) – Eddy

+2

只要確保觸發器可以處理多行插入/更新 – HLGEM

2

計算列將只計算(對於非持久化),或在某些領域的計算依賴於改變(爲PERSISTED)。

所以你可以用同一個函數(沒有觸發器)的一種方法是重新處理你的存儲過程。更新可能是這樣的......

ECLARE @myVar varchar(max) 
UPDATE dbo.myTable 
SET [value1] = 3, 
    [value2] = CASE WHEN [value2] < 3 THEN 3 ELSE [value2] END 
WHERE ... 

這不是自動的,你可能有一個觸發,但如果你能避免這些 - 他們往往過於有點像的工作,當談到修改你的表格,維護,升級等。而且你必須確保它們可以優雅地失敗,以防萬一。

+0

我建議一個而不是觸發器,不是因爲我認爲做更多工作會很有趣,而是因爲我假設基於他可能剛剛更新存儲過程來執行該案例的問題,如果它很簡單。我的猜測是,對於數據修改,存在(a)沒有存儲過程,(b)許多存儲過程,或(c)臨時存儲過程和存儲過程的混合。 –

+0

@Aaron - 我意識到這一點,而且實際上我會傾向於做出同樣的假設。但爲了避免不必要的痛苦和痛苦:-P,我總是想確保沒有可行的替代方案。有時觸發器是正確的答案,我知道。這是你給出的一個很好的答案。 – Chains

相關問題