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 2008 Forums
 Transact-SQL (2008)
 Need help removing cursor

Author  Topic 

jay_snow
Starting Member

3 Posts

Posted - 2013-08-30 : 05:31:17
Hi ,

I have inherrited a system with a lot of hideously unoptimized code, i am currently trying to remove a cursor from a job that takes a LONG time to run every night. However i dont seem to be able to replicate what its doing with set based logic. I know what i want to do, get the data into a temp table and use a case statement to determine which rows should have the proc executed. However i have not been able to get this to work yet...............does anyone have any examples for code i can use as an alternative to this cursor.............any tips pointers or examples would be greatly appreciated.

-- INFLATE THE STOCK IN MOM
IF (@SYNCTYPE='INCREMENT')
BEGIN
DECLARE C1 CURSOR FOR
-- SHOW THE RESULTS
SELECT NUMBER,
MOM_AVAIL_STOCK,
MOM_PHYS_STOCK,
WH_PHYS_STOCK,
WH_PHYS_STOCK - MOM_PHYS_STOCK AS DIFF
FROM @RES
WHERE MOM_PHYS_STOCK != WH_PHYS_STOCK
AND (WH_PHYS_STOCK - MOM_PHYS_STOCK) > 0
ORDER BY NUMBER
OPEN C1
FETCH NEXT FROM C1 INTO @N, @MA, @MP, @WP, @D
WHILE @@FETCH_STATUS = 0
BEGIN
IF (@D != 0)
BEGIN
EXEC MOM$BRAINTREESTOCKSYNC @NUMBER=@N,@UNITS=@D,@USERID='WEB',@NOTATION='BRAINTREE Stock Sync'
END

FETCH NEXT FROM C1 INTO @N, @MA, @MP, @WP, @D
END
CLOSE C1
DEALLOCATE C1
END



Jay_Snow

bandi
Master Smack Fu Yak Hacker

2242 Posts

Posted - 2013-08-30 : 05:48:06
What is the purpose of stored procedure "MOM$BRAINTREESTOCKSYNC"
Depends on the above logic we can make out changes

--
Chandu
Go to Top of Page

jay_snow
Starting Member

3 Posts

Posted - 2013-08-30 : 07:56:59
Thanks for the reply! This is the code for the proc.........

