SQL查找某些记录类型的父ID

时间:2013-08-21 20:33:38

标签: sql sql-server tsql

我有一张如下表:

ID         Type      ParentID
001         C          007
002         C          005
003         B          007
004         C          008
005         R          NULL
006         C          004
007         B          004
008         R          009
009         X          NULL

类型层次结构是X> R> C = B.我需要找到B和C的所有记录'R父级。 挑战是一些B或C记录的父母是B或C,X需要被排除在外。 结果将是:

ID         Type      ParentID     MasterParentID
001         C          007           008
002         C          005           005
003         B          007           008
004         C          008           008
005         R          NULL          NULL
006         C          004           008
007         B          004           008 
008         R          009           NULL
009         X          NULL          NULL

有什么建议吗?非常感激。

3 个答案:

答案 0 :(得分:1)

在SQL Server 2005及更高版本中,“common table expression”可以执行此操作...

-- Assuming this table structure
--CREATE TABLE dbo.Test ( ID char(3), Type char(1), ParentID char(3))

;
WITH Tree(StartID, StartType, Parent, Child) AS
(
    SELECT ID, Type, cast(NULL as char(3)), ID
    FROM Test
    WHERE ParentID IS NULL

    UNION ALL

    SELECT
        -- Skip over the "X" rows...
        CASE WHEN Tree.StartType = 'X'
            THEN Test.ID
            ELSE Tree.StartID
        END,
        CASE WHEN Tree.StartType = 'X'
            THEN Test.Type
            ELSE Tree.StartType
        END,
        Test.ParentID,
        Test.ID
    FROM Test
        INNER JOIN Tree
        ON Test.ParentID = Tree.Child
)

SELECT Test.ID, Test.Type, Test.ParentID,
    CASE WHEN Tree.StartID = Test.ID
        THEN NULL
        ELSE Tree.StartID
    END AS MasterParentID
FROM Test
    LEFT OUTER JOIN Tree
    ON Test.ID = Tree.Child
ORDER BY Test.ID

答案 1 :(得分:1)

以下是使用CTE实现该问题的查询,也是working demo

  ;with Childs as
  (
      select ID, Type, ParentID, 0 Level
      from SomeHierarchy
      union all
      select Childs.ID, SomeHierarchy.Type, SomeHierarchy.ParentID, Childs.Level + 1 Level
      from 
          SomeHierarchy
          inner join Childs on Childs.ParentID = SomeHierarchy.ID
      where
          SomeHierarchy.Type not in ('R', 'X')

  )
  select 
    SomeHierarchy.ID, SomeHierarchy.Type, SomeHierarchy.ParentID, NewChilds.ParentID MasterParentID
  from SomeHierarchy
    inner join (
                  select *, Row_Number() over(Partition by ID order by Level desc)  RowNum
                  from Childs
                  where
                    ParentID is not null or Level = 0
                ) NewChilds on NewChilds.ID = SomeHierarchy.ID
  where
    NewChilds.RowNum = 1

答案 2 :(得分:1)

你需要递归CTE:

with cte1 as (
    select
       T.ID, T.Type, T.ParentID,
       case
          when T2.Type = 'X' then cast(null as varchar(3))
          else T.ParentID
       end as MasterParentID
    from Table1 as T
        left outer join Table1 as T2 on T2.ID = T.ParentID
), cte2 as (
    select
        T.ID, T.Type, T.ParentID,
        T.MasterParentID, T.ID as MasterParentID2
    from cte1 as T
    where T.MasterParentID is null

    union all

    select
        T.ID, T.Type, T.ParentID,
        c.MasterParentID2 as MAsterParentID,
        c.MasterParentID2 as MAsterParentID2
    from cte1 as T
        inner join cte2 as c on c.ID = T.MasterParentID
)
select
    T.ID, T.Type, T.ParentID, T.MasterParentID
from cte2 as T
order by ID asc

sql fiddle demo