web-dev-qa-db-ja.com

SYBASEで変更が行われていないときにUPDATE TRIGGERが起動しないようにする

Sybaseでは、メインテーブルtestと監査テーブル_test_a_があります。監査テーブルは、挿入、更新、削除のトリガーによって更新されます。今問題は、古いデータ(変更なし)で更新クエリを使用すると、トリガーがまだ発生し、監査テーブルに記録されます(変更がない場合の重複を防ぐため)。

test

_Id | NAME | DESC
_

_test_a_は

_updated_by | date | Id | NAME | DESC
_

これは私が持っている更新トリガーです:

_create trigger test_utrig on test for update as  
insert into audit..test_a select 'update',update_by(),getdate() inserted.* from inserted
_

if (update(Id) or update(NAME) or update(DESC))を使用しようとしましたが、変更がない場合でも更新トリガーが起動されます。変更が行われていないときにトリガーが発火しないようにする方法を教えてください。

3
samule

SyBaseはわかりませんが、 ドキュメント から、1つ以上の列が更新されているかどうかを確認できるように見えます。次のように更新されているかどうかを確認するだけで十分です。

create trigger test_utrig on test 
for update as  
    if update (id)
        insert into audit..test_a (updated_by, date, Id, ,NAME, DESC)
        select update_by(), getdate(), inserted.Id, inserted.NAME, inserted.DESC 
        from inserted

トリガーと監査テーブルの列数が一致していないようです。そのため、定数「update」を削除しました。

2
Lennart

insertedテーブルに情報があるかどうかだけでなく、deletedと異なるかどうかも確認する必要があります。

Test

Id | NAME | DESC

Test_a

Event | updated_by | date | Id | NAME | DESC

このトリガーは、IDが変更されるのを防ぎ、他の列に変更があるかどうかを確認します。変更がある場合は、Test_aテーブルに挿入します。

CREATE TRIGGER test_utrig on test for update as 
    IF UPDATE(Id)
    BEGIN
        raiserror 9000 "Can't change Id"
        RETURN
    END 
    INSERT INTO audit..test_a
    SELECT 'Update',
            update_by(),
            getdate(),
            i.* 
    FROM
        inserted i,
        deleted  d
    WHERE
        i.Id = d.Id
    AND (   i.NAME <> d.NAME
         OR i.DESC <> d.DESC)

それが役に立てば幸い。

1
Nicolas

サンプルトリガーはT-SQLのようですので、(IQ、SQLAnywhereまたはAdvantageとは対照的に)ASEを使用していることを前提としているので、fwiw ...

...「古いデータを使用してクエリを更新する(変更なし)」と述べましたが、更新ではデータの変更が実行されるため(古い値と新しい値が同じであっても)、ASEでは矛盾します。

次を実行するとします。

_update tableA
set    col1 = 5
where  col1 = 5
_

論理的に列が更新/変更されていないと言えるかもしれません。

しかし技術的に更新されました、つまり、Sybase ASE willの更新を実行しますカラム。つまり、_col1_が「set」句のターゲットとして表示された場合、if update(col1)...は常にtrueを返します。

Sybase ASEはnotを実行して古い値と新しい値を比較し、同じ値が参照されている場合は更新を「無視」します。そして、いいえ、これは愚かな/ばかげたソフトウェアの場合ではなく、むしろあなたがそれを行うように命じているソフトウェアの場合です。

この種の更新が何らかの下流のアクティビティを強制するために使用されることが何度かありました。簡単な例の1つは、表示プログラムの「最終更新」フラグの更新を強制することです(価格が変更されていなくても、「最終更新」の日付/タイムスタンプを定期的に更新する株価/為替ティッカーを考えてください。したがって、ディスプレイがフリーズ/ハングしていないことをユーザーに通知します)。

また、(T-SQL)プログラマーが注意を払っていなかったために、不要な更新でCPUサイクルを無駄にしたことも何度かありました。 [インデックスエントリを削除してから(再)挿入する必要があるため、更新された列がインデックスの一部である場合は、特に顕著になります。このため、(低速またはパフォーマンスの低い)遅延更新が発生します。]

更新を実行しない場合は、トリガーをコーディングして、列の古い/削除された値と新しい/挿入された値を比較し、適切であると考えるものを実行する必要があります。

1
markp-fuso