USE [MailOrderManager]
GO
/****** Object: StoredProcedure [dbo].[MOM$BRAINTREESTOCKSYNC] Script Date: 30/08/2013 11:35:30 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO



-- Make changes to the bin quantities
-- neilb: 2010-10-14 - First Draft
-- neilb: 2010-10-23 - Write to POP..MOM_SUSPENSE and add @NOTATION
-- neilb: 2011-03-17 - Convert for use with BRAINTREE Bins
-- davidh: 2011-04-06 - If no bin exists we must ALTER one
ALTER PROCEDURE [dbo].[MOM$BRAINTREESTOCKSYNC]
(
@NUMBER varchar(20),
@UNITS int,
@USERID varchar(20),
@NOTATION varchar(255)
)
AS
SET NOCOUNT ON
-- ========================================================
-- Declare Variables
-- ========================================================
DECLARE @BIN_ID int -- Bin_id of the bin we are going to inflate / deflate
DECLARE @SBIN_ID int -- Suspense Bin_id
DECLARE @INVENT_ID int -- Used as the key for the FIFO pricing table
DECLARE @UNITCOST NUMERIC(12,2) -- Unit Cost for FIFO pricing
DECLARE @TRANS_ID int -- Used as the key for the transaction table
DECLARE @NEWINVTOTAL NUMERIC(12,2) -- Total Of Units

-- ========================================================
-- Setup some variables used throughout the script.
-- ========================================================
SELECT TOP 1 @BIN_ID=BIN_ID FROM BIN WITH (NOLOCK) WHERE BINDESC='BRAINTREE' AND NUMBER=@NUMBER
SELECT TOP 1 @NEWINVTOTAL=NEWINVTOT FROM INVTRANS WITH (NOLOCK) WHERE NUMBER=@NUMBER ORDER BY TRANS_ID DESC
SELECT TOP 1 @UNITCOST=COLSCOST FROM ST_EXTRA WHERE NUMBER=@NUMBER

IF @BIN_ID IS NULL
BEGIN

-- ===========================================
-- Insert a row into the bin table
-- ===========================================
INSERT INTO MailOrderManager..BIN DEFAULT VALUES
SELECT @BIN_ID = @@IDENTITY

UPDATE MailOrderManager..BIN SET
NUMBER=UPPER(@NUMBER),
BINDESC='BRAINTREE',
STATUS='A',
SELL_PRIOR=1
WHERE
BIN_ID = @BIN_ID

END

-- ========================================================
-- Increase the amount in the bin
-- Inflate the stock
-- ========================================================
IF (@UNITS > 0)
BEGIN
-- Increase the value of stock we have bound to this bin

-- ========================================================
-- Insert New Inventor Row
-- ========================================================
INSERT INTO INVENTOR DEFAULT VALUES
SELECT @INVENT_ID=@@IDENTITY
UPDATE INVENTOR SET
NUMBER = @NUMBER,
DELIV_DATE = dateadd(dd,0, datediff(dd,0,GETDATE())),
UNIT_COST = IsNull(@UNITCOST,0),
DELIV_QTY = @UNITS,
UNITS = @UNITS,
BIN_ID = @BIN_ID
WHERE
INVENT_ID = @INVENT_ID

-- ========================================================
-- UPDATE THE QTY IN THE SOURCE AND TARGET BINS
-- ========================================================
UPDATE BIN SET
UNITS = UNITS + @UNITS
WHERE
BIN_ID = @BIN_ID

-- ========================================================
-- UPDATE THE QTY IN THE STOCK TABLE
-- ========================================================
--UPDATE STOCK SET
-- UNITS = UNITS + @UNITS
--WHERE
-- NUMBER = @NUMBER


-- ========================================================
-- INSERT NEW ROW TO THE INVTRANS TABLE
-- ========================================================
INSERT INTO INVTRANS DEFAULT VALUES
SELECT @TRANS_ID=@@IDENTITY
UPDATE INVTRANS SET
NUMBER = @NUMBER,
INVENT_ID = @INVENT_ID,
TRANS_DATE = dateadd(dd,0, datediff(dd,0,GETDATE())),
TRANSTYPE = 'A',
QUANTITY = @UNITS,
UNIT_COST = IsNull(@UNITCOST,0),
TOTAL_AMT = IsNull(@UNITCOST,0) * @UNITS,
USERID = @USERID,
NEWINVTOT = IsNull(@NEWINVTOTAL,0) + @UNITS,
NOTATION = @NOTATION,
BIN_ID = @BIN_ID
WHERE
TRANS_ID = @TRANS_ID

END
ELSE
BEGIN

-- ========================================================
-- There is enough available units for us to remove the units from the inventor table
-- ========================================================
SELECT @INVENT_ID=INVENT_ID
FROM INVENTOR WITH (NOLOCK)
WHERE NUMBER=@NUMBER AND BIN_ID=@BIN_ID

IF (@INVENT_ID IS NULL)
BEGIN
-- ========================================================
-- Insert New Inventor Row
-- ========================================================
INSERT INTO INVENTOR DEFAULT VALUES
SELECT @INVENT_ID=@@IDENTITY
UPDATE INVENTOR SET
NUMBER = @NUMBER,
DELIV_DATE = dateadd(dd,0, datediff(dd,0,GETDATE())),
UNIT_COST = IsNull(@UNITCOST,0),
DELIV_QTY = @UNITS*-1,
UNITS = @UNITS*-1,
BIN_ID = @BIN_ID
WHERE
INVENT_ID = @INVENT_ID
END


-- ========================================================
-- Update The Inventor Row
-- ========================================================
UPDATE INVENTOR SET
UNITS = @UNITS+UNITS
WHERE
INVENT_ID = @INVENT_ID

-- ========================================================
-- UPDATE THE QTY IN THE SOURCE AND TARGET BINS
-- ========================================================
UPDATE BIN SET
UNITS = UNITS + @UNITS
WHERE
BIN_ID = @BIN_ID

-- ========================================================
-- UPDATE THE QTY IN THE STOCK TABLE
-- ========================================================
--UPDATE STOCK SET
-- UNITS = UNITS + @UNITS
--WHERE
-- NUMBER = @NUMBER


-- ========================================================
-- INSERT NEW ROW TO THE INVTRANS TABLE
-- ========================================================
INSERT INTO INVTRANS DEFAULT VALUES
SELECT @TRANS_ID=@@IDENTITY
UPDATE INVTRANS SET
NUMBER = @NUMBER,
INVENT_ID = @INVENT_ID,
TRANS_DATE = dateadd(dd,0, datediff(dd,0,GETDATE())),
TRANSTYPE = 'A',
QUANTITY = @UNITS,
UNIT_COST = IsNull(@UNITCOST,0),
TOTAL_AMT = IsNull(@UNITCOST,0) * @UNITS,
USERID = @USERID,
NEWINVTOT = IsNull(@NEWINVTOTAL,0) + @UNITS,
NOTATION = @NOTATION,
BIN_ID = @BIN_ID
WHERE
TRANS_ID = @TRANS_ID

END
-- =============================================================
-- INSERT A ROW INTO THE POP..MOM_SUSPENSE TABLE FOR AUDIT TRAIL
-- neilb: 2010-10-23
-- =============================================================

INSERT INTO POP..MOM_SUSPENSE
([DATE],NUMBER,UNITS,USERID,NOTATION)
SELECT GETDATE(),@NUMBER,@UNITS,@USERID,@NOTATION


Jay_Snow
Go to Top of Page

ScottPletcher
Aged Yak Warrior

550 Posts

Posted - 2013-08-30 : 14:55:46
I suggest rewriting the [MOM$BRAINTREESTOCKSYNC] procedure to also accept a table as input. That allows you to keep all the SYNC logic in one place but also do set-based INSERTs/UPDATEs to the underlying table rather than having to use a cursor and send each row through individually, which will be vastly slower than a set-based approach.
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

30421 Posts

Posted - 2013-08-30 : 17:57:34
Something like this?
CREATE TABLE	#Bin
(
Number VARCHAR(100) NOT NULL,
Units INT NOT NULL,
Bin_ID INT NOT NULL,
Notation VARCHAR(100) NOT NULL,
UserID VARCHAR(100) NOT NULL
);

MERGE MailOrderManager.dbo.BIN AS tgt
USING (
SELECT UPPER(Number) AS Number,
WH_PHYS_STOCK - MOM_PHYS_STOCK AS Units,
'WEB' AS UserID,
'BRAINTREE Stock Sync' AS Notation,
'BRAINTREE' AS BinDesc,
'A' AS [Status],
1 AS Sell_Prior
FROM @RES
WHERE WH_PHYS_STOCK > MOM_PHYS_STOCK
) AS src ON src.BinDesc = tgt.BinDesc
AND src.Number = tgt.Number
WHEN NOT MATCHED BY TARGET
THEN INSERT (
Number,
BinDesc,
[Status],
Sell_Prior,
Units
)
VALUES (
src.Number,
src.BinDesc,
src.[Status],
src.Sell_Prior,
src.Units
)
WHEN MATCHED
THEN UPDATE
SET tgt.Units += src.Units
OUTPUT src.Number,
src.Units,
inserted.Bin_ID,
src.Notation,
src.UserID
INTO #Bin
(
Number,
Units,
Bin_ID,
Notation,
UserID
);

CREATE TABLE #Invent
(
Number VARCHAR(100) NOT NULL,
Invent_ID INT NOT NULL,
Units INT NOT NULL,
Unit_Cost MONEY NOT NULL,
Bin_ID INT NOT NULL,
Notation VARCHAR(100) NOT NULL,
UserID VARCHAR(100) NOT NULL
);

MERGE dbo.Inventor AS tgt
USING (
SELECT s.Number,
CAST(GETDATE() AS DATE) AS Deliv_Date,
COALESCE(w.UnitCost, 0) AS Unit_Cost,
s.Units AS Deliv_Qty,
s.Units,
s.Bin_ID,
Notation,
UserID
FROM #Stage AS s
LEFT JOIN (
SELECT Number,
MAX(ColsCost) AS UnitCost
FROM dbo.ST_EXTRA
GROUP BY Number
) AS w ON w.Number = s.Number
) AS src ON src.Number = tgt.Number
AND src.Bin_ID = tgt.Bin_ID
WHEN NOT MATCHED BY TARGET
THEN INSERT (
Number,
Deliv_Date,
Unit_Cost,
Deliv_Qty,
Units,
Bin_ID
)
VALUES (
src.Number,
src.Deliv_Date,
src.Unit_Cost,
src.Deliv_Qty,
src.Units,
src.Bin_ID
)
WHEN MATCHED
THEN UPDATE
SET tgt.Units += src.Units
OUTPUT src.Number,
inserted.Invent_ID,
src.Units,
src.Unit_Cost,
src.Bin_ID,
src.Notation,
src.UserID
INTO #Invent
(
Number,
Invent_ID,
Units,
Unit_Cost,
Bin_ID,
Notation,
UserID
);

DROP TABLE #Bin;

INSERT dbo.INVTRANS
(
Number,
Invent_ID,
Trans_Date,
TransType,
Quantity,
Unit_Cost,
Total_Amt,
UserID,
NewInvTot,
Notation,
Bin_ID
)
OUTPUT inserted.Trans_Date AS [Date],
inserted.Number,
inserted.Units,
inserted.UserID,
inserted.Notation
INTO POP..MOM_SUSPENSE
(
[Date],
NUMBER,
UNITS,
USERID,
NOTATION
)
SELECT i.Number,
i.Invent_ID,
CAST(GETDATE() AS DATE) AS Trans_Date,
'A' AS TransType,
i.Units AS Quantity,
i.Unit_Cost,
i.Unit_Cost * i.Units AS Totalt_Amt,
i.UserID AS UserID,
COALESCE(q.NewInvTotal, 0) + i.Units AS NewInvTot,
i.Notation AS Notation,
i.Bin_ID
FROM #Invent AS i
OUTER APPLY (
SELECT TOP(1) x.NewInvTot AS NewInvTotal
FROM dbo.INVTRANS AS x WITH (NOLOCK)
WHERE x.Number = i.Number
ORDER BY x.Trans_ID DESC
) AS q(NewInvTotal);

DROP TABLE #Invent;



Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA
Go to Top of Page

jay_snow
Starting Member

3 Posts

Posted - 2013-09-03 : 03:48:34
Thanks very much for the advice, and the example........i will have a go at using that approach and let you know if it works! :)

Jay_Snow
Go to Top of Page
   

- Advertisement -