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 を再実行します。それはうまくいくかもしれません。うまくいったら、これを再編集して解決策として投稿します。