具有“N”个级别的 SQL Server 父子表

问题描述 投票:0回答:1

此查询:

SELECT pcn.id,
       pcn.config_id,
       pcnc.nombre_nivel,
       pcnc.orden_nivel,
       pcn.nivel_padre_id,
       pcnc.empresa_id,
       pcnc.proyecto_id,
       pcnc.activo AS activo_config,
       pcnc.usuario_id,
       pcn.activo
FROM puebles_ciclos_niveles pcn
JOIN puebles_ciclos_niveles_config pcnc ON pcn.config_id = pcnc.id

提供以下结果:

我需要的数据顺序如下:

这里的“nivel_padre_id”代表父ID。

我尝试过用 CTE 表来制作它,问题是 CTE 表只处理一个级别,如下所示:

WITH RecursiveCTE AS (
SELECT
    pcn.id, pcn.config_id, pcnc.nombre_nivel, pcnc.orden_nivel,pcn.nivel_padre_id,
    pcnc.empresa_id, pcnc.proyecto_id, pcnc.activo AS activo_config, pcnc.usuario_id,pcn.activo
FROM
    puebles_ciclos_niveles pcn
JOIN
    puebles_ciclos_niveles_config pcnc ON pcn.config_id = pcnc.id
WHERE
    pcn.nivel_padre_id = 0 -- Selecting the root level

UNION ALL

SELECT
    pcn.id, pcn.config_id, pcnc.nombre_nivel, pcnc.orden_nivel, pcn.nivel_padre_id, pcnc.empresa_id, pcnc.proyecto_id,
    pcnc.activo AS activo_config, pcnc.usuario_id, pcn.activo
FROM
    puebles_ciclos_niveles pcn
JOIN
    puebles_ciclos_niveles_config pcnc ON pcn.config_id = pcnc.id
JOIN
    RecursiveCTE rc ON pcn.nivel_padre_id = rc.id
)

    SELECT
        id, config_id, nombre_nivel, orden_nivel,
        nivel_padre_id, empresa_id, proyecto_id,
        activo_config, usuario_id, activo
    FROM
    RecursiveCTE

此 CTE 查询生成以下内容:

有什么办法可以得到想要的结果吗? (Parent - Child(1) - Child(2) - Child(3) - Children (4) -如果没有找到更多的children则停止,返回处理上一级-)

创建并插入脚本

sql sql-server parent-child recursive-query recursive-cte
1个回答
0
投票

因为您希望结果集中有特定的排序,所以需要提供

order by
子句。但是用什么来订购呢?这是您的查询,添加了一列 -
path
,它表示从根节点到该特定行的路径。

WITH RecursiveCTE AS (
SELECT
    pcn.id, pcn.config_id, pcnc.nombre_nivel, pcnc.orden_nivel,pcn.nivel_padre_id,
    pcnc.empresa_id, pcnc.proyecto_id, pcnc.activo AS activo_config, pcnc.usuario_id,pcn.activo,
    [path] = cast(concat('/', pcn.id, '/' ) as varchar(1000))
FROM
    puebles_ciclos_niveles pcn
JOIN
    puebles_ciclos_niveles_config pcnc ON pcn.config_id = pcnc.id
WHERE
    pcn.nivel_padre_id = 0 -- Selecting the root level

UNION ALL

SELECT
    pcn.id, pcn.config_id, pcnc.nombre_nivel, pcnc.orden_nivel, pcn.nivel_padre_id, pcnc.empresa_id, pcnc.proyecto_id,
    pcnc.activo AS activo_config, pcnc.usuario_id, pcn.activo,
    [path] = cast(concat(rc.[path], pcn.id, '/' ) as varchar(1000))
FROM
    puebles_ciclos_niveles pcn
JOIN
    puebles_ciclos_niveles_config pcnc ON pcn.config_id = pcnc.id
JOIN
    RecursiveCTE rc ON pcn.nivel_padre_id = rc.id
)

    SELECT
        id, config_id, nombre_nivel, orden_nivel,
        nivel_padre_id, empresa_id, proyecto_id,
        activo_config, usuario_id, activo,
        [path]
    FROM
    RecursiveCTE
    order by [path];

通过说明,基本元素的

path
就是该行的
id
,由斜线包围。对于后续/递归元素,我采用父级的路径,将此行的
id
附加到它,并以另一个斜杠结束。这是一个带有演示的db fiddle

注意 - 路径格式的选择不是任意的。 SQL Server 有一种名为 hierarchyid 的数据类型,您可以使用它来获得这种行为,其成本比在查询时动态计算它要便宜得多(需要在数据突变时维护它的开销)。如果您选择使用我使用的

path
格式,则可以直接转换为
hierarchyid

© www.soinside.com 2019 - 2024. All rights reserved.