假设我在DB中有很多行(在本例中是SQLServer 2008 ),这些行可以用来创建方程。
-----------------------------------------------------
OperationID | EquationID | Operation | Amount | Order
-----------------------------------------------------
1 | 1 | + | 12 | 1
2 | 1 | + | 12 | 2
3 | 2 | / | 2 | 3
4 | 2 | + | 12 | 1
5 | 2 | - | 2 | 2
-----------------------------------------------------我需要想出一种方法来评估这张表中的方程式。
方程1: 12 + 12 = 24
方程2:(12-2)/2=5
我想不出一种在不迭代行的情况下获得这些结果的方法。我知道的唯一方法是使用游标,或者通过使用temp表和while循环。有什么更好的方法吗?如果不是一般情况下,什么将执行更好的游标或同时循环?
注意:这有点简化,在这个项目的这个阶段,我们只能猜测数据会是什么样子。假设每个“等式”将有大约100到1000个操作,每天将有几千个“等式”需要处理。
发布于 2010-10-26 20:17:44
已经证明,递归CTE的性能比循环要好得多,可以得到运行总计。这只是一个实际使用变量操作符的运行总数,因此性能方面的好处应该适用于这里。
创建行为类似循环的递归CTE的方法如下所示:
;WITH cte AS (
SELECT equation, number, order FROM table WHERE order = 1
UNION ALL
SELECT table.equation,
CASE WHEN table.operation = '+' THEN cte.number + table.number
WHEN table.operation = '-' THEN cte.number - table.number END AS number, --etc.
table.order FROM table INNER JOIN cte ON table.order = cte.order + 1 AND table.equation = cte.equation
)
SELECT equation, number, order
FROM cte
OPTION (MAXRECURSION 1000);第一个选择获取最左边的数字,并且UNION对它返回的数字执行以下操作。Max递归选项将一个方程中的操作数限制为1000。当然,你可以把这个调得更高。
这个答案有点不完整,因为最后的select查询将返回中间结果。不过,这很容易过滤。
发布于 2010-10-26 20:47:58
我已经清理了/充实了一些mootinator's answer,并在这里展示了这些代码。我标记了这个答案社区wiki,因为mootinator的答案值得称赞。这是在不编辑答案的情况下展示代码的最简单的方法。
declare @equations table (
OperationID int,
EquationID int,
Operation char(1),
Amount int,
[Order] int
)
insert into @equations
(OperationID, EquationID, Operation, Amount, [Order])
values
(1, 1, '+', 12, 1),
(2, 1, '+', 12, 2),
(3, 2, '/', 2, 3),
(4, 2, '+', 12, 1),
(5, 2, '-', 2, 2)
;with cteCalc as (
select EquationID, Amount, [Order]
from @equations
where [Order] = 1
union all
select e.equationid,
case when e.Operation = '+' then c.Amount + e.Amount
when e.Operation = '-' then c.Amount - e.Amount
when e.Operation = '*' then c.Amount * e.Amount
when e.Operation = '/' then c.Amount / e.Amount
end AS Amount,
e.[Order]
from @equations e
inner join cteCalc c
on e.EquationID= c.EquationID
where e.[Order] = c.[Order] + 1
),
cteMaxOrder as (
select EquationID, MAX([Order]) as MaxOrder
from cteCalc
group by EquationID
)
select c.EquationID, c.Amount
from cteMaxOrder mo
inner join cteCalc c
on mo.EquationID = c.EquationID
and mo.MaxOrder = c.[Order]
order by c.EquationID
option (maxrecursion 1000)https://stackoverflow.com/questions/4027477
复制相似问题