我需要计算存储在字符串中的数学表达式的结果(例如:'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
)。
如果没有括号,则必须像在标准计算中一样考虑数学运算符的优先级。
在替换所有值并从空值中清除表达式之后,我使用execute immediate来计算最终结果。
谢谢你的帮忙!
发布于 2017-06-14 18:07:23
您可以使用动态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
发布于 2017-06-14 16:59:36
但这是针对SQL Server的。您必须调整它以处理诸如-*、/、(& )之类的运算符。您可以在此处管理您的空值。
基本上,你必须将这个表达式放入一个堆栈中&评估(Pop) &求解你的表达式。
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
https://stackoverflow.com/questions/44539791
复制相似问题