昨天我回答了一个递归CTE的问题,揭示了这些在SQL Server中实现的方式存在的问题(可能也存在于其他RDBMS中?)。基本上,当我尝试对当前递归级别使用ROW_NUMBER
时,它会针对当前递归级别的每个行子集运行。我期望这将在真正的SET逻辑中起作用,并针对整个当前递归级别运行。
从这篇MSDN文章看来,我发现的问题是有意为之的:
CTE递归部分中的分析和聚合函数应用于当前递归级别的数据集,而不是CTE的数据集。 像ROW_NUMBER这样的函数仅在由当前递归级别传递给它们的数据子集上运行,而不是在传递给CTE递归部分的整个数据集上运行。 有关详细信息,请参见J.在递归CTE中使用分析函数。
在我的挖掘过程中,我找不到任何解释为什么选择以这种方式工作的地方?这更像是集合语言中的过程性方法,因此它与我的SQL思维流程相矛盾,并且在我看来非常令人困惑。 有人知道并/或可以解释为什么递归CTE以程序方式处理递归级别的分析函数吗?
这是帮助可视化的代码:
请注意,每个代码输出中的RowNumber
列。
WITH myCTE
AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY Score desc) AS RowNumber, 1 AS RecurseLevel
FROM tblGroups
WHERE ParentId IS NULL
UNION ALL
SELECT tblGroups.*,
ROW_NUMBER() OVER (ORDER BY myCTE.RowNumber , tblGroups.Score desc) AS RowNumber,
RecurseLevel + 1 AS RecurseLevel
FROM tblGroups
JOIN myCTE
ON myCTE.GroupID = tblGroups.ParentID
)
SELECT *
FROM myCTE
WHERE RecurseLevel = 2;
这里是第二个SQLFiddle,展示了我希望公共表表达式(CTE)实现的功能(只需要展示第二层级以显示问题)。
WITH myCTE
AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY Score desc) AS RowNumber, 1 AS RecurseLevel
FROM tblGroups
WHERE ParentId IS NULL
)
SELECT tblGroups.*,
ROW_NUMBER() OVER (ORDER BY myCTE.RowNumber , tblGroups.Score desc) AS RowNumber,
RecurseLevel + 1 AS RecurseLevel
FROM tblGroups
JOIN myCTE
ON myCTE.GroupID = tblGroups.ParentID;
我一直认为SQL递归CTE的运行方式应该更像这个while循环
DECLARE @RecursionLevel INT
SET @RecursionLevel = 0
SELECT *, ROW_NUMBER() OVER (ORDER BY Score desc) AS RowNumber, @RecursionLevel AS recurseLevel
INTO #RecursiveTable
FROM tblGroups
WHERE ParentId IS NULL
WHILE EXISTS( SELECT tblGroups.* FROM tblGroups JOIN #RecursiveTable ON #RecursiveTable.GroupID = tblGroups.ParentID WHERE recurseLevel = @RecursionLevel)
BEGIN
INSERT INTO #RecursiveTable
SELECT tblGroups.*,
ROW_NUMBER() OVER (ORDER BY #RecursiveTable.RowNumber , tblGroups.Score desc) AS RowNumber,
recurseLevel + 1 AS recurseLevel
FROM tblGroups
JOIN #RecursiveTable
ON #RecursiveTable.GroupID = tblGroups.ParentID
WHERE recurseLevel = @RecursionLevel
SET @RecursionLevel = @RecursionLevel + 1
END
SELECT * FROM #RecursiveTable ORDER BY RecurseLevel;
EXCEPT
也存在类似问题如此问题所述。 - Martin SmithEXCEPT
将加入 列表。一个 Connect 项目 关于 ROW_NUMBER 表明,他们在2008年也曾这样做过,但为hierarchyid
s 的某些用例颠倒了它。 - Martin Smith