SQL Server 2014 触发器及其创建位置

ape*_*esa 1 sql-server

我使用的是 SQL Server 2014 标准版。我正在开发一个供应链 DW,我目前正在构建一个登陆模式,该模式将用于登陆来自源系统的数据,然后将该数据移动到暂存模式以开始 ETL 过程。在将那几天的数据移入 Staging 后,我正在截断登录表。我在触发器中使用 Hashbytes,它将向每个记录添加一个哈希值,以便在向上游移动时进行比较。

CREATE TRIGGER trgr_hashval_mara ON land.mara
FOR UPDATE, INSERT AS
UPDATE land.mara
SET HashVal = (SELECT hashbytes('md5', (SELECT material, MaterialDesc FOR xml raw)));
Run Code Online (Sandbox Code Playgroud)

我可以整天创建这些,但我无法使用如下的常规语法删除它们。执行 DROP 语句会产生错误。

 DROP TRIGGER trgr_hashval_mara;
Run Code Online (Sandbox Code Playgroud)

"Can't find trigger or you don't have permission to drop trigger."

但是,以下语句返回了我创建的触发器列表。

select * from ibscm01.sys.triggers
Run Code Online (Sandbox Code Playgroud)

我似乎也无法在 DB 树中找到它们。我看到了 Database Triggers 子项,但没有显示项目/触发器。我正在使用 Toad for SQL server 6.7,它应该是当前版本。还使用带有 AD 的 Windows 身份验证,并且我具有 dbo 权限。

在此处输入图片说明

谢谢,帕特

Sol*_*zky 5

触发器将与创建它们的表位于同一架构中。如果 Schema 未在CREATE TRIGGER语句中指定,则会自动处理,或者如果已指定但与表的 Schema 不同,则强制执行。CREATE TRIGGER的 MSDN 文档指出:

DML 触发器的范围限定为创建它们的表或视图的架构。

一个简单的测试证实了这条规则的执行:

CREATE SCHEMA [TriggerTest];
GO

CREATE TABLE dbo.TriggerSchemaTest (Col1 INT);
GO

CREATE TRIGGER [TriggerTest].[DifferentSchemaThanTable]
ON [dbo].[TriggerSchemaTest]
AFTER INSERT
AS
BEGIN
  DECLARE @DoNothing INT;
END;
GO
Run Code Online (Sandbox Code Playgroud)

产生以下错误:

消息 2103,级别 15,状态 1,过程 DifferentSchemaThanTable,第 6 行
无法创建触发器“TriggerTest.DifferentSchemaThanTable”,因为其架构与目标表或视图的架构不同。


根据DROP TRIGGER的 SQL Server 2012 & 2014 MSDN 页面,删除触发器的语法是(基本上):

DROP TRIGGER [schema_name.]trigger_name;
Run Code Online (Sandbox Code Playgroud)

因此,如果您想知道特定触发器(及其父表)所在的架构,请使用以下查询:

SELECT ss.[name] AS [TableAndTriggerSchemaName],
       so.[name] AS [TriggerName],
       st.[name] AS [TableName]
FROM   sys.objects so
INNER JOIN sys.schemas ss
        ON ss.[schema_id] = so.[schema_id]
INNER JOIN sys.tables st
        ON st.[object_id] = so.[parent_object_id]
WHERE  so.[name] = N'trgr_hashval_mara';
Run Code Online (Sandbox Code Playgroud)

还:

  • 这就是为什么在创建 Schema 绑定对象时最好始终指定 Schema 名称(而不是依赖于默认行为)的原因之一(可读性)。因此你应该使用:CREATE TRIGGER land.trgr_hashval_mara ON land.mara...
  • 如果那是您的整个实际 Trigger 代码,则存在一个大问题:它正在为每个INSERTandUPDATE语句更新表的所有行。这真的是我们想要的吗?您需要加入INSERTED伪表,以便仅更新实际更改的行。
  • 您可能希望SET NOCOUNT ON;在每个触发器的顶部添加。