开发者

Replace SQL Server 2005 cursor

开发者 https://www.devze.com 2023-03-30 11:55 出处:网络
Here is the simplified cursor: SET IMPLICIT_TRANSACTIONS ON SET @curTemp = CURSOR FAST_FORWARD FOR SELECT gpno, ssn FROM EligCov Group BY gpno, ssn

Here is the simplified cursor:

SET IMPLICIT_TRANSACTIONS ON

SET @curTemp = CURSOR FAST_FORWARD
FOR
    SELECT gpno, ssn FROM EligCov Group BY gpno, ssn
OPEN @curTemp

-- loop through cursor and build output report table
FETCH NEXT FROM @curTemp INTO @gpno, @ssn
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @trnCnt = @trnCnt + 1

    -- get the max CovEndDate for 开发者_开发百科this group/ssn combo
    SELECT @MaxCovEndDate=MAX(CovEndDate) FROM Payroll WHERE GroupNo=@gpno AND SSN=@ssn
    UPDATE EligCov SET CovEndDate = @MaxCovEndDate WHERE gpno=@gpno AND ssn=@ssn

    -- check transaction counts and commit if needed
    IF @trnCnt % 2000 = 0
    BEGIN
        IF @@TRANCOUNT > 0
        BEGIN
            COMMIT
        END
    END
    FETCH NEXT FROM @curTemp INTO @gpno, @ssn
END
CLOSE @curTemp
DEALLOCATE @curTemp 

SET IMPLICIT_TRANSACTIONS OFF

Basically table EligCov has one distinct groupNo/SSN combo. Table Payroll will have many groupno/ssn combinations. Each row in the Payroll table has a CovEndDate column containing a date.

I need to just select the max(CovEndDate) for a certain gpno/ssn combination (this could be from one row or hundreds) from Payroll and update the CovEndDate in the EligCov table (always one row for a specific groupno/ssn combo).

The payroll table has 10,000,000+ rows and the EligCov table has ~200,000 rows. Is there a way to change this to not use a cursor?

To restate, for each group/ssn in EligCov look through all the records in Payroll with the same group/ssn and grab the max(CovEndDate) and update the CovEndDate in the EligCov table.

Thanks.


Sure - pretty easy - use a CTE (Common Table Expression) that partitions your data by the "grouping" set.

;WITH DataToUpdate AS
(
    SELECT  
        GroupNo, SSN, CovEndDate AS 'MaxCovEndDate',
        ROW_NUMBER() OVER(PARTITION BY GroupNo,SSN ORDER BY CovEndDate DESC) AS 'RowNum'
    FROM dbo.Payroll 
UPDATE 
)
UPDATE dbo.EligCov 
SET CovEndDate = d.MaxCovEndDate 
FROM DataToUpdate d
WHERE gpno = d.GroupNo 
  AND ssn = d.SSN 
  AND d.RowNum = 1   -- select the latest date - the one with RowNum = 1

The CTE partitions your data by GroupNo,SSN - so each group of GroupNo,SSN is handed out new ROW_NUMBER(), starting at 1. Since the rows are sorted by CovEndDate DESC, the latest/most recent CovEndDate gets RowNum = 1.

Based on that CTE, you then update the EligCov table, only taking those most recent entries, for each group of GroupNo,SSN


One possible method:

UPDATE
    EC
SET
    CovEndDate = SQ.CovEndDate
FROM
    EligCov EC
INNER JOIN (
        SELECT gpno, ssn, MAX(CovEndDate) AS max_dt
        FROM Payroll
        GROUP BY gpno, ssn) SQ ON
    SQ.gpno = EC.gpno AND
    SQ.ssn = EC.ssn

More importantly though, I'd ask if it's really necessary to have that column in EligCov, which is against rules of normalization for a relational database.

0

精彩评论

暂无评论...
验证码 换一张
取 消