我真的希望有人可以帮助我...
我有一个触发器来处理向表中插入新记录。正如您将在下面看到的,此触发器将一条记录插入到另一个表中,该表依次执行该表上的触发器,该表调用存储过程(我试图在触发器内执行此操作,但它失败并且很难测试它失败了,所以我把它移到了自己的小单位。)
在存储过程中,调用从Active Directory数据库(ADSI)中提取信息并更新新插入的记录。但是,这是触发器调用时失败的地方。当我通过简单地执行它来调用它,并传递记录进行更新时,它的效果很好......有人能指出我正确的方向吗?请!
在YYY中触发#1
USE [YYY]
GO
/****** Object: Trigger [dbo].[NewCustodian] Script Date: 08/04/2014 09:38:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[NewCustodian]
ON [YYY].[dbo].[Custodians]
AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
DECLARE @CaseID varchar(20);
DECLARE DBcursor CURSOR FOR
SELECT [XXX].[dbo].[tblCase].CaseID from [XXX].[dbo].[tblCase] Where [XXX].[dbo].[tblCase].SQLSVR_Case_ID = 'YYY';
Open DBcursor; FETCH DBCursor into @CaseID;
CLOSE DBcursor; DEALLOCATE DBcursor;
DECLARE @NAME varchar(255);
DECLARE @TAG varchar(255);
SELECT @NAME = name FROM inserted;
SELECT @TAG = tag FROM inserted;
IF NOT EXISTS (Select eID from [XXX].[dbo].[tblNames]
WHERE eID = @TAG and CaseID = @CaseID)
BEGIN
INSERT INTO [XXX].[dbo].[tblNames] (CaseID, Name, eID)
Values (@CaseID, @NAME, @Tag);
END
END
在XXX中触发#2
USE [XXX]
GO
/****** Object: Trigger [dbo].[tblNames_New] Script Date: 08/04/2014 08:56:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
-- Create date:
-- Description:
-- =============================================
ALTER TRIGGER [dbo].[tblNames_New]
ON [XXX].[dbo].[tblNames]
AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
DECLARE @NamesID varchar(10)
DECLARE @TAG varchar(10);
DECLARE @return_value int
SELECT @NamesID = namesID FROM inserted
EXEC dbo.UpdateNames @NamesID;
End
存储过程:
USE [XXX]
GO
/****** Object: StoredProcedure [dbo].[UpdateNames] Script Date: 08/04/2014 08:14:52 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
-- Create date:
-- Description:
-- =============================================
ALTER PROCEDURE [dbo].[UpdateNames]
@NamesID int
AS
BEGIN
SET FMTONLY OFF;
SET NOCOUNT ON;
DECLARE @eID varchar(10);
DECLARE @TAG varchar(10);
DECLARE @SQL nvarchar(555);
DECLARE @DBresults as table (
eID nvarchar(100),
mobile nvarchar(100),
mail nvarchar(100),
phone nvarchar(100),
name nvarchar(50),
legacyExchangeDN nvarchar(100),
Title nvarchar(100),
homeDirectory nvarchar(100));
DECLARE @mobile nvarchar(100)
DECLARE @mail nvarchar(100)
DECLARE @phone nvarchar(100) = 'Error'
DECLARE @name nvarchar(100)
DECLARE @legacyExchangeDN nvarchar(100)
DECLARE @Title nvarchar(100) = 'Error'
DECLARE @homeDirectory nvarchar(100)
SET @eID = (Select eID from [XXX].[dbo].[tblNames] Where NamesID = @NamesID)
SET @SQL = N'SELECT * FROM OpenQuery ( ADSI, ''SELECT homeDirectory,Title,legacyExchangeDN,displayName, telephoneNumber, mail, mobile,samAccountName
FROM ''''LDAP://domain.com''''
WHERE objectClass = ''''User'''' and samAccountName = ''''' + @eID+ ''''''') As tblADSI'
INSERT INTO @DBresults
EXEC sp_executesql @SQL
DECLARE DBcursor CURSOR FOR
SELECT * from @DBresults;
Open DBcursor; FETCH DBCursor into @eID, @mobile, @mail, @phone, @Name, @legacyExchangeDN, @Title, @homeDirectory;
CLOSE DBcursor; DEALLOCATE DBcursor;
UPDATE XXX.dbo.tblNames
SET Job_Title = @Title,
Phone = @Phone
Where NamesID = @NamesID;
END
答案 0 :(得分:1)
正如我在评论中所说 - 触发器应该非常小,灵活,精简 - 不要在触发器内进行任何广泛且耗时的处理,并避免任何会导致性能瓶颈的事情,特别是游标!
原因是每当INSERT
操作发生时触发器就会被触发,你无法控制它被调用的时间和次数。当触发器工作时,主应用程序将等待并挂起 - 因此,请不要长时间使用 - 从触发器快速返回以继续使用主应用程序。
我的方法是:
创建一个新的单独表格,您可以从第一个原始触发器中插入一些关键信息
CREATE TABLE NewCustodianInserted
(
ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
CaseID VARCHAR(20),
Tag VARCHAR(255),
Handled BIT DEFAULT (0)
);
更改Custodians
表上的原始触发器,只需将这些关键信息插入新的“命令”表中:
CREATE TRIGGER [dbo].[NewCustodian]
ON [YYY].[dbo].[Custodians]
AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
-- insert key pieces about the new custodian into "command" table
INSERT INTO dbo.NewCustodianInserted (CaseID, Tag)
SELECT i.CaseId, i.Tag
FROM Inserted i
WHERE NOT EXISTS (SELECT * FROM [XXX].[dbo].[tblNames] WHERE eID = i.Tag AND CaseID = i.CaseID)
END
在一个单独的过程中,例如计划每隔5分钟(或对您的应用程序有意义的任何内容)运行的SQL Server代理作业,读取“命令”表,让新的保管人处理,调用长期运行的存储过程从中更新Active Directory。在这里,由于它从您的主应用程序异步运行,因此您可以使用几乎所需的游标,因为您要为新表中的每一行调用存储过程。
CREATE PROCEDURE HandleNewCustodians
AS
BEGIN
SET NOCOUNT ON;
DECLARE @CaseID VARCHAR(20);
DECLARE @Tag VARCHAR(255);
DECLARE @NamesID varchar(10);
DECLARE CustodianCursor CURSOR FAST_FORWARD
FOR
SELECT CaseID, Tag FROM dbo.NewCustodianInserted WHERE Handled = 0
OPEN CustodianCursor
FETCH NEXT FROM CustodianCursor INTO @CaseID, @Tag;
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @NamesID = NameID
FROM [XXX].[dbo].[tblNames] WHERE eID = @Tag AND CaseID = @CaseID
EXEC dbo.UpdateNames @NamesID;
FETCH NEXT FROM CustodianCursor INTO @CaseID, @Tag;
END
CLOSE CustodianCursor;
DEALLOCATE CustodianCursor;
END