0

I have two cursors, I want to loop through first one, and use its values as parameters for the second cursor and then do some processing. I know how to do this in PL-SQL, but T-SQL puzzles me.

I have gotten so far. For some reason the nested cursor does not print anything.

DECLARE @period DATE
DECLARE @table_type VARCHAR(2)
DECLARE @clmn_clr VARCHAR(100)
DECLARE @clmn_per VARCHAR(100)
DECLARE @period_num INT
DECLARE @period_date DATE
DECLARE @table_type2 VARCHAR(2)

DECLARE c_table CURSOR FOR SELECT   period,
                                    table_type
                            FROM    #period_table
DECLARE c_period CURSOR LOCAL FAST_FORWARD FOR SELECT   clmn_clr,
                                                        clmn_per,
                                                        period_num,
                                                        period_date,
                                                        table_type
                                                 FROM   #column_period
                                                 WHERE  table_type = @table_type

OPEN c_table
    FETCH NEXT FROM c_table
    INTO @period, @table_type
WHILE @@FETCH_STATUS = 0
BEGIN
    print @period
    print @table_type
    print '------------'
    FETCH NEXT FROM c_table
        INTO @period, @table_type

    --Nested cursor
    OPEN c_period
        FETCH NEXT FROM c_period
        INTO @clmn_clr, @clmn_per, @period_num, @period_date, @table_type2

    BEGIN
        print @clmn_clr
        print @clmn_per
        print @period_num
        print @period_date
        print @table_type2
        FETCH NEXT FROM c_period
            INTO @clmn_clr, @clmn_per, @period_num, @period_date, @table_type2
    END
    CLOSE c_period
    DEALLOCATE c_period
END
CLOSE c_table
DEALLOCATE c_table

It does print the first line from cursor c_table but that is all.

Also, any comments for how to do this in T-SQL better are very welcomed.

2 Answers 2

1

There is no need in nesting, here is the only cursor that can do everything:

DECLARE c_period CURSOR LOCAL FAST_FORWARD FOR
    SELECT  p.period,
            c.clmn_clr,
            c.clmn_per,
            c.period_num,
            c.period_date,
            c.table_type
    FROM   #period_table p
    INNER JOIN #column_period c
    ON c.table_type = p.table_type
    ORDER BY p.table_type

I never tested it but id does not seem to me that MSSQL allows something like "dynamic parameter binding" for cursor. Since you opened it - it's done. It only can react on data modifications if appripriate options applied.

You may reopen cursor if you still need nesting for any purpose. Fetch @table_type from outer cursor, then DECLARE ... OPEN nested cursor.

Also note that strings to print (if this is your real subject) can be obtained with single select, withot any cursors (search "string aggregation" for mssql).

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, but I need nesting, this was simplified code. No, printing is just for debugging, but can be useful in the future.
@HonzaB take a look at third paragraph for nested cursors.
1

Here is working solution I have found - I only moved the nested cursor inside.

DECLARE @period DATE
DECLARE @table_type VARCHAR(2)

DECLARE @clmn_clr VARCHAR(100)
DECLARE @clmn_per VARCHAR(100)
DECLARE @period_num INT
DECLARE @period_date DATE
DECLARE @table_type2 VARCHAR(2)

DECLARE c_table CURSOR FOR SELECT   period,
                                    table_type
                            FROM    #period_table
--Fetch first row
OPEN c_table
    FETCH NEXT FROM c_table
    INTO @period, @table_type
--Loop starts here, until it is empty
WHILE @@FETCH_STATUS = 0
BEGIN
    print @period
    print @table_type
    print '----------'

    --Nested cursor
    DECLARE c_period CURSOR LOCAL FAST_FORWARD FOR SELECT   clmn_clr,
                                                            clmn_per,
                                                            period_num,
                                                            period_date,
                                                            table_type
                                                     FROM   #column_period
                                                     WHERE  table_type = @table_type
    OPEN c_period
        FETCH NEXT FROM c_period
        INTO @clmn_clr, @clmn_per, @period_num, @period_date, @table_type2
    WHILE @@FETCH_STATUS = 0
    BEGIN
        print @clmn_clr
        print @clmn_per
        print @period_num
        print @period_date
        print @table_type2
        FETCH NEXT FROM c_period
            INTO @clmn_clr, @clmn_per, @period_num, @period_date, @table_type2
    END
    CLOSE c_period
    DEALLOCATE c_period

    FETCH NEXT FROM c_table
        INTO @period, @table_type
END
CLOSE c_table
DEALLOCATE c_table

3 Comments

Maybe I do not get this correctly, but why do you need a CURSOR at all? Cursors are send from the dark side of the universe to pull poor db people away from the light of set based approaches... What are you doing in this cursor? At the moment it is a procedural (sigh) equivalent of an INNER JOIN, isn't it?
Yes, it seems like case for a simple INNER JOIN, but it is not.I am well aware of disadvantages. But those are only small auxiliary tables (<50 rows), which will execute a lot of queries, which are similar, but need different parameters. Which are stored in those tables. So the heavy lifting will be done by simple SQL.
Ah I see... Happy Coding!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.