记录集为空时更新SQL变量

时间:2012-09-26 01:40:47

标签: tsql sql-server-2005

我们在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类型逻辑?

3 个答案:

答案 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