Sql server 递归乘法sql server
有没有办法把一个数字乘以一个比率,把这个数字乘以另一个比率,再把最后一个数字乘以另一个比率 乘法将是: 100+100*0.1=110 110+110*0.3=143 143+143*0.2=171.6 我有下表“收入”和“比率”,我想得到一个查询结果作为“结果”。 我想我应该使用递归查询,但我不知道如何编写它 我正在使用SQL serverSql server 递归乘法sql server,sql-server,recursion,sql-server-2012,Sql Server,Recursion,Sql Server 2012,有没有办法把一个数字乘以一个比率,把这个数字乘以另一个比率,再把最后一个数字乘以另一个比率 乘法将是: 100+100*0.1=110 110+110*0.3=143 143+143*0.2=171.6 我有下表“收入”和“比率”,我想得到一个查询结果作为“结果”。 我想我应该使用递归查询,但我不知道如何编写它 我正在使用SQL server with revenue as ( select '100' revenue ) , ratios as ( select '1' month_n, '
with
revenue as (
select '100' revenue
)
,
ratios as
(
select '1' month_n, '0,1' ratio
union
select '2' month_n, '0,3' ratio
union
select '3' month_n, '0,2' ratio
),
outcome as
(
select '1' month_n, '0,1' ratio, '110' result
union
select '2' month_n, '0,3' ratio, '143' result
union
select '3' month_n, '0,2' ratio, '171,6' result
)
select * from outcome
如果月份在无间隙的情况下增加,则可以通过在月份\u n-1上加入来进行递归:
with
revenue as (
select 100 revenue
)
,
ratios as
(
select 1 month_n, 0.1 ratio
union
select 2 month_n, 0.3 ratio
union
select 3 month_n, 0.2 ratio
),
outcome as
(
select (select MIN(month_n) from ratios) - 1 MONTH_n, 0.0 ratio, cast(revenue as float) result, 1 IsBase from revenue
union all
select r.month_n , r.ratio, (r.ratio + 1.0) * o.result, 0
from ratios r
join outcome o on o.MONTH_n = r.month_n - 1
)
select MONTH_n,ratio,result from outcome where IsBase = 0
结果:
MONTH_n ratio result
1 0.1 110
2 0.3 143
3 0.2 171,6
但更安全的做法是在指数中使用行数,特别是在出现多年的情况下
作为一个完全不重要的旁注,您也可以在不使用下面多余的“基本”行的情况下编写此代码,但这会将计算定义放在两行中。并不是说这会导致额外的计算,只是一个可维护性问题
....,
outcome as
(
select top 1 MONTH_n, ratio, (ratio + 1.0) * cast(revenue as float) result from revenue , ratios order by month_n
union all
select r.month_n , r.ratio, (r.ratio + 1.0) * o.result
from ratios r
join outcome o on o.MONTH_n = r.month_n - 1
)
select * from outcome
如果您的比率不为空,并且始终大于-1(因为您无论如何都需要加1才能得到乘法因子),并且您也在使用SQL Server 2012或更高版本,则您的查询可以在不递归的情况下解决:
WITH Revenue (Revenue) AS (SELECT 100),
Ratios AS (SELECT * FROM (VALUES (1, 0.1), (2, 0.3), (3, 0.2)) t (Month_n, Ratio))
SELECT ra.month_n,
ra.Ratio,
CompoundRatio = EXP(SUM(LOG((1 + ra.Ratio))) OVER(ORDER BY Month_n)),
Result = rv.Revenue * EXP(SUM(LOG((1 + ra.Ratio))) OVER(ORDER BY Month_n))
FROM Ratios AS ra
CROSS JOIN Revenue AS rv;
其中:
month_n Ratio Compound Result
-------------------------------------
1 0.1 1.1 110
2 0.3 1.43 143
3 0.2 1.716 171.6
您可以使用窗口函数汇总以前的比率,以获得复合比率,尽管由于SQL Server没有产品聚合,您需要使用LOG
和EXP
来获得以前比率的乘积
如果你的比率可以是负数和/或0,那么你仍然可以这样做,但是你的逻辑会变得更复杂。有关检查所做操作的更多说明,请参阅:
WITH Revenue (Revenue) AS (SELECT 100),
Ratios AS (SELECT * FROM (VALUES (1, 0.1), (2, 0.3), (3, 0.2), (4, -0.1), (5, 0.2), (6, -0.2), (7, 0.05), (8, -1.1)) t (Month_n, Ratio))
SELECT ra.month_n,
ra.Ratio,
CompoundRatio = CASE WHEN MIN(ABS(ra.Ratio + 1)) OVER(ORDER BY ra.Month_n) = 0 THEN 0
ELSE CASE WHEN SUM(CASE WHEN ra.Ratio < -1 THEN 1 ELSE 0 END)
OVER(ORDER BY ra.Month_n) % 2 = 1 THEN -1 ELSE 1 END *
EXP(SUM(LOG(ABS(NULLIF(1 + ra.Ratio, 0)))) OVER(ORDER BY Month_n))
END,
Result = CASE WHEN MIN(ABS(ra.Ratio + 1)) OVER(ORDER BY ra.Month_n) = 0 THEN 0
ELSE CASE WHEN SUM(CASE WHEN ra.Ratio < -1 THEN 1 ELSE 0 END)
OVER(ORDER BY ra.Month_n) % 2 = 1 THEN -1 ELSE 1 END *
EXP(SUM(LOG(ABS(NULLIF(1 + ra.Ratio, 0)))) OVER(ORDER BY Month_n))
END * rv.Revenue
FROM Ratios AS ra
CROSS JOIN Revenue AS rv;
您使用的是什么版本的SQL Server?谢谢GarethD。我使用的是SQL server 2012,但我确实有很多负比率。我猜使用EXP时,它不会与负比率一起工作。你的负值是否小于-1?无论如何,每个比率都要加上1——重写第一个
100+100*0.1
等式相当于100*(1+0.1)
,因此,即使你的比率是-0.9,这对当前方法来说也不是问题。如果你的值低于这个,那么我将添加一个更新的公式来解释这个。不,不,它们不能小于-1。好的,我将尝试您的第一个解决方案tooThanks GarethD,我花了一些时间使其适应真实的查询,但它工作得非常完美非常感谢我。这就是我在用递归法求解它时寻找的答案。但是您还提到尝试超前/滞后函数,这可能会使它更简单,因为实际查询比我给出的示例复杂得多
month_n Ratio CompoundRatio SQLResult Equation
------------------------------------------------------------------------
1 0.1 1.1 110 100 + 100 x 0.1 = 110
2 0.3 1.43 143 110 + 110 x 0.3 = 143
3 0.2 1.716 171.6 143 + 143 x 0.2 = 171.6
4 -0.1 1.5444 154.44 171.6 + 171.6 x -0.1 = 154.44
5 0.2 1.85328 185.328 154.44 + 154.44 x 0.2 = 185.328
6 -0.2 1.482624 148.2624 185.328 + 185.328 x -0.2 = 148.2624
7 0.05 1.5567552 155.67552 148.2624 + 148.2624 x 0.05 = 155.67552
8 -1.1 -0.15567552 -15.567552 155.67552 + 155.67552 x -1.1 = -15.567552