1

我的 SQL 2008R2 数据库中有一个游标。此游标获取数据列表,解析数据的每一行,然后通过存储过程运行解析的数据行。

DECLARE ExecsDataCursor CURSOR FAST_FORWARD FOR
    SELECT TOP (@GuessListSize)
        ExecutiveId,
        CompanyExecutiveId,
        Email,
        CompanyId,
        @EmailPatternID EmailPatternID,
        ExecNameForSorting
    FROM
        CompanyExecutive
    WHERE
        CurrentlyWithCompany = 1
        AND
        Email IS NULL
        AND
        CompanyExecutiveId NOT IN 
        (
            SELECT CompanyExecutiveId 
            FROM ExecsData_ExecutiveCandidates
            WHERE EmailPatternID = @EmailPatternID
        )
    ORDER BY
        CompanyExecutiveId

    OPEN ExecsDataCursor

    DECLARE
        @ExecutiveId INT,
        @CompanyExecutiveId INT,
        @Email NVARCHAR(255),
        @CompanyId INT,
        @EmailPatternID_ForCursor TINYINT,
        @ExecName NVARCHAR(255)

    FETCH NEXT FROM ExecsDataCursor
    INTO 
        @ExecutiveId ,
        @CompanyExecutiveId ,
        @Email ,
        @CompanyId ,
        @EmailPatternID_ForCursor,
        @ExecName

    DECLARE 
        @FirstName NVARCHAR(50) = '',
        @MiddleName NVARCHAR(50) = '',
        @LastName NVARCHAR(50) = '',
        @ExampleEmail NVARCHAR(255),
        @Domain NVARCHAR(50) = ''

    WHILE @@FETCH_STATUS = 0
    BEGIN

        IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) = 1
        BEGIN
            SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1
        END

        IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) = 2
        BEGIN
            SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1
            SELECT @LastName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 2
        END

        IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) >= 3
        BEGIN
            SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1
            SELECT @MiddleName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 2
            SELECT @LastName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = (SELECT MAX(id) FROM dbo.splitString(@ExecName,' '))
        END

        SELECT @ExampleEmail = MAX(Email) FROM CompanyExecutive WHERE Email IS NOT NULL AND CompanyId = @CompanyId
        SELECT @Domain = SUBSTRING(@ExampleEmail, CHARINDEX('@', @ExampleEmail), LEN(@ExampleEmail))            

        IF @EmailPatternID = 1 BEGIN BEGIN TRY EXEC ExecsData_Guess_fnamelname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 2 BEGIN BEGIN TRY EXEC ExecsData_Guess_fnamedotlname@domain_DataMe @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 3 BEGIN BEGIN TRY EXEC ExecsData_Guess_finitiallname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 4 BEGIN BEGIN TRY EXEC ExecsData_Guess_finitialdotlname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 5 BEGIN BEGIN TRY EXEC ExecsData_Guess_finitial_lname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 6 BEGIN BEGIN TRY EXEC ExecsData_Guess_fname_lname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 7 BEGIN BEGIN TRY EXEC ExecsData_Guess_fnamelinitial@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 8 BEGIN BEGIN TRY EXEC ExecsData_Guess_lnamefinitial@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 9 BEGIN BEGIN TRY EXEC ExecsData_Guess_fname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 10 BEGIN BEGIN TRY EXEC ExecsData_Guess_lname_fname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 11 BEGIN BEGIN TRY EXEC ExecsData_Guess_lname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 12 BEGIN BEGIN TRY EXEC ExecsData_Guess_finitiallinitial@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END
        IF @EmailPatternID = 13 BEGIN BEGIN TRY EXEC ExecsData_Guess_lnamedotfname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID END TRY BEGIN CATCH END CATCH  END

            FETCH NEXT FROM ExecsDataCursor
                INTO 
                    @ExecutiveId ,
                    @CompanyExecutiveId ,
                    @Email ,
                    @CompanyId ,
                    @EmailPatternID_ForCursor,
                    @ExecName
    END
    CLOSE ExecsDataCursor
    DEALLOCATE ExecsDataCursor

