使用游标返回指定数量的结果

时间:2013-06-18 21:36:05

标签: sql-server-2008-r2

我的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

因为Cursor旨在咀嚼预定义的数据列表,所以我不确定如何使所述游标“动态”并返回用户指定的结果数,而不管错误。 WHILE循环只有在没有命中CATCH块的情况下执行SP时才会增加“计数器”,但我不知道如何将其集成到Cursor中,或者我是否可以。

这里有什么显而易见的东西吗?

(根据要求,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插入过程。我发现的一个问题是我们的许多执行者都没有将域连接到电子邮件地址。扩展脚本可以查找域信息的区域已将过程改进为接近用户指定的完成。虽然它仍然不完美,但它是朝着正确方向迈出的一步。

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

1 个答案:

答案 0 :(得分:0)

正如帖子最后一段所述,我最终使用了嵌套的SP。最外面的SP运行一个WHILE循环,跟踪请求的许多高管。然后它使用指定的执行数运行生成SP。如果返回的数字小于请求的数字,它将保留在WHILE循环中。

我们的数据小组正在记录生成SP中的错误。