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

Hierarchical SQL Queries: Best SQL query to obtain the whole branch of a tree from a [nodeid, parentid] pairs table given the end node id

有什么方法可以在 SQL 中发送递归查询吗?

给定结束节点 ID,我需要按级别排序直至根节点(具有 parentid = NULL)的所有行。例如。如果我有类似的东西:

nodeid | parentid
a      | NULL    
b      | a       
c      | b       

在查询 end_node_id = c 之后,我会得到如下内容:

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,按照评论中的要求,您可以使用 connect by 运算符来生成层次结构,并使用 level 伪列来获取深度:

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

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

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

SELECT     IDCATEGORY, IDPARENTCATEGORY, LEVEL
FROM       TNODES
START WITH IDCATEGORY=122
CONNECT BY IDCATEGORY = PRIOR IDPARENTCATEGORY;

使用视图的示例,因此它归结为单个标准 SQL 查询(需要 >= 10g):

CREATE OR REPLACE VIEW VNODES AS 
SELECT CONNECT_BY_ROOT IDCATEGORY "IDBRANCH", IDCATEGORY, IDPARENTCATEGORY, LEVEL AS LVL
FROM TNODES 
CONNECT BY IDCATEGORY = PRIOR IDPARENTCATEGORY;

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

http://sqlfiddle.com/#!4/18ba80/3

Postgres >= 8.4,使用 WITH RECURSIVE Common Table Expression 查询:

WITH RECURSIVE BRANCH(IDPARENTCATEGORY, IDCATEGORY, LEVEL) AS (
    SELECT IDPARENTCATEGORY, IDCATEGORY, 1 AS LEVEL FROM TNODES WHERE IDCATEGORY = 122
  UNION ALL
    SELECT p.IDPARENTCATEGORY, p.IDCATEGORY, LEVEL+1
    FROM BRANCH pr, TNODES p
    WHERE p.IDCATEGORY = pr.IDPARENTCATEGORY
  )
SELECT IDCATEGORY,IDPARENTCATEGORY, LEVEL
FROM BRANCH
ORDER BY LEVEL ASC

使用视图的示例,因此它归结为单个标准 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;

http://sqlfiddle.com/#!11/42870/2