SQL触发器阻止位列从1更新为0?
在SQL Server 2008中给定一个具有位类型的列,如何编写触发器以允许从0更新为1,但不允许从1更新为0?SQL触发器阻止位列从1更新为0?
换句话说,一旦该位被设置为1,它应该始终为1
触发器必须努力多个更新,例如:
UPDATE Table SET BitField = 0
如果失败的任何行,其中位域= 1
编辑:为了给出一些背景下,问号比特/标志是否需要被处理货币交易。如果该位= 1,则该事务已经被处理。如果该位重置为0,则该事务可能会被复制,因此我需要在数据库级别强制该位不能重置为0.
我需要防止针对数据库运行的直接查询作为应用程序级别的错误。我不能确定存储过程总是用来更新表,所以我认为触发器是执行这一逻辑的唯一方法。
看起来,你是需要一个简单的触发后
CREATE TABLE YourTable(
PK int Primary key,
bitCol bit
)
CREATE TRIGGER YourTableTrigger
ON YourTable
AFTER UPDATE
AS
DECLARE @nrOfViolations int
select @nrOfViolations = count(*) from deleted d
join YourTable t on d.PK = t.PK
where d.bitCol = 1 and t.bitCol = 0
if @nrOfViolations > 0
BEGIN
RAISERROR('Failed', 16, 1);
ROLLBACK TRANSACTION
END
如果您想对其进行优化并且对违规次数不感兴趣,您可以使用EXISTS运算符。 – buckley
我会实际上使用EXISTS来实现它。另一方面,如果OP曾决定记录失败的更新,那么知道违规数量可能会有用,并且您的答案显示如何获取该数字。 –
一种方式将是一个替代触发器,通过让所有的更新,除了任何改变位域,一旦它等于1。在该它可以让所有更新通过,除了位域更改。
CREATE TRIGGER OneWayBitChange
ON YourTable
INSTEAD OF UPDATE
AS
BEGIN
UPDATE YourTable SET /* update all fields from original update except bitfield */
Field1 = i.Field1,
Field2 = i.Field2,
Field3 = i.Field3
FROM YourTable
INNER JOIN Inserted i ON i.PrimaryKey = YourTable.PrimaryKey
UPDATE YourTable SET /* update bitfield only if it's not already a 1 */
BitField = i.BitField
FROM YourTable
INNER JOIN Inserted i ON i.PrimaryKey = YourTable.PrimaryKey
WHERE IsNull(YourTable.BitField,0) < 1
END
GO
以上将允许所有更新接受一个字段从1去别的(0或null)时。
如果你想取消该行的任何更新当试图对位领域取得了可以修改的身体是这样的:
UPDATE YourTable SET /* update all except bitfield changes from 1 to 0 */
Field1 = i.Field1,
Field2 = i.Field2,
Field3 = i.Field3,
BitField = i.BitField
FROM YourTable
INNER JOIN Inserted i ON i.PrimaryKey = YourTable.PrimaryKey
WHERE IsNull(BitField,0) = 0 OR IsNull(i.BitField,0) = 1
我不会在触发埋葬。我会让你的存储过程(SP)更新表格来检查值。例如:
CREATE PROCEDURE dbo.proc_update_my_table
@id AS INT,
-- Whatever other params you need
@the_bit_field AS BIT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @existing_value AS BIT
SELECT @existing_value = the_bit_field FROM dbo.Table1 t WHERE t.id = @id
IF @existing_value = 1 AND @the_bit_field = 0
BEGIN
RAISERROR('Fail.', 10, 1)
RETURN -1
END
-- Update the table as normal.
END
GO
使用触发器是一种像试图让小偷(错误)出了家门后,他通过敞开的大门(SP的查询)得到英寸锁定前门,而不是;)
看看'INSTEAD OF'触发器 – Lamak
这是一个免费的自动售货机! –
@HLGEM - 有时候一个问题很简单,但在海报的知识基础之外,他们不知道该怎么去尝试 - 没关系。 – RThomas