Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用非父-子递归sql查询_Sql_Sql Server_Tsql_Recursion_Ssms - Fatal编程技术网

使用非父-子递归sql查询

使用非父-子递归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

我对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行作为结果:

我知道它可以用外部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,但我仍然需要递归。我会改变上面的问题,让你们更了解我想要什么。