Недавно я реализовал очень похожее решение для этого и пришлось работать через ряд препятствий, поэтому я отправляю решение здесь в надежде, что это поможет.
Я хотел бы иметь столбец RecordCreated и LastModified, который управлялся базой данных, а не пользовательским агентом. В этом случае RecordCreated будет datetime, когда сначала была вставлена строка, а LastModified - в последний раз, когда строка была обновлена. Я также хотел, чтобы пользователь не мог изменять эти столбцы напрямую. Вот что я сделал:
Добавлены две колонки в моей таблице как обнуляемого столбцов SMALLDATETIME:
RecordCreated SMALLDATETIME,
LastModified SMALLDATETIME
Создано ПОСЛЕ триггер для таблицы:
CREATE TRIGGER dbo.WidgetProductionTrigger ON dbo.WidgetProduction AFTER INSERT, UPDATE AS BEGIN
Спусковой механизм сначала проверяет, если пользователь попытался вставить/изменить значения моих столбцов. Я столкнулся с проблемой, с функцией UPDATE() всегда возвращает истину, так что требовалось немного больше логики:
DECLARE @RecordCreated SMALLDATETIME;
SELECT @RecordCreated = RecordCreated FROM INSERTED;
IF UPDATE(RecordCreated) AND NOT @RecordCreated IS NULL BEGIN
RAISERROR('RecordCreated is not user maintainable.', 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END;
DECLARE @LastModified SMALLDATETIME;
SELECT @LastModified = LastModified FROM INSERTED;
IF UPDATE(LastModified) AND NOT @LastModified IS NULL BEGIN
RAISERROR('LastModified is not user maintainable.', 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END;
Далее, у меня есть логика, чтобы добавить требуемые значения в столбцах после каждой вставки или обновления. Я проверяю, чтобы увидеть, если запись вставляется или обновление и выполнить соответствующую логику:
IF EXISTS (SELECT * FROM DELETED) BEGIN
UPDATE dbo.WidgetProduction SET
LastModified = CAST(GETDATE() AS SMALLDATETIME)
WHERE ProductionRecordID IN (SELECT ProductionRecordID FROM INSERTED);
END ELSE BEGIN
UPDATE dbo.WidgetProduction SET
RecordCreated = CAST(GETDATE() AS SMALLDATETIME),
LastModified = CAST(GETDATE() AS SMALLDATETIME)
WHERE ProductionRecordID IN (SELECT ProductionRecordID FROM INSERTED);
END;
Это решение работает так, как ожидалось.
Я надеялся избежать необходимости откатов и просто так, чтобы она не могла быть написана в. Мне нравится ваш ответ. Другой способ сделать это - сделать вместо триггера, как показано ниже, но это нужно поддерживать с таблицей. Я не уверен, что было бы лучше. – GordyII