【问题标题】:T-SQL - Tehnique for evaluation of boolean expression stringT-SQL - 计算布尔表达式字符串的技术
【发布时间】:2013-04-15 03:23:27
【问题描述】:

我需要根据表达式填充“值”字段可以是“0”或“1”(假或真)。

以下是简单数据:

1   1 * 1 + 1   NULL
2   0 + 0       NULL
3   1 + 0 * 0   NULL
4   0 * 1       NULL
5   0 * 1 * 1   NULL

“表达式”字段是 nvarchar 类型,包含条件和布尔运算符的结果。 所以,上面的数据可以这样格式化:

1   TRUE AND TRUE OR TRUE     NULL
2   FALSE OR FALSE            NULL
3   TRUE OR FALSE AND FALSE   NULL
4   FALSE AND TRUE            NULL
5   FALSE AND TRUE AND TRUE   NULL

在最后,'Expression' 字段可以包含 AND/OR 和多个 TRUE 和 FALSE。

正如我所说,我需要的是计算表达式值 - 检查它是真还是假。

整个逻辑都在过程中,我可以为每一行构建动态 sql 并执行它, 但在我的实际情况下,我将有数百行,因此为每一行创建循环并调用 execute_sql 听起来不是一个好的解决方案。

是否有任何内置函数可以帮助我评估这些字符串,因为我无法在过程中使用交叉应用。

【问题讨论】:

    标签: sql-server-2012 execute boolean-expression


    【解决方案1】:

    我创建了一个用户定义的标量函数,输入参数是用于评估和返回值的字符串 - 0 或 1(假或真)。现在,我可以做愿望交叉申请了……

    以下是示例:

    SELECT [dbo].[fn_XxCustom_EvaluateExpression] ('0')                 -- 0
    SELECT [dbo].[fn_XxCustom_EvaluateExpression] ('1')                 -- 1
    SELECT [dbo].[fn_XxCustom_EvaluateExpression] ('1*1')               -- 1
    SELECT [dbo].[fn_XxCustom_EvaluateExpression] ('1+1')               -- 1
    SELECT [dbo].[fn_XxCustom_EvaluateExpression] ('1*0')               -- 0
    SELECT [dbo].[fn_XxCustom_EvaluateExpression] ('0+1*0*1+0*1+0')     -- 0
    SELECT [dbo].[fn_XxCustom_EvaluateExpression] ('1+1+0+1*0*1+1*1+0') -- 1
    

    我相信有更好的方法可以做到这一点,也许使用反向波兰表示法和递归 CTE,但还没有时间尝试。无论如何,如果有人需要做类似的事情,这是源代码:

    IF  EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fn_XxCustom_EvaluateExpression]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
    BEGIN
        DROP FUNCTION [dbo].[fn_XxCustom_EvaluateExpression]
    END
    
    GO
    
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE FUNCTION [dbo].[fn_XxCustom_EvaluateExpression]
    (
        @Expression NVARCHAR(MAX)
    )
    RETURNS TINYINT
    AS
    BEGIN
    
        DECLARE @ExpressionValue TINYINT = 0
    
        IF LEN(@Expression) > 0 AND @Expression IS NOT NULL
        BEGIN
    
            -- Checking if this is expression 
            IF CHARINDEX('+', @Expression) = 0 AND CHARINDEX('*', @Expression) = 0 
                BEGIN
                    SET @ExpressionValue = CAST(@Expression AS TINYINT)
                END
            ELSE
                BEGIN
    
                    -- Checking if the expression is computed (contains both '*' and '+')
                    IF CHARINDEX('+', @Expression) > 0 AND CHARINDEX('*', @Expression) > 0
                        BEGIN 
    
                            DECLARE @ExpressionsTable TABLE
                            (
                                 ExpressionID INT IDENTITY(1,1)
                                ,Expression NVARCHAR(MAX)
                                ,ExpressionValue TINYINT
                            )
    
                            DECLARE @XML XML = N'<r><![CDATA[' + REPLACE(@Expression, '+', ']]></r><r><![CDATA[') + ']]></r>'
    
                            -- Populate the table with simple expressions (expression which only contains '+' or '*' is simple)
                            INSERT INTO @ExpressionsTable (Expression)
                            SELECT DISTINCT RTRIM(LTRIM(T.c.value('.', 'nvarchar(250)')))
                            FROM @xml.nodes('//r') T(c)
    
                            -- Creating a simple expressions with result values 
                            UPDATE @ExpressionsTable
                            SET ExpressionValue = IIF(CHARINDEX('+', Expression) = 0 AND CHARINDEX('*', Expression) = 0 , Expression, IIF(CHARINDEX('+', Expression) > 0,IIF(CHARINDEX('1', Expression) > 0, 1, 0),IIF(CHARINDEX('0', Expression) > 0, 0, 1)))
    
                            -- Evaluating the final expression
                            SET @ExpressionValue = IIF(CHARINDEX('1', SUBSTRING((SELECT '+' + CAST(ExpressionValue AS VARCHAR(1)) FROM @ExpressionsTable FOR XML PATH('')),2,4000)) > 0, 1, 0)
    
                        END
                    ELSE
                    -- Checking the type of the simple expression (does it contains '+' or '*')
                        BEGIN
                            SET @ExpressionValue = IIF(CHARINDEX('+', @Expression) > 0,IIF(CHARINDEX('1', @Expression) > 0, 1, 0),IIF(CHARINDEX('0', @Expression) > 0, 0, 1))
                        END
                END
        END
    
        RETURN @ExpressionValue
    
    END
    GO
    

    【讨论】:

    • 也许可以试试这样的:declare @exp varchar(100); select @exp='1+1+0+1*0*1+1*1+0'; select @exp=replace(REPLACE(@exp,'+','&amp;'),'*','&amp;') select @exp; exec ('select '+@exp);
    • @LoztInSpace 我不想使用“exec”语句,因为我需要这样做数百次。那是我最初的问题,因此我制作了一个标量函数,该函数将在行中执行。对此的替代方法是创建一个循环并在其中执行动态 SQL 语句。
    【解决方案2】:

    为什么不在插入时而不是在查询时评估它?一位(结果)的成本与解析和执行查询的成本可能是值得的。您可以将其作为触发器 (yuk) 或使用 UDF 计算的列(更好)。

    您所要做的几乎就是将一些动态 SQL 链接到一些搜索和替换(我认为)。

    如果您的组合数量有限,另一种方法只是查找表达式(减去空格等)和结果。

    【讨论】:

    • 因为每个值(0 或 1)都是复杂的选择语句和检查的结果。
    • 您可能想要更新您的问题和示例输入/输出列表(尤其是标题)。我现在真的不清楚你拥有什么或追求什么。
    • 我自己设法找到了问题所在。无论如何 +1 试图帮助我。
    猜你喜欢
    • 2021-08-26
    • 1970-01-01
    • 2011-06-04
    • 2011-06-09
    • 1970-01-01
    • 2012-12-01
    • 2021-09-19
    • 1970-01-01
    相关资源
    最近更新 更多