Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.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
游标与While循环-SQLServer_Sql_Sql Server - Fatal编程技术网

游标与While循环-SQLServer

游标与While循环-SQLServer,sql,sql-server,Sql,Sql Server,假设我在数据库中有一堆行(本例中是SQLServer2008),可以用来创建方程 ----------------------------------------------------- OperationID | EquationID | Operation | Amount | Order ----------------------------------------------------- 1 | 1 | + | 12

假设我在数据库中有一堆行(本例中是SQLServer2008),可以用来创建方程

 -----------------------------------------------------
 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

我想不出一种不遍历行就能得到这些结果的方法。我知道的唯一方法是使用游标或使用临时表和while循环。有没有更好的方法?如果不是一般情况下,什么将执行更好的游标或while循环


注意:这有点简化,在项目的这个阶段,我们只能猜测数据会是什么样子。假设每个“方程”将有大约100到1000个运算,每天将有几千个“方程”需要处理。

已经证明,递归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);
第一个SELECT获取最左边的数字,UNION all对其返回的数字执行以下操作。maxrecursion选项将一个等式中的操作数限制为1000。当然,你可以把这个设定得更高


这个答案有些不完整,因为最终的select查询将返回中间结果。不过,这很容易过滤。

我已经清理/充实了一些代码,并在这里介绍这些代码。我在社区维基上标记了这个答案,因为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)

如果您使用的是SQLServer2005+,那么可以使用递归CTE,使用大小写来表示+、-、/,或者*我想,括号是如何处理的?是基于顺序列完成的吗?你怎么知道括号应该放在哪里?我最初的想法是,在插入到这个结构之前,你可能有一个“格式良好”的方程,所以我想问你为什么不能完整地存储方程?您可以始终将其参数化(例如“(@p1-@p2)/@p3”),以允许在执行时分配值。更简单…更简单=好:)是的,括号基于顺序列。在这个简化的示例中,我可以存储完整的公式,但实际的“公式”将有数千个操作和周期性添加的操作。最终查询如何返回中间结果?如果我只选择所有结果,例如,它将返回:等式:1 Order:1 Number:12和Order:2 Number:24。这个例子更像是一个只需要实际总数的运行总数。当然,如果你只想得到一个等式的结果,你可以选择TOP 1,其中等式=1 ORDER BY ORDER DESC+1我冒昧地把你的代码充实了一点。在社区维基上做了我的回答,因为你值得表扬。谢谢。我刚从SQLServer2000升级,所以我正在使用CTE经历一个“一切看起来都像钉子”的阶段。呵呵。