SQL触发器阻止位列从1更新为0?

问题描述:

在SQL Server 2008中给定一个具有位类型的列,如何编写触发器以允许从0更新为1,但不允许从1更新为0?SQL触发器阻止位列从1更新为0?

换句话说,一旦该位被设置为1,它应该始终为1

触发器必须努力多个更新,例如:

UPDATE Table SET BitField = 0 

如果失败的任何行,其中位域= 1

编辑:为了给出一些背景下,问号比特/标志是否需要被处理货币交易。如果该位= 1,则该事务已经被处理。如果该位重置为0,则该事务可能会被复制,因此我需要在数据库级别强制该位不能重置为0.

我需要防止针对数据库运行的直接查询作为应用程序级别的错误。我不能确定存储过程总是用来更新表,所以我认为触发器是执行这一逻辑的唯一方法。

+0

看看'INSTEAD OF'触发器 – Lamak

+1

这是一个免费的自动售货机! –

+2

@HLGEM - 有时候一个问题很简单,但在海报的知识基础之外,他们不知道该怎么去尝试 - 没关系。 – RThomas

看起来,你是需要一个简单的触发后

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

如果您想对其进行优化并且对违规次数不感兴趣,您可以使用EXISTS运算符。 – buckley

+0

我会实际上使用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的查询)得到英寸锁定前门,而不是;)

+0

优秀的+1点 - 我在实际的问题中陷入了困境。 – RThomas

+0

@HardCode,好点,但我试图阻止某人直接执行查询(通过SSMS或其他方式)。我的应用程序已经为用户强制实施必要的逻辑,所以我更关心某人,可能是偶然的,用一个直接查询来改变数据,比如“UPDATE Table SET BitField = 0”。我可能应该在问题中包含这些信息。 –

+0

那么在那种情况下,是的,你需要一个触发器。 – HardCode