查询列出所有等级父母和兄弟姐妹及其子女,但不列出自己的孩子

时间:2014-04-22 06:29:45

标签: sql sql-server

我是一个基本的SQL表,每行之间都有一个简单的层次连接。也就是说,每行都有一个ParentID,并使用它与另一行连接。其内容如下

AccountID  |  AccountName  |  ParentID
---------------------------------------
    1            Mathew        0
    2            Philip        1
    3            John          2
    4            Susan         2
    5            Anita         1
    6            Aimy          1
    7            Elsa          3
    8            Anna          7
    .............................
.................................
    45           Kristoff      8

希望结构清晰

但是我对listng的要求有点奇怪。那是当我们传递一个AccountID时,它应该列出所有的父母和兄弟姐妹和兄弟姐妹的孩子。但它永远不会将该AccountID的任何子项列入任何级别。我可以用图片更详细地解释一下。对不起,图片清晰..我的是一个旧的手机摄像头.. enter image description here

当我们通过AccountID 4 时,它应列出所有家长及其兄弟姐妹,但不应列出4,6,7,8,9,10 。这意味着应该在结果中避免帐户及其中的任何子项(基于图片树元素)。希望解释清楚。

4 个答案:

答案 0 :(得分:9)

如果我说得对,你需要输出整个表格,除了4和它的所有后代,然后尝试这个递归查询:

WITH CT AS 
(
  SELECT * FROM T WHERE AccountID=4
  UNION ALL
  SELECT T.* FROM T 
     JOIN CT ON T.ParentID = CT.AccountId
)
SELECT * FROM T WHERE AccountID 
                NOT IN (SELECT AccountID FROM CT)

SQLFiddle demo

回答评论中的问题:

  

因此它不会遍历顶部。它只遍历指定   帐户。例如,如果我将4作为第一个参数传递,将2传递为第二个参数   参数,结果应该是这些值2,5,11,12

您应该从ID = 2开始并前往底部排除ID = 4,因此您在ID = 4后剪切整个子树:

WITH CT AS 
(
  SELECT * FROM T WHERE AccountID=2
  UNION ALL
  SELECT T.* FROM T 
     JOIN CT ON T.ParentID = CT.AccountId
  WHERE T.AccountId<>4
)

SELECT * FROM CT 

答案 1 :(得分:3)

试试这个:

;with cte as
(select accountid,parentid, 0 as level from tbl
 where parentid = 0
 union all
 select t.accountid,t.parentid,(level+1) from 
 cte c inner join tbl t on c.accountid= t.parentid
)
select * from cte
where level < (select level from cte where accountid = @accountid)

当您传入参数@accountid时,这将返回参数前级别上所有节点的accountid值。

如果要返回除输入本身以外的所有输入,则可以将where子句更改为;

where level <=(select level from cte where accountid= @accountid ) 
and accountid <> @accountid

在您的示例中,如果@accountid = 4,则返回值1,2,3(祖先)以及5,13,​​14(兄弟姐妹)。

答案 2 :(得分:1)

这会回报你的目标吗?

declare @AccountID int
set @AccountID = 4

;with parents
as (

    select AccountID, AccountName, ParentID
    from Account
    where AccountID = (select ParentID from Account Where AccountID = @AccountID)

    union all

    select A.AccountID, A.AccountName, A.ParentID
    from Account as A
    join parents as P
        on P.ParentID = A.AccountID
    ),
children
as (
    select AccountID, AccountName, ParentID
    from parents

    union all

    select A.AccountID, A.AccountName, A.ParentID
    from Account as A
    join children as C
        on C.AccountID = A.ParentID
    where A.AccountID <> @AccountID
    )
select distinct AccountID, AccountName, ParentID
from children
order by AccountID

答案 3 :(得分:1)

对我而言,听起来你想要进入树上。所以考虑这个测试数据

DECLARE @tbl TABLE(AccountID INT,AccountName VARCHAR(100),ParentID INT)
INSERT INTO @tbl
VALUES
(1,'Mathew',0),
(2,'Philip',1),
(3,'John',2),
(4,'Susan',2),
(5,'Anita',1),
(6,'Aimy',1),
(7,'Elsa',3),
(8,'Anna',7)

我会写一个这样的查询:

DECLARE @AcountID INT=4

;WITH CTE
AS
(
    SELECT
        tbl.AccountID,
        tbl.AccountName,
        tbl.ParentID
    FROM
        @tbl AS tbl
    WHERE
        tbl.AccountID=@AcountID
    UNION ALL
    SELECT
        tbl.AccountID,
        tbl.AccountName,
        tbl.ParentID
    FROM
        @tbl AS tbl
    JOIN CTE
        ON CTE.ParentID=tbl.AccountID
)
SELECT
    *
FROM
    CTE
WHERE
    NOT CTE.AccountID=@AcountID

这将返回如下结果:

2   Philip  1
1   Mathew  0