0

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

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

最后一次迭代中,当没有更多“孩子”时,我希望该ChildNum字段具有FieldNum. 在所有以前的迭代中,ChildNum应该有该ChildNum字段的值,就像现在一样。

任何人都可以建议一种方法来实现这一点,使用上述查询作为起点?

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

4

2 回答 2

2

当没有更多孩子时,这意味着 ChildNum 为 NULL,因此:

...

UNION ALL 

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

编辑:(在大安评论之后)

好的,在这种情况下,我们可以检查 ChildNum 'children' count :

    ...

    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

...

编辑2:

让我们把支票移到外面:

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
于 2009-09-25T09:00:32.363 回答
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
于 2009-09-25T11:02:49.020 回答