算术/逻辑运算基于列值

时间:2016-02-11 08:21:16

标签: sql sql-server tsql sql-server-2012

我想根据列值进行算术运算。请考虑以下示例

CREATE TABLE #test
  (
     cont_sal    INT,
     check_value INT,
     operator    VARCHAR(50)
  )

INSERT #test
VALUES (10,20,'+'),
       (20,10,'+'),
       (10,20,'-'),
       (20,10,'-') 

预期结果:

cont_sal    check_value result
--------    ----------- ------
10          20          30
20          10          30
10          20          -10
20          10          10

我可以使用CASE语句执行此操作。

SELECT cont_sal,
       check_value,
       CASE
         WHEN operator = '+' THEN cont_sal + check_value
         when operator = '-' THEN cont_sal - check_value
       END result
FROM   #test 

但有没有办法动态地做到这一点。运算符可以是/%*。像这样的东西

DECLARE @sql NVARCHAR(max)=''

SET @sql = 'select cont_sal ' + 'operator'
           + ' check_value from #test '

--PRINT @sql

EXEC Sp_executesql
  @sql 

这显然不起作用

  

Msg 102,Level 15,State 1,Line 1语法不正确   'check_value'。

2 个答案:

答案 0 :(得分:5)

好问题。

我会使用case表达式,因为:

  1. 只有five arithmetic operators
  2. 您无法直接对算术运算符进行参数化。
  3. 您无法执行动态SQL内联。
  4. 但也有其他选择。您可以构建然后执行动态SQL语句。

    -- Query will be stored here.
    DECLARE @Qry VARCHAR(255) = '';
    
    -- Build up the query.
    SELECT
        @Qry = 
            @Qry 
            +   CASE ROW_NUMBER() OVER (ORDER BY cont_sal)
                    WHEN 1 THEN 'SELECT '
                    ELSE 'UNION ALL SELECT '
                END 
            + ''''
            + Expression 
            + ''''
            + ' AS Expression,'
            + Expression
            + ' AS Result '
    FROM
        #test AS t
            CROSS APPLY
                (
                    -- Avoid typing expression twice.
                    SELECT
                        CAST(cont_sal AS VARCHAR(50)) 
                            + ' '
                            + operator 
                            + ' '
                            + CAST(check_value AS VARCHAR(50)) AS Expression        
                ) AS ex
    ;
    
    -- Execute it.
    EXECUTE(@Qry);
    

    或者您可以使用交叉应用来使用强力计算结果。

    SELECT
        *       
    FROM
        #test AS t
    
            CROSS APPLY
                (
                    VALUES
                        ('+', cont_sal + check_value),
                        ('-', cont_sal - check_value),
                        ('*', cont_sal * check_value),
                        ('/', cont_sal / NULLIF(check_value, 0)),
                        ('%', cont_sal % NULLIF(check_value, 0))
                ) AS ex(operator, result)
    WHERE
        ex.operator = t.operator
    ;
    

    这里计算每个可能的操作。那些不需要的东西会从结果集中过滤掉。这种方法更易于读写,但运行从不需要的计算。也就是说,它确实生成了一个更快的查询计划,这是我的动态示例。

    修改

    感谢@Damien_The_Unbeliever,他指出我的漏洞除以零错误。我使用NULLIF将0替换为空值,这样可以避免错误。

    我只更新了第二个例子。

答案 1 :(得分:1)

免责声明:我是项目的所有者Eval SQL.NET

该库允许直接在T-SQL中使用C#语法来动态计算算术表达式。运算符优先级和括号值得尊重,并且库超出了简单的数学表达式。

    var message = "hello [[xxx]] bye [[ZZZ]]"
    
    var result, re = /\[\[(.*?)\]\]/g;
    while ((result = re.exec(message)) != null) {
        switch (result[1].toLowerCase()) {

            case "xxx":
                console.log("found xxx");
                break;

            case "zzz":
                console.log("found zzz");
                break;
        }
    }

文档:SQL Server Eval - Dynamically evaluate arithmetic operation and expression