如何计算 SQL Server 中 nvarchar 变量中保存的数学表达式

问题描述 投票:0回答:5

我想计算保存在 sql server 变量中的数学表达式

我用谷歌搜索了很多,找到了 3 个解决方案,但不适用于我的场景

1-这个解决方案无法在函数内执行但我需要它在函数内

declare @expression nvarchar(max)
set @expression = '2*3*100'

declare @sql nvarchar(max)
set @sql = 'select @result = ' + @expression

declare @result int
exec sp_executesql @sql, N'@result int output', @result = @result out

select @result

2-这个无法保存到变量中但我需要将结果存储到变量中

DECLARE @LocalVariable VARCHAR(32);
SET @LocalVariable = '2*3*100';
EXEC('SELECT ' + @LocalVariable);

3-我找到的最后一个解决方案给了我一个错误

DECLARE @x xml 
DECLARE @v decimal(20,4) 
SET @x = '' 
DECLARE @calculatedDataString nvarchar(1000) = '(1 div 100)*((118 div 100)*300.000000)' 
SET @v= @x.value('sql:variable("@calculatedDataString")', 'decimal(20,4)') 
SELECT @v 

错误是

Msg 8114, Level 16, State 5, Line 5
Error converting data type nvarchar to numeric.

请指教

sql sql-server mathematical-expressions
5个回答
3
投票

也许这可能有帮助。

下面将计算一系列表达式,并将结果保存到#temp 表中。从那里您可以将各个结果存储到变量中

这是一个大幅缩小的版本。完整的模型是为宏观替换而构建的(即计算多个数据集的一系列或财务比率)

如果您提供更强大的用例,也许我可以进一步提供帮助

示例

Declare @Expression table (ID int,Expression varchar(max))
Insert Into @Expression values
 (1,'(1/100.0)*((118/100.0)*300.00000)')           -- Simple Calculation
,(2,'datediff(DD,''2016-07-29'',GetDate())')       -- System Functions
,(3,'(Select max(name) from master..spt_values)')  -- Select Value From Table
,(4,'convert(date,GetDate())')                     -- Get Today's Date


IF OBJECT_ID(N'tempdb..#Results') IS NOT NULL
BEGIN
    DROP TABLE #Results
END
Create table #Results (ID int,Value varchar(max))

Declare @SQL varchar(max)=''
Select  @SQL = @SQL+concat(',(',ID,',cast(',Expression,' as varchar(max)))') From @Expression 
Select  @SQL = 'Insert Into #Results Select * From ('+Stuff(@SQL,1,1,'values')+') N(ID,Value)'
Exec(@SQL)

Select * From #Results

