我在SQL Server 2005数据库的表中有一个“InsertTime”字段,当首次将记录插入数据库时,该字段默认为“getDate()”。我想确保此列不会再次更新。
可以将此列设置为readonly,还是有更好的方法可以在不为开发人员编写所有sql的情况下执行此操作?
答案 0 :(得分:4)
您可以通过创建UPDATE触发器来实现'只读'字段,该触发器检查该列的更新,然后将其回滚。
IF EXISTS (SELECT name FROM sys.objects
WHERE name = 'ReadOnlyInsertTime_tr' AND type = 'TR')
DROP TRIGGER dbo.ReadOnlyInsertTime_tr;
GO
CREATE TRIGGER ReadOnlyInsertTime_tr
ON dbo.MyTable
AFTER UPDATE
AS
IF (UPDATE(InsertTime))
BEGIN
ROLLBACK
-- Raise an informative error
-- RAISERROR (50009, 16, 10)
END;
GO
答案 1 :(得分:2)
另一种方法是重新创建InsertDate的原始值。 更新行时,原始行将移动到(逻辑)“已删除”表。 所以...
ALTER TRIGGER trgDocuments
ON dbo.Documents
FOR INSERT, UPDATE
AS
-- For new records set the created date and the updated date to Now
UPDATE Documents SET DateCreated = GetDate(), DateUpdated = GetDate() Where DocumentId in (SELECT DocumentId From inserted)
-- For updated records set the created date to the original created date and the updated date to Now
UPDATE Documents SET DateCreated = (SELECT DateCreated FROM deleted d WHERE DocumentId = d.DocumentId) Where DocumentId in (SELECT DocumentId From deleted)
UPDATE Documents SET DateUpdated = GetDate() Where DocumentId in (SELECT DocumentId From deleted)
答案 2 :(得分:1)
而不是触发器也可以完成这项工作。
CREATE TRIGGER [dbo].[MyTableUpdateTrigger]
ON [dbo].[MyTable]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON
UPDATE MyTable
SET Column1 = Inserted.Column1
,Column2 = Inserted.Column2
-- Don't set this for the "InsertTime" field.
FROM Inserted
INNER JOIN MyTable
ON Inserted.TheKey = MyTable.TheKey
END
答案 3 :(得分:1)
编写存储过程以在此表中执行Update,并确保它不会触及InsertTime字段。 然后设置所有用户的权限,以便他们自己不能在此表上执行原始更新,但可以调用存储过程。
答案 4 :(得分:0)
我最近为此实施了一个非常类似的解决方案,并且必须解决许多障碍,所以我在这里发布解决方案,希望它会有所帮助。
我想要做的是拥有一个由数据库而不是用户代理管理的RecordCreated和LastModified列。在这种情况下,RecordCreated将是首次插入行时的日期时间,而LastModified将是最后一次更新行的时间。我还想阻止用户直接修改这些列。这是我做的:
在我的表中添加了两列作为可空的SMALLDATETIME列:
RecordCreated SMALLDATETIME,
LastModified SMALLDATETIME
为表格创建了一个AFTER触发器:
CREATE TRIGGER dbo.WidgetProductionTrigger ON dbo.WidgetProduction AFTER INSERT, UPDATE AS BEGIN
触发器首先检查用户是否尝试插入/修改列的值。我遇到UPDATE()函数总是返回true的问题,因此需要一些额外的逻辑:
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;
此解决方案完全按预期工作。
答案 5 :(得分:0)
使用计算列是其中一种解决方案,如本文所述:Computed Column with Current DateTime?