Pரத*_*ீப் 11 sql sql-server sql-server-2008
我有两张桌子
WAC表
ID wac_inc item
-- ----------------- ----
1 2.310000000000000 A
2 1.100000000000000 A
3 2.130000000000000 A
4 1.340000000000000 A
Run Code Online (Sandbox Code Playgroud)
基线表
item baseline
---- ------------------
A 10.000000000000000
Run Code Online (Sandbox Code Playgroud)
预期结果
ID wac_inc item Running_Mul
-- ----------------- ---- -----------
1 2.310000000000000 A 10.231 -- 10 * (1+(2.310000000000000/100))
2 1.100000000000000 A 10.343541 -- 10.231 * (1+(1.100000000000000/100))
3 2.130000000000000 A 10.563858 -- 10.343541 * (1+(2.130000000000000/100))
4 1.340000000000000 A 10.705413 -- 10.563858 * (1+(1.340000000000000/100))
Run Code Online (Sandbox Code Playgroud)
找到的公式running_mul
是
基线*(1 +(wac_inc/100))
这里对于每一行,前一行的Running_Mul
值是baseline
和第一行的baseline
来源baseline table
.
希望我说清楚.AFAIK我们可以使用,CURSOR
但我想尽可能避免 RBAR
.任何人都可以建议我做更好的方法.
尝试:
DECLARE @t TABLE
(
ID INT ,
wac DECIMAL(30, 10) ,
item CHAR(1)
)
DECLARE @b TABLE
(
item CHAR(1) ,
baseline DECIMAL(30, 10)
)
INSERT INTO @t
VALUES ( 1, 2.31, 'A' ),
( 2, 1.10, 'A' ),
( 3, 2.13, 'A' ),
( 4, 1.34, 'A' )
INSERT INTO @b
VALUES ( 'A', 10 );
WITH ordercte
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY item ORDER BY ID ) AS rn
FROM @t
),
rec
AS ( SELECT t.item ,
t.ID ,
t.wac ,
t.rn ,
b.baseline * ( 1 + ( t.wac / 100 ) ) AS m
FROM ordercte t
JOIN @b b ON b.item = t.item
WHERE t.rn = 1
UNION ALL
SELECT t.item ,
t.ID ,
t.wac ,
t.rn ,
c.m * ( 1 + ( t.wac / 100 ) )
FROM ordercte t
JOIN rec c ON t.item = c.item
AND t.rn = c.rn + 1
)
SELECT id ,
wac ,
item ,
m
FROM rec
Run Code Online (Sandbox Code Playgroud)
输出:
id wac item m
1 2.3100000000 A 10.231000
2 1.1000000000 A 10.343541
3 2.1300000000 A 10.563858
4 1.3400000000 A 10.705414
Run Code Online (Sandbox Code Playgroud)
EDIT1
我试图实现LOG EXP技巧,但除非@usr引导我解决方案,否则无法管理.所以用户@usr的所有积分:
WITH ordercte
AS ( SELECT t.ID ,
t.wac ,
t.item ,
b.baseline ,
ROW_NUMBER() OVER ( PARTITION BY t.item ORDER BY ID ) AS rn
FROM @t t
JOIN @b b ON b.item = t.item
)
SELECT baseline
* EXP(SUM(LOG(( 1 + ( wac / 100 ) ))) OVER ( PARTITION BY item ORDER BY rn )) AS m
FROM ordercte
Run Code Online (Sandbox Code Playgroud)
要不就:
SELECT t.ID, t.wac, t.item, baseline
* EXP(SUM(LOG(( 1 + ( wac / 100 ) ))) OVER ( PARTITION BY t.item ORDER BY t.ID )) AS m
FROM @t t
JOIN @b b ON b.item = t.item
Run Code Online (Sandbox Code Playgroud)
如果ID是您订购的字段.
输出:
ID wac item m
1 2.3100000000 A 10.231
2 1.1000000000 A 10.343541
3 2.1300000000 A 10.5638584233
4 1.3400000000 A 10.7054141261722
Run Code Online (Sandbox Code Playgroud)
EDIT2
对于SQL 2008,请使用:
WITH cte
AS ( SELECT t.ID ,
t.wac ,
t.item ,
baseline ,
( SELECT SUM(LOG(( 1 + ( wac / 100 ) )))
FROM @t it
WHERE it.item = t.item AND it.ID <= t.ID
) AS e
FROM @t t
JOIN @b b ON b.item = t.item
)
SELECT ID, wac, item, baseline * EXP(e) AS m
FROM cte
Run Code Online (Sandbox Code Playgroud)
EDIT3
这是SQL Server 2008的完整解决方案,使用NULL和负值拨号:
WITH cte
AS ( SELECT t.ID ,
t.wac ,
t.item ,
b.baseline ,
ca.e,
ca.n,
ca.m
FROM @t t
JOIN @b b ON b.item = t.item
CROSS APPLY(SELECT SUM(LOG(ABS(NULLIF( 1 + wac / 100 , 0)))) as e,
SUM(SIGN(CASE WHEN 1 + wac / 100 < 0 THEN 1 ELSE 0 END)) AS n,
MIN(ABS(1 + wac / 100)) AS m
FROM @t it
WHERE it.item = t.item AND it.ID <= t.ID
) ca
)
SELECT ID, wac, item, baseline *
CASE
WHEN m = 0 THEN 0
WHEN n % 2 = 1 THEN -1 * EXP(e)
ELSE EXP(e)
END as Result
FROM cte
Run Code Online (Sandbox Code Playgroud)
您可以使用以下数学技巧将一系列乘法转换为一系列加法:
exp(log(a) + log(b)) = a * b
Run Code Online (Sandbox Code Playgroud)
所以MUL(a)
是EXP(SUM(LOG(a)))
.
SELECT SUM(val) AS [Sum], EXP(SUM(LOG(val))) AS Product
FROM (VALUES
(1), (2), (3), (4)
) x(val)
Run Code Online (Sandbox Code Playgroud)
这会发出sum = 10, product = 24
.
潜在的问题是四舍五入的错误和零因素.
您现在可以使用常用方法之一来实现运行聚合,例如窗口函数.这是一个已解决的问题.
为了完整起见,这里是 SQL Server 2012 的完整解决方案,它使用EXP(SUM(LOG(val)))
@usr 在另一个答案中建议的技巧。
WITH
CTE
AS
(
SELECT
0 AS ID
,item
,baseline AS wac_inc
,baseline AS m
FROM baseline
UNION ALL
SELECT
ID
,item
,wac_inc
,1 + wac_inc/100 AS m
FROM wac
)
SELECT
ID
,item
,wac_inc
,m
,EXP(SUM(LOG(m)) OVER (PARTITION BY item ORDER BY ID ROWS UNBOUNDED PRECEDING)) AS MulRows
FROM CTE;
Run Code Online (Sandbox Code Playgroud)
结果集
ID item wac_inc m MulRows
0 A 10.000000000000000 10.000000000000000 10
1 A 2.310000000000000 1.023100000000000 10.231
2 A 1.100000000000000 1.011000000000000 10.343541
3 A 2.130000000000000 1.021300000000000 10.5638584233
4 A 1.340000000000000 1.013400000000000 10.7054141261722
Run Code Online (Sandbox Code Playgroud)
如果 SQL Server 2012 可用,则此窗口SUM
非常有效。对于以前的版本,任何基于集合的解决方案都会导致O(n*n)
复杂性,这意味着游标将是更好的方法。这是 Aaron Bertrand 写的一篇非常好的文章,比较了计算运行总计的不同方法:http://sqlperformance.com/2012/07/t-sql-queries/running-totals
或者 SO 问题:计算运行总计/运行余额
当然,如果您的表很小,那么由于游标开销,基于集合的O(n*n)
复杂解决方案可能比使用游标的解决方案运行得更快,因此您需要使用真实数据检查性能。O(n)
归档时间: |
|
查看次数: |
1942 次 |
最近记录: |