Home > Enterprise >  Use cursor for with 2 tables to insert rows
Use cursor for with 2 tables to insert rows

Time:12-20

I have 2 tables: items and cost.

  • In table items, I have old item code and new item code
  • In table cost, I have the item code and the cost

I want to create new rows in table cost for the new item code according to the cost that already exist for the old item code.

For example:

enter image description here

enter image description here

I expect to see this result after I run the cursor in the cost table:

enter image description here

I try to run this, but it's been running forever and duplicates every row 100000 times:

DECLARE @item_code_old nvarchar (50)
DECLARE @item_code_new nvarchar (50)

DECLARE CostCURSOR CURSOR FOR
    SELECT item_code_old, item_code_new 
    FROM item 
    WHERE company = 'AEW' AND item_code_new IS NOT NULL

OPEN CostCURSOR 

FETCH NEXT FROM CostCURSOR INTO @item_code_old, @item_code_new

WHILE (@@FETCH_STATUS = 0)
BEGIN
    SELECT @item_code_old = item_code_old 
    FROM cost 
    WHERE company = 'AEW' AND year = 2021

    INSERT INTO cost
        SELECT
            company,
            year,
            month,
            @item_code_new,
            unit_cost
        FROM
            cost
        WHERE
            company = 'AEW' AND year = 2021

    FETCH NEXT FROM CostCURSOR INTO @item_code_old, @item_code_new
END

CLOSE CostCURSOR 
DEALLOCATE CostCURSOR

What am I missing?

CodePudding user response:

What you are doing with your variables doesn't really make sense, you fetch your next value into @item_code_old, but then at the start of each loop you then assign it a value pretty much at random:

SELECT  @item_code_old = item_code_old
FROM    cost
WHERE   company = 'AEW'
AND     year = 2021;

Then when it comes to inserting the new cost, you don't use this variable at all:

INSERT INTO cost
SELECT  company, year, month, @item_code_new, unit_cost
FROM    cost
WHERE   company = 'AEW'
AND     year = 2021;

I'd guess that you don't need this first step that reassigns @item_code_old, and you do need to apply the filter to the insert query.

With that being said, a cursor is completely unnecessary here (which you'll find is often the case with cursors), you can do this with a single insert, using something like this:

INSERT Cost (Company, Year, Month, item_code_old, unit_cost)
SELECT  c.company, c.year, c.month, i.item_code_new, c.unit_cost
FROM    cost AS c
        INNER JOIN Item AS i
            ON c.item_code_old = i.item_code_old
WHERE   c.company = 'AEW'
AND     c.year = 2021
AND     i.item_code_new IS NOT NULL;

For the sake of completeness, your cursor solution would be something the following, but I would stress this is not a good approach. Cursors should be a last resort, and are probably something it is not even worth practising as it is not something you will find very useful. Instead of practicing cursors, instead practice trying to find the set-based approach, this will be significantly better use of your time. Anyway, rant over:

DECLARE @item_code_old NVARCHAR(50);
DECLARE @item_code_new NVARCHAR(50);


DECLARE CostCURSOR CURSOR LOCAL FAST_FORWARD FOR
    SELECT  item_code_old, item_code_new
    FROM    item
    WHERE   company = 'AEW'
    AND     item_code_new IS NOT NULL;

OPEN CostCURSOR;
FETCH NEXT FROM CostCURSOR INTO @item_code_old, @item_code_new;

WHILE(@@FETCH_STATUS = 0)
BEGIN

    INSERT INTO cost (Company, Year, Month, Item_Code_Old, unit_cost)
    SELECT  company, year, month, @item_code_new, unit_cost
    FROM    cost
    WHERE   company = 'AEW'
    AND     year = 2021
    AND     item_code_old = @item_code_old;

    FETCH NEXT FROM CostCURSOR INTO @item_code_old, @item_code_new;

END;
CLOSE CostCURSOR;
DEALLOCATE CostCURSOR;
  • Related