Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 调用存储过程时触发器失败_Sql_Sql Server_Stored Procedures - Fatal编程技术网

Sql 调用存储过程时触发器失败

Sql 调用存储过程时触发器失败,sql,sql-server,stored-procedures,Sql,Sql Server,Stored Procedures,我真的希望有人能帮我 我有一个触发器来处理向表中插入新记录的操作。正如您将在下面看到的,此触发器将一条记录插入到另一个表中,该表依次在该表上执行一个触发器,该触发器调用一个存储过程(我尝试在触发器本身中执行该操作,但失败了,并且很难测试失败的位置,因此我将其移动到自己的小单元中) 在存储过程中,会调用从Active Directory数据库(ADSI)提取信息并更新新插入的记录。但是,这就是触发器调用时失败的地方。当我通过简单地执行它来调用它,并传递要更新的记录时,它工作得非常好。。。谁能给我指

我真的希望有人能帮我

我有一个触发器来处理向表中插入新记录的操作。正如您将在下面看到的,此触发器将一条记录插入到另一个表中,该表依次在该表上执行一个触发器,该触发器调用一个存储过程(我尝试在触发器本身中执行该操作,但失败了,并且很难测试失败的位置,因此我将其移动到自己的小单元中)

在存储过程中,会调用从Active Directory数据库(ADSI)提取信息并更新新插入的记录。但是,这就是触发器调用时失败的地方。当我通过简单地执行它来调用它,并传递要更新的记录时,它工作得非常好。。。谁能给我指出正确的方向吗?请

YYY中的触发器#1

XXX中的触发器#2

存储过程:

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

正如我在评论中所说的——触发器应该非常小、灵活、精简——不要在触发器内部进行任何广泛而耗时的处理,并避免任何可能导致性能瓶颈的事情,尤其是游标

其原因是,每当发生
INSERT
操作时,触发器都会被触发,您无法控制调用它的时间和次数。当触发器工作时,主应用程序将等待并挂起-因此,不要让这太长时间-从触发器快速返回以继续使用主应用程序

我的做法是:

  • 创建一个新的单独表,在其中插入一些关键信息,这些信息来自第一个原始触发器

    CREATE TABLE NewCustodianInserted 
    (
        ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, 
        CaseID VARCHAR(20), 
        Tag VARCHAR(255),
        Handled BIT DEFAULT (0)
    );
    
  • 更改
    保管人
    表上的原始触发器,将这些关键信息插入新的“命令”表中:

  • 在一个单独的过程中,例如计划每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
    

您正在使用游标在第一个触发器中检索单个值并将其存储到变量中?一个触发器,它包含一个游标,然后调用另一个触发器,该触发器依次调用更新ADSI的存储过程并再次包含另一个游标。。。。。。天哪!触发器应该非常小、快速、灵活。不要在触发器中执行任何广泛的处理!如果您需要处理,则永远不要让触发器在“命令”表中插入一行,然后使用一个单独的异步进程来完成繁重的工作!还有:在触发器内部,N E V E R。使用光标!哇,真是一团糟。触发器中有一个光标。光标不查询已插入的内容。它只能处理单行插入。在触发器中使用光标会产生令人震惊的性能问题。究竟为什么要使用光标填充单个值?您的第二个触发器具有相同的基本缺陷,它无法处理基于集合的操作。然后,您存储的进程使用了同样有缺陷的概念,即使用游标填充变量。好的,伙计们。。与其批评我做错的每件事,我该如何正确地做。。。请注意,直到上周,我还没有写过触发器。。。甚至都不知道它们的存在。我并不宣称对他们有任何了解。我理解批评的必要性,但是来吧,帮帮我。谢谢。这就是我请求帮助时所寻找的!
CREATE TABLE NewCustodianInserted 
(
    ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, 
    CaseID VARCHAR(20), 
    Tag VARCHAR(255),
    Handled BIT DEFAULT (0)
);
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
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