我的表中有一个名为Value1的列。然后我有一个计算列,Value2,公式为;
(CASE WHEN [Value1] > [Value2] THEN [Value1] ELSE [Value2] END)
我不能保存这个,因为SQL Server在公式中的Value2计算列的自引用时很容易。
我还能做些什么吗?
答案 0 :(得分: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
现在让我们插入几行并证明我们可以维护Value2,而无需直接插入或更新该列:
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
答案 1 :(得分:2)
计算列仅在记录为SELECTED时(非PERSISTED)或计算所依赖的某个字段(对于PERSISTED)进行计算。
因此,一种可以提供相同功能(没有触发器)的方法是重新处理存储过程。更新可能会像这样......
ECLARE @myVar varchar(max)
UPDATE dbo.myTable
SET [value1] = 3,
[value2] = CASE WHEN [value2] < 3 THEN 3 ELSE [value2] END
WHERE ...
它不像触发器那样自动,但是如果你可以避免那些 - 它们通常有点像工作,当涉及到修改你的表,维护,升级等。你必须确保他们能够优雅地失败,以防万一。