我们在SQL Server 2005中有一个循环,它在一个表上循环,让每个项都变为父项,直到它到达树的顶部:
DECLARE @T Table
(
ItemID INT NOT NULL PRIMARY KEY,
AncestorID INT NULL
)
其中包含以下数据:
ItemID | AncestorID
1 2
2 3
3 4
4 NULL
我们有一个基本上这样做的循环:
DECLARE @AncestorID INT
SELECT @AncestorID = 1
WHILE (@AncestorID IS NOT NULL)
BEGIN
--Do some work
SELECT @AncestorID = T.AncestorID
FROM @T t
WHERE T.ItemID = @AncestorID
print @AncestorID
END
(是的,我知道SQL是基于设置的,这是逐行处理的,“做一些工作”需要逐行完成)。
直到今天,当我们结束无休止的循环时,这一直都很好。事实证明原因是一些错误的数据:
ItemID | AncestorID
1 2
2 3
4 NULL
ItemID
3已删除。循环现在永远不会结束,因为AncestorID
永远不会NULL
- 它保持在3。
如果@AncestorID
查询返回0行,是否有重写select语句使SELECT
为null,或者我是否需要单独的SELECT
语句来计算记录和一些IF ELSE
类型逻辑?
答案 0 :(得分:4)
无论如何都要重写select语句以生成@AncestorID 如果SELECT查询返回0行,则为null,
您可以在T.AncestorID
上使用汇总。
SELECT @AncestorID = min(T.AncestorID)
FROM @T t
WHERE T.ItemID = @AncestorID
答案 1 :(得分:2)
您可以使用其他变量,例如@PreviousAncestorId
,保留上一个值并在查询前将@AncestorId
重置为NULL
。
您可以在查询后检查@@RowCount
以查看是否找到了一行。
代码仍然存在处理数据中任意长度周期的问题,例如两行值相同的行。您需要跟踪访问过的行以检测周期。一个简单的现实检查是计算循环的迭代次数,并根据行数进行检查。
答案 2 :(得分:2)
使用Break
e.g。
WHILE (@AncestorID IS NOT NULL)
BEGIN
SELECT T.AncestorID INTO #TEMP
FROM @T t WHERE T.ItemID = @AncestorID
IF((SELECT COUNT(*) FROM #TEMP) = 0) BREAK;
SELECT @AncestorID=T.AncestorID
FROM #TEMP t
print @AncestorID
DROP TABLE #TEMP
END