2017-06-14 65 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