使用非父-子递归sql查询
我对sql和t-sql并不陌生,但在过去我从未使用过递归查询——所有问题都是用WHILE或CURSOR解决的。我只有一个问题——如何组织递归查询,以解决以下问题:我想使用某个分区中的最后一行数据进行操作。无法理解如何在分区的最后一级停止递归使用非父-子递归sql查询,sql,sql-server,tsql,recursion,ssms,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
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行作为结果:
我知道它可以用外部APPLY、join、WHILE或CURSOR方法来解决。你能和我分享一些功能吗?让我了解如何使用递归cte查询获得相同的结果?这里的求和函数就是一个例子——对于这个问题,递归查询是最好的方法,因为我将在大的情况下使用许多标量函数,它将使用分区中最后一行的值和当前行分区的值
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)
谢谢。
对不起,我的英语水平不好
如果我在下面的例子中尝试同样的问题,是否正确?我想这需要正确地说明递归查询将以何种顺序处理任何数据。下面的代码将帮助您理解我想要解决的问题:
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)
对于您的特定示例,递归是不必要的。您只需要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 row,则在前面提到的同一版本的SQL Server中引入了滞后/领先排名函数
编辑:啊,我明白了。您只想知道如何正确编写递归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;
最后,当迭代没有生成任何新行时,它会自动停止。顺便说一句,在您的输出示例中,它应该是7,或者您基本上想要的是当s列为2->v1+v2当3>v1+v2+v3时?i-是键,s-是步骤,v-是值。我举这个例子是为了简单地理解,因为我想通过递归查询实现这个结果。在递归中,我们得到了所有关键示例的1个步骤。在联合中,我们得到了处理当前键的前一行的所有其他步骤。若我们讨论case条件,超前和滞后函数并没有帮助。我写了一个简单的例子,只是为了得到关于停止递归的简单答案。我知道分区函数可以得到同样的结果,只是对于这5行的exmaple,但我仍然需要递归。我会改变上面的问题,让你们更了解我想要什么。