计算数学字符串中的NULL值而不用0 PL / SQL替换它们

时间:2017-06-14 08:45:04

标签: sql oracle math plsql operators

我需要计算存储在字符串中的数学表达式的结果(例如:'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*BA+B+C)。

如果没有括号,则必须遵守数学运算符的优先级,如标准计算中那样。

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

感谢您的帮助!

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:-1)

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

但这适用于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