0

我们在 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

ItemID3被删除。循环现在永远不会结束,因为AncestorIDis never NULL- 它保持在 3。

如果查询返回 0 行,是否有重写 select 语句以使@AncestorIDnull SELECT,或者我需要有一个单独的SELECT语句来计算记录和一些IF ELSE类型逻辑?

4

3 回答 3

4

如果 SELECT 查询返回 0 行,是否有重写 select 语句以使 @AncestorID 为空,

您可以在T.AncestorID.

SELECT @AncestorID = min(T.AncestorID)   
FROM @T t  
WHERE T.ItemID = @AncestorID
于 2012-09-26T03:02:27.837 回答
2

您可以使用另一个变量,例如@PreviousAncestorId,保存以前的值并重置@AncestorIdNULL查询之前。

您可以@@RowCount在查询后检查是否找到了一行。

代码在处理数据中任意长度的循环时仍然存在问题,例如两个值相同的行。您需要跟踪访问的行以检测周期。一个简单的现实检查是计算循环的迭代次数并根据行数检查它。

于 2012-09-26T02:32:26.003 回答
2

用一个Break

例如

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
于 2012-09-26T04:37:28.177 回答