You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归CTE实现人员自身及继承属性查询异常求助

问题:查询人员自身及向上继承的所有属性

数据库结构与测试数据

CREATE TABLE tbl_Attribute 
(  
    AttributeID INT NOT NULL,  
    Name VARCHAR(100) NOT NULL 
)

INSERT INTO tbl_Attribute (AttributeID, Name) 
VALUES (1, 'Genius'), (2, 'Smart'), (3, 'Pretty'), (4, 'Ugly')

CREATE TABLE tbl_Person 
( 
    PersonID INT NOT NULL,  
    Name VARCHAR(100) NOT NULL,  
    ParentPersonID INT NULL 
)

INSERT INTO tbl_Person (PersonID, Name, ParentPersonID) 
VALUES (1, 'GrandMother', NULL), (2, 'Mother', 1), 
       (3, 'Daughter', 2), (4, 'Son', 2)

CREATE TABLE tbl_PersonAttribute 
(
    PersonID INT NOT NULL,  
    AttributeID INT NOT NULL 
)

INSERT INTO tbl_PersonAttribute (PersonID, AttributeID) 
VALUES 
  (1, 1) -- GrandMother - Genius
, (2, 2) -- Mother - Smart
, (3, 3) -- Daughter - Pretty
, (4, 4) -- Son - Ugly

原递归CTE代码(存在问题)

原代码仅能部分获取属性,无法正确传递顶层继承属性:

WITH PersonAttrCTE AS 
(
    -- get base (parent is null)
    SELECT 
        p.PersonID,
        p.Name,
        a.Name AS AttributeName,
        CAST('Myself' AS VARCHAR(100)) [Inherit]
    FROM 
        tbl_Person p
    INNER JOIN 
        tbl_PersonAttribute pa ON p.PersonID = pa.PersonID
    INNER JOIN 
        tbl_Attribute a ON pa.AttributeID = a.AttributeID
    WHERE 
        p.ParentPersonID IS NULL

    UNION ALL

    -- get the direct attributes
    SELECT 
        p.PersonID,
        p.Name,
        a.Name AS AttributeName,
        pCTE.Name [Inherit]
    FROM 
        tbl_Person p
    INNER JOIN 
        PersonAttrCTE pCTE ON p.ParentPersonID = pCTE.PersonID
    INNER JOIN 
        tbl_PersonAttribute pa ON p.PersonID = pa.PersonID
    INNER JOIN 
        tbl_Attribute a ON pa.AttributeID = a.AttributeID

    UNION ALL

    -- get inherited attributes
    SELECT 
        p.PersonID,
        p.Name,
        a.Name AS AttributeName,
        pac.Name [Inherit]
    FROM 
        tbl_Person p
    INNER JOIN 
        PersonAttrCTE pac ON p.ParentPersonID = pac.PersonID
    INNER JOIN 
        tbl_PersonAttribute pa ON pac.PersonID = pa.PersonID
    INNER JOIN 
        tbl_Attribute a ON pa.AttributeID = a.AttributeID
)
SELECT DISTINCT
    *
FROM 
    PersonAttrCTE c
ORDER BY 
    PersonID

问题分析

  1. 原锚点仅选取顶层无父节点的人员,遗漏了其他人员的自身属性;
  2. 递归部分拆分两个UNION ALL,逻辑冗余且层级传递错误,导致顶层属性无法传递到孙辈。

正确思路:

  • 锚点覆盖所有人员的自身属性;
  • 递归仅处理属性继承传递:将父节点的所有属性(自身+已继承的)传递给子节点,并标记继承来源。

修正后的递归CTE代码

WITH PersonAttrCTE AS 
(
    -- 锚点:所有人员的自身属性
    SELECT 
        p.PersonID,
        p.Name,
        a.Name AS AttributeName,
        CAST('Myself' AS VARCHAR(100)) AS [Inherit]
    FROM 
        tbl_Person p
    INNER JOIN 
        tbl_PersonAttribute pa ON p.PersonID = pa.PersonID
    INNER JOIN 
        tbl_Attribute a ON pa.AttributeID = a.AttributeID

    UNION ALL

    -- 递归:将父节点的所有属性传递给子节点
    SELECT 
        child.PersonID,
        child.Name,
        pac.AttributeName,
        parent.Name AS [Inherit]
    FROM 
        PersonAttrCTE pac
    INNER JOIN 
        tbl_Person parent ON pac.PersonID = parent.PersonID
    INNER JOIN 
        tbl_Person child ON parent.PersonID = child.ParentPersonID
)
SELECT DISTINCT
    PersonID,
    Name,
    AttributeName,
    [Inherit]
FROM 
    PersonAttrCTE
ORDER BY 
    PersonID, 
    CASE [Inherit] WHEN 'Myself' THEN 1 ELSE 2 END -- 优先显示自身属性

预期结果

  • GrandMother:Genius(Myself)
  • Mother:Smart(Myself)、Genius(GrandMother)
  • Daughter:Pretty(Myself)、Smart(Mother)、Genius(GrandMother)
  • Son:Ugly(Myself)、Smart(Mother)、Genius(GrandMother)

内容的提问来源于stack exchange,提问作者Vincent Dagpin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 09:43:20