Help with Cursors

  • I have inherited the following code involving cursors which happens to be step1 in a job, currently this step is taking 19 hours to run, there has to be something wrong with this code, I am not a big fan of cursors nor have used it, can somebody look over the code and see what is going on here.

    declare @curr_LoanID varchar(10)

    declare LettersQueue_cursor CURSOR for

    select LoanID from srv.dbo.loan where nextcoupondate <= convert(varchar(10),dateadd(dd,3,getdate()),101)

    and nextcoupondate > '4/10/2009' and LoanID not in

    (select LoanID from M1CustLetters where StatementDate >= convert(varchar(10),dateadd(dd,-4,getdate()),101))

    and LoanID not in (select LoanID from srv.dbo.Status where CouponStop = 1)

    or

    loanid in (select loanid from srv.dbo.usr_m1_letter_requests

    where customerstatement >= convert(varchar(10),dateadd(dd,-4,getdate()),101)

    and customerstatement <= convert(varchar(10),dateadd(dd,3,getdate()),101)

    and loanid not in (select loanid from m1custletters

    where StatementDate >= convert(varchar(10),dateadd(dd,-4,getdate()),101)))

    and LoanID not in (select LoanID from service.dbo.Status where CouponStop = 1)

    or

    loanid in (select loanid from srv.dbo.loan where right(loanid,7) not in

    (select loanid from m1lettersqueue)

    and lastbilldate <= getdate() and lastbilldate >= dateadd(dd,-14,getdate())

    and loanid not in (select loanid from service.dbo.status where CouponStop = 1)

    and loanid not in (select loanid from m1custletters where statementdate >= dateadd(dd,-30,getdate()))

    and duedate <= dateadd(dd,30,getdate()))

    OPEN LettersQueue_cursor

    FETCH LettersQueue_cursor into @curr_LoanID

    WHILE @@FETCH_STATUS=0

    BEGIN

    if exists (select * from srv.dbo.loan where loanid = @curr_LoanID and lastbilldate is null)

    begin

    update srv.dbo.loan set lastbilldate = dateadd(mm,-1,nextcoupondate) where loanid = @curr_LoanID

    end

    if not exists (select * from m1lettersqueue where loanid = right(@curr_LoanID,7)

    and statementdate = convert(varchar(10),getdate(),101))

    begin

    insert into m1lettersqueue (loanid,statementdate)

    select right(@curr_LoanID,7),convert(varchar(10),getdate(),101)

    end

    FETCH LettersQueue_cursor into @curr_LoanID

    END

    close LettersQueue_cursor

    deallocate LettersQueue_cursor

    go

  • Can you post DDL statements for all tables involved in the queries?

    _____________
    Code for TallyGenerator

  • CREATE TABLE [dbo].[M1CustLetters](

    [LoanID] [nvarchar](10) NOT NULL,

    [StatementDate] [datetime] NOT NULL,

    [CustomerName] [varchar](40) NOT NULL,

    [Address1] [varchar](40) NOT NULL,

    [Address2] [varchar](40) NOT NULL,

    [BankPool] [varchar](12) NOT NULL,

    [AcctNum] [varchar](12) NOT NULL,

    [DueDate] [datetime] NOT NULL,

    [NextStatementDate] [datetime] NOT NULL,

    [CurrentBalance] [varchar](17) NOT NULL,

    [Payment] [varchar](11) NOT NULL,

    [PastDue] [varchar](11) NOT NULL,

    [LateCharge] [varchar](10) NOT NULL,

    [OtherCharge] [varchar](10) NOT NULL,

    [TotalDue] [varchar](11) NOT NULL,

    [BankMessage] [varchar](60) NOT NULL

    ) ON [PRIMARY]

    CREATE TABLE [dbo].[M1LettersQueue](

    [LoanID] [nvarchar](10) NOT NULL,

    [StatementDate] [datetime] NOT NULL

    ) ON [PRIMARY]

    CREATE TABLE [dbo].[MailingAddress](

    [LoanID] [varchar](10) NOT NULL,

    [AssmRecCounter] [tinyint] NOT NULL DEFAULT (0),

    [AddressLine1] [varchar](40) NULL,

    [AddressLine2] [varchar](40) NULL,

    [City] [varchar](25) NULL,

    [State] [varchar](25) NULL,

    [Zip] [varchar](10) NULL,

    [PromotionalMail] [tinyint] NOT NULL DEFAULT (1),

    [FirstLine] [tinyint] NOT NULL DEFAULT (1),

    [SecondLine] [tinyint] NOT NULL DEFAULT (0),

    [PrivacyRequested] [tinyint] NOT NULL DEFAULT (0),

    [CountryCode] [varchar](3) NOT NULL DEFAULT ('USA'),

    [PrimaryMailing] [tinyint] NOT NULL DEFAULT (1),

    [ReturnedMail] [bit] NOT NULL CONSTRAINT [DF_MailingAddress_ReturnedMail] DEFAULT (0),

    [AddressIndicator] [tinyint] NOT NULL DEFAULT ((0)),

    [AddressLine3] [varchar](40) NULL,

    [MailingAddressID] [int] IDENTITY(1,1) NOT NULL,

    [TimeZone] [tinyint] NOT NULL DEFAULT ((0)),

    [CityCode] [varchar](10) NULL,

    CONSTRAINT [MailingAddress_PK] PRIMARY KEY NONCLUSTERED

    (

    [MailingAddressID] ASC

    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]

    ) ON [PRIMARY]

    GO

    Do you want the DDL for loan table? it is approx. 100 columns

  • I am not a fan of cursors, never used it. Is there a way we can write the code without it? Any help would be appreciated.

  • I don't have test data, but this should be equivalent to your code.

    SELECT LoanID

    INTO #Loans

    FROM srv.dbo.loan

    WHERE nextcoupondate <= convert(VARCHAR(10), dateadd(dd, 3, getdate()), 101)

    AND nextcoupondate > '4/10/2009'

    AND LoanID NOT IN (

    SELECT LoanID

    FROM M1CustLetters

    WHERE StatementDate >= convert(VARCHAR(10), dateadd(dd, - 4, getdate()), 101)

    )

    AND LoanID NOT IN (

    SELECT LoanID

    FROM srv.dbo.STATUS

    WHERE CouponStop = 1

    )

    OR loanid IN (

    SELECT loanid

    FROM srv.dbo.usr_m1_letter_requests

    WHERE customerstatement >= convert(VARCHAR(10), dateadd(dd, - 4, getdate()), 101)

    AND customerstatement <= convert(VARCHAR(10), dateadd(dd, 3, getdate()), 101)

    AND loanid NOT IN (

    SELECT loanid

    FROM m1custletters

    WHERE StatementDate >= convert(VARCHAR(10), dateadd(dd, - 4, getdate()), 101)

    )

    )

    AND LoanID NOT IN (

    SELECT LoanID

    FROM service.dbo.STATUS

    WHERE CouponStop = 1

    )

    OR loanid IN (

    SELECT loanid

    FROM srv.dbo.loan

    WHERE right(loanid, 7) NOT IN (

    SELECT loanid

    FROM m1lettersqueue

    )

    AND lastbilldate <= getdate()

    AND lastbilldate >= dateadd(dd, - 14, getdate())

    AND loanid NOT IN (

    SELECT loanid

    FROM service.dbo.STATUS

    WHERE CouponStop = 1

    )

    AND loanid NOT IN (

    SELECT loanid

    FROM m1custletters

    WHERE statementdate >= dateadd(dd, - 30, getdate())

    )

    AND duedate <= dateadd(dd, 30, getdate())

    )

    UPDATE srv.dbo.loan

    SET lastbilldate = dateadd(mm, - 1, nextcoupondate)

    WHERE loanid IN (SELECT LoanID FROM #Loans)

    AND lastbilldate IS NULL;

    INSERT INTO m1lettersqueue (

    loanid

    ,statementdate

    )

    SELECT loanid

    ,convert(VARCHAR(10), getdate(), 101)

    FROM m1lettersqueue

    WHERE loanid NOT IN (SELECT right(LoanID, 7) FROM #Loans)

    OR statementdate != convert(VARCHAR(10), getdate(), 101);

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • SQLPain (12/16/2015)


    I have inherited the following code involving cursors which happens to be step1 in a job, currently this step is taking 19 hours to run, there has to be something wrong with this code, I am not a big fan of cursors nor have used it, can somebody look over the code and see what is going on here.

    declare @curr_LoanID varchar(10)

    declare LettersQueue_cursor CURSOR for

    select LoanID from srv.dbo.loan where nextcoupondate <= convert(varchar(10),dateadd(dd,3,getdate()),101)

    and nextcoupondate > '4/10/2009' and LoanID not in

    (select LoanID from M1CustLetters where StatementDate >= convert(varchar(10),dateadd(dd,-4,getdate()),101))

    and LoanID not in (select LoanID from srv.dbo.Status where CouponStop = 1)

    or

    loanid in (select loanid from srv.dbo.usr_m1_letter_requests

    where customerstatement >= convert(varchar(10),dateadd(dd,-4,getdate()),101)

    and customerstatement <= convert(varchar(10),dateadd(dd,3,getdate()),101)

    and loanid not in (select loanid from m1custletters

    where StatementDate >= convert(varchar(10),dateadd(dd,-4,getdate()),101)))

    and LoanID not in (select LoanID from service.dbo.Status where CouponStop = 1)

    or

    loanid in (select loanid from srv.dbo.loan where right(loanid,7) not in

    (select loanid from m1lettersqueue)

    and lastbilldate <= getdate() and lastbilldate >= dateadd(dd,-14,getdate())

    and loanid not in (select loanid from service.dbo.status where CouponStop = 1)

    and loanid not in (select loanid from m1custletters where statementdate >= dateadd(dd,-30,getdate()))

    and duedate <= dateadd(dd,30,getdate()))

    OPEN LettersQueue_cursor

    FETCH LettersQueue_cursor into @curr_LoanID

    WHILE @@FETCH_STATUS=0

    BEGIN

    if exists (select * from srv.dbo.loan where loanid = @curr_LoanID and lastbilldate is null)

    begin

    update srv.dbo.loan set lastbilldate = dateadd(mm,-1,nextcoupondate) where loanid = @curr_LoanID

    end

    if not exists (select * from m1lettersqueue where loanid = right(@curr_LoanID,7)

    and statementdate = convert(varchar(10),getdate(),101))

    begin

    insert into m1lettersqueue (loanid,statementdate)

    select right(@curr_LoanID,7),convert(varchar(10),getdate(),101)

    end

    FETCH LettersQueue_cursor into @curr_LoanID

    END

    close LettersQueue_cursor

    deallocate LettersQueue_cursor

    go

    Check your ANDs and ORs. They don't appear to make sense and your query is probably processing many more rows than it should. Use brackets where appropriate.


    [font="Arial"]Low-hanging fruit picker and defender of the moggies[/font]

    For better assistance in answering your questions, please read this[/url].


    Understanding and using APPLY, (I)[/url] and (II)[/url] Paul White[/url]

    Hidden RBAR: Triangular Joins[/url] / The "Numbers" or "Tally" Table: What it is and how it replaces a loop[/url] Jeff Moden[/url]

  • ChrisM@home (1/6/2016)


    Check your ANDs and ORs. They don't appear to make sense and your query is probably processing many more rows than it should. Use brackets where appropriate.

    You're right, I didn't pay much attention to that part of the query. I'd probably change it to use set operators (UNION, INTERSECT, EXCEPT), but I won't suggest anything without being able to test the code.

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • Thanks Luis,

    Even the following is taking endless amount of time, I kill it after 3-4 minutes, I am trying to see if there are any repetitions which we can avoid, plus the dates are also not making a lot of sense here.

    SELECT LoanID

    --INTO #Loans

    FROM srv.dbo.loan

    WHERE nextcoupondate <= convert(VARCHAR(10), dateadd(dd, 3, getdate()), 101)

    AND nextcoupondate > '4/10/2009'

    AND LoanID NOT IN (

    SELECT LoanID

    FROM M1CustLetters

    WHERE StatementDate >= convert(VARCHAR(10), dateadd(dd, - 4, getdate()), 101)

    )

    AND LoanID NOT IN (

    SELECT LoanID

    FROM srv.dbo.STATUS

    WHERE CouponStop = 1

    )

    OR loanid IN (

    SELECT loanid

    FROM srv.dbo.usr_m1_letter_requests

    WHERE customerstatement >= convert(VARCHAR(10), dateadd(dd, - 4, getdate()), 101)

    AND customerstatement <= convert(VARCHAR(10), dateadd(dd, 3, getdate()), 101)

    AND loanid NOT IN (

    SELECT loanid

    FROM m1custletters

    WHERE StatementDate >= convert(VARCHAR(10), dateadd(dd, - 4, getdate()), 101)

    )

    )

    AND LoanID NOT IN (

    SELECT LoanID

    FROM service.dbo.STATUS

    WHERE CouponStop = 1

    )

    OR loanid IN (

    SELECT loanid

    FROM srv.dbo.loan

    WHERE right(loanid, 7) NOT IN (

    SELECT loanid

    FROM m1lettersqueue

    )

    AND lastbilldate <= getdate()

    AND lastbilldate >= dateadd(dd, - 14, getdate())

    AND loanid NOT IN (

    SELECT loanid

    FROM service.dbo.STATUS

    WHERE CouponStop = 1

    )

    AND loanid NOT IN (

    SELECT loanid

    FROM m1custletters

    WHERE statementdate >= dateadd(dd, - 30, getdate())

    )

    AND duedate <= dateadd(dd, 30, getdate())

    )

    This is the step 2 of the job:

    declare @curr_LoanID varchar(10)

    declare CustumerLetters_cursor CURSOR for

    select LoanID from srv.dbo.Participation where right(LoanID,7) in (select LoanID from M1LettersQueue

    where StatementDate = convert(varchar(10),getdate(),101))

    order by InvestorID asc

    OPEN CustumerLetters_cursor

    FETCH CustumerLetters_cursor into @curr_LoanID

    WHILE @@FETCH_STATUS=0

    BEGIN

    --select LoanID = @curr_LoanID

    exec M1_CreateCustStatements @curr_LoanID

    FETCH CustumerLetters_cursor into @curr_LoanID

    END

    close CustumerLetters_cursor

    deallocate CustumerLetters_cursor

    go

  • Can anyone make sense of what exactly is happening with the tables(loan, usr_m1_letter_requests, m1lettersque)?

Viewing 9 posts - 1 through 8 (of 8 total)

You must be logged in to reply to this topic. Login to reply