SQL Server: How to get all child records given a parent id in a self referencing table SQL Server: How to get all child records given a parent id in a self referencing table sql sql

SQL Server: How to get all child records given a parent id in a self referencing table


You can try this

DECLARE @Table TABLE(        ID INT,        ParentID INT,        NAME VARCHAR(20))INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 1, NULL, 'A'INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 2, 1, 'B-1'INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 3, 1, 'B-2'INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 4, 2, 'C-1'INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 5, 2, 'C-2'DECLARE @ID INTSELECT @ID = 2;WITH ret AS(        SELECT  *        FROM    @Table        WHERE   ID = @ID        UNION ALL        SELECT  t.*        FROM    @Table t INNER JOIN                ret r ON t.ParentID = r.ID)SELECT  *FROM    ret


Unless you are using Oracle, your table structure is not suitable for the problem described. What you are attempting to do is grab a hierarchy (traversing a tree structure).

There is an article, More Trees & Hierarchies in SQL, that describes one method of solving the hierarchy problem. He basically adds a "lineage" column describing the hierarchy to every row.


Recursion in CTE looks bit expensive, so I have wrote this function which make use of recursive function call but much faster that CTE recursion.

CREATE FUNCTION [dbo].[Fn_GetSubCategories](@p_ParentCategoryId INT) RETURNS @ResultTable TABLE (       Id INT)ASBEGIN--Insert first level subcategories.INSERT INTO @ResultTable SELECT Id FROM Category WHERE ParentCategoryId = @p_ParentCategoryId OR Id = @p_ParentCategoryIdDECLARE @Id INTDECLARE @ParentCategory TABLE(Id INT)DECLARE cur_categories CURSORLOCAL STATIC READ_ONLY FORWARD_ONLY FOR SELECT Id FROM Category WHERE ParentCategoryId = @p_ParentCategoryId and Id != @p_ParentCategoryIdOPEN cur_categoriesIF @@CURSOR_ROWS > 0     BEGIN      FETCH NEXT FROM cur_categories INTO @Id     WHILE @@FETCH_STATUS = 0     BEGIN        --Insert remaining level sub categories.        IF EXISTS(SELECT 1 FROM Category WHERE ParentCategoryId = @Id AND Id != @Id)        BEGIN            INSERT INTO @ResultTable            SELECT DISTINCT C.Id from Fn_GetSubCategories(@Id) C INNER JOIN @ResultTable R ON C.Id != R.Id        END     FETCH NEXT FROM cur_categories INTO @Id     END     --Delete duplicate records     ;WITH CTE AS     (SELECT *,ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Id) AS RN FROM @ResultTable)     DELETE FROM CTE WHERE RN<>1ENDCLOSE cur_categoriesDEALLOCATE cur_categoriesRETURNEND