审计表更新触发器无法使用存储过程工作

问题描述 投票:0回答:2

我有桌子

tblA

其上定义了一个触发器,如果更新了任何行,则会将更改写入审核表。

现在,如果在 SQL Server 上我右键单击并直接编辑一行,我会看到审核表中发生了更改。

如果我调用存储过程进行更新,我确实会看到

tblA
已更新,但更改的值不会进入审核表。看起来扳机根本没有被触发。

就触发触发器而言,直接编辑表或通过存储过程更新有什么区别。


Trigger 

USE [dbSuppHousing]
GO
/****** Object:  Trigger [dbo].[tblSurvey_trigger]    Script Date: 9/22/2015 2:32:51 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/* =============================================
 
 Create date: 08/27/15
 Description:   Trigger to Add audit records to audtSurvey
                        
// =============================================*/
ALTER TRIGGER [dbo].[tblSurvey_trigger] on [dbo].[tblSurvey] 

FOR UPDATE,DELETE

AS

SET NOCOUNT ON

Declare   @FieldName varchar(100)
        , @Deleted varchar(4000)
        , @Inserted varchar(4000)
        , @SurveyID numeric
        , @LoginName varchar(100)

Declare  @currentDate datetime = null                                   
SET @currentDate = getdate()

Set @Deleted = ''
Set @Inserted = ''

Select * into #Deleted From Deleted
Select * into #Inserted From Inserted

Create Table #DT ([NameValue] varchar(1000))
Create Table #IT ([NameValue] varchar(1000))

Begin Transaction
    Declare  auSurveyCur cursor for Select Survey_ID from #Deleted Order By Survey_ID
    open auSurveyCur
    fetch next from auSurveyCur into @SurveyID
    while @@fetch_status = 0
        Begin
                Declare  auU cursor 
                for Select [name] from syscolumns where id = object_id('dbo.tblSurvey')
                open auU
                fetch next from auU into @FieldName
                while @@fetch_status = 0
                Begin
                    
                    Insert into #DT execute ('Select ' + @FieldName + ' From #Deleted Where Survey_ID = ' + @SurveyID)
                    Insert into #IT execute ('Select ' + @FieldName + ' From #Inserted Where Survey_ID = ' + @SurveyID)
                    
                            
                                Set @Deleted = (Select isnull(NameValue,'--') From #DT)
                                Set @Inserted = (Select isnull(NameValue,'--') From #IT)
                                If (@Deleted <> @Inserted)
                                Begin
                                    SELECT @LoginName=Login_Name
                                
                                    From Inserted Where Survey_ID=@SurveyID
                                    if @Deleted = '--' begin set @Deleted = null end 
                                    if @Inserted = '--' begin set @Inserted = null end 
                                    
                                    --@ForWhat=1 means info is for tbSurvey 
                                    --In future there may be more tables for auditing and we use same
                                    --Stored procedure to insert audit. Each table has its own audit table.

                                

                                    Execute dbo.InsertauInfo @Surv_ID=@SurveyID
                                                            , @auSurveyFieldName=@FieldName
                                                            , @auSurveyChangedFrom=@Deleted
                                                            , @auSurveyChangedTo=@Inserted
                                                            , @auSurveyUpdatedBy=@LoginName
                                                            , @auSurveyUpdateDate=@currentDate
                                                            , @ForWhat=1
                                End
                    Delete From #DT
                    Delete From #IT
                    fetch next from auU into @FieldName
                End
                close auU
                deallocate auU
                fetch next from auSurveyCur into @SurveyID
        END
    
    close auSurveyCur
    deallocate auSurveyCur
Commit  Transaction

代码

InsertauInfo

ALTER PROCEDURE [dbo].[InsertauInfo]
@Surv_ID bigint,
@auSurveyFieldName varchar(100),
@auSurveyChangedFrom varchar(max),
@auSurveyChangedTo varchar(max),
@auSurveyUpdatedBy varchar(100),
@auSurveyUpdateDate datetime,
@ForWhat int

AS

BEGIN   
    SET NOCOUNT ON; 
    IF (@ForWhat=1)
    BEGIN
        INSERT INTO auSurvey
                            ( Survey_ID
                            , auSurveyFieldName
                            , auSurveyChangedFrom
                            , auSurveyChangedTo
                            , auSurveyUpdateDate
                            , auSurveyUpdatedBy
                            )
        VALUES
                            ( @Surv_ID
                            , @auSurveyFieldName
                            , @auSurveyChangedFrom
                            , @auSurveyChangedTo
                            , @auSurveyUpdateDate
                            , @auSurveyUpdatedBy                            
                            )
    END

--ELSE IF (@ForWhat=2)
--      BEGIN
--              INSERT INTO ABC
                                
--      END 
END

不会导致触发器触发的存储过程示例:

好吧,我要疯了,但是如果我直接在数据库中运行这个非常简单的存储过程,触发器就会被触发。但是,如果我从 C# Web 运行,存储过程将在 tblSurvey 更新后运行,但触发器不会被触发。

ALTER PROCEDURE [dbo].[spUpdateSurveyDataTest]


AS
BEGIN

Update tblSurvey

Set 
[s1FirstName]='YES TRIGGER WORKS  for sureYES'
Where Survey_Id=327

  
END
sql sql-server
2个回答
1
投票

您的触发器仅在更新和删除时触发,这就是它在您编辑表时触发的原因。 存储过程正在执行触发器未检测到的插入。 您的触发器应该是INSERT、UPDATE、DELETE


0
投票

问题的关键正如我在问题中提到的:

触发器无法从应用程序运行,但我可以直接从数据库更新中触发它。

问题是应用程序使用自己的通用用户连接到数据库,该用户没有触发器的执行权限。

让事情变得更复杂的是,应用程序级别也不例外。

修复方法是添加

WITH EXECUTE AS OWNER 

到扳机。

© www.soinside.com 2019 - 2024. All rights reserved.