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

带关联查询的递归层级JSON T-SQL问题:添加关联后根项重复

解决递归生成嵌套JSON时关联表导致根项重复的问题

问题背景

原本用于生成N层级嵌套JSON的递归函数,仅查询property表时能正常工作,适配任意深度的父子结构。但添加与someTable的左关联后,出现根项重复的问题,无法同时保留嵌套功能和获取关联表的额外数据。

原正常工作的函数:

CREATE FUNCTION dbo.GetJson (@parentID int)
RETURNS nvarchar(max)
AS BEGIN
    RETURN (
        SELECT
          propertyID,
          title,
          typeid,
          [value],
          children = JSON_QUERY(dbo.GetJson(propertyID))
        FROM property p
        WHERE EXISTS (SELECT parentID INTERSECT SELECT @parentID)
        FOR JSON PATH
    );
END;

关联后出现问题的函数:

CREATE FUNCTION dbo.GetJson (@parentID int)
RETURNS nvarchar(max)
AS BEGIN
    RETURN (
        SELECT
          p.propertyID,
          p.title,
          p.typeid,
          p.[value],
          s.someField,
          children = JSON_QUERY(dbo.GetJson(propertyID))
        FROM property p
            LEFT OUTER JOIN someTable s ON s.propertyID = p.propertyID
        WHERE EXISTS (SELECT parentID INTERSECT SELECT @parentID)
        FOR JSON PATH
    );
END;

问题原因

根项重复是因为左关联后,单个property记录对应了someTable中的多条记录,导致FOR JSON PATH生成了多条结构相同(仅关联字段不同)的根节点;即使是一对一关联,若关联字段存在NULL值,也可能触发重复问题。

解决方案

方案1:仅获取关联表的单条记录(一对一或取指定一条)

如果someTable与property是一对一关系,或你只需要每条property对应的某一条关联记录,用OUTER APPLY + TOP 1确保每条property仅返回一条结果:

CREATE FUNCTION dbo.GetJson (@parentID int)
RETURNS nvarchar(max)
AS BEGIN
    RETURN (
        SELECT
          p.propertyID,
          p.title,
          p.typeid,
          p.[value],
          s.someField,
          children = JSON_QUERY(dbo.GetJson(p.propertyID))
        FROM property p
        OUTER APPLY (
            -- 取关联表中对应propertyID的第一条记录,可加ORDER BY指定规则
            SELECT TOP 1 someField
            FROM someTable s
            WHERE s.propertyID = p.propertyID
            -- ORDER BY s.createTime DESC -- 可选:按时间取最新记录
        ) s
        WHERE EXISTS (SELECT p.parentID INTERSECT SELECT @parentID)
        FOR JSON PATH
    );
END;

方案2:将关联表的多条记录合并为JSON数组(一对多场景)

如果property对应someTable的多条记录,需要把这些记录作为数组嵌套在JSON中,而不是重复根节点:

CREATE FUNCTION dbo.GetJson (@parentID int)
RETURNS nvarchar(max)
AS BEGIN
    RETURN (
        SELECT
          p.propertyID,
          p.title,
          p.typeid,
          p.[value],
          -- 将关联表的多条记录生成为JSON数组
          someFields = JSON_QUERY(
              (SELECT someField FROM someTable s WHERE s.propertyID = p.propertyID FOR JSON PATH)
          ),
          children = JSON_QUERY(dbo.GetJson(p.propertyID))
        FROM property p
        WHERE EXISTS (SELECT p.parentID INTERSECT SELECT @parentID)
        FOR JSON PATH
    );
END;

方案3:去重关联结果(适用于意外重复的场景)

如果关联后出现无意义的重复记录(比如someTable存在重复的propertyID),可以用GROUP BY去重:

CREATE FUNCTION dbo.GetJson (@parentID int)
RETURNS nvarchar(max)
AS BEGIN
    RETURN (
        SELECT
          p.propertyID,
          p.title,
          p.typeid,
          p.[value],
          -- 用聚合函数取唯一值,比如MAX/STRING_AGG
          MAX(s.someField) AS someField,
          children = JSON_QUERY(dbo.GetJson(p.propertyID))
        FROM property p
        LEFT JOIN someTable s ON s.propertyID = p.propertyID
        WHERE EXISTS (SELECT p.parentID INTERSECT SELECT @parentID)
        GROUP BY p.propertyID, p.title, p.typeid, p.[value]
        FOR JSON PATH
    );
END;

内容的提问来源于stack exchange,提问作者Chris Ward

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:54:27