Есть ли обходной путь, позволяющий использовать вычисляемый столбец в его собственной формуле - PullRequest
1 голос
/ 25 августа 2011

В моей таблице есть столбец с именем Value1.Затем у меня есть вычисляемый столбец Value2 с формулой:

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

Я не могу сохранить это, поскольку SQL Server блокирует самоссылку к вычисляемому столбцу Value2 в формуле.

Есть ли что-нибудь еще, что я могу сделать?

Ответы [ 2 ]

5 голосов
/ 25 августа 2011

Похоже, вам нужно отслеживать не только то, что значение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

An 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

An 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
2 голосов
/ 25 августа 2011

Вычисляемые столбцы будут вычисляться только тогда, когда запись ВЫБРАНА (для не PERSISTED) или когда изменяется какое-либо поле, от которого зависит вычисление (для PERSISTED).

Таким образом, одним из способов выполнения той же функции (без триггера) было бы немного переработать хранимую процедуру. Обновление может выглядеть следующим образом ...

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

Это не так автоматически, как вы могли бы с триггером, но если вы можете избежать этого - они часто слишком похожи на работу, когда дело доходит до модификации вашего стола, обслуживания, обновлений и т. Д. И вы должны убедиться, что они могут изящно провалиться, на всякий случай.

...