【问题标题】:How to use CTE recursion to get a running total of a column如何使用 CTE 递归来获得一列的运行总计
【发布时间】:2023-03-17 10:00:01
【问题描述】:

一直在研究CTE递归,但似乎还是一头雾水。

我有表:utb(date, b_id, v_id, b_vol)

我需要得到该列的总和:b_vol。

问题是,如果 row_number 是偶数,我需要除,如果它是奇数,我需要相乘,所以本质上是:

P1= b_vol1, P2 = b_vol1/b_vol2, P3= b_vol1/b_vol2*b_vol3, P4= b_vol1/b_vol2*b_vol3/b_vol4

所以,基本上是 P(n)= (P(n-1)(*OR/(b_vol(n)))

我似乎不知道如何将其放入查询中。

感谢您抽出宝贵时间阅读本文。我希望你能帮忙。

【问题讨论】:

  • 显示一些输入数据和预期的输出。
  • 在这种情况下,请不要打扰,制作一个比递归 cte 更清晰的简单光标。
  • @vkp 我已经添加了所需的输出。列 (SV) 是唯一的新列,因此其他列是原始输入。
  • @GiorgiNakeuri 我将不得不研究一下光标是什么,谢谢你的想法!

标签: sql sql-server recursion common-table-expression


【解决方案1】:

我的示例表只有 1 列 B_VOL。试试这个

DECLARE @SampleData AS TABLE ( B_VOL int)
INSERT INTO @SampleData VALUES (50), (50), ( 50), (50) ,(155), (255)

;WITH temp AS
(
   SELECT sd.*, row_number() OVER(ORDER BY (SELECT null)) - 1 AS RowIndex FROM @SampleData sd
)
,cte AS
(
   SELECT TOP 1  t.RowIndex, CAST( t.B_VOL  AS decimal(18,7)) AS sv FROM temp t ORDER BY t.RowIndex ASC
   UNION ALL
   SELECT t.RowIndex, CAST(cte.sv * (CASE WHEN t.RowIndex % 2 = 1 THEN CAST(1 AS decimal(18,7))/t.B_VOL ELSE t.B_VOL  END) AS  decimal(18,7)) AS sv                                 
   FROM  cte 
   INNER JOIN temp t ON cte.RowIndex + 1 = t.RowIndex 
)
SELECT  t.*, c.sv
FROM temp t
INNER JOIN cte c ON t.RowIndex = c.RowIndex
OPTION(MAXRECURSION 0)

【讨论】:

  • 这基本上成功了!我必须修改一些精确的东西,但除此之外,你的递归创造了奇迹。我要研究它:D。谢谢 triV!
  • 你在最后一个额外的内部连接
【解决方案2】:

首先,CTE 并不是解决此问题的最佳方法。但 。 . .

with u as (
      select u.*, row_number() over (order by date) - 1 as seqnum
      from utb u
     ),
     cte as (
      select seqnum, b_vol as result
      from u
      union all
      select cte.seqnum, cte.result * (case when seqnum % 2 = 1 then 1.0 / b_vol else b_vol end) as result
      from cte join
           u
           on u.seqnum = cte.seqnum + 1
     )
select *
from cte;

【讨论】:

  • 嗨,戈登。我得到了上面的查询来给出结果,但它没有计算任何东西。结果列只是打印出 b_vol 值。有什么想法吗?
  • @UncleJesse 。 . . .可能是因为b_vol 是一个整数。您可能需要转换为某种数字类型。
【解决方案3】:

你应该试试这个,

DECLARE @SampleData AS TABLE ( B_VOL int)
INSERT INTO @SampleData VALUES (50), (50), ( 50), (50) ,(155), (255)

;with CTE as
(
select S.B_VOL,ROW_NUMBER()over(order by ((select null)))rn
from @SampleData S
)
,CTE1 AS
(
select b_vol,cast(b_vol as float) sv,1 rn1 
from cte    where rn=1

union ALL

select c.b_vol,
case when (c1.rn1+1)%2=0
THEN c1.sv/cast(c.b_vol as float)
ELSE
c1.sv*cast(c.b_vol as float)
end
,c1.rn1+1
from CTE C
inner join CTE1 c1
on c.rn=c1.rn1+1
where c1.rn1<7
)

select * from cte1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多