2

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

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

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

UPDATE Table SET BitField = 0

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

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

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

4

3 回答 3

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 
于 2012-05-17T19:20:32.727 回答
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 
于 2012-05-17T19:43:17.127 回答
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 的查询)进入后试图让他离开房子。而是锁上前门;)

于 2012-05-17T19:57:54.567 回答