Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Optimize SP

Author  Topic 

dee-u
Starting Member

14 Posts

Posted - 2009-03-25 : 03:29:20
Below is my SP. It is working but as the record no. grows it is getting slower executing this so I wish to optimize it. It is based on cursors since I cannot for the life of me convert it to set-based one. Anyone got suggestions? Thank you so much!

ALTER PROCEDURE UpdateExpenditure 
AS
SET NOCOUNT ON

DECLARE @income_code INT,
@totalcost MONEY,
@eyeglass MONEY,
@expenditure MONEY,
@balance MONEY,
@rCount INT,
@rPos INT,
@outsideRecords INT

DECLARE income_cursor CURSOR FOR
SELECT tabEGPurchase.Code
FROM tabEGPurchase
INNER JOIN tabEGPayments
ON tabEGPurchase.Code = tabEGPayments.Code
INNER JOIN tabEarningRecords
ON tabEGPayments.IncomeCode = tabEarningRecords.SEQUENCE
LEFT OUTER JOIN tabFrameList
ON tabEGPurchase.EyeglassCode = tabFrameList.ControlCode
WHERE (DATEDIFF(MONTH,tabEarningRecords.DateEarned,GETDATE()) > 0)
GROUP BY tabEGPurchase.Code

BEGIN TRAN --Start transaction

UPDATE tabEarningRecords
SET Expenditure = 0
WHERE (SEQUENCE IN (SELECT tabEarningRecords.SEQUENCE
FROM tabEGPurchase
INNER JOIN tabEGPayments
ON tabEGPurchase.Code = tabEGPayments.Code
INNER JOIN tabEarningRecords
ON tabEGPayments.IncomeCode = tabEarningRecords.SEQUENCE))

--Check if an error occured, if yes then Rollback and Exit
IF (@@ERROR <> 0)
BEGIN
ROLLBACK TRAN

PRINT 'Error Encountered'

RETURN (99)
END

OPEN income_cursor

FETCH NEXT FROM income_cursor
INTO @income_code

WHILE @@FETCH_STATUS = 0
BEGIN
--Get Total Cost
SELECT @totalcost = ISNULL(tabFrameList.BuyingPrice,0) + ISNULL(tabEGPurchase.MTC,0)
FROM tabEGPurchase
LEFT OUTER JOIN tabFrameList
ON tabEGPurchase.EyeglassCode = tabFrameList.ControlCode
WHERE tabEGPurchase.Code = @income_code

--Get Balance
SELECT @balance = (tabEGPurchase.EyeglassPrice - tabEGPurchase.Discount - SUM(tabEGPayments.PaymentAmount))
FROM tabEGPurchase
INNER JOIN tabEGPayments
ON tabEGPurchase.Code = tabEGPayments.Code
WHERE tabEGPurchase.Code = @income_code
GROUP BY tabEGPurchase.EyeglassPrice,
tabEGPurchase.Discount

--Get Recordcount
SELECT @rCount = Count(tabEarningRecords.EyeGlass)
FROM tabEGPurchase
INNER JOIN tabEGPayments
ON tabEGPurchase.Code = tabEGPayments.Code
INNER JOIN tabEarningRecords
ON tabEGPayments.IncomeCode = tabEarningRecords.SEQUENCE
LEFT OUTER JOIN tabFrameList
ON tabEGPurchase.EyeglassCode = tabFrameList.ControlCode
WHERE (DateDiff(MONTH,tabEarningRecords.DateEarned,GETDATE()) > 0)
AND (tabEGPurchase.Code = @income_code)

PRINT 'Recordcount: ' + Convert(NVARCHAR,@rCount)

--Get records that do not match conditions
SELECT @outsideRecords = COUNT(tabEGPurchase.Code)
FROM tabEarningRecords
INNER JOIN tabEGPayments
ON tabEarningRecords.SEQUENCE = tabEGPayments.IncomeCode
INNER JOIN tabEGPurchase
ON tabEGPayments.Code = tabEGPurchase.Code
WHERE (DATEDIFF(MONTH,tabEarningRecords.DateEarned,GETDATE()) = 0)
AND (tabEGPurchase.Code = @income_code)

SET @rPos = 1

DECLARE income2_cursor CURSOR FOR
SELECT tabEarningRecords.EyeGlass
FROM tabEGPurchase
INNER JOIN tabEGPayments
ON tabEGPurchase.Code = tabEGPayments.Code
INNER JOIN tabEarningRecords
ON tabEGPayments.IncomeCode = tabEarningRecords.SEQUENCE
LEFT OUTER JOIN tabFrameList
ON tabEGPurchase.EyeglassCode = tabFrameList.ControlCode
WHERE (DateDiff(MONTH,tabEarningRecords.DateEarned,GETDATE()) > 0)
AND (tabEGPurchase.Code = @income_code)

OPEN income2_cursor

FETCH NEXT FROM income2_cursor
INTO @eyeglass

WHILE @@FETCH_STATUS = 0
BEGIN
IF (@totalcost >= @eyeglass)
BEGIN
SET @totalcost = @totalcost - @eyeglass

IF @rPos < @rCount
BEGIN
SET @expenditure = @eyeglass
END
ELSE
IF @balance = 0
BEGIN
IF @outsideRecords = 0
SET @expenditure = @eyeglass + @totalcost
ELSE
SET @expenditure = @eyeglass
END
ELSE
BEGIN
SET @expenditure = @eyeglass
END
END
ELSE
BEGIN
SET @expenditure = @totalcost

SET @totalcost = 0
END

UPDATE tabEarningRecords
SET Expenditure = @expenditure
WHERE CURRENT OF income2_cursor

--Check if an error occured, if yes then Rollback and Exit
IF (@@ERROR <> 0)
BEGIN
ROLLBACK TRAN

PRINT 'Error Encountered'

RETURN (99)
END

PRINT 'eyeglass : ' + Convert(NVARCHAR,@eyeglass)

PRINT 'expenditure : ' + Convert(NVARCHAR,@expenditure)

PRINT 'remaining : ' + Convert(NVARCHAR,@totalcost)

PRINT ''

IF (@totalcost = 0)
BREAK

FETCH NEXT FROM income2_cursor
INTO @eyeglass

SET @rPos = @rPos + 1
END

CLOSE income2_cursor

DEALLOCATE income2_cursor

-- Get the next author.
FETCH NEXT FROM income_cursor
INTO @income_code
END

CLOSE income_cursor

DEALLOCATE income_cursor

COMMIT TRAN --Commit transaction

GO

sunitabeck
Master Smack Fu Yak Hacker

5155 Posts

Posted - 2009-03-31 : 20:14:23
Dee, with so many people who have in-depth knowledge of SQL regularly contributing to this forum, it is more likely than not that there are people who can give brilliant solutions to your problem if one exists.

However, the reason no one has responded to your question yet I suspect, is because your query is too long and too complex for someone who may want to spend no more than 5 minutes on any given post.

Reduce your problem to something that is 5 or 10 lines of code, and you will get a response.
Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2009-03-31 : 21:30:27
Agreed.

I'm taking a stab at this but cannot for the life of me figure out what you're trying to do. If you could explain in simple terms the result you're trying to get that would be helpful. More helpful would be sample data, along with the exact output you want from it. Please include enough data so that sums and counts will match, but please keep it as minimal as possible (no more than 30-40 rows total)

Some advice I CAN give:

1. Lose the LEFT JOIN in the first cursor declaration, you don't need it.
2. I don't see what advantage the PRINT statements give, might as well get rid of them.
3. The transaction is probably your biggest performance hit. You really only have one UPDATE to perform so you don't truly need it.
4. Consolidate your queries where the join conditions are identical, you have at least 3 like that. (see below about table variables)
5. If you can't get rid of the cursor loop, don't have it do UPDATE...WHERE CURRENT OF. Instead, insert the results of the cursor operations into a temp table or even better, a table variable. Then do a single UPDATE by joining to this table, and outside the cursor and transaction statements.
Go to Top of Page
   

- Advertisement -