不可变SQL列
是否可以在MSSQL中将列标记为不可变 似乎这将是一个有用的DDL特性;一旦在定义为与主键的特定值关系的行“row”中设置了值,则在不删除该行的情况下无法更改该值不可变SQL列,sql,sql-server,sql-server-2008,ddl,Sql,Sql Server,Sql Server 2008,Ddl,是否可以在MSSQL中将列标记为不可变 似乎这将是一个有用的DDL特性;一旦在定义为与主键的特定值关系的行“row”中设置了值,则在不删除该行的情况下无法更改该值 显然,与大多数事情一样,这在应用程序层是完全可行的,但SQL DDL的一半乐趣在于检查应用程序代码的错误。据我所知,这在DDL中是不可能的。但是,您可以实现更新前触发器以满足您的需求。在更新前触发器中,您可以引发异常或执行任何您想要的操作,而不是更新行。否,SQL Server中没有此类功能 我能想到的最接近的是表上的更新触发器,它检
显然,与大多数事情一样,这在应用程序层是完全可行的,但SQL DDL的一半乐趣在于检查应用程序代码的错误。据我所知,这在DDL中是不可能的。但是,您可以实现更新前触发器以满足您的需求。在更新前触发器中,您可以引发异常或执行任何您想要的操作,而不是更新行。否,SQL Server中没有此类功能
我能想到的最接近的是表上的更新触发器,它检查插入和删除的逻辑表的特定列中的值是否相同,并拒绝更改行的更新。如果执行DML的用户不是对象的所有者,而不是数据库本身的db_所有者,您可以只授予该表的插入权限,但不授予其更新权限: 假设一个id为col1,col2的表 通过这些授权,用户可以插入行并为所有三列提供值。他还可以更新id和col2列,但不能更新col1列
db_所有者和表的创建者/所有者可以始终更新所有列。我不知道是否有办法从这些ROLW中撤销该权限。另一种方法是拒绝对表的更新权限,并创建一个用户有权执行的存储过程,该过程不会更新不可变字段。可以使用如下更新触发器:
CREATE TRIGGER trgAfterUpdateAsset ON dbo.Asset
FOR UPDATE AS
IF UPDATE(AssetTypeID) AND EXISTS (SELECT * FROM inserted i JOIN deleted d ON i.ID = d.ID WHERE i.AssetTypeID <> d.AssetTypeID)
BEGIN
RAISERROR ('AssetTypeID cannot change.', 16, 1);
ROLLBACK TRAN
END
注意:该表有一个名为ID的主键列
只有当AssetTypeID的值更改时,我才会拒绝更新。因此,该列可能出现在更新中,如果它指定了旧值,则它将通过。我需要这种方法如果设置错误,您将如何修复它?如果执行DML的用户不是表的所有者,您可以撤销该列的更新权限。然后它只能被插入,但不再更新我知道这在PostgreSQL中是可能的,但还没有在SQL中尝试过Server@a_horse_with_no_name-对我来说这似乎是个答案。这听起来是个好主意,@jaraics已经编写了相应的代码。
CREATE TRIGGER trgAfterUpdateAsset ON dbo.Asset
FOR UPDATE AS
IF UPDATE(AssetTypeID) AND EXISTS (SELECT * FROM inserted i JOIN deleted d ON i.ID = d.ID WHERE i.AssetTypeID <> d.AssetTypeID)
BEGIN
RAISERROR ('AssetTypeID cannot change.', 16, 1);
ROLLBACK TRAN
END