我在SQL Server数据库中有一个层次结构。我正在尝试编写一个查询来获取给定元素下结构中的所有元素。
因此,给定一个包含列id和parent_id的DB表,这就是我所做的:
WITH recursive_cte (root_id, id) AS (
SELECT parent_id, id
FROM test_cte
UNION ALL
SELECT t.parent_id, r.id
FROM test_cte t
INNER JOIN recursive_cte r
ON (r.root_id=t.id)
)
SELECT *
FROM recursive_cte
WHERE root_id=0
现在,如果在id = 0的元素下的结构中存在循环引用,则从DBMS获得错误(在语句完成之前,最大递归100已用尽)。这很好,循环引用的存在已经是一个错误。
但是如果我在另一个元素下的结构中有一个循环引用,查询将始终给出错误。即使我指定了将记录集限制为非循环记录集的条件(例如WHERE root_id=0
)。
例如:
id|parent_id|name |
--+---------+---------------+
0 |NULL |TEST A |
1 |4 |TEST CIRCULAR |
2 |0 |TEST B |
3 |2 |TEST C |
4 |1 |TEST CIRCULAR B|
我希望我的查询在条件root_id=0
没有错误的情况下工作。有没有办法做到这一点?
答案 0 :(得分:2)
这可能不是一个优雅的解决方案,但似乎有效。将访问过的ID列表存储在列表中,并将其从进一步搜索中排除。我认为这是您的查询的正确比较:
WITH recursive_cte(root_id, id, ids) AS (
SELECT parent_id, id, ',' + cast(id as varchar(8000)) + ',' as ids
FROM test_cte
UNION ALL
SELECT t.parent_id, r.id, ids + cast(id as varchar(8000)) + ','
FROM test_cte t INNER JOIN
recursive_cte r
ON r.root_id = t.id
WHERE ',' + r.ids + ',' not like '%,' + cast(t.id as varchar(8000)) + ',%'
)
SELECT *
FROM recursive_cte
WHERE root_id = 0;
答案 1 :(得分:1)
您需要将WHERE过滤器放在查询的CTE部分,如下所示:
WITH recursive_cte (root_id, id) AS (
SELECT parent_id, id
FROM test_cte
WHERE id=0 -- Restrict your recursion to start from the item with id = 0, instead of considdering all items.
UNION ALL
SELECT t.parent_id, r.id
FROM test_cte t
INNER JOIN recursive_cte r
ON (r.root_id=t.id)
)
SELECT *
FROM recursive_cte