2010-01-20 93 views
5

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

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

+0

我希望,以避免回滚的需求,只是有它,这样它不能被写入。我喜欢你的答案。另一种做法是做一个如下所示的触发器,但必须在表中维护。我不确定哪个更好。 – GordyII

回答

1

编写一个存储过程在此表中进行更新,并确保它不触及InsertTime字段。 然后设置所有用户的权限,以便他们本身不能在此表上执行原始更新,但可以调用存储过程。

+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 
+0

+1我喜欢这个解决方案;我要补充的一件事是,如果你在'AFTER INSERT'触发器中写入'InsertTime',那么你需要在该触发器的持续时间内禁用该触发器。 – briantyler

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 
+0

那么如果用户尝试更新禁止列时如何提出错误? – Ian

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) 
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; 

此解决方案完全按照预期。