分层SQL查询:从给定结束节点id的[nodeid,parentid]pairs表中获取树的整个分支的最佳SQL查询

分层SQL查询:从给定结束节点id的[nodeid,parentid]pairs表中获取树的整个分支的最佳SQL查询,sql,tree,hierarchical-data,recursive-query,hierarchical-query,Sql,Tree,Hierarchical Data,Recursive Query,Hierarchical Query,有没有任何方法可以在SQL中发送递归查询 给定结束节点id,我需要按级别排序到根节点(其parentid=NULL)的所有行。例如,如果我有以下情况: nodeid | parentid a | NULL b | a c | b nodeid | parentid | depth a | NULL | 0 b | a | 1 c | b | 2 查询完end\u

有没有任何方法可以在SQL中发送递归查询

给定结束节点id,我需要按级别排序到根节点(其parentid=NULL)的所有行。例如,如果我有以下情况:

nodeid | parentid
a      | NULL    
b      | a       
c      | b       
nodeid | parentid | depth
a      | NULL     | 0
b      | a        | 1
c      | b        | 2
查询完
end\u node\u id=c
,我会得到如下结果:

nodeid | parentid
a      | NULL    
b      | a       
c      | b       
nodeid | parentid | depth
a      | NULL     | 0
b      | a        | 1
c      | b        | 2
(除了深度,我还可以使用到给定端点节点的距离)

我能想到的唯一(也是显而易见的)方法是每行执行一次查询,直到到达父节点为止


有更有效的方法吗?

如果您使用的是mssql 2005+,您可以这样做:

测试数据:

DECLARE @tbl TABLE(nodeId VARCHAR(10),parentid VARCHAR(10))

INSERT INTO @tbl
VALUES ('a',null),('b','a'),('c','b')
查询

;WITH CTE
AS
(
    SELECT
        tbl.nodeId,
        tbl.parentid,
        0 AS Depth
    FROM
        @tbl as tbl
    WHERE
        tbl.parentid IS NULL
    UNION ALL
    SELECT
        tbl.nodeId,
        tbl.parentid,
        CTE.Depth+1 AS Depth
    FROM
        @tbl AS tbl
        JOIN CTE
            ON tbl.parentid=CTE.nodeId
)
SELECT
    *
FROM
    CTE

对于Oracle,根据注释中的要求,您可以使用运算符生成层次结构,并使用
level
伪列获取深度:

SELECT     nodeid, parentid, LEVEL
FROM       t
START WITH parentid IS NULL
CONNECT BY parentid = PRIOR nodeid;

以以下解决方案结束(其中level是到结束节点的距离)

Oracle,使用(感谢@Mureinik提供的信息):

示例:使用视图,使其归结为单个标准SQL查询(要求>=10g):

Postgres>=8.4,使用查询:

使用视图的示例,可将其归结为单个标准SQL查询:

CREATE OR REPLACE VIEW VNODES AS 
WITH RECURSIVE BRANCH(IDBRANCH,IDPARENTCATEGORY,IDCATEGORY,LVL) AS (
  SELECT IDCATEGORY AS IDBRANCH, IDPARENTCATEGORY, IDCATEGORY, 1 AS LVL FROM TNODES
  UNION ALL
    SELECT pr.IDBRANCH, p.IDPARENTCATEGORY, p.IDCATEGORY, LVL+1
    FROM BRANCH pr, TNODES p
    WHERE p.IDCATEGORY = pr.IDPARENTCATEGORY
  )
SELECT IDBRANCH, IDCATEGORY, IDPARENTCATEGORY, LVL
FROM BRANCH;

SELECT * FROM VNODES WHERE IDBRANCH = 122 ORDER BY LVL ASC;

您使用的是什么RDBMS?它必须适用于Oracle和Postgres(尽管通用解决方案是理想的)
和递归的
()似乎适用于Postgres。现在我需要一个Oracle解决方案检查下面我的答案是否有Oracle解决方案我已将其标记为已接受,因为START WITH/CONNECT BY正是Oracle解决方案所需的,尽管实际查询略有不同(end node id是提供的节点id,而不是根节点id)。请查看我的答案以了解实际的解决方案。(很抱歉,我没有接受您的答案,您向我展示了在Oracle中获得所需解决方案所需的全部内容,但我觉得我必须提供更详细的答案,说明如何在Oracle和postgresql中使用视图,将问题简化为一个简单的标准SQL select查询)这与接受的解决方案有相同的问题:我希望提供一个结束节点ID来获得分支而不是根节点ID,但是这样做是一个简单的改变,所以我认为它也是一个有效的答案。
CREATE OR REPLACE VIEW VNODES AS 
WITH RECURSIVE BRANCH(IDBRANCH,IDPARENTCATEGORY,IDCATEGORY,LVL) AS (
  SELECT IDCATEGORY AS IDBRANCH, IDPARENTCATEGORY, IDCATEGORY, 1 AS LVL FROM TNODES
  UNION ALL
    SELECT pr.IDBRANCH, p.IDPARENTCATEGORY, p.IDCATEGORY, LVL+1
    FROM BRANCH pr, TNODES p
    WHERE p.IDCATEGORY = pr.IDPARENTCATEGORY
  )
SELECT IDBRANCH, IDCATEGORY, IDPARENTCATEGORY, LVL
FROM BRANCH;

SELECT * FROM VNODES WHERE IDBRANCH = 122 ORDER BY LVL ASC;