我的表中有一列叫做Value1。然後我有一個計算列,Value2,公式爲;是否有一種解決方法,允許在其公式中使用計算列
(CASE WHEN [Value1] > [Value2] THEN [Value1] ELSE [Value2] END)
我無法保存此信息,因爲SQL Server在公式中的Value2計算列的自引用上很差。
還有什麼我可以做的嗎?
我的表中有一列叫做Value1。然後我有一個計算列,Value2,公式爲;是否有一種解決方法,允許在其公式中使用計算列
(CASE WHEN [Value1] > [Value2] THEN [Value1] ELSE [Value2] END)
我無法保存此信息,因爲SQL Server在公式中的Value2計算列的自引用上很差。
還有什麼我可以做的嗎?
看起來好像你需要跟蹤不僅是現在的價值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
計算列將只計算(對於非持久化),或在某些領域的計算依賴於改變(爲PERSISTED)。
所以你可以用同一個函數(沒有觸發器)的一種方法是重新處理你的存儲過程。更新可能是這樣的......
ECLARE @myVar varchar(max)
UPDATE dbo.myTable
SET [value1] = 3,
[value2] = CASE WHEN [value2] < 3 THEN 3 ELSE [value2] END
WHERE ...
這不是自動的,你可能有一個觸發,但如果你能避免這些 - 他們往往過於有點像的工作,當談到修改你的表格,維護,升級等。而且你必須確保它們可以優雅地失敗,以防萬一。
我建議一個而不是觸發器,不是因爲我認爲做更多工作會很有趣,而是因爲我假設基於他可能剛剛更新存儲過程來執行該案例的問題,如果它很簡單。我的猜測是,對於數據修改,存在(a)沒有存儲過程,(b)許多存儲過程,或(c)臨時存儲過程和存儲過程的混合。 –
@Aaron - 我意識到這一點,而且實際上我會傾向於做出同樣的假設。但爲了避免不必要的痛苦和痛苦:-P,我總是想確保沒有可行的替代方案。有時觸發器是正確的答案,我知道。這是你給出的一個很好的答案。 – Chains
遞歸讓我頭暈目眩。如果您輸入Value1 = 5,Value2將如何成爲5以外的任何其他值? –