计算SQL Server中每个特定xml节点的级别数

时间:2018-10-22 16:01:36

标签: sql-server xml tsql

我正在尝试确定SQL Server的xml文件中所有实体标签的节点级别:

<root>
<Entities>
<Entity Name="E1">
    <Entity Name="E11">
        <Entity Name="E12">
            <Entity Name="E121"/>
            <Entity Name="E122"/>
            <Entity Name="E123"/>
        </Entity>
        <Entity Name="E13"/>
    </Entity>
</Entity>
<Entity Name="E2">
    <Entity Name="E22"/>
</Entity>
</Entities>
</root>

我需要这样返回的数据:

Name  Level
-----------
E1    1
E11   2
E12   3
E121  4
E122  4
E121  4
E13   3
E2    1
E22   2

2 个答案:

答案 0 :(得分:0)

您可以像这样使用递归CTE:

declare @doc xml = '
<root>
<Entities>
<Entity Name="E1">
    <Entity Name="E11">
        <Entity Name="E12">
            <Entity Name="E121"/>
            <Entity Name="E122"/>
            <Entity Name="E123"/>
        </Entity>
        <Entity Name="E13"/>
    </Entity>
</Entity>
<Entity Name="E2">
    <Entity Name="E22"/>
</Entity>
</Entities>
</root>';

with q as
(
  select r.e.value('@Name','varchar(10)') Name, r.e.query('.') Entity, 1 depth
  from @doc.nodes('/root/Entities/Entity') r(e)
  union all
  select c.e.value('@Name','varchar(10)'), c.e.query('.') Entity, q.depth + 1 depth
  from q
  cross apply q.Entity.nodes('./Entity/Entity') c(e)
)
select Name, depth
from q
order by Name

输出

Name       depth
---------- -----------
E1         1
E11        2
E12        3
E121       4
E122       4
E123       4
E13        3
E2         1
E22        2

(9 rows affected)

答案 1 :(得分:0)

我还建议一种递归方法,但是是一种通用方法。这将遍历XML 逐个节点(当然不是属性@Name,这仅对您的XML有效)。

注意:某些事情可能需要处理名称空间:

DECLARE @xml XML=
N'<root>
<Entities>
<Entity Name="E1">
    <Entity Name="E11">
        <Entity Name="E12">
            <Entity Name="E121"/>
            <Entity Name="E122"/>
            <Entity Name="E123"/>
        </Entity>
        <Entity Name="E13"/>
    </Entity>
</Entity>
<Entity Name="E2">
    <Entity Name="E22"/>
</Entity>
</Entities>
</root>';

WITH cte AS
(
    SELECT 1 AS Step 
          ,a.value('local-name(.)','nvarchar(max)') AS ElementPath
          ,a.value('@Name','nvarchar(max)') AS Content
          ,a.query('./*') AS TheNode
    FROM @xml.nodes('/*') A(a)
    UNION ALL
    SELECT cte.Step +1 
          ,cte.ElementPath + '/' + a.value('local-name(.)','nvarchar(max)') 
          ,a.value('@Name','nvarchar(max)')
          ,a.query('./*')
    FROM cte
    CROSS APPLY TheNode.nodes('*') A(a)
)
SELECT *
      ,TheNode.value('count(//*)','int') CountSubNodes
FROM cte
ORDER BY Content;

Step会告诉您您正在寻找的答案。当元素是最终叶节点时,子节点的计数将为零。

结果

+------+-------------------------------------------+---------+---------------+
| Step | ElementPath                               | Content | CountSubNodes |
+------+-------------------------------------------+---------+---------------+
| 1    | root                                      | NULL    | 10            |
+------+-------------------------------------------+---------+---------------+
| 2    | root/Entities                             | NULL    | 9             |
+------+-------------------------------------------+---------+---------------+
| 3    | root/Entities/Entity                      | E1      | 6             |
+------+-------------------------------------------+---------+---------------+
| 4    | root/Entities/Entity/Entity               | E11     | 5             |
+------+-------------------------------------------+---------+---------------+
| 5    | root/Entities/Entity/Entity/Entity        | E12     | 3             |
+------+-------------------------------------------+---------+---------------+
| 6    | root/Entities/Entity/Entity/Entity/Entity | E121    | 0             |
+------+-------------------------------------------+---------+---------------+
| 6    | root/Entities/Entity/Entity/Entity/Entity | E122    | 0             |
+------+-------------------------------------------+---------+---------------+
| 6    | root/Entities/Entity/Entity/Entity/Entity | E123    | 0             |
+------+-------------------------------------------+---------+---------------+
| 5    | root/Entities/Entity/Entity/Entity        | E13     | 0             |
+------+-------------------------------------------+---------+---------------+
| 3    | root/Entities/Entity                      | E2      | 1             |
+------+-------------------------------------------+---------+---------------+
| 4    | root/Entities/Entity/Entity               | E22     | 0             |
+------+-------------------------------------------+---------+---------------+