SQL Server 2005 - 将列设置为只读

时间:2010-01-20 02:55:36

标签: sql-server sql-server-2005

我在SQL Server 2005数据库的表中有一个“InsertTime”字段,当首次将记录插入数据库时​​,该字段默认为“getDate()”。我想确保此列不会再次更新。

可以将此列设置为readonly,还是有更好的方法可以在不为开发人员编写所有sql的情况下执行此操作?

6 个答案:

答案 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?