tSQL 触发逻辑,最好有 IF 子句,还是 IN 子句?

Posted

技术标签:

【中文标题】tSQL 触发逻辑,最好有 IF 子句,还是 IN 子句?【英文标题】:tSQL Trigger Logic, better to have IF clause, or IN clause? 【发布时间】:2014-04-09 15:43:42 【问题描述】:

我一直在尝试创建触发器来减少需要编写的客户端代码。我编写了以下两个 tSQL 触发器,它们似乎都产生了相同的结果,我只是想知道哪一个是更正确的方法。如果这有什么不同,我正在使用 SQL Server 2012。

哪一个使用更少的资源 执行速度更快 更安全地抵御攻击 等等……
CREATE TRIGGER tr_ProductGroup_INSERT_GroupMap
    ON [qmgmt].[dbo].[ProductGroup]
    After INSERT
AS
BEGIN
    if (
           select count([inserted].[groupID]) 
           from [inserted] 
           where [inserted].[groupID] = 1
       ) = 0
    begin
        insert into [qmgmt].[dbo].[GroupMap]([parentGroupID], [childGroupID])
        select  1, [inserted].[groupID]
        from [inserted]
    end
END
GO


CREATE TRIGGER tr_ProductGroup_INSERT_GroupMap
    ON [qmgmt].[dbo].[ProductGroup]
    After INSERT
AS
BEGIN
    insert into [qmgmt].[dbo].[GroupMap]([parentGroupID], [childGroupID])
    select  1, [inserted].[groupID]
    from [inserted]
    Where[inserted].[groupID] in 
        (
            select [inserted].[groupID] 
            from [inserted] 
            where [inserted].[groupID] <> 1
        )
END
GO

更新:

基于这里的一些 cmets 是我正在使用的插入。无论我使用哪个触发器,GroupMap 表的结果都是一样的。

insert into [qmgmt].[dbo].[ProductGroup]([groupName], [groupDescription]) values ('root', 'The root of all groups')
insert into [qmgmt].[dbo].[ProductGroup]([groupName], [groupDescription]) values ('orphans', 'This is where the members of deleted groups go')
insert into [qmgmt].[dbo].[ProductGroup]([groupName], [groupDescription]) values ('SMGMT', 'Support Management')
insert into [qmgmt].[dbo].[ProductGroup]([groupName], [groupDescription]) values ('ST1', 'Support Tier 1')
insert into [qmgmt].[dbo].[ProductGroup]([groupName], [groupDescription]) values ('ST2', ' Support Tier 2')
insert into [qmgmt].[dbo].[ProductGroup]([groupName], [groupDescription]) values ('ST3', 'Support Tier 3')
insert into [qmgmt].[dbo].[ProductGroup]([groupName], [groupDescription]) values ('SaaSMGMT', 'Express Management')
insert into [qmgmt].[dbo].[ProductGroup]([groupName], [groupDescription]) values ('SaaSSup', 'Support Express')

【问题讨论】:

您确实意识到这两个触发器的行为不同,对吧? (如果inserted 中有 2 行,[groupID] 1 有 2 行,[groupID] 2 有 1 行) 它真的做同样的事情吗?如果插入了 groupID = 1,则不会在第一个版本中插入任何内容。您从第二个版本中插入的所有 groupId 1 插入一些东西... 我在问题的末尾添加了插入内容。 @BrandonB。问题不在于您插入的内容。问题是你的 2 个触发器不做同样的事情。而不同的事情取决于你的 [inserted] 表中的内容。 @BrandonB 也许您缺少的是 [inserted] 理论上可以有多行。一次只考虑 SQL 可能会导致以后出现无法预料的问题。 【参考方案1】:

由于评论太小而无法放入此示例,因此我将其放入答案中。人们说您的触发器在功能上有所不同的原因是,尽管您的测试逐行插入,但当您在一次操作中向表中插入多行时,触发器也会触发。根据您的示例,您可以尝试以下操作:

insert into [qmgmt].[dbo].[ProductGroup]([groupName], [groupDescription]) 
SELECT 'root', 'The root of all groups'
UNION ALL
SELECT 'orphans', 'This is where the members of deleted groups go'
UNION ALL
SELECT 'SMGMT', 'Support Management'

执行此查询时,inserted 表将包含 3 行,并且(取决于数据)2 个触发器代码示例的结果可能会给出不同的结果。

别担心,这是一个常见的误解。 SQL 的经验法则是始终考虑记录集,而不是“带字段的单个记录”。


至于你的问题(是的,我想要一个真正的答案=)

我建议对第二个进行修改。

CREATE TRIGGER tr_ProductGroup_INSERT_GroupMap
    ON [qmgmt].[dbo].[ProductGroup]
    After INSERT
AS
BEGIN
    insert into [qmgmt].[dbo].[GroupMap]([parentGroupID], [childGroupID])
    select  1, [inserted].[groupID]
    from [inserted]
   where [inserted].[groupID] <> 1        
END

这样服务器只需要运行一次inserted,决定要“保留”哪些记录,然后立即将它们存储到目标表中。

现在的问题是,如果这符合您的要求......

【讨论】:

我特别喜欢您建议使用多行插入进行测试。创建触发器而不以这种方式测试是不负责任的。

以上是关于tSQL 触发逻辑,最好有 IF 子句,还是 IN 子句?的主要内容,如果未能解决你的问题,请参考以下文章

在 where 子句中使用 DATEADD 的 TSQL 性能问题

Where 子句 TSQL 中的 case 表达式

TSQL 分组集(Grouping Sets)

TSQL——on 子句的顺序是不是重要

TSQL order by 子句中排序列的多种写法

具有多个带有 AND 类型逻辑连接的 where IN 子句的配置单元查询