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)
 Can a cursor be passed as a parameter to a sp?

Author  Topic 

Utpal
Posting Yak Master

179 Posts

Posted - 2002-09-14 : 08:18:40
Hi everybody,
I am using SQL Server 7.0. Can a cursor declared in one stored procedure be passed as a parameter to another stored procedure? If not, can it be emulated in any way?


robvolk
Most Valuable Yak

15732 Posts

Posted - 2002-09-14 : 11:42:29
According to Books Online, cursor variables can only be used as output variables in a stored procedure. I *think* you might be able to open it in the receiving stored procedure, but I can't find a definite yes/no in BOL about it and I can't test it.

The best thing to do is NOT use cursor. Put the results into a temp table (or regular table). It can be created in Procedure A and referenced in Procedure B.

Go to Top of Page

Utpal
Posting Yak Master

179 Posts

Posted - 2002-09-16 : 02:07:07
quote:

The best thing to do is NOT use cursor. Put the results into a temp table (or regular table). It can be created in Procedure A and referenced in Procedure B.



I used this technique in other stored procedures. In this one as I have to anyway open a cursor, I thought passing the cursor as a parameter would be the fastest and would consume minimum server resources, because in the temp table approach, first the temp table has to be created, then it has to be filled with the results, then a cursor has to be declared from the other stored procedure. Tell me if I am wrong.




Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2002-09-16 : 08:22:52
quote:
In this one as I have to anyway open a cursor
Well, if you think that you HAVE TO use a cursor, it's a fair bet that you're doing it wrong

If you post your code, your table structures, and what you're trying to accomplish, we can take a stab at another, non-cursor approach. We've done it before.

Go to Top of Page

M.E.
Aged Yak Warrior

539 Posts

Posted - 2002-09-16 : 16:10:27
I've seen something simular done passing table variables around. Cursor loads a table var and passes that to a different server. On the same note I tore it apart and made it setbased... Hehehe so much nicer that way

-----------------------
Take my advice, I dare ya
Go to Top of Page

Utpal
Posting Yak Master

179 Posts

Posted - 2002-09-17 : 06:43:25
quote:

If you post your code, your table structures, and what you're trying to accomplish, we can take a stab at another, non-cursor approach. We've done it before.



Basically, the sp generates standard costs of items as on a given date and stores it in the StdCost_Master table. The standard cost of a raw material is based on the weighted average price of its purchases. The standard cost of a sub-assembly or finished good is calculated based on the values (qty * standard cost) of its constituents, which is contained in the Parts_List table. I am opening the cursor for the purpose of calculation of standard cost of a sub-assembly/finished good, which is done using a recursive sp Std_Cost_Derived.

The table structures (relevant fields) are as follows:

Item_Master
part_no
description
opening_stock

StdCost_Master (Std. costs of part_no as on various dates)
part_no
cost_date
cost

Parts_List (Details of constituents of part_no)
part_no
rm_part_no
qty

The code of the Std Cost generation sp is as follows:


CREATE PROCEDURE Generate_Std_Costs @cost_date DateTime, @rmc Bit, @fga Bit AS

DECLARE @part_no Char(8), @opening_stock Numeric(9,3), @last_cost_date Datetime, @last_cost Money, @new_cost Money, @update Bit

SET NOCOUNT ON

BEGIN TRANSACTION

DECLARE Cursor_Item_Master CURSOR
LOCAL FAST_FORWARD
FOR
SELECT Item_Master.part_no, Item_Master.opening_stock, StdCost_Master.last_cost_date, StdCost_Master.last_cost
FROM Item_Master LEFT JOIN
( SELECT A.part_no, A.cost_date AS last_cost_date, A.cost AS last_cost FROM StdCost_Master A
INNER JOIN
( SELECT part_no, MAX(cost_date) AS last_cost_date
FROM StdCost_Master
WHERE cost_date < @cost_date
GROUP BY part_no ) B
ON A.part_no = B.part_no AND A.cost_date = B.last_cost_date ) StdCost_Master
ON Item_Master.part_no = StdCost_Master.part_no
ORDER BY Item_Master.group_code

OPEN Cursor_Item_Master

FETCH NEXT FROM Cursor_Item_Master INTO @part_no, @opening_stock, @last_cost_date, @last_cost

WHILE @@FETCH_STATUS = 0
BEGIN

SET @new_cost = 0

IF EXISTS ( SELECT rm_part_no, qty FROM Parts_List WHERE part_no = @part_no )
BEGIN

IF @fga = 1
EXECUTE Std_Cost_Derived @part_no, @rmc, @cost_date, @new_cost = @new_cost OUTPUT

SET @update = @fga

END

ELSE
BEGIN

IF @rmc = 1
EXECUTE Std_Cost_Purchase_Based @part_no, @cost_date, @opening_stock, @last_cost_date, @last_cost,
@new_cost = @new_cost OUTPUT

SET @update = @rmc

END

IF @update = 1
BEGIN
IF EXISTS ( SELECT cost FROM StdCost_Master WHERE part_no = @part_no AND cost_date = @cost_date )
UPDATE StdCost_Master
SET cost = @new_cost
WHERE part_no = @part_no AND cost_date = @cost_date
ELSE
INSERT INTO StdCost_Master VALUES ( @part_no, @cost_date, @new_cost )
END

FETCH NEXT FROM Cursor_Item_Master INTO @part_no, @opening_stock, @last_cost_date, @last_cost

END

CLOSE Cursor_Item_Master
DEALLOCATE Cursor_Item_Master

IF EXISTS( SELECT cost_date FROM StdCost_Dates WHERE cost_date = @cost_date )
UPDATE StdCost_Dates
SET rmc = CASE rmc WHEN 1 THEN 1 ELSE @rmc END,
fga = CASE fga WHEN 1 THEN 1 ELSE @fga END
ELSE
INSERT INTO StdCost_Dates VALUES ( @cost_date, @rmc, @fga )

COMMIT TRANSACTION

SET NOCOUNT OFF

RETURN




CREATE PROCEDURE Std_Cost_Derived @part_no Char(8), @rmc Bit, @cost_date Datetime, @new_cost Money OUTPUT AS

DECLARE @rm_part_no Char(8), @qty Numeric(9,3), @rm_new_cost Money,
@opening_stock Numeric(9,3), @last_cost_date Datetime, @last_cost Money

DECLARE Cursor_Parts_List CURSOR
LOCAL FAST_FORWARD
FOR
SELECT rm_part_no, qty
FROM Parts_List
WHERE part_no = @part_no

OPEN Cursor_Parts_List

FETCH NEXT FROM Cursor_Parts_List INTO @rm_part_no, @qty

IF @@FETCH_STATUS = 0
BEGIN

WHILE @@FETCH_STATUS = 0
BEGIN

SET @rm_new_cost = 0

EXECUTE Std_Cost_Derived @rm_part_no, @rmc, @cost_date, @new_cost = @rm_new_cost OUTPUT

SET @new_cost = @new_cost + ( @rm_new_cost * @qty )

FETCH NEXT FROM Cursor_Parts_List INTO @rm_part_no, @qty

END

END

ELSE
BEGIN

IF @rmc = 1
BEGIN
SELECT @opening_stock = Item_Master.opening_stock, @last_cost_date = StdCost_Master.last_cost_date,
@last_cost = StdCost_Master.last_cost
FROM Item_Master
LEFT JOIN
( SELECT A.part_no, A.cost_date AS last_cost_date, A.cost AS last_cost FROM StdCost_Master A
INNER JOIN
( SELECT part_no, MAX(cost_date) AS last_cost_date
FROM StdCost_Master
WHERE cost_date < @cost_date
GROUP BY part_no ) B
ON A.part_no = B.part_no AND A.cost_date = B.last_cost_date ) StdCost_Master
ON Item_Master.part_no = StdCost_Master.part_no
WHERE Item_Master.part_no = @part_no
EXECUTE Std_Cost_Purchase_Based @part_no, @cost_date, @opening_stock, @last_cost_date, @last_cost, @new_cost = @new_cost OUTPUT
END

END

RETURN



To determine whether the item is a sub-assembly/finished good or a raw material, I am using:
	IF EXISTS ( SELECT rm_part_no, qty FROM Parts_List WHERE part_no = @part_no )


Again in the Std_Cost_Derived sp, using the same query I am opening a cursor. If instead of using the above code (IF EXISTS (...)),
I opened a cursor there itself and passed it as a parameter to the Std_Cost_Derived sp, I wouldn't have had to run the same query again in Std_Cost_Derived.

So let me know what is the best way to implement this.




Edited by - Utpal on 09/17/2002 06:45:06

Edited by - Utpal on 09/17/2002 06:56:31

Edited by - Utpal on 09/17/2002 06:58:14

Edited by - Utpal on 09/17/2002 07:00:34

Edited by - Utpal on 09/17/2002 08:13:30
Go to Top of Page
   

- Advertisement -