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 挿入プロセスを少し確認することにしました。私が見つけた問題の 1 つは、幹部の多くがドメインをプルしてメール アドレスに連結していないことでした。スクリプトがドメイン情報を検索できる領域を拡大することで、プロセスが改善され、ユーザー指定の完了に近づいています。まだ完璧ではありませんが、正しい方向への一歩です。

カーソルに特定の数の行を動的にプルさせる方法を見つけることに関しては、この特定の SP を、WHILE ループを使用する 2 番目の SP にネストする可能性があると考えています。したがって、基本的には、リストサイズがユーザー指定のリストサイズよりも小さい間は、挿入 SP を再実行します。それはうまくいくかもしれません。うまくいったら、これを再編集して解決策として投稿します。

4

1 に答える 1

0

投稿の最後の段落で提案したように、ネストされた SP を使用することになりました。最も外側の SP は、要求された exec の数を追跡する WHILE ループを実行します。次に、指定された数の exec で世代 SP を実行します。返された数値が要求された数値よりも小さい場合、WHILE ループに残ります。

ジェネレーション SP のエラーはログに記録されており、データ チームによって確認されています。

于 2013-07-15T23:02:53.730 に答える