我需要计算存储在字符串中的数学表达式的结果(例如:'A*(B+C)+(D*E)+F+G*(H+I)'
)。
该字符串可以包含任何数学运算符。
我的程序的第一步(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*B
或A+B+C
)。
如果没有括号,则必须遵守数学运算符的优先级,如标准计算中那样。
在替换所有值并从NULL值清除表达式后,我使用execute immediate来计算最终结果。
感谢您的帮助!
答案 0 :(得分:0)
您可以使用动态SQL(在计算中使用Oracle的NULL
值逻辑来实现它 - 所以NULL + anything = NULL
和NULL * 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
答案 1 :(得分:-1)
但这适用于SQL Server。您必须对其进行调整以处理运算符,例如 - *,/,(&amp;)。 &安培;你可以在这里管理你的空值。
基本上你必须把这个表达式放在一个堆栈中。评价(流行)&amp;解决你的表达。
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