如何在 SQL 服务器中 运行 字符串数学表达式(触发器或函数)

How to run string math expression in SQL Server (trigger or function)

我要运行:

 select Mycalculatefunction('((3*4)-3)*5') 
 select ('((3*4)-3)*5')

输出:((3*4)-3)*5 错误(不是整数值)

我想要的输出是:45

我定义了一个存储过程:

create PROCEDURE dbo.Eval
    (@exp varchar(MAX))
AS
    SET NOCOUNT ON

    DECLARE @SQLString NVARCHAR(MAX)
    SET @SQLString = 'SELECT '+@exp

    EXEC sp_executesql @SQLString

我称之为:

exec dbo.Eval '((3*4)-3)*5'

这个过程是触发器怎么办?

您的 SP 存在注入漏洞。 F.e。我通过了exec dbo.Eval '1;DROP TABLE some_table;'。最好使用 xml.query:

CREATE PROCEDURE dbo.Eval 
    @formula nvarchar(max)
AS
DECLARE @sql nvarchar(max)

SELECT @sql = N'
DECLARE @x xml = ''''
SELECT CAST(@x.query('''+@formula+''') as nvarchar(max))'

EXEC sp_executesql @sql

然后

EXEC dbo.Eval '((3*4)-3)*5'

输出:

45

触发器部分(因为没有关于你的表的信息,只是一般性的解释,我添加了完整的批次和评论):

--Create table that will store Formulas
CREATE TABLE Formulas (
    ID int IDENTITY(1,1) NOT NULL,
    Formula nvarchar(max) NULL,
    CONSTRAINT PK_ID PRIMARY KEY (ID)
) 
GO
--Create table to store results of the formulas
CREATE TABLE Results (
    T1_ID int NOT NULL,
    Result int NULL
) 
GO
--Linked by ID
ALTER TABLE Results ADD CONSTRAINT FK_Formulas_Results FOREIGN KEY (T1_ID)
REFERENCES Formulas (ID)
GO
--Create a Table Valued Parameter
CREATE TYPE FormulaResults AS TABLE ( 
    ID int NOT NULL,
    Formula nvarchar(max) NULL
)
GO
--Create a procedure to do the count
CREATE PROCEDURE dbo.GetResults 
    @TVP FormulaResults READONLY
AS
DECLARE @sql nvarchar(max)

SELECT @sql = N'DECLARE @x xml = '''' '

SELECT @sql = @sql + 'SELECT '+CAST(ID as nvarchar(max))+' as ID, CAST(@x.query('''+Formula+''') as nvarchar(max)) UNION ALL '
FROM @TVP

SELECT @sql = LEFT(@sql,LEN(@sql)-LEN('UNION ALL '))

EXEC sp_executesql @sql
GO
--Create a trigger that will count formula after insert and update
CREATE TRIGGER GetResultsTrigger
ON Formulas
AFTER INSERT, UPDATE
AS
DECLARE @FormulaTVP AS FormulaResults
DECLARE @Results TABLE(
    T1_ID int NOT NULL,
    Result int NULL
) 


INSERT INTO @FormulaTVP
SELECT *
FROM inserted

INSERT INTO @Results
EXEC dbo.GetResults @FormulaTVP

MERGE Results r
USING @Results s
ON r.T1_ID = s.T1_ID
WHEN NOT MATCHED THEN
    INSERT VALUES (s.T1_ID, s.Result)
WHEN MATCHED THEN
    UPDATE SET Result = s.Result;

之后运行:

INSERT INTO [Formulas] VALUES
('1+3'),('2+2*8')


SELECT  [ID],
        [Formula]
FROM [Test].[dbo].[Formulas]

SELECT [T1_ID],
        [Result]
FROM [Test].[dbo].[Results]

输出:

ID  Formula
1   1+3
2   2+2*8

T1_ID   Result
1       4
2       18

图片1

 ALTER FUNCTION [dbo].[Calculate]
    ( @expression AS VARCHAR(MAX) 
    )
    RETURNS xml
    AS
    BEGIN
      -- routine body goes here, e.g.
      -- SELECT 'Navicat for SQL Server'
    DECLARE @result xml
    declare @x xml=''
    --I can not pass as a parameter
    select @result=@x.query(('(4*3)*5-10')) 

    return   @result; 


END

我调用这个函数:

  SELECT  CAST(CAST(CAST(dbo.[Calculate]('How do I pass parameters') AS XML) AS VARCHAR(100)) AS DECIMAL(4,2))

输出:

50.00

select  @result=@x.query('sql:variable("@expression")') 

result: '2+2' :(((