Declare @Var decimal(10,4) = (Select Value From #Results where ID=1)
Select @Var  -- 3.5400

临时表

ID  Value
1   3.54000000000000000
2   243
3   YES OR NO
4   2017-03-29

2
投票

最后一个解决方案失败,因为

SET @v= @x.value('sql:variable("@calculatedDataString")', 'decimal(20,4)')
不计算表达式,它尝试将
@calculatedDataString
转换为十进制,这在大多数情况下肯定会失败。

我知道的唯一解决方案是 CLR 函数。您不妨看看这个项目https://github.com/zzzprojects/Eval-SQL.NET

它使用您可以使用的方法创建

SQLNET
UDT,有点

SELECT  SQLNET::New(@calculatedDataString).EvalInt()

请参阅 https://learn.microsoft.com/en-us/sql/relational-databases/clr-integration-database-objects-user-define-types/registering-user-define-types-in-sql-server 了解如何在 sql-server 中注册 UDT。


1
投票

这是我已经投入生产多年的解决方案。令人惊讶的是,考虑到 RegEx 的强大功能,却没有提供解决方案。

这是使用安全的 CLR 程序集,该程序集确实假定某些服务器级别的访问权限。这意味着这可能在 AWS RDS 的某些情况下不起作用,或者在 Azure SQL 托管实例以外的任何情况下(例如新的“无服务器”选项)。

我目前正在 Azure SQL 实例中测试 R 语言的实现,该实例具有此限制。感谢:https://www.mssqltips.com/sqlservertip/4748/sql-server-2016-regular-expressions-with-the-r-language/

CREATE ASSEMBLY [TESTSCORING1_CLR_CS]
FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300EE56E84B0000000000000000E00002210B010800000C00000006000000000000DE2B0000002000000040000000004000002000000002000004000000000000000400000000000000008000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000902B00004B00000000400000B003000000000000000000000000000000000000006000000C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000E40B000000200000000C000000020000000000000000000000000000200000602E72737263000000B00300000040000000040000000E0000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000001200000000000000000000000000004000004200000000000000000000000000000000C02B0000000000004800000002000500B4210000DC09000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B30040077000000010000110F00280F00000A2D067E1000000A2A0F00280F00000A6F1100000A0A72010000700672110000707215000070281200000A7221000070281300000A0B0772250000707229000070281200000A0B7E1000000A0C7E01000004076F1400000AA5160000016C281500000A0CDE09267E1000000A0CDE00082A000110000000005300196C00090100000142731600000A6F1700000A80010000042A1E02281800000A2A000000133004003D000000020000110F00280F00000A2C090F01280F00000A2D02142A0F00280F00000A6F1100000A0A0F01280F00000A6F1100000A0B060716176F1900000A6F1A00000A2A4A03027415000001510303506F1B00000A512A46027235000070281C00000A28040000062A00001330030021000000030000110F00280F00000A2D02142A0F00280F00000A6F1100000A0A0614176F1D00000A2A3A03027415000001281E00000A542A1E02281800000A2A42534A4201000100000000000C00000076322E302E35303732370000000005006C00000044030000237E0000B00300003C04000023537472696E677300000000EC0700003C000000235553002808000010000000234755494400000038080000A401000023426C6F620000000000000002000001571502000900000000FA013300160000010000001A000000030000000100000009000000090000001E0000000E00000003000000010000000400000000000A00010000000000060066005F000A00890078000E00BD00A8000E00C700A80006000801F5000600A20183010600C301B1010600DA01B1010600F701B10106001602B10106002F02B10106004802B10106006302B10106007E02B1010600970283010600AB02B1010600E402C40206000403C4020E005103360312009D037E030600AB035F000600C2035F000A00DC036D000A00E8036D00060017045F0006002A045F00000000000100000000000100010001001000220039000500010001000100100046003900050002000400310098000A005020000000009600D1000E000100F520000000008618EF0015000200E420000000009118D5036C000200002100000000960014011900020049210000000096002401220004005C2100000000960034012900060070210000000096004501290007009D21000000009600570130000800AC21000000008618EF0015000A00000001006601000001007101000002007501000001007F01020002007101000001007101000001007101000001007F0102000200AF013100EF0015003900EF0037004100EF0037004900EF0037005100EF0037005900EF0037006100EF0037006900EF0037007100EF0037007900EF003C008100EF0037008900EF0041009100EF0015009900EF001500210066034B00190070034F00090075034B00A100A3035300A900B20353001100B9035A001900C9035F00B900EF001500C100F00370000900EF001500A9000004C500A9000C04CC00A90012044B002100C903D800A9000C042301D100320430012000730046002E00230047012E002B004D012E00330035012E006B0082012E001B0047012E003B005A012E00630079012E00130035012E00430047012E0053004701800073007500C00073007500E0007300DE006500D3002C010480000001000000C60EFF5300000000000022030000020000000000000000000000010056000000000002000000000000000000000001006D000000000002000000000000000000000001009C000000000002000000000000000000000001005F00000000000000003C4D6F64756C653E005445535453434F52494E47315F434C525F43532E646C6C0041726974686D6574696343616C63756C6174696F6E73005445535453434F52494E473100537472696E6746756E6374696F6E73006D73636F726C69620053797374656D004F626A6563740053797374656D2E586D6C0053797374656D2E586D6C2E58506174680058506174684E6176696761746F72006E61760053797374656D2E446174610053797374656D2E446174612E53716C54797065730053716C446F75626C650053716C537472696E67004576616C7561746541726974686D657468696345787072657373696F6E002E63746F720053797374656D2E436F6C6C656374696F6E730049456E756D657261626C650066537472696E67446C327461626C6500436861726C69737446696C6C526F770066537472696E6743646C327461626C650066537472696E67496E7473327461626C6500496E746C69737446696C6C526F770065787072657373696F6E007374720064656C696D6974657200726F770053797374656D2E52756E74696D652E496E7465726F705365727669636573004F7574417474726962757465006E0053797374656D2E5265666C656374696F6E00417373656D626C795469746C6541747472696275746500417373656D626C794465736372697074696F6E41747472696275746500417373656D626C79436F6E66696775726174696F6E41747472696275746500417373656D626C79436F6D70616E7941747472696275746500417373656D626C7950726F6475637441747472696275746500417373656D626C79436F7079726967687441747472696275746500417373656D626C7954726164656D61726B41747472696275746500417373656D626C7943756C7475726541747472696275746500436F6D56697369626C6541747472696275746500417373656D626C7956657273696F6E4174747269627574650053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300436F6D70696C6174696F6E52656C61786174696F6E734174747269627574650052756E74696D65436F6D7061746962696C697479417474726962757465005445535453434F52494E47315F434C525F4353004D6963726F736F66742E53716C5365727665722E5365727665720053716C46756E6374696F6E417474726962757465006765745F56616C7565004E756C6C00546F537472696E670053797374656D2E546578742E526567756C617245787072657373696F6E73005265676578005265706C61636500537472696E6700436F6E636174004576616C7561746500446F75626C65006F705F496D706C69636974002E6363746F7200586D6C446F63756D656E7400586D6C4E6F6465004372656174654E6176696761746F7200546F4368617241727261790053706C6974005472696D00537472696E6753706C69744F7074696F6E7300436F6E7665727400546F496E743332000000000F6E0075006D00620065007200280000032F00000B200064006900760020000003290000032500000B20006D006F006400200000032C0000000000437A1F06B1F8A74D94BF2C5F099F89790008B77A5C561934E08903061209060001110D111103200001080002121511111111060002011C100E06000112151111060002011C1008042001010E0420010102042001010804010000000320000E0306110D0600030E0E0E0E0420011C0E050001110D0D0607030E0E110D0300000104200012094F01000200540E1146696C6C526F774D6574686F644E616D650F436861726C69737446696C6C526F77540E0F5461626C65446566696E6974696F6E144974656D4944206E76617263686172286D6178290620021D0308080620011D0E1D030407020E0E05000111110E4401000200540E1146696C6C526F774D6574686F644E616D650E496E746C69737446696C6C526F77540E0F5461626C65446566696E6974696F6E0A4974656D494420696E740820021D0E1D0311650307010E040001080E1101000C5445535453434F52494E473100000501000000000C010007436F6D7054656B00001E010019436F7079726967687420C2A920436F6D7054656B203230303600000801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F777301000000B82B00000000000000000000CE2B0000002000000000000000000000000000000000000000000000C02B00000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF25002040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000001800008000000000000000000000000000000100010000003000008000000000000000000000000000000100000000004800000058400000580300000000000000000000580334000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE0000010000000100FF53C60E00000100FF53C60E3F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B004B8020000010053007400720069006E006700460069006C00650049006E0066006F00000094020000010030003000300030003000340062003000000030000800010043006F006D00700061006E0079004E0061006D0065000000000043006F006D007000540065006B00000044000D000100460069006C0065004400650073006300720069007000740069006F006E00000000005400450053005400530043004F00520049004E00470031000000000040000F000100460069006C006500560065007200730069006F006E000000000031002E0030002E0033003700380032002E00320031003500300033000000000050001800010049006E007400650072006E0061006C004E0061006D00650000005400450053005400530043004F00520049004E00470031005F0043004C0052005F00430053002E0064006C006C0000005800190001004C006500670061006C0043006F007000790072006900670068007400000043006F0070007900720069006700680074002000A900200043006F006D007000540065006B0020003200300030003600000000005800180001004F0072006900670069006E0061006C00460069006C0065006E0061006D00650000005400450053005400530043004F00520049004E00470031005F0043004C0052005F00430053002E0064006C006C0000003C000D000100500072006F0064007500630074004E0061006D006500000000005400450053005400530043004F00520049004E00470031000000000044000F000100500072006F006400750063007400560065007200730069006F006E00000031002E0030002E0033003700380032002E00320031003500300033000000000048000F00010041007300730065006D0062006C0079002000560065007200730069006F006E00000031002E0030002E0033003700380032002E0032003100350030003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000C000000E03B00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
WITH PERMISSION_SET = SAFE
GO


CREATE FUNCTION [dbo].[EvaluateArithmethicExpression](@expression [nvarchar](4000))
RETURNS [float] WITH EXECUTE AS CALLER
AS 
EXTERNAL NAME [TESTSCORING1_CLR_CS].[TESTSCORING1.ArithmeticCalculations].[EvaluateArithmethicExpression]
GO

-- Demo some simple evaluations
SELECT [dbo].[EvaluateArithmethicExpression]('1<10') as one, [dbo].[EvaluateArithmethicExpression]('1+1') as two, [dbo].[EvaluateArithmethicExpression]('300/100') as three
GO

1
投票

只是为了好玩,我实现了一个纯 T-SQL 函数,它可以计算基本算术(

+ - / * ( )
和优先级)。虽然我没有对它进行基准测试,但很明显该解决方案无法与基于 CLR 的解决方案竞争。不过,由于它是纯T-SQL,所以可能可以用在CLR不能用的地方。如果不添加词法和语法错误处理代码并正确测试它,这还不能用于生产。

它基本上是一个将字符串拆分为字符的语句,然后对这些字符进行标记,最后应用调车场算法,将两个堆栈存储为 XML 列来计算结果。

CREATE FUNCTION fnEval(@s nvarchar(MAX))
RETURNS float
AS 
BEGIN
    -- Token Types:
    -- -1 => error
    -- 0 => whitespace
    -- 1 => number
    -- 2 => opening parens
    -- 3 => closing parens
    -- 4 => operator + -
    -- 5 => operator * /
    DECLARE @result float;
    WITH cteChar AS (
        SELECT 0 ix, CAST(N' ' AS nchar(1)) c, 0 iType, 1 iGroup -- Anchor
        UNION ALL 
        SELECT LEN(@s)+1, NULL, 3, -1 iGroup -- Finalizer
        UNION ALL
        SELECT c.ix+1, CAST(SUBSTRING(@s, c.ix+1, 1) AS nchar(1)), CASE 
            WHEN SUBSTRING(@s, c.ix+1, 1) LIKE CASE WHEN c.iType=1 and c.c=N'e' THEN N'[0123456789\+\-]' WHEN c.iType=1 THEN N'[0123456789.e]' ELSE N'[0123456789]' END ESCAPE N'\' THEN 1 
            WHEN SUBSTRING(@s, c.ix+1, 1)=N'(' THEN 2 
            WHEN SUBSTRING(@s, c.ix+1, 1)=N')' THEN 3 
            WHEN SUBSTRING(@s, c.ix+1, 1) IN (N'+', N'-') THEN 4
            WHEN SUBSTRING(@s, c.ix+1, 1) IN (N'*', N'/') THEN 5
            WHEN RTRIM(SUBSTRING(@s, c.ix+1, 1))=N'' THEN 0 
            ELSE -1 
        END, CASE 
            WHEN SUBSTRING(@s, c.ix+1, 1) LIKE CASE WHEN c.iType=1 and c.c=N'e' then N'[0123456789\+\-]' WHEN c.iType=1 THEN N'[0123456789.e]' END ESCAPE N'\' THEN c.iGroup 
            ELSE c.iGroup+1
        END
        FROM cteChar c 
        WHERE c.ix<LEN(@s)
    ), cteToken AS (
        SELECT CAST(ROW_NUMBER() OVER (ORDER BY MIN(c.ix)) AS int) ix, STRING_AGG(c.c, N'') WITHIN GROUP (ORDER BY c.ix) s, c.iType
        FROM cteChar c
        WHERE c.iType>0 -- We could handle lexical errors here
        GROUP BY c.iGroup, c.iType
    ), cteParser AS (
        SELECT CASE WHEN EXISTS (SELECT * FROM cteToken f WHERE f.ix>2) THEN CAST(0 AS bit) ELSE CAST(1 AS bit) END bResult, t.ix+1 ixNext, CASE WHEN t.iType=1 THEN 
                (SELECT t.s [@val] FOR XML PATH(N'operand'), TYPE) 
            END xOperand, CASE WHEN t.iType>1 THEN 
                (SELECT t.s [@val], t.iType [@type] FOR XML PATH(N'operator'), TYPE) 
            END xOperator
        FROM cteToken t
        WHERE t.ix=1
        UNION ALL
        SELECT CASE WHEN p.xOperator.exist(N'/*')=0 AND t.s IS NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, t.ix+CASE WHEN (t.iType>3 AND t.iType<=p.xOperator.value(N'*[1]/@type', 'int')) OR (t.iType=3 AND NOT p.xOperator.value(N'*[1]/@type', 'int')=2) THEN 0 ELSE 1 END,
            CASE 
            WHEN t.iType=1 THEN 
                (SELECT t.s [@val], p.xOperand.query(N'*') FOR XML PATH(N'operand'), TYPE) 
            WHEN (t.iType>3 AND t.iType<=p.xOperator.value(N'*[1]/@type', 'int')) OR (t.iType=3 AND NOT p.xOperator.value(N'*[1]/@type', 'int')=2) THEN
                (SELECT CASE p.xOperator.value(N'*[1]/@val', 'nchar') 
                    WHEN N'+' THEN
                        p.xOperand.value(N'*[1]/*[1]/@val', 'float')+p.xOperand.value(N'*[1]/@val', 'float')
                    WHEN N'-' THEN
                        p.xOperand.value(N'*[1]/*[1]/@val', 'float')-p.xOperand.value(N'*[1]/@val', 'float')
                    WHEN N'*' THEN
                        p.xOperand.value(N'*[1]/*[1]/@val', 'float')*p.xOperand.value(N'*[1]/@val', 'float')
                    WHEN N'/' THEN
                        p.xOperand.value(N'*[1]/*[1]/@val', 'float')/p.xOperand.value(N'*[1]/@val', 'float')
                    END [@val], p.xOperand.query(N'*/*/*') FOR XML PATH(N'operand'), TYPE)
            ELSE
                p.xOperand
            END xOperand, 
            CASE 
            WHEN t.iType=1 THEN 
                p.xOperator
            WHEN (t.iType>3 AND t.iType<=p.xOperator.value(N'*[1]/@type', 'int')) OR (t.iType=3) THEN
                p.xOperator.query(N'/*/*')
            ELSE
                (SELECT t.s [@val], t.iType [@type], p.xOperator.query(N'*') FOR XML PATH(N'operator'), TYPE) 
            END xOperator
        FROM cteToken t
        JOIN cteParser p ON p.ixNext=t.ix AND p.bResult=CAST(0 AS bit)
    )
    SELECT @result=p.xOperand.value(N'/ *[1]/@val', 'float')
        FROM cteParser p
        WHERE bResult=CAST(1 AS bit)
        OPTION (MAXRECURSION 0);
    RETURN @result;
END

0
投票
    MS SQL SERVER
UserDefinedFunction 

/****** Object:  [dbo].[MyMathMDAS] ******/

CREATE FUNCTION [dbo].[MyMathMDAS] (@EXP Varchar(8000)) RETURNS Varchar(8000) AS
BEGIN
    DECLARE @i int, @p2 int, @oCnt int
    DECLARE @oAct Varchar(1), @ch0 Varchar(1), @ch Varchar(1), @ch1 Varchar(1), @Operator Varchar(1)
    DECLARE @LeftTx Varchar(8000), @RightTx Varchar(8000), @Result Varchar(8000)=''
    DECLARE @BEString Varchar(8000)
    DECLARE @R3 Varchar(1000)
    DECLARE @nResult Numeric(36,15) = 0
    Set @EXP = Replace(@EXP, ' ','')
    while 1=1 begin
        Set @EXP = Replace(@EXP, '/+','/')
        Set @EXP = Replace(@EXP, '*+','*')
        Set @EXP = Replace(@EXP, '+-','-')
        Set @EXP = Replace(@EXP, '-+','-')
        Set @EXP = Replace(@EXP, '--','+')
        Set @EXP = Replace(@EXP, '++','+')
        if      Charindex('/+',@EXP)=0 
            AND Charindex('*+',@EXP)=0 
            AND Charindex('+-',@EXP)=0 
            AND Charindex('-+',@EXP)=0 
            AND Charindex('--',@EXP)=0 
            AND Charindex('++',@EXP)=0  
        begin
            break
        end
    end
    Set @oCnt = 1
    while @oCnt<=4 BEGIN
        set @oAct = SUBSTRING('*/+-', @oCnt, 1)
        Set @LeftTx = ''
        Set @Operator = ''
        Set @RightTx = ''
        Set @R3 = '|'
        Set @p2 = -1
        Set @i = 1
        WHILE @i <= len(@EXP) BEGIN
            Set @ch = SUBSTRING(@EXP, @i, 1)
            Set @ch1 = SUBSTRING(@EXP, @i+1, 1)
            if (@oAct='*' OR @oAct='/') AND (@ch='*' OR @ch='/') begin
                set @oAct = @ch
            end
            if (Charindex(@ch,'0123456789.')>0) begin 
                if Right(@R3,1)<>'N' Set @R3 = @R3 +'N'
            end else if @ch = @oAct begin 
                if Right(@R3,1)<>'O' Set @R3 = @R3 +'O'
            end else if @ch = '-' and (@oAct ='*' OR @oAct ='/') and (Right(@R3,2)='NO') begin 
                Set @RightTx = @RightTx + @ch -- Attn
            end else if Right(@R3,1)<>'|' begin
                Set @R3 = @R3 +'|'
                Set @LeftTx = ''
                Set @Operator = ''
                Set @RightTx = ''
            end
            if Right(@R3,3)='NON' begin
                Set @RightTx = @RightTx + @ch
                set @p2 = @i
            end else if Right(@R3,2)='NO' begin 
                Set @Operator = @oAct
            end else if Right(@R3,1)='N' begin
                Set @LeftTx = @LeftTx + @ch
            end 
            if  (Right(@R3,3)='NON') AND (Charindex(@ch1,'0123456789.')=0) begin
                SET @ch0 = SUBSTRING(@EXP, CHARINDEX(@LeftTx +@Operator +@RightTx, @EXP)-1, 1)
                if @ch0='-' set @leftTx = '-' + @leftTx
                --------------------------------------------------------------------------------------------------------
                if @Operator = '*'      set @nResult = Cast(@leftTx as NUMERIC(36,15)) * Cast(@RightTx as NUMERIC(36,15))
                else if @Operator = '/' set @nResult = Cast(@leftTx as NUMERIC(36,15)) / Cast(@RightTx as NUMERIC(36,15))
                else if @Operator = '+' set @nResult = Cast(@leftTx as NUMERIC(36,15)) + Cast(@RightTx as NUMERIC(36,15))
                else if @Operator = '-' set @nResult = Cast(@leftTx as NUMERIC(36,15)) - Cast(@RightTx as NUMERIC(36,15))
                else set @nResult = 0
                --------------------------------------------------------------------------------------------------------
                set @Result  = cast(@nResult as varchar(1000))
                if (@ch0='-') and (@nResult>=0) begin
                    set @Result  = '+' + @Result 
                end
                set @BEString = SUBSTRING(@EXP, 1, @i - Len(@LeftTx +@Operator +@RightTx))
                if Right(@BEString,1)='-' set @BEString = Left(@BEString, LEN(@BEString)-1)
                Set @EXP = @BEString + @Result +SUBSTRING(@EXP, @p2+1, 8000)
                Set @i = 1
                Set @p2 = -1
                Set @LeftTx = ''
                Set @Operator = ''
                Set @RightTx = ''
                Set @R3 = '|'
            end else begin
                Set @i = @i + 1
            end
        END
        set @oCnt = @oCnt + 1
    end
    RETURN @EXP
END

GO
------------------------------------------------
------------------------------------------------
------------------------------------------------
CREATE FUNCTION [dbo].[MyMathEvalF] (@EXP Varchar(8000)) RETURNS Varchar(8000) as
begin
    DECLARE @nResult Numeric(36,15)=0
    DECLARE @Result Varchar(8000)
    DECLARE @i1 integer=0, @i2 integer=0, @i3 integer=0, @i4 integer=0, @i5 integer=0 
    DECLARE @Func Varchar(50) = '', @P1 Varchar(100) = '', @P2 Varchar(100) = '', @P3 Varchar(100) = '', @P4 Varchar(100) = ''
    set @i1 = CHARINDEX('(', @EXP, 0)
    if @i1>0 set @i2 = CHARINDEX(',', @EXP, @i1+1)
    if @i2>0 set @i3 = CHARINDEX(',', @EXP, @i2+1)
    if @i3>0 set @i4 = CHARINDEX(',', @EXP, @i3+1)
    if @i4>0 set @i5 = CHARINDEX(',', @EXP, @i4+1)
    if @i2=0 set @i2 = CHARINDEX(')', @EXP, @i1+1) else if @i3=0 set @i3 = CHARINDEX(')', @EXP, @i2+1) else if @i4=0 set @i4 = CHARINDEX(')', @EXP, @i3+1) else if @i5=0 set @i5 = CHARINDEX(')', @EXP, @i4+1)
    Set @Func = Substring(@EXP, 1, @i1)
    if @i2>0 Set @P1 = Substring(@EXP, @i1+1, @i2-@i1-1)
    if @i3>0 Set @P2 = Substring(@EXP, @i2+1, @i3-@i2-1)
    if @i4>0 Set @P3 = Substring(@EXP, @i3+1, @i4-@i3-1)
    if @i5>0 Set @P4 = Substring(@EXP, @i4+1, @i5-@i4-1)
    if @Func = 'ROUND(' AND @p1<>'' AND @p2<>'' begin
        set @nResult = ROUND(@p1, cast(@p2 as Integer))
        set @Result = cast(@nResult as varchar(1000))
    end else if @Func = 'POWER(' AND @p1<>'' AND @p2<>'' begin
        set @nResult = POWER(@p1, @p2)
        set @Result = cast(@nResult as varchar(1000))
    end else if @Func = 'SQRT(' AND @p1<>'' begin
        set @nResult = SQRT(@p1)
        set @Result = cast(@nResult as varchar(1000))
    end else if @Func = 'LOG(' AND @p1<>'' begin
        set @nResult = LOG(@p1)
        set @Result = cast(@nResult as varchar(1000))
    end else if @Func = 'SIN(' AND @p1<>'' begin
        set @nResult = SIN(@p1)
        set @Result = cast(@nResult as varchar(1000))
    end else if @Func = 'COS(' AND @p1<>'' begin
        set @nResult = COS(@p1)
        set @Result = cast(@nResult as varchar(1000))
    end else if @Func = 'TAN(' AND @p1<>'' begin
        set @nResult = TAN(@p1)
        set @Result = cast(@nResult as varchar(1000))
    end else begin
        set @Result = @EXP
    end
    RETURN @Result
end

GO

------------------------------------------------
------------------------------------------------
------------------------------------------------
CREATE FUNCTION [dbo].[MyEval] (@EXP Varchar(8000)) RETURNS Varchar(8000) as
begin
    DECLARE @S1 Varchar(8000), @S2 Varchar(8000), @S3 Varchar(8000), @NewExp Varchar(8000) =''
    DECLARE @Result Varchar(8000), @Result1 Varchar(8000)
    DECLARE @L int, @t int, @cnt int
    DECLARE @ch Varchar(1)
    Set @EXP = UPPER(Replace(isnull(@EXP,''), ' ',''))
    Set @L = Len(@EXP)
    Set @S1 = ''    Set @S2 = ''    Set @S3 = ''
    Set @t = 0
    Set @cnt=1
    while @cnt<=@L begin
        set @ch = Substring(@exp, @cnt, 1)
        if @ch='(' set @t = @t+1
        if @ch=')' set @t = @t-1
        if (@t=0 and @ch<>')') OR (@t=1 and @ch='(') Set @S1 = @S1 + @ch
        else if (@t>0) Set @S2 = @S2 + @ch
        else if (@t=0 and @ch=')') begin
            Set @S3 = @S3 + @ch
            if (Charindex('(', @S2)>0) begin
                set @Result  = dbo.MyEval(@S2)
            end else begin
                set @Result  = dbo.MyMathMDAS(@S2)
            end
            if ISNUMERIC(@Result)=1 AND Right(@S1,2) in ('(','*(','/(','+(','-(',',(') begin
                set @S1 = Left(@S1, len(@S1)-1)
                set @S3 = ''
            end
            if Right(@S1,1)='+' AND LEFT(@Result,1)='-' begin
                set @S1 = Left(@S1, len(@S1)-1)
            end
            if Right(@S1,1)='-' AND LEFT(@Result,1)='-' begin
                set @S1 = Left(@S1, len(@S1)-1)
                set @Result = '+' +Substring(@Result, 2, 8000)
            end 
            if Right(@S1,6) in ('ROUND(', 'POWER(') begin
                set @Result1 =  Right(@S1,6) + @Result + Left(@S3, 1)
                set @Result1 =  dbo.MyMathEvalF(@Result1)        
                set @Result = Substring(@S1, 1, len(@S1)-6) + @Result1 
            end else if Right(@S1,5) in ('SQRT(') begin
                set @Result1 =  Right(@S1,5) + @Result + Left(@S3, 1)
                set @Result1 =  dbo.MyMathEvalF(@Result1)        
                set @Result = Substring(@S1, 1, len(@S1)-5) + @Result1 
            end else if Right(@S1,4) in ('LOG(','SIN(','COS(','TAN(') begin
                set @Result1 =  Right(@S1,4) + @Result + Left(@S3, 1)
                set @Result1 =  dbo.MyMathEvalF(@Result1)        
                set @Result = Substring(@S1, 1, len(@S1)-4) + @Result1 
            end else begin
                set @Result = @S1 + @Result +@S3
            end 
            Set @NewExp = @NewExp +@Result
            Set @S1 = ''    Set @S2 = ''    Set @S3 = ''
        end
        set @cnt = @cnt+1
    end
    Set @NewExp = @NewExp +@S1
    set @Result = dbo.MyMathMDAS(@NewExp)
    if LEFT(@Result,1)='+'      set @Result = Substring(@Result, 2, 8000)
    RETURN @Result
end


GO

------------------------------------------------
------------------------------------------------
------------------------------------------------

CREATE FUNCTION [dbo].[MyCalcMRP] (
    @EXP Varchar(8000), 
    @varName1 Varchar(50), 
    @VarValue1 Numeric(18,6))
    RETURNS Varchar(8000) as
begin
    set @EXP  = Replace (@EXP, @varName1, isnull(str(@VarValue1,18,6),''))
    DECLARE @Result Varchar(8000) = dbo.MyEval(@EXP)  
    RETURN @Result
end


GO


------------------------------------------------------------------------------------------------------------------------------------------------
USAS :
/*
select dbo.MyEval('10+(((((((((( 10*+-20 ))))))))))*5+1') , 10+(((((((((( 10*+-20 ))))))))))*5+1
select dbo.MyEval('Round(15.666666,2) + LOG(5.666666)*2') , Round(15.666666,2) + LOG(5.666666)*2 


Select dbo.MyCalcMRP('115.666666+[MRP]*2+10/3', '[MRP]',1), 115.666666+1*2+10/3, 115.666666+1*2+10.0/3
*/


/*
Drop Table IF Exists #Tmp;
select top 0  cast('' as varchar(50)) as exp1,cast(0 as float) as MRP into #Tmp
insert into #Tmp values ('round(6.6666*7+MRP*2/100,2)',11)
insert into #Tmp values ('(6.6666*7+MRP*2/1002)',11)
insert into #Tmp values ('5*777+MRP*3/100',12)
insert into #Tmp values ('50*11',0)
insert into #Tmp values (null,null)
Select 
    A.*, 
    dbo.MyCalcMRP(A.Exp1,'MRP',A.MRP) as ResultAsVarchar,
    cast(dbo.MyCalcMRP(A.Exp1,'MRP',A.MRP) as float) as ResultAsFloat,
    dbo.MyEval( Replace (EXP1, 'MRP', isnull(str(A.MRP,18,6),'')) )  as EvalValueVarchar,
    cast(dbo.MyEval( Replace (EXP1, 'MRP', isnull(str(A.MRP,18,6),'')) )  as float) as EvalValueFloat
from #Tmp A
*/

------------------------------------------------
------------------------------------------------
------------------------------------------------
© www.soinside.com 2019 - 2024. All rights reserved.