我有桌子
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
您的触发器仅在更新和删除时触发,这就是它在您编辑表时触发的原因。 存储过程正在执行触发器未检测到的插入。 您的触发器应该是INSERT、UPDATE、DELETE。
问题的关键正如我在问题中提到的:
触发器无法从应用程序运行,但我可以直接从数据库更新中触发它。
问题是应用程序使用自己的通用用户连接到数据库,该用户没有触发器的执行权限。
让事情变得更复杂的是,应用程序级别也不例外。
修复方法是添加
WITH EXECUTE AS OWNER
到扳机。