这工作得很好,至少符合我的预期。游标在大约 19 秒内处理 8000 行。8000 行由用户输入指定,该输入提供给@GuessListSize 参数。然而,解析的数据并不总是被正确处理,这是意料之中的。因此,try-catch 代码。我们真的不需要游标对失败的存储过程执行做任何事情。我们开始在一个单独的表中跟踪它们,以便我们可以弄清楚将来如何更好地处理这些数据点。

这样做的问题是光标现在不会返回完整列表。我们希望得到用户指定大小的列表。所以游标拉出指定大小的列表,因为它应该,但其中一些条目可能没有被存储过程正确处理,返回一个小于指定大小的列表。

所以接下来我尝试的是一个 WHILE 循环。现在,WHILE 循环运行良好。它返回了用户请求的所有行。但是,运行相同大小的数据集需要将近 30 分钟。这显然是不可接受的。

DECLARE
        @ExecutiveId INT,
        @CompanyExecutiveId INT,
        @Email NVARCHAR(255),
        @CompanyId INT,
        @EmailPatternID_ForCursor TINYINT,
        @ExecName NVARCHAR(255) 


    DECLARE 
        @FirstName NVARCHAR(50) = '',
        @MiddleName NVARCHAR(50) = '',
        @LastName NVARCHAR(50) = '',
        @ExampleEmail NVARCHAR(255),
        @Domain NVARCHAR(50) = '',
        @Counter SMALLINT = 0

    --WHILE @@FETCH_STATUS = 0
    WHILE @Counter < @GuessListSize
    BEGIN

        SELECT @CompanyExecutiveId = 
            MIN(CompanyExecutiveID) 
        FROM CompanyExecutive 
        WHERE CurrentlyWithCompany = 1 AND Email IS NULL 
            AND 
            CompanyExecutiveId NOT IN 
            (SELECT CompanyExecutiveId FROM ExecsData_ExecutiveCandidates WHERE EmailPatternID = @EmailPatternID)
            AND
            CompanyExecutiveID NOT IN
            (SELECT CompanyExecutiveId FROM ExecsData_Errors)

        SELECT
            @ExecutiveId = ExecutiveId,
            @Email = Email,
            @CompanyId = CompanyId,
            @EmailPatternID_ForCursor = @EmailPatternID,
            @ExecName = ExecNameForSorting
        FROM 
            CompanyExecutive
        WHERE
            CompanyExecutiveId = @CompanyExecutiveId

        IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) = 1
        BEGIN
            SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1
        END

        IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) = 2
        BEGIN
            SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1
            SELECT @LastName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 2
        END

        IF (SELECT COUNT(*) FROM dbo.splitString(@ExecName,' ')) >= 3
        BEGIN
            SELECT @FirstName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 1
            SELECT @MiddleName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = 2
            SELECT @LastName = Data FROM dbo.splitString(@ExecName,' ') WHERE id = (SELECT MAX(id) FROM dbo.splitString(@ExecName,' '))
        END

        SELECT @ExampleEmail = MAX(Email) FROM CompanyExecutive WHERE Email IS NOT NULL AND CompanyId = @CompanyId
        SELECT @Domain = SUBSTRING(@ExampleEmail, CHARINDEX('@', @ExampleEmail), LEN(@ExampleEmail))

    IF @EmailPatternID = 1 BEGIN BEGIN TRY EXEC ExecsData_Guess_fnamelname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 2 BEGIN BEGIN TRY EXEC ExecsData_Guess_fnamedotlname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 3 BEGIN BEGIN TRY EXEC ExecsData_Guess_finitiallname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 4 BEGIN BEGIN TRY EXEC ExecsData_Guess_finitialdotlname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 5 BEGIN BEGIN TRY EXEC ExecsData_Guess_finitial_lname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 6 BEGIN BEGIN TRY EXEC ExecsData_Guess_fname_lname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 7 BEGIN BEGIN TRY EXEC ExecsData_Guess_fnamelinitial@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 8 BEGIN BEGIN TRY EXEC ExecsData_Guess_lnamefinitial@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 9 BEGIN BEGIN TRY EXEC ExecsData_Guess_fname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 10 BEGIN BEGIN TRY EXEC ExecsData_Guess_lname_fname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 11 BEGIN BEGIN TRY EXEC ExecsData_Guess_lname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 12 BEGIN BEGIN TRY EXEC ExecsData_Guess_finitiallinitial@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END
    IF @EmailPatternID = 13 BEGIN BEGIN TRY EXEC ExecsData_Guess_lnamedotfname@domain_DataME @ExecutiveID ,@CompanyExecutiveID ,@FirstName,@MiddleName ,@LastName ,@Domain ,@CompanyID; SET @Counter = @Counter + 1; END TRY BEGIN CATCH INSERT INTO ExecsData_Errors (CompanyExecutiveID,EmailPatternID) VALUES (@CompanyExecutiveId,@EmailPatternID) END CATCH  END

    END

因为光标旨在浏览预定义的数据列表,所以我不确定如何使所述光标“动态”并返回用户指定数量的结果,而不管错误如何。WHILE 循环只有在 SP 执行时没有碰到 CATCH 块时才会增加“计数器”,但我不知道如何将它集成到光标中,或者我什至可以。

我在这里有什么明显的遗漏吗?

(根据要求,INSERT SQL SP)

ALTER PROCEDURE [dbo].[ExecsData_Guess_fname@domain_DataMe] 
( 
    @ExecutiveID int,
    @CompanyExecutiveID int,
    @FirstName nvarchar(50),
    @MiddleName nvarchar(50),
    @LastName nvarchar(50),
    @DomainName nvarchar(255),
    @CompanyID int
) 
AS 

SET NOCOUNT ON 

SET TRANSACTION ISOLATION LEVEL READ COMMITTED 
DECLARE @GUESS nvarchar(255)

DECLARE @FirstInitial nvarchar(1)
DECLARE @MiddleInitial nvarchar(1)
DECLARE @LastInitial nvarchar(1)

set @FirstInitial = SUBSTRING(@FirstName, 1, 1) 
set @MiddleInitial = SUBSTRING(@MiddleName, 1, 1) 
set @LastInitial = SUBSTRING(@LastName, 1, 1) 

--*****Example****** 
--FirstName = Andy, 
--Middle Name = Xanadu,  
--Last Name = Farag, 
--Domain = @umphreys.com
--******************

--ex. andy@umphreys.com
set @GUESS = LTRIM(@FirstName)+ @DomainName
EXEC ExecsData_InsertEmailGuessByExec_DataMe
        @ExecutiveID,
        @CompanyExecutiveID,
        @GUESS,
        @CompanyID,
        9


RETURN (@@ERROR) 

ALTER PROCEDURE [dbo].[ExecsData_InsertEmailGuessByExec_DataMe]
( 
    @ExecutiveID int,
    @CompanyExecutiveID int, 
    @EmailAddress nvarchar(50),
    @CompanyID int,
    @EmailPatternID tinyint
)
AS

BEGIN
    INSERT ExecsData_ExecutiveCandidates
    (
        ExecutiveID,
        CompanyExecutiveID,
        EmailAddress,
        CompanyID,
        EmailPatternID,
        GuessTimestamp
    )

    VALUES
    ( 
        @ExecutiveID,
        @CompanyExecutiveID, 
        @EmailAddress,
        @CompanyID,
        @EmailPatternID,
        CURRENT_TIMESTAMP
    )
END

根据 RBarryYoung 的建议,我选择稍微看看实际的 SP 插入过程。我发现的一个问题是,我们的许多 Exec 并没有提取域来连接到电子邮件地址。扩展脚本可以查找域信息的区域已将过程改进为接近用户指定的完成。虽然它仍然不完美,但它是朝着正确方向迈出的一步。

至于寻找动态强制游标拉出特定行数的方法,我想我可能会将这个特定的 SP 嵌套在使用 WHILE 循环的第二个 SP 中。所以基本上,当列表大小小于用户指定的列表大小时,它会重新执行插入 SP。那可能行得通。如果可行,我将重新编辑并将其作为解决方案发布。

4

1 回答 1

0

正如文章最后一段所建议的,我最终使用了嵌套的 SP。最外层的 SP 运行一个 WHILE 循环,该循环跟踪请求的执行次数。然后它使用指定数量的 exec 运行生成 SP。如果返回的数字小于请求的数字,则保留在 WHILE 循环中。

正在记录生成 SP 中的错误,以供我们的数据团队审查。

于 2013-07-15T23:02:53.730 回答