MS SQL Server 2008 R2では、実行中の挿入/更新を何かをチェックして許可またはロールバックする(raiserror
を介して)事前挿入および事前更新トリガーが必要です。トリガーからのトランザクションのロールバック
質問:INSTEAD OF
でトリガーします。実際に挿入または更新を明示的に記述する必要がありますか?デフォルトの挿入または更新を実行し、「事前チェック」だけを実行する必要があるためです。
MS SQL Server 2008 R2では、実行中の挿入/更新を何かをチェックして許可またはロールバックする(raiserror
を介して)事前挿入および事前更新トリガーが必要です。トリガーからのトランザクションのロールバック
質問:INSTEAD OF
でトリガーします。実際に挿入または更新を明示的に記述する必要がありますか?デフォルトの挿入または更新を実行し、「事前チェック」だけを実行する必要があるためです。
はい。
明示的にはINSERT
またはUPDATE
と記述する必要があります。
トリガーは、DML操作INSTEAD OF
を実行します。トリガーをブランクのままにしておくと、INSERTED
/DELETED
テーブルが作成され、入力されている以外は何も起こりません。tempdb
。
コメントの議論から、私はこれをトリガすることは一切ありませんが、ユニークなフィルタリングされたインデックスCREATE UNIQUE INDEX ix ON T(a,b,c) WHERE c <> ''
を使用します。これは、パフォーマンスが向上し、並行処理を行う際に潜在的なロジックの問題を回避する可能性が高くなります。
ありがとうございます。これらのDML操作で挿入された行と更新された行の別名はなんですか? – Cartesius00
@James - 'INSERTED'と' DELETED'ですが、これらはテーブルではありません。トリガは文ごとに1回発生します。だから、 'INSERT INTO YourTable SELECT * FROM INSERTED'は典型的な' INSERT'のトリガーとなります。 –
'YourTable'にID列と他の多くの列が含まれているとどうなりますか? 'SELECT *'は問題ですね。 – Cartesius00
実際に挿入または更新する場合を除き、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
「事前チェック」の本質とは何ですか?トリガには、 'inserted' /' deleted'テーブルを管理するオーバーヘッドがあります。それは別の方法で実施することができるものですか? –
私たちが必要とするのは、1つの列の空の文字列を無視してトリプル(3列)に固有の制約です。 – Cartesius00
タプル '(a、b、c)'の場合、 'c'が空文字列の値を持つ場合、ユニーク制約の目的でそのタプルを完全に無視しますか? –