Mixer
Mixer

Reputation: 183

How to loop, search and concatenate string in with cursor in TSQL?

I have this set of data

psrid   parent_psrid    description
1   NULL    Work Management
2   1   Asset Maintenance
3   2   Code
4   3   asset type code
5   3   asset class code
6   3   asset class code - common rate type code
7   3   asset type code - asset status code
8   3   asset material class code - common rate type code
9   3   external interface code
10  2   Asset
11  10  asset
12  10  asset attachment
13  10  asset - common rate type code
14  2   Warranty
15  14  asset warranty attachment
16  1   CRM
17  16  Request
18  17  request
19  16  Code
20  19  crm request type code - crm task type code
21  19  task category code
22  19  request category code
23  19  request type code
24  19  task type code

I want to create a stored procedure to concatenate description of selected psrid with descriptions of all other rows that have parent_psrid which matches the psrid from previous row, so on and so forth until the parent psrid is null. Please note, it will only look and concatenate descriptions with the rows above it (psrid is primary key and sorted).

This is like a zic-zac mapping. For example, if we start at psrid 10 and parent_psrid is 2 as below picture, then the final concatenated string would be Work Management > Asset Maintenance > Asset

enter image description here

I have got to this far but I don't know what to do next.

-- Declare a variables
DECLARE @in_psrid int = 10,
        @psrid nvarchar(255),
        @spsone_datasecurity_model_parent_psrid nvarchar(255),
        @object_description nvarchar(255)

-- Declare a variable of type TABLE. It will be used as a temporary table.
DECLARE @myTable TABLE (
    [psrid]        int,
    [spsone_datasecurity_model_parent_psrid]   int,
    [object_description]   nvarchar(255)
)

-- Insert required data in the variable of type TABLE
INSERT INTO @myTable
SELECT [psrid], [spsone_datasecurity_model_parent_psrid], [object_description]
FROM [IcjisTest].[dbo].[Book2]

-- Declare cursor
DECLARE cur_psrid CURSOR
    FOR SELECT [psrid], [spsone_datasecurity_model_parent_psrid], [object_description]
    FROM @myTable
    WHERE [psrid] = @in_psrid;

OPEN cur_psrid;

FETCH NEXT FROM cur_psrid INTO 
    @psrid, 
    @spsone_datasecurity_model_parent_psrid,
    @object_description;

WHILE @@FETCH_STATUS = 0
    BEGIN
        PRINT @psrid + @spsone_datasecurity_model_parent_psrid + @object_description;
        FETCH NEXT FROM cur_psrid INTO 
            @psrid, 
            @spsone_datasecurity_model_parent_psrid,
            @object_description;
    END;

    CLOSE cur_psrid;

DEALLOCATE cur_psrid;

Please help! Thank you.

Upvotes: 0

Views: 446

Answers (1)

JNevill
JNevill

Reputation: 50034

Any time you think "I should loop" in a database you should immediately think "but there must be a better "set" approach to solving this".

A recursive CTE is the better "set" approach to solving this. Check out Example D in that link in the "Examples" section of the page.

WITH buildstring As
(
    /*
     * Recursive Seed - Starting point of recursive lookup
     */
    SELECT psrid, parent_psrid, description, 1 as depth
    FROM yourtable
    WHERE psrid = 10

    UNION ALL

    /* 
     * Recursive Member - The part that loops until the join(s) fail
     * Note that we refer to the CTE itself (buildstring) in the 
     * FROM clause, which is what causes the recursiveness. 
     */
    SELECT
        yourtable.psrid,
        yourtable.parent_psrid,
        buildstring.description + " " + yourtable.description,
        buildstring.depth + 1
    FROM buildstring
        INNER JOIN yourtable 
            ON buildstring.parent_psrid = yourtable.psrid
    WHERE depth < 20 --Just in case you get into an infinite cycle
          
)
SELECT * 
FROM (SELECT description, row_number() OVER (ORDER BY depth DESC) as rn FROM buildstring) depth
WHERE rn = 1 --Get the last record created by the recursive CTE

That should get you in the ballpark. You'll most likely want to tweak that a bit to get whatever output you are looking for, but that should spit out a description with all parent descriptions of psrid of 10.

Upvotes: 1

Related Questions