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

时间:2016-02-07 10:47:13

标签: sql sql-server tsql recursion ssms

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

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方法解决它。您可以分享我的任何功能,以了解如何使用recurcive cte查询获得相同的结果? SUM函数只是例如 - 对于那个问题,recurcive查询是最好的方法因为我将在大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

1 个答案:

答案 0 :(得分:0)

对于您的特定示例,递归是不必要的。您只需要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;

如果您需要访问previos / next行,则在上述相同版本的SQL Server中引入了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;

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