【问题标题】:Query to List all hierarchical parents and siblings and their childrens, but not list own childrens查询列出所有分层的父母和兄弟姐妹及其孩子,但不列出自己的孩子
【发布时间】:2014-04-22 06:29:44
【问题描述】:

我有一个基本的 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

希望结构清晰

但我列出这些的要求有点奇怪。也就是说,当我们传递一个 AccountID 时,它应该列出它的所有父母和兄弟姐妹以及孩子的兄弟姐妹。但它永远不会将该 AccountID 的任何子项列出到任何级别。我可以用一张图片更详细地解释一下。抱歉图片的清晰度..我的是旧手机摄像头..

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

【问题讨论】:

  • 还应该显示 5,11,12,... - 没有 4,6,7,8,9,10 的整个表吗?还是只有 4 - 2,1 的父母?
  • @valex 是的.. 正是.. 我提到的就是它的兄弟姐妹和他们的孩子以及它的所有父母..

标签: sql sql-server


【解决方案1】:

如果我做对了,并且您需要输出除 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 

【讨论】:

  • 对不起.. 如果您不介意,我需要更多支持。我们如何修改查询,使其不会从第二个参数向上移动。所以它不会遍历到顶部。它只遍历指定的帐户。例如,如果我将 4 作为第一个参数,将 2 作为第二个参数,则结果应该是这些值 2,5,11,12
【解决方案2】:

试试这个:

;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(兄弟)。

【讨论】:

    【解决方案3】:

    这会返回你所追求的吗?

    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
    

    【讨论】:

      【解决方案4】:

      对我来说,听起来你想上树。所以考虑到这个测试数据

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-04
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多