使用递归 sql 查询不适用于父子

Using recursive sql query not for parent-child

我不是 sql 和 t-sql 的新手,但过去我从未使用过递归查询 - 所有问题都通过 WHILE 或 CURSOR 解决了。我只有 1 个问题 - 如何针对以下问题组织递归查询:我想使用特定分区中的最后一行数据进行操作。无法理解如何在分区的最后一级停止我的递归。

CREATE TABLE #temp
(i int
, s int
, v int);

INSERT INTO #temp

SELECT 1, 1, 10
UNION
SELECT 1, 2, 20
UNION
SELECT 2, 1, 5
UNION
SELECT 2, 2, 5
UNION
SELECT 2, 3, 2

WITH CTE AS

(
SELECT i
, s
, v
FROM #temp
WHERE s=1

UNION ALL

SELECT t.i
, t.s
, t.v + cte.v as new_v
FROM #temp t
INNER JOIN cte
ON (cte.i=t.i)
WHERE t.s>1
)

SELECT *
FROM cte

OPTION(MAXRECURSION 0)

我想得到 5 行作为结果:

result

我知道可以使用 OUTER APPLY、JOINS、WHILE 或 CURSOR 方法解决。您能否分享任何功能让我了解如何使用递归 cte 查询获得相同的结果?例如,SUM 函数 - 对于这个问题,递归查询是最好的方法,因为我将在大 CASE 中使用许多标量函数,这些函数将使用分区中最后一行的值和当前行分区的值。

谢谢。 对不起,我的英语水平不好。

如果我用下面的例子尝试同样的问题,是否正确?我猜想需要正确说明递归查询将以何种顺序进行任何数据操作。下面的代码将帮助您理解我想要解决的问题:

CREATE TABLE #temp
(i_key int
, step int
, step_h int
, value int);

INSERT INTO #temp

SELECT 1, 1, NULL, 20
UNION
SELECT 1, 2, 1, 20
UNION
SELECT 2, 1, NULL, 10
UNION
SELECT 2, 2, 1, 10
UNION
SELECT 2, 3, 2, 5

WITH CTE AS

(
SELECT i_key
, step
, value
FROM #temp
WHERE step=1
--AND i_key=2

UNION ALL

SELECT t.i_key
, t.step
, CASE
        WHEN cte.value - t.value <=0 THEN 0
        ELSE cte.value - t.value
END as value
FROM #temp t
INNER JOIN cte
ON (cte.i_key=t.i_key
AND cte.step=t.step_h)
--WHERE t.step>1
)

SELECT *
FROM CTE

OPTION(MAXRECURSION 0)

父子结构总是需要解决这个问题吗? 所以我想这可以通过另一个连接来完成(没有父子列)。

AND cte.step=t.step-1

对于您的特定示例,递归是不必要的。您只需要 SQL Server 2012 或更高版本:

select t.*,
    sum(t.v) over(partition by t.i order by t.s) as [RT]
from #temp t
order by t.i, t.s;

如果您需要访问上一行/下一行,在上述相同版本的SQL服务器中引入了lag()/lead()排名功能。

编辑: 啊,我明白了。您只是想知道如何正确编写递归 CTE。这是第二个示例的(看似)正确的代码:

with cte as (
    select t.i_key, t.step, t.value
    from @temp t
    where t.step_h is null
    union all
    select c.i_key, t.step, case
        when c.value < t.value then 0
        else c.value - t.value
    end as [Value]
    from @temp t
        inner join cte c on c.step = t.step_h
            and c.i_key = t.i_key
)
select *
from cte c
order by c.i_key, c.step;

最后,当迭代没有产生任何新行时,它会自行停止。