2017-06-14 66 views
0

我需要计算存储在字符串中的数学表达式的结果(例如:'A*(B+C)+(D*E)+F+G*(H+I)')。 该字符串可以包含任何数学运算符。以数学字符串计算NULL值而不用0替换它们PL/SQL

我的程序(一个PL/SQL程序)的第一步是与他们的价值观来取代变量(可以是NULL

但是,因为我需要我不能用零替换NULL值区分总结果是NULL还是0

示例#1:

我期望有NULL作为结果,而不是0。

NULL*(B+C)+(NULL*10)+NULL+5*(NULL+NULL) 

例#3:

我期望有0作为结果

NULL*(B+C)+(NULL*10)+0+5*(NULL+NULL) 

示例2:

我希望有99作为结果

NULL*(B+C)+(NULL*10)+99+5*(NULL+NULL) 

有没有办法动态地做到这一点?数学表达式可以是任何其他类型('A*B+C*D+E*G''A*(B+C)+D*(E+F)'或简单的A*BA+B+C)。

如果没有括号,数学运算符的优先级必须像在标准计算中一样受到尊重。

替换所有值并从NULL值中清除表达式后,我使用execute immediate来计算最终结果。

感谢您的帮助!

+5

您的需求呢没有道理。 NULL + NULL结果为NULL,但0 + NULL结果为0,但10 * NULL结果为NULL?用所有可能的操作符的NULL和非NULL值处理的完整定义更新你的问题。 – nop77svk

+0

如果我的意见里面有一个NULL值,几乎每次结果都必须为NULL,除了所有的NULL都在方括号中,如(...)* 0 - > 0或(...)^ 0 - > 1. Fe在你的例子中#3:如果第一个NULL代表,我不知道,但可以是5百万,那么结果是0 + 5 000 000 *(A + B)(... + 10倍的任何和5倍的其他任何) - >隐含你用0代替所有NULL – am2

+0

也许你可以做到以下几点:用随机值替换所有NULL两次并比较结果。如果两个结果都是相同的,你可以希望,NULL不起任何作用,但是当然你可以找到其中的一种组合,它给了你一个假的朋友。 – am2

回答

-1

这里有https://social.msdn.microsoft.com/Forums/sqlserver/en-US/434baca4-56dd-4ba3-896c-a04e2d29b5ef/stack-with-sql-server?forum=transactsql

一个不错的功能,但是这是为SQL Server。您必须修改它以处理操作员,如 - *,/,(&)。 &你可以在这里管理你的空值。

基本上你必须在堆栈中推这个表达式&评估(流行)&解决你的表情。

create table dbo.Stack 
(
stkID int identity(1,1) not null primary key, 
stkData varchar(50) not null, 
) 
go 

create procedure dbo.spStackPush 
(
@stkData varchar(10) 
) 
as 
begin 
set nocount on 
insert into Stack (stkData) values (@stkData) 
if @@error <> 0 raiserror('Could not push to stack', 16, 1) 
return 0 
end 
go 

create procedure dbo.spStackPop 
(
@stkData varchar(10) output 
) 
as 
begin 
set nocount on 
declare @stkID int 
select 
@stkData = stkData, 
@stkID = stkID 
from dbo.Stack 
where stkID = (select max(stkID) from dbo.Stack) 

delete from dbo.Stack where stkID = @stkID 
return 0 
end 
go 

create procedure dbo.spStackEvaluate 
(
@stkData varchar(10) output 
) 
as 
begin 
set nocount on 
declare @stkLeft varchar(10) 
declare @stkRight varchar(10) 
declare @stkNext varchar(10) 

exec dbo.spStackPop @stkData output 

if @stkData = '+' 
begin 
exec dbo.spStackPop @stkLeft output 
exec dbo.spStackPop @stkRight output 

set @stkData = cast(@stkLeft as int) + cast(@stkRight as int) 
end 

if exists(select 1 from dbo.Stack) 
begin 
exec dbo.spStackPop @stkNext output 
exec dbo.spStackPush @stkData 
exec dbo.spStackPush @stkNext 
exec dbo.spStackEvaluate @stkData output 
end 

return 0 
end 
go 

-- Test script 
delete dbo.Stack 

declare @stkData varchar(10) 

exec dbo.spStackPush '10' 
exec dbo.spStackPush '+' 
exec dbo.spStackPush '20' 
exec dbo.spStackPush '+' 
exec dbo.spStackPush '30' 
exec dbo.spStackPush '40' 
exec dbo.spStackPush '+' 

exec dbo.spStackEvaluate @stkData output 
print @stkData 
+1

'sql'标记不是Microsoft SQL SERVER的同义词。 –

+0

@NicholasKrasnov是的,我知道。我想展示使用堆栈作为数据结构来评估表达式的方法。我添加了代码(尽管是sql server的事件),这样如果链接断开,代码仍然存在。 –

0

您可以使用动态SQL(使用Oracle的逻辑计算中NULL值 - 这样NULL + anything = NULLNULL * anything = NULL)做到这一点:

DECLARE 
    SUBTYPE VARIABLE_TYPE IS VARCHAR2(5); 
    TYPE VARIABLE_MAP IS TABLE OF NUMBER INDEX BY VARIABLE_TYPE; 

    variables VARIABLE_MAP; 
    expression VARCHAR2(4000) := 'A*(B+C)+(D*E)+F+G*(H+I)'; 
    v   VARIABLE_TYPE; 
    e   VARCHAR2(4000); 
    r   NUMBER; 
BEGIN 
    -- Populate the variables values 
    variables('A') := 1; 
    variables('B') := 2; 
    variables('C') := 3; 
    variables('D') := 4; 
    variables('E') := 5; 
    variables('F') := 6; 
    variables('G') := 7; 
    variables('H') := 8; 
    variables('I') := 9; 

    -- Replace the variables with their values: 
    e := expression; 
    v := variables.FIRST; 
    WHILE v IS NOT NULL LOOP 
    e := REPLACE(e, v, COALESCE(TO_CHAR(variables(v)), 'NULL')); 
    v := variables.NEXT(v); 
    END LOOP; 

    -- Perform the calculation 
    EXECUTE IMMEDIATE 'BEGIN :1 := ' || e || '; END;' USING IN OUT r; 

    -- Output the result 
    DBMS_OUTPUT.PUT_LINE(r); 
END; 
/

输出

150 
+0

感谢您的建议代码,但我试着用这些值运行您的代码: 变量('A'):= NULL; 变量('B'):= 2;变量('C'):= 3; 变量('D'):= NULL; 变量('E'):= NULL; 变量('F'):= NULL; 变量('G'):= NULL; 变量('H'):= 8; 变量('I'):= 9; ,因为e在EXECUTE IMMEDIATE之前返回了*(2 + 3)+(*)++ *(8 + 9),所以失败。预期的结果是NULL。 – user8159167

+0

@ user8159167更新 – MT0

+0

我真的需要避免标准的NULL定义,正如我在我的文章中所说的那样,数学表达式是动态的,所以可能有如下形式:'A *(B + C)+(D * E)+ F + G *(H + I)+2 所以我期望结果如下:2。对于COALESCE,我仍然得到错误的结果(我得到的是NULL而不是2,因为execute immediate不能计算包含未知值的表达式)。但是这里需要的是如果NULL +或+ NULL忽略NULL值并且如果任何操作数为NULL则忽略整个A * B。我希望这很清楚? – user8159167