SQL触发器可以防止位列从1更新为0?

时间:2012-05-17 19:13:52

标签: sql sql-server-2008

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

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

触发器必须适用于多个更新,例如:

UPDATE Table SET BitField = 0

BitField = 1的任何行都应该失败。

编辑:为了给出一些背景知识,有问题的位/标记标记是否需要处理货币交易。如果位= 1,则事务已处理完毕。如果该位重置为0,则事务可能会重复,因此我需要在数据库级别强制执行该位不能重置为0.

我需要防止针对数据库运行的直接查询以及应用程序级错误。我无法确定是否总是会使用存储过程来更新表,因此我认为触发器是强制执行此逻辑的唯一方法。

3 个答案:

答案 0 :(得分:4)

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

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 

答案 1 :(得分:2)

一种方法是使用触发器来进行所有更新,除了在等于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 

答案 2 :(得分:2)

我不会把它埋在触发器中。我有你的存储过程(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的查询)将小偷(错误)赶出家门。改为锁上前门;)