递归查询中的条件

时间:2009-09-25 08:54:55

标签: sql sql-server recursion hierarchy

我在MS SQL中有以下递归表值函数,以便从数据库中检索对象的层次结构:


WITH tmpField (ParentNum, ChildNum, FieldNum, FieldDescr, Iteration) AS
(
  SELECT Field.ParentNum, Field.ChildNum, Field.FieldNum, Field.FieldDescr, 1
  FROM Field
  WHERE Field.ParentNum = @ParentNum

  UNION ALL 

  SELECT Field.ParentNum, Field.ChildNum, Field.FieldNum, Field.FieldDescr, tmpField.Iteration + 1
  FROM Field INNER JOIN 
  tmpField on Field.ParentNum = tmpField.ChildNum
)
SELECT DISTINCT ParentNum AS ParentNum, ChildNum AS ChildNum, FieldNum, FieldDescr
FROM tmpField

我想通过以下方式修改它:

last 迭代中,当没有“子”时,我希望ChildNum字段的值为FieldNum。在之前的所有迭代中,ChildNum应该具有ChildNum字段的值,就像现在一样。

有人建议使用上述查询作为起点来实现此目的吗?

请注意:尽管名称如此,但字段ChildNum不引用任何子行,但应将其解释为该行的标识符。

2 个答案:

答案 0 :(得分:2)

当没有更多子项时,意味着ChildNum为NULL,所以:

...

UNION ALL 

  SELECT Field.ParentNum, 
         COALESCE(Field.ChildNum, Field.FieldNum) ChildNum,
         Field.FieldNum,
         ...

编辑:(跟随大安评论)

好的,在这种情况下,我们可以查看ChildNum'孩子的计数:

    ...

    UNION ALL 

      SELECT F1.ParentNum, 
             CASE WHEN (SELECT COUNT(1) 
                          FROM FIELD F2 
                         WHERE F2.ParentNum = F1.ChildNum) = 0 
                  THEN F1.FieldNum
                  ELSE F1.ChildNum
             END ChildNum,
             F1.FieldNum, F1.FieldDescr, tmpField.Iteration + 1
      FROM Field F1 INNER JOIN 
      tmpField on F1.ParentNum = tmpField.ChildNum

...

EDIT2:

让我们把支票搬到外面:

WITH tmpField (ParentNum, ChildNum, FieldNum, FieldDescr, Iteration) AS
(
  SELECT Field.ParentNum, Field.ChildNum, Field.FieldNum, Field.FieldDescr, 1
  FROM Field
  WHERE Field.ParentNum = @ParentNum

  UNION ALL 

  SELECT Field.ParentNum, Field.ChildNum, Field.FieldNum, Field.FieldDescr, tmpField.Iteration + 1
  FROM Field INNER JOIN 
  tmpField on Field.ParentNum = tmpField.ChildNum
)
SELECT DISTINCT ParentNum AS ParentNum, 
                CASE WHEN EXISTS (SELECT NULL 
                                    FROM Field f 
                                   WHERE tmpField.ChildNum = f.ParentNum) 
                      THEN tmpField.ChildNum
                      ELSE tmpField.FieldNum
                 END ChildNum,
                FieldNum,
                FieldDescr
FROM tmpField

答案 1 :(得分:1)

这应该返回您需要的数据。 我删除了迭代,因为你以后不再使用它

加入版本

;WITH tmpField (ParentNum, ChildNum, FieldNum, FieldDescr) AS
(
  SELECT f.ParentNum, f.ChildNum, f.FieldNum, f.FieldDescr
    FROM Field f
   WHERE f.ParentNum = @ParentNum
  UNION ALL 
  SELECT f.ParentNum, f.ChildNum, f.FieldNum, f.FieldDescr
    FROM Field f 
   INNER JOIN tmpField on f.ParentNum = tmpField.ChildNum
)
SELECT t.ParentNum AS ParentNum, 
       Case When p.ParentNum is Null 
            Then t.FieldNum 
            Else t.ChildNum 
        End AS ChildNum, 
       t.FieldNum, 
       t.FieldDescr
FROM tmpField t
Left Join (Select distinct ParentNum From Field) p on t.ChildNum=p.ParentNum

SUBQUERY VERSION(修改为使用EXISTS代替COUNT)

;WITH tmpField (ParentNum, ChildNum, FieldNum, FieldDescr) AS
(
  SELECT f.ParentNum, f.ChildNum, f.FieldNum, f.FieldDescr
    FROM Field f
   WHERE f.ParentNum = @ParentNum
  UNION ALL 
  SELECT f.ParentNum, f.ChildNum, f.FieldNum, f.FieldDescr
    FROM Field f 
   INNER JOIN tmpField on f.ParentNum = tmpField.ChildNum
)
SELECT t.ParentNum AS ParentNum, 
       Case When Exists(Select * from Field p Where t.ChildNum=p.ParentNum)
            Then t.ChildNum 
            Else t.FieldNum 
        End AS ChildNum, 
       t.FieldNum, 
       t.FieldDescr
FROM tmpField t