我在SQL Server 2005数据库中的表中有一个“插入时间”字段,该数据库在记录首次插入数据库时默认为“getDate()”。我想确保这一列不再更新。SQL Server 2005 - 将列设置为只读
可以将此列设置为只读吗?还是有更好的方法可以在不为开发人员编写所有SQL的情况下执行此操作?
我在SQL Server 2005数据库中的表中有一个“插入时间”字段,该数据库在记录首次插入数据库时默认为“getDate()”。我想确保这一列不再更新。SQL Server 2005 - 将列设置为只读
可以将此列设置为只读吗?还是有更好的方法可以在不为开发人员编写所有SQL的情况下执行此操作?
编写一个存储过程在此表中进行更新,并确保它不触及InsertTime字段。 然后设置所有用户的权限,以便他们本身不能在此表上执行原始更新,但可以调用存储过程。
并让开发人员编写存储过程。 –
您可以通过创建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我喜欢这个解决方案;我要补充的一件事是,如果你在'AFTER INSERT'触发器中写入'InsertTime',那么你需要在该触发器的持续时间内禁用该触发器。 – briantyler
而不是触发器也可以做这个工作。
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
那么如果用户尝试更新禁止列时如何提出错误? – Ian
另一种方法是重新创建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)
最近我实现了一个非常类似的解决方案,这一点,必须通过一些障碍的工作,所以我在这里张贴的解决方案,希望这将有助于。
我想要做的是有一个由数据库而不是用户代理管理的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;
此解决方案完全按照预期。
使用计算列是解决方案之一,因为在这个岗位解释说:Computed Column with Current DateTime?
我希望,以避免回滚的需求,只是有它,这样它不能被写入。我喜欢你的答案。另一种做法是做一个如下所示的触发器,但必须在表中维护。我不确定哪个更好。 – GordyII