web-dev-qa-db-ja.com

トリガーをデータベースから削除できないのはなぜですか?

私が管理しているデータベースの1つは、データウェアハウスにデータを引き出すために復元する会社のベンダーによって提供されています。私は、データベースユーザーを通過し、ベンダーからすべてのユーザーを削除するストアドプロシージャを作成しています。 1人のユーザーがいて、これをuserxと呼びます。これは、このユーザーとして実行するように設定されているトリガーがあるため、削除できません。これをtrg_write_somethingと呼びます。私が走ると:

DROP TRIGGER trg_write_something

次のエラーメッセージが表示されます。

メッセージ50000、レベル16、状態1、プロシージャPreserveTrigger、行18
トリガー[trg_write_something]をデータベースから削除できません。


メッセージ3609、レベル16、状態2、手順trg_write_something、行4
トランザクションはトリガーで終了しました。バッチは中止されました。

トリガーを変更しようとすると、同じエラーが発生します。

3
Kevin Kelso

トランザクションは DDLトリガーPreserveTriggerでロールバックされます。削除しようとしているトリガーtrg_write_somethingではありません。これは、テーブルレベルのトリガーのコードとは関係がなく、権限も関係ありません。システム管理者は、DDLトリガーなどを盲目的にバイパスすることはできませんが、トリガーのコードが、何をすべきかを決定する前にユーザーのセキュリティレベルをチェックするように記述されている可能性があります(ただし、これは一般的ではありません)。もちろん、システム管理者がDDLトリガーを無効または削除するのは非常に簡単です。

DDLトリガー内でユーザー定義のエラーメッセージが表示され、その後に明示的なROLLBACK TRANSACTION;が続くため、これらの特定のエラーが表示されます。上記のコメントで、それはランタイムエラーが原因である可能性があることを述べましたが、DDLトリガーを発生させることができなかった場合を除いて、受信しているエラーメッセージのペアを生成する(または明示的なロールバックを強制する)には十分ではありませんバッチを終了するのに十分な重大なエラーレベル-16はそれを行いません)。

このDDLトリガーは次のようにして見つけることができます。

SELECT name
  FROM sys.triggers
  WHERE name = N'PreserveTrigger'
  AND parent_class_desc = N'DATABASE';

または、次のようなすべてのDDLトリガー:

SELECT name
  FROM sys.triggers
  WHERE parent_class_desc = N'DATABASE';

(オブジェクトエクスプローラーのProgrammability > Database Triggersでも確認できます。)

そして、あなたはこの方法でコードを見ることができます(おそらくあなたはそれを落とす前に行うべきです-おそらくそれが現在この特定のトリガーを落とすあなたの邪魔になっているとしても、それは理由のためにそこにあります):

SELECT m.[definition]
  FROM sys.sql_modules AS m
  INNER JOIN sys.triggers AS t
  ON m.[object_id] = t.[object_id]
  WHERE t.name = N'PreserveTrigger';

または、オブジェクトエクスプローラーで右クリックしてScript Database Trigger As > CREATE To > New Query Editor Windowを選択します。

このように一時的にトリガーを無効にすることができます...

DISABLE TRIGGER PreserveTrigger ON DATABASE;

...繰り返しますが、これはおそらく単にドロップするよりも優れています/安全です。

4
Aaron Bertrand