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つの方法は、トリガーの代わりに、ビットフィールドが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)に移行するときに、すべての更新が1つのフィールドを受け入れることを許可します。

ビットフィールドで試行が行われたときにその行の更新をキャンセルする場合は、次のように本文を変更できます。

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 に答える