SQL Server Query to get parent child

mrwjdhj3  于 2023-04-19  发布在  其他
关注(0)|答案(2)|浏览(150)

I've 2 tables representing a similar folder structure like following:

table1
| Id | Name |
| ------------ | ------------ |
| 1 | a |
| 2 | a_b |
| 3 | a_b_c |
| 4 | x |
| 5 | x_z |
| 6 | x_z_y |

table2

parentIdchildId
12
23

My input is a_b_c. Is there a way (without cursors) with a single query fetch all parents of input a_b_c? Expected result would be:

IdName
3a_b_c
2b_c
1-a
wgeznvg7

wgeznvg71#

Something like this perhaps:

select *
into #t
from (
    VALUES  (1, N'a')
    ,   (2, N'a_b')
    ,   (3, N'a_b_c')
    ,   (4, N'x')
    ,   (5, N'x_z')
    ,   (6, N'x_z_y')
) t (Id,Name)

select *
into #t2
from (
    VALUES  (1, 2)
    ,   (2, 3)
) t (parentId,childId)

;WITH CTE AS (
    select id, t2.parentId
    from #t t
    LEFT join #t2 t2
        ON  t2.childId = t.id
    where t.name = 'a_b_c'
    union all
    select  t2.childid, t2.parentid
    from    #t2 t2
    INNER JOIN CTE c
        On  c.parentID = t2.childid
    )
, CTE2 AS (
    select id
    from cte
    union
    select parentid
    from cte
)
select *
from CTE2 c
inner join #t t
    ON  t.id = c.id
;

I had to create root rows by doing a UNION, usually the hierarchy table2 should contain both those with and without parents

velaa5lx

velaa5lx2#

Using the provided example data (and embellishing on it a little):

DECLARE @Table1 TABLE (Id INT, Name NVARCHAR(20));
INSERT INTO @Table1 (Id, Name) VALUES 
(1, 'a'), (2, 'a_b  '), (3, 'a_b_c'), 
(4, 'x    '), (5, 'x_z  '), (6, 'x_z_y');

DECLARE @Table2 TABLE (parentId INT, childId INT);
INSERT INTO @Table2 (parentId, childId) VALUES
(1, 2), (2, 3);

INSERT INTO @Table2 (parentId, childId) VALUES
(6, 5), (5, 4);

This is a classic uses for recursive common table expressions. We're going to start with all the root children, and work our way through:

DECLARE @TargetRow NVARCHAR(20) = 'a_b_c';

;WITH rCTE AS (
SELECT a.childId AS topLevelChild, a.parentId, a.childId
  FROM @Table2 a
    LEFT OUTER JOIN @Table2 b
      ON a.childId = b.parentId
    INNER JOIN @Table1 t
      ON a.childId = t.Id
 WHERE b.parentId IS NULL
   AND (t.Name = @TargetRow OR @TargetRow IS NULL)
UNION ALL
SELECT topLevelChild, r.parentId, r.childId
  FROM rCTE a
    INNER JOIN @Table2 r
      ON a.parentId = r.childId
)

SELECT a.childId, t.Name
  FROM rCTE a
    INNER JOIN @Table1 t
      ON a.childId = t.Id
 WHERE a.topLevelChild = a.childId
UNION ALL
SELECT a.parentId, t.Name
  FROM rCTE a
    INNER JOIN @Table1 t
      ON a.parentId = t.Id;

I've added a variable into the mix which optionally allows you to limit the rows returned to a particular child, if you leave it null it returns all rows.

childIdName
3a_b_c
2a_b
1a

相关问题