Search

Custom Search

Saturday, January 17, 2009

Recursive Call in Stored Procedures

Recursion is a way of allowing a function to call itself. It results to an iteration of process. Let us have the simple example below that computes for the result of an exponent function:

static void Main(string[] args)
{
double result = exponent(3,4);
Console.WriteLine(result);
Console.ReadKey();
}

private static double exponent(double _base, double power)
{
double result= _base;
if (power > 0)
{
result = result * exponent(_base, power - 1);
}
else
{
result = 1;
}

return result;
}


This is the sample recursive call function in C#. Take note that in recursion there should be a way to terminate the recursion through conditions or else it will bring you to an infinite loop.

Now how can we implement this in SQL? It is allowed to call a stored procedure within a stored procedure. Unfortunately Stored procedure does not return values directly. In case of User Defined Function(UDF), it is not allowed to call a function within a function. Recursions should have a return value in order to determine how the loop will terminate.

The trick here is to use Temporary table to communicate with the calling stored procedure. For simplicity, let's use the same example in getting the result of an exponent:

ALTER PROCEDURE [dbo].[RecursiveCallExponent] (
@base float,
@power float
)
AS
BEGIN

IF(@power > 0)
BEGIN
UPDATE #Result SET Result = Result * @Base
SET @power = @power -1
exec RecursiveCallExponent @base, @power
END
END
GO
-------------------------

ALTER PROCEDURE GetExponent (
-- Add the parameters for the stored procedure here
@base float,
@power float
)
AS
BEGIN
CREATE TABLE #Result (Result float)
insert into #Result (Result) values (1 )
exec RecursiveCallExponent @base, @power

SELECT Result FROM #Result
DROP TABLE #Result
END
GO

GetExponent here is the main stored procedure call. Observe that The Temporary table is created in the main stored procedure to be used by the recursive procedure (RecursiveCallExponent). We cannot create it inside the recursive procedure for it will raise "Object exists" error since we are iterating inside it. Now we can run
"EXEC GetExponent(3,4)"
and will give you a result of 81.

I used recursive on my application to get all consultant with a specific skill in the Heirarchy of skillsets. The scenario is this, I have a Hierachical table which represents the Heirarchy of Skills, e.g. Words, Excel and Powerpoint under MSOffice and MSOffice, Explorer and Media Player under Windows. When I choose specific skills like MSOffice, I should be able to get all consultant under MSOffice including those consultant who has special skills for Powerpoint, Excel and Word and even those under it if it still have sub categories.

4 comments:

  1. Hi Vince. Glad to know you have a blog. It's a good way of expressing yourself, learning from other people, making friends and of course, it can also serve as your study notes. As for me, I created an blog account only so I can comment on my brother's blog. Shame on me. :D

    Now let's go to your recursion. I have nothing against recursion but there are 2 good reasons why we should shy away from it as much as possible. First, it's not straightforward. Although guys like us can readily understand the concept, it still requires our brain one hop just to reach the point. Second, its slower than a direct call. I know your example is pretty much contrived and had you presented a much complex one, like that of the project you're working on, then a recursion would have been justified. So for your Exponent method, it's much better to write it in a non-recursive manner like this

    static double Exponent(double baseNumber, double power)
    {
    double result = baseNumber;
    if (power == 0)
    return 1;
    for (double i = 1; i < Math.Abs(power); i++)
    result *= baseNumber;
    if (power < 0)
    result = 1 / result;

    return result;
    }

    I'm sure if you asked the devs around you to implement factorial, you would get a recursion implementation. Devs usually resort to recursion everytime they see a parameter applied to itself inside the method. Like any other math functions, Factorial can be implemented in non-recursive (preferred) way.

    I know BAI is an MS shop so I'll just assume you're using SQL Server. With the 2005 version, you can use CTE for recursion. Let's say you have a table def like this:

    Skills
    SkillId int PK
    ParentSkillID int (FK to SkillId)

    and with the following tuples

    Id ParentSkill
    1 null
    2 1
    3 1
    4 2
    5 3
    6 null
    7 6

    where 6 and 7 are topmost skills.

    Recursion query thru CTE involves 2 components: the anchor and the recursion itself. They are always joined together by a UNION All. So the query for the above table will be

    ;with AllSkills as
    (
    -- The first query is called the anchor'
    -- It establishes the starting point for the recursion
    SELECT Id, parentId, [level] = 1
    FROM dbo.Skill anchorTable
    WHERE anchorTable.parentId IS NULL

    UNION ALL

    -- This is actually where the
    -- recursion takes place.
    -- Notice it makes a reference to the CTE RecursionT

    SELECT childTable.Id, childTable.parentId,[level]+1
    FROM dbo.Skill childTable
    JOIN AllSkills ON childTable.ParentId = AllSkills.Id
    )
    SELECT * FROM AllSkills ORDER BY parentId, Id

    SQL Server 2008 even raises the ante with the new UDT HeirarchyID. You can now query heirarchy data even without CTEs.

    ReplyDelete
  2. Thank you sir Gio,

    This one is really informative. Actually I just used Calculating exponents to illustrate recursion the simplest way.

    The CTE sample you posted is really helpful, I will try to refactor my stored procedure to use that.

    I hope to hear more comments from the expert(you) on my next posts.

    Thanks again!

    ReplyDelete
  3. Anytime Vince. Continue blogging. See, you wouldn't have learned this CTE thing this soon if you weren't blogging. ;)

    ReplyDelete
  4. Just some minor corrections from my pos. In my example , I meant 1 and 6 being the topmost skills and the RecursiveT which I mentioned in the comment should have been AllSkills table. :)

    ReplyDelete

Adsense Banner