Fra*_*Man 5 t-sql recursion sql-server-2008
我在我的数据库中有自我依赖的实体(a),它们是从另一个实体(b)引用的,并且给定一个特定的(b)实体,我需要获得所需的所有(a)实体.这些是多对多的映射,所以我有一个单独的映射表.我认为使用CTE的递归选择是我最好的选择,但我遇到了一个问题:
这个小提琴说明了我的问题.如果某些用户引入了循环引用,则我的递归选择将会突然停止.我一直在绞尽脑汁试图找到解决这个问题的方法.应该注意的是,虽然我已经在小提琴中引入了外键,但外键实际上并没有被我正在使用的系统所尊重(与DBA长期争论) - 我引入它们以使数据流更清晰.
递归查询,适用于那些不想点击小提琴的人:
WITH recur(objID) AS (
SELECT usesObjID
FROM #otherObj
WHERE otherObjID = 1
UNION ALL
SELECT slaveObjID
FROM #objMap
INNER JOIN recur
on #objMap.masterObjID = recur.objID
)SELECT objID from recur
Run Code Online (Sandbox Code Playgroud)
有什么想法吗?这个设计不是生产中的,所以我可以稍微改变一下架构,但我不想依赖于在插入时发现循环引用,除非可以通过T-SQL完成.
可以设置MAXRECURSIONCTE,这将阻止无限循环,但你仍然会得到奇怪的结果,因为查询将继续在循环中运行,直到命中最大递归.
挑战在于循环涉及多个步骤,因此您不能只检查子项的直接父级,以确定您是否处于循环中.
处理此问题的一种方法是向CTE添加一个额外的列...此新列将 tree跟踪到目前为止已包含的所有ID,并在ID重复时停止.
WITH recur(objID, Tree) AS (
SELECT
usesObjID,
CAST(',' + CAST(usesObjID AS VARCHAR) + ',' AS VARCHAR) AS Tree
FROM otherObj
WHERE otherObjID = 1
UNION ALL
SELECT
slaveObjID,
CAST(recur.Tree + CAST(slaveObjID AS VARCHAR) + ',' AS VARCHAR) AS Tree
FROM objMap
INNER JOIN recur
ON objMap.masterObjID = recur.objID
WHERE recur.Tree NOT LIKE '%,' + CAST(slaveObjID AS VARCHAR) + ',%'
)SELECT objID from recur
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2163 次 |
| 最近记录: |