在 SQL Server 函数上计算字符串

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

我正在尝试找到一种解决方法来计算 SQL Server 中的字符串,就像 JavaScript 上的

eval()
函数一样。困难的是我需要它在函数中执行此操作,以便我可以在存储过程的查询中使用它。

Supply = '2 + 2 * 3'
Demand = '2'

SELECT Name, CAST(dbo.CalculateString(Supply) * Demand AS DECIMAL(18, 1))  AS CalculatedValue FROM Stocks;

the expected output is 
Candy 16

我明白了:

  1. 使用动态查询,但我不能,因为SQL Server中的函数不支持执行动态查询。
  2. 使用存储过程,但我也需要将计算字符串的值输出与另一个字段结合起来进行计算,所以我不能(?)。

有什么解决办法吗?我正在使用 SQL Server 16.0.1000.6

sql sql-server stored-procedures user-defined-functions dynamicquery
1个回答
0
投票

可以吗?是的

你想做吗?不

让我示范一下。

首先让我们创建一些示例数据:

CREATE TABLE Stocks( ID INT IDENTITY, Supply VARCHAR( 50 ), Demand VARCHAR( 50 ))
INSERT INTO Stocks( Supply, Demand )
SELECT '2 + 2 * 3', '2'
UNION ALL
SELECT '2 - 2 * 3', '2 / 2'

现在,我们创建将动态评估您的列的过程(请注意,过程已适当命名):

CREATE OR ALTER PROCEDURE DirtyHack
AS
    SET NOCOUNT ON;

    DECLARE @ID INT, @Supply VARCHAR( 50 ), @Demand VARCHAR( 50 )
    DECLARE @EvalQuery NVARCHAR( 500 ), @EvaluatedSupply INT, @EvaluatedDemand INT

    CREATE TABLE #Result( ID INT, EvaluatedSupply INT, EvaluatedDemand INT )

    DECLARE iterator CURSOR LOCAL FAST_FORWARD
    FOR SELECT ID, Supply, Demand FROM Stocks

    OPEN iterator
    FETCH NEXT FROM iterator INTO @ID, @Supply, @Demand
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @EvalQuery = N'SET @EvaluatedSupply = ' + @Supply + '; SET @EvaluatedDemand = ' + @Demand + ';'
        EXEC sp_executesql @EvalQuery, N'@EvaluatedSupply INT OUTPUT, @EvaluatedDemand INT OUTPUT',
            @EvaluatedSupply = @EvaluatedSupply OUTPUT, @EvaluatedDemand = @EvaluatedDemand OUTPUT
        
        INSERT INTO #Result
        SELECT @ID, @EvaluatedSupply, @EvaluatedDemand

        FETCH NEXT FROM iterator INTO @ID, @Supply, @Demand
    END
    CLOSE iterator
    DEALLOCATE iterator

    SELECT ID, EvaluatedSupply, EvaluatedDemand FROM #Result

    RETURN;

该过程非常简单:使用游标循环遍历每一行并动态评估列,然后将结果存储到临时表中。对于更大的桌子,性能将会很缓慢。

然后我们使用

OPENQUERY
技巧将这个存储过程转换为视图:

CREATE OR ALTER VIEW VeryDirtyHack
AS
    SELECT *
    FROM OPENQUERY( SELF, 'EXEC Playground.dbo.DirtyHack WITH RESULT SETS(( ID INT, EvaluatedSupply INT, EvaluatedDemand INT ))' ) AS Eval;

SELF
是指向自身的链接服务器的名称。
WITH RESULT SETS
对于避免 SQL Server 对结果集的格式感到困惑是必要的。

您可以创建一个函数来代替视图,但这不会对功能产生任何影响。

现在你可以这样做:

SELECT *, EvaluatedSupply * EvaluatedDemand AS CalculatedValue
FROM Stocks AS S
    INNER JOIN VeryDirtyHack AS VDH ON S.ID = VDH.ID

结果:

ID          Supply     Demand  ID  EvaluatedSupply EvaluatedDemand CalculatedValue
----------- ---------- ------- --- --------------- --------------- ---------------
1           2 + 2 * 3  2       1   8               2               16
2           2 - 2 * 3  2 / 2   2   -4              1               -4

这在 SQL Server 中是最“hacky”的。由于过程中执行 RBAR,性能会受到影响。由于无法将参数传递给

OPENQUERY
函数,因此无法“优化”存储过程。

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