T-SQL查询以提取父对象';s标签和所有子项';s标签 背景

T-SQL查询以提取父对象';s标签和所有子项';s标签 背景,sql,sql-server,tsql,recursive-query,Sql,Sql Server,Tsql,Recursive Query,我在SQL Server中有一个DB模式,如下所示: 每个“id”记录可能有一个子记录(存储在同一个表中)。每个孩子可以有任意数量的子孩子。我不知道层级的数量,但它的深度可能不会超过10级 在本例中,有: 3个根元素:id的1,2,3 id为1:id为4和5的1个孩子和1个孩子的孩子(分别) 问题: 我需要能够查询以获得一个id的所有标记的结果,包括它的所有子标记。例如,根据上面的表数据,我需要输出如下: | id | tag | |---- |----- | | 1

我在SQL Server中有一个DB模式,如下所示:

每个“id”记录可能有一个子记录(存储在同一个表中)。每个孩子可以有任意数量的子孩子。我不知道层级的数量,但它的深度可能不会超过10级

在本例中,有:

  • 3个根元素:id的
    1
    2
    3
  • id为
    1
    :id为
    4
    5
    的1个孩子和1个孩子的孩子(分别)
问题: 我需要能够查询以获得一个id的所有标记的结果,包括它的所有子标记。例如,根据上面的表数据,我需要输出如下:

| id    | tag   |
|----   |-----  |
| 1     | A     |
| 1     | B     |
| 1     | D     |
| 1     | E     |
| 2     | C     |
| 3     | C     |
| 4     | B     |
| 5     | D     |
| 5     | E     |
注意,我需要孩子们仍然出现

如果“n”是层次结构级别的数量,那么在不多次将表连接到自身“n”的情况下,这是否可行

编辑 为了澄清,每个id也是一个根元素。因此,知道一个ID是否也是子ID的唯一方法是查看该ID是否有另一个记录,其中有一个子ID。我制作了另一个版本的SQL Fiddle来演示这一点。请注意,id 2现在有一个子项:


是的,不需要n次加入表,就可以使用CTE(公共表表达式)

在您的情况下,代码应该类似于:

WITH cte (id, tag, child_id, parent) AS
(
    SELECT id, tag, child_id, id
    FROM demo
    WHERE id NOT IN(SELECT child_id FROM demo WHERE child_id IS NOT NULL)
    UNION ALL
    SELECT demo.id, demo.tag, demo.child_id, cte.parent
    FROM demo
        JOIN cte
            ON cte.child_id = demo.id
)
SELECT parent, tag
FROM cte
WHERE tag IS NOT NULL
UNION 
SELECT id, tag
FROM demo
WHERE tag IS NOT NULL
ORDER BY parent, tag

编辑:动态确定基本元素。

SQL Server支持使用“递归公共表表达式”或“递归CTE”的分层查询。为什么在结果集中将5更改为6?这是需求还是输入错误?@KannanKandasamy,需求输入错误,谢谢你让我知道。ID为
1
的元素是根元素吗(因为需要的结果示例)?或者以不同的方式询问:让所有根元素的ID为
1
?@R.Horber。上例中的根元素是1、2和3。并非所有根元素的id都为1。感谢您的回复。这个解决方案似乎在最大递归上出错了。即使将max recursion选项设置为1000似乎也无法解决这个问题。我将这个示例加载到SQLFiddle中,以演示:您是对的。我无法测试它(因为我不再有本地SQL Server)。我的查询中有一个逻辑错误,导致无限循环。我正在努力修复它。。。我会让你知道的谢谢你再次更新!我应该澄清一下,我不知道哪些id是根元素。有时元素既是根元素又是子元素。根据您的查询,您认为知道哪些元素是根是一项困难的要求吗?也许有一个比中的
更好的选择,我还没有想到或者我没有意识到。事实是,递归查询必须从某个点(基/根元素)开始。使用
标记为空
子id不为空
我没有得到您想要的结果或无限循环…第三次确实很有魅力,非常感谢您坚持我!
| id    | tag   | child_id  |
|----   |-----  |---------- |
| 1     | A     |           |
| 1     |       | 4         |
| 2     | C     |           |
| 2     |       | 5         |
| 3     | C     |           |
| 4     | B     |           |
| 4     |       | 5         |
| 5     | D     |           |
| 5     | E     |           |
WITH cte (id, tag, child_id, parent) AS
(
    SELECT id, tag, child_id, id
    FROM demo
    WHERE id NOT IN(SELECT child_id FROM demo WHERE child_id IS NOT NULL)
    UNION ALL
    SELECT demo.id, demo.tag, demo.child_id, cte.parent
    FROM demo
        JOIN cte
            ON cte.child_id = demo.id
)
SELECT parent, tag
FROM cte
WHERE tag IS NOT NULL
UNION 
SELECT id, tag
FROM demo
WHERE tag IS NOT NULL
ORDER BY parent, tag