2012-04-09 32 views
10

MS SQL Server 2008 R2では、実行中の挿入/更新を何かをチェックして許可またはロールバックする(raiserrorを介して)事前挿入および事前更新トリガーが必要です。トリガーからのトランザクションのロールバック

質問INSTEAD OFでトリガーします。実際に挿入または更新を明示的に記述する必要がありますか?デフォルトの挿入または更新を実行し、「事前チェック」だけを実行する必要があるためです。

+0

「事前チェック」の本質とは何ですか?トリガには、 'inserted' /' deleted'テーブルを管理するオーバーヘッドがあります。それは別の方法で実施することができるものですか? –

+0

私たちが必要とするのは、1つの列の空の文字列を無視してトリプル(3列)に固有の制約です。 – Cartesius00

+0

タプル '(a、b、c)'の場合、 'c'が空文字列の値を持つ場合、ユニーク制約の目的でそのタプルを完全に無視しますか? –

答えて

9

はい。

明示的にはINSERTまたはUPDATEと記述する必要があります。

トリガーは、DML操作INSTEAD OFを実行します。トリガーをブランクのままにしておくと、INSERTED/DELETEDテーブルが作成され、入力されている以外は何も起こりません。tempdb

コメントの議論から、私はこれをトリガすることは一切ありませんが、ユニークなフィルタリングされたインデックスCREATE UNIQUE INDEX ix ON T(a,b,c) WHERE c <> ''を使用します。これは、パフォーマンスが向上し、並行処理を行う際に潜在的なロジックの問題を回避する可能性が高くなります。

+0

ありがとうございます。これらのDML操作で挿入された行と更新された行の別名はなんですか? – Cartesius00

+0

@James - 'INSERTED'と' DELETED'ですが、これらはテーブルではありません。トリガは文ごとに1回発生します。だから、 'INSERT INTO YourTable SELECT * FROM INSERTED'は典型的な' INSERT'のトリガーとなります。 –

+0

'YourTable'にID列と他の多くの列が含まれているとどうなりますか? 'SELECT *'は問題ですね。 – Cartesius00

3

実際に挿入または更新する場合を除き、INSTEAD OFトリガは不要です。あなたの場合は、代わりにFOR INSERT, UPDATEトリガーが必要です。

この例のトリガーは、誰かがtitlesテーブルにデータを追加または変更しようとすると、クライアントにメッセージを出力します。

USE pubs 
IF EXISTS (SELECT name FROM sysobjects 
     WHERE name = 'reminder' AND type = 'TR') 
    DROP TRIGGER reminder 
GO 
CREATE TRIGGER reminder 
ON titles 
FOR INSERT, UPDATE 
AS RAISERROR ('inserts and updates to the titles table is not allowed', 16, 1) 
GO 

また、同様IF EXISTSまたはCOLUMNS_UPDATEDのようなものを使用することができます。

ここでは、ロールバックを使用する別の例を示します。

USE pubs 
IF EXISTS (SELECT name FROM sysobjects 
     WHERE name = 'employee_insupd' AND type = 'TR') 
    DROP TRIGGER employee_insupd 
GO 
CREATE TRIGGER employee_insupd 
ON employee 
FOR INSERT, UPDATE 
AS 
/* Get the range of level for this job type from the jobs table. */ 
DECLARE @min_lvl tinyint, 
    @max_lvl tinyint, 
    @emp_lvl tinyint, 
    @job_id smallint 
SELECT @min_lvl = min_lvl, 
    @max_lvl = max_lvl, 
    @emp_lvl = i.job_lvl, 
    @job_id = i.job_id 
FROM employee e INNER JOIN inserted i ON e.emp_id = i.emp_id 
    JOIN jobs j ON j.job_id = i.job_id 
IF (@job_id = 1) and (@emp_lvl <> 10) 
BEGIN 
    RAISERROR ('Job id 1 expects the default level of 10.', 16, 1) 
    ROLLBACK TRANSACTION 
END 
ELSE 
IF NOT (@emp_lvl BETWEEN @min_lvl AND @max_lvl) 
BEGIN 
    RAISERROR ('The level for job_id:%d should be between %d and %d.', 
     16, 1, @job_id, @min_lvl, @max_lvl) 
    ROLLBACK TRANSACTION 
END 

私はあなたが取引を持っているかいないかどうかわからないんだけど、あなたのケースでは、次のような何かをしたいと思う:

USE myDatabase 

    IF EXISTS (SELECT name FROM sysobjects 
      WHERE name = 'myTable' AND type = 'TR') 
     DROP TRIGGER tr_myTrigger 
    GO 
    CREATE TRIGGER tr_myTrigger 
    ON myTable 
    FOR INSERT, UPDATE 
    AS 

if(exists(select * from inserted where rtrim(c) <> '')) 
begin 
    -- check to make sure the insert(s) are unique 

    if(exists(
     select * from inserted i 
     join dbo.myTable t on i.a = t.a and i.b = t.b and i.c = t.c) 

    begin 
     raiserror('Duplicate(s) found', 16, 1) 
     rollback transaction 
    end 
end 
関連する問題