【问题标题】:How to debug a T-SQL trigger?如何调试 T-SQL 触发器?
【发布时间】:2020-05-26 20:55:58
【问题描述】:

我有一个表 t,它有一个名为 trgInsAfter 的“插入后”触发器。我究竟该如何调试它?我不是这方面的专家,所以执行的问题和步骤可能看起来很愚蠢。

到目前为止我执行的步骤是: 1. 通过SSMS 连接到server instance(使用Windows Admin 帐户)

  1. 在SSMS的左侧树中右键单击触发器节点并双击打开它,触发器的代码在一个新的查询窗口(称为Window-1)中打开为:blah....,

    ALTER TRIGGER trgInsAfter AS .... BEGIN ... END
    
  2. 打开另一个查询窗口(称为Window-2),输入sql在t表中插入一行:

    insert t(c1,c2) values(1,'aaa')
    
  3. 在 Window-1 中设置断点(在触发器的代码中)

  4. 在 Window-2 中设置断点(插入 SQL 代码)

  5. 当 Window-2 是当前窗口时,单击工具栏上的“调试”按钮

    插入 SQL 代码的断点被命中,但是当我查看 Window-1 时,触发器代码中的断点有一个工具提示说 'unable to bind SQL breakpoint, object containing the breakpoint not loaded'

我可以理解问题:SSMS 怎么知道 Window-1 中的代码是触发器

我想调试?我看不到在哪里告诉 SSMS '嘿,这个查询编辑器中的代码是表 t 的插入触发器的代码'

有什么建议吗?

谢谢

【问题讨论】:

标签: sql


【解决方案1】:

其实你想多了。

我首先在一个窗口中运行此查询(进行设置):

create table X(ID int not null)
create table Y(ID int not null)
go
create trigger T_X on X
after insert
as
    insert into Y(ID) select inserted.ID
go

然后我可以丢弃该窗口。我打开一个新的查询窗口,写:

insert into X(ID) values (1),(2)

并在该行设置断点。然后我启动调试器(Debug 从菜单或工具栏或 Alt-F5 中)并等待(有一段时间,调试器从来没有太快)让它到达那个断点。然后,在到达那里后,我选择Step Into (F11)。瞧(又稍等片刻)打开了一个新窗口,这是我的触发器,调试器停止的下一行代码是触发器中的insert into Y... 行。我现在可以在触发器中设置我想要的任何其他断点。

【讨论】:

  • 完美,F11 成功了!我想我已经使用 C++/C# 代码太久了,并且养成了加载所有相关源代码文件和预设断点的习惯 :(
  • 只想在包含触发器源代码的自动弹出窗口中添加它,它的路径格式如下:mssql:://mywin7pc\bdsql/mydemodb/?/=338100245 \//?/=id
  • 很遗憾,我无法在虚拟表 inserted 和 deleted 中看到值
  • @Santhos - 不仅仅是inserted 和deleted。您会发现在调试时没有简单的方法来检查任何表格内容。恐怕非常缺乏调试经验。
  • @Damien_The_Unbeliever 你是完全正确的。我已经决定采用不同的方法,创建了一个临时调试表,并且我正在使用插入、时间戳和一些辅助触发器以非常古老的方式进行调试。
【解决方案2】:

SSMS 中有一个 DEBUG 菜单,但您可能需要在服务器上才能进行调试,因此如果是远程访问,则可能不会对其进行设置。 该调试选项将允许您执行代码,并以这种方式进入触发器并对其进行调试(就像您调试大多数其他代码一样)。

如果无法访问调试菜单/功能,则必须“手动”调试:

首先通过将触发器的输入插入调试表来确保触发器正常运行。然后您可以验证它是否正确调用。 然后,您可以使用调试表中的值调试触发器的查询,就像调试任何其他 sql 查询一样。

【讨论】:

    【解决方案3】:

    我也无法Step Into,它会直接超过我的INSTEAD OF INSERT 触发器。所以我最终将触发器替换为:

    ALTER TRIGGER [MyView_Instead_Insert] 
       ON  [MyView] 
       INSTEAD OF INSERT
    AS 
    BEGIN
    SET NOCOUNT ON
    
    select * into temp from INSERTED
    
    END
    

    它创建了一个名为 temp 的表,其中的列名和值为 INSERTED。

    【讨论】:

    • 你拯救了我的一天。我真的很欣赏你的解决方案。非常感谢!
    【解决方案4】:

    无论出于何种原因,我都无法让@Damien_The_Unbeliever 的解决方案发挥作用。 至少,不在附加到表的触发器上。当我执行Step Into 时,它每次只执行查询,而无需进入触发器。

    然后我在这种方法的 cmets 中注意到,无论如何您都看不到任何表值。

    那么……

    我最终创建了一个通用调试表。

    USE [Your_DB]
    GO
    
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    SET ANSI_PADDING ON
    GO
    
    CREATE TABLE [dbo].[Debug_Table](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [Name] [varchar](60) NOT NULL,
        [Value] [sql_variant] NULL,
        [Description] [varchar](max) NULL,
        [Captured] [datetime] NOT NULL
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    
    GO
    
    SET ANSI_PADDING OFF
    GO
    

    然后在我的触发器中我做了这样的事情......

    DECLARE @ItemNum nvarchar(128)
    SELECT  @ItemNum = Item_Number FROM inserted
    
    DECLARE @debugOn as bit = 1
    -- Debug
        IF @debugOn = 1
        BEGIN
            INSERT INTO Debug_Table (Name, Value, Description, Captured)
            VALUES ( 'Item Number', @ItemNum, 'The item number from the inserted table in tr_VaultItemIterations_ZCode_Monitor.', GETDATE())
        END;
    -- End Debug
    

    从表中触发触发器后,我可以查看插入到 Debug_Table 中的任何变量。

    完成调试后,您可以通过将@debugOn 变量更改为0 轻松关闭调试插入,以防您将来需要再次调试;或者干脆删除调试代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-13
      • 2013-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-23
      相关资源
      最近更新 更多