【问题标题】:Table Audit Trigger with Stored Procedure ID具有存储过程 ID 的表审计触发器
【发布时间】:2017-06-22 06:20:25
【问题描述】:

我有一个由多层深的存储过程启动的过程。最多可能涉及 12 个后续存储过程。

我有一个表在上述过程中错误地更新了列,我想知道是哪个存储过程导致错误更新。

我通过触发器查看了表审计,并尝试使用 SCOPE_IDENTITY 函数来确定哪个存储过程是罪魁祸首,但它向我的审计表返回了一个 NULL 值。

我正在尝试做的事情可能吗?我基本上是在尝试使用它而不是调试,过去我的成功有限,而且我不想编辑存储过程来捕获信息。

这是我的代码:我创建了一个测试存储过程来更新相关表。

    --Create test Sproc

    IF EXISTS (SELECT * FROM sys.objects (NOLOCK) WHERE name LIKE 'usp_update_pkd')
    BEGIN 
      DROP PROCEDURE usp_update_pkd
    END
    GO

    CREATE PROCEDURE usp_update_pkd
    @p_order_number VARCHAR(30)

    AS

    UPDATE t_pick_detail
    SET status =  'XXX'
    WHERE order_number = @p_order_number
    RETURN
    GO


    --Create Audit Table
    IF EXISTS (SELECT * FROM sys.objects (NOLOCK) WHERE name LIKE 't_pkd_audit')
      BEGIN 
        DROP TABLE t_pkd_audit
      END
    GO
    CREATE TABLE t_pkd_audit
    (
      order_audit_id INTEGER IDENTITY(1,1) PRIMARY KEY,
      wave_id        VARCHAR(10),
      work_type      VARCHAR(20),
      order_number   VARCHAR(20),
      sproc_id       NVARCHAR(128),
      updated_on     DATETIME
    )
    GO

      --Create Trigger
      IF EXISTS (SELECT * FROM sys.objects (NOLOCK) WHERE name LIKE 'pkd_audit_record') 
    BEGIN 
      DROP TRIGGER pkd_audit_record
    END
    GO

    CREATE TRIGGER pkd_audit_record ON t_pick_detail
    AFTER UPDATE
    AS
    BEGIN
      INSERT INTO t_pkd_audit 
      (wave_id, work_type, order_number, sproc_id, updated_on )
      SELECT DISTINCT i.wave_id, i.work_type, i.order_number, CAST(SCOPE_IDENTITY() AS VARCHAR), GETDATE() 
      FROM  t_pick_detail t 
      INNER JOIN inserted i
      ON  t.order_number = i.order_number
      AND t.line_number  = i.line_number 
    END
    GO

    --Execute test SProc
    EXEC usp_update_pkd '4045'

    --Check Results
    SELECT * FROM t_pkd_audit (NOLOCK)

--Result Set
order_audit_id|wave_id|work_type|order_number|sproc_id|updated_on
1             |NULL   |17       |4045        |NULL    |2017-06-22 00:47:52.513

非常感谢任何帮助。

【问题讨论】:

  • 您尝试过 context_info 吗? docs.microsoft.com/en-us/sql/t-sql/functions/…
  • 嗨,彼得,根据我的阅读,这将需要我修改相关存储过程并在其源代码中设置 context_info 值。我的理解正确吗?如果 SQL 服务器在执行 DML 时没有其他方式隐式跟踪它所在的过程,那么这可能会起作用。

标签: sql-server stored-procedures database-trigger audit-trail


【解决方案1】:

将包含存储过程名称的列添加到您的审计表中。因为它有一个默认值,你不需要改变你的触发器,但你可以删除 sproc_id 如果你喜欢。默认值将采用存储在 context_info 中的 @@PROCID 并使用它来获取存储过程名称。

CREATE TABLE t_pkd_audit
(
    order_audit_id INTEGER IDENTITY(1,1) PRIMARY KEY,
    wave_id        VARCHAR(10),
    work_type      VARCHAR(20),
    order_number   VARCHAR(20),
    sproc_id       NVARCHAR(128),
    updated_on     DATETIME,
    SpName [varchar](128) NULL CONSTRAINT [DF_a_hist_sourceName]  DEFAULT (object_name(CONVERT([int],CONVERT([varbinary](4),context_info()))))
)

对于 12 个存储过程中的每一个,从以下开始:

declare @calledBy varbinary(128) = coalesce(Context_info(),0),@proc int
select @proc = @@PROCID
set context_info @proc

它将存储过程的id放在context_info中,并将父存储过程的id存储在一个变量中。

在每个存储过程结束时。如果您使用返回,则在每次返回之前添加以下代码以将父存储过程的 id 写回 context_info。

set context_info @calledby

【讨论】:

  • 感谢彼得,在阅读了您的第一条评论后,我离开并尝试了一些东西,基本上得到了您提交的答案。再次感谢您的帮助。我从应用程序触发了这个过程,当它完成时,发现审计表中有违规的存储过程名称!发现并修复了错误!
猜你喜欢
  • 2011-02-09
  • 2011-12-29
  • 1970-01-01
  • 2014-04-19
  • 2021-06-22
  • 2021-06-05
  • 1970-01-01
  • 2016-11-06
相关资源
最近更新 更多