Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
不可变SQL列_Sql_Sql Server_Sql Server 2008_Ddl - Fatal编程技术网

不可变SQL列

不可变SQL列,sql,sql-server,sql-server-2008,ddl,Sql,Sql Server,Sql Server 2008,Ddl,是否可以在MSSQL中将列标记为不可变 似乎这将是一个有用的DDL特性;一旦在定义为与主键的特定值关系的行“row”中设置了值,则在不删除该行的情况下无法更改该值 显然,与大多数事情一样,这在应用程序层是完全可行的,但SQL DDL的一半乐趣在于检查应用程序代码的错误。据我所知,这在DDL中是不可能的。但是,您可以实现更新前触发器以满足您的需求。在更新前触发器中,您可以引发异常或执行任何您想要的操作,而不是更新行。否,SQL Server中没有此类功能 我能想到的最接近的是表上的更新触发器,它检

是否可以在MSSQL中将列标记为不可变

似乎这将是一个有用的DDL特性;一旦在定义为与主键的特定值关系的行“row”中设置了值,则在不删除该行的情况下无法更改该值


显然,与大多数事情一样,这在应用程序层是完全可行的,但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