算术/逻辑运算基于列值

ask*_*low 11 sql t-sql sql-server 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,'-') 
Run Code Online (Sandbox Code Playgroud)

预期结果:

cont_sal    check_value result
--------    ----------- ------
10          20          30
20          10          30
10          20          -10
20          10          10
Run Code Online (Sandbox Code Playgroud)

我可以使用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 
Run Code Online (Sandbox Code Playgroud)

但有没有办法动态地做到这一点.操作员可以像任何东西/,%,*.像这样的东西

DECLARE @sql NVARCHAR(max)=''

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

--PRINT @sql

EXEC Sp_executesql
  @sql 
Run Code Online (Sandbox Code Playgroud)

这显然不起作用

消息102,级别15,状态1,行1'check_value'附近的语法不正确.

des*_*ata 5

好问题.

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

  1. 只有五个算术运算符.
  2. 您不能直接参数化算术运算符.
  3. 您无法执行动态SQL内联.

但也有其他选择.您可以构建然后执行动态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);
Run Code Online (Sandbox Code Playgroud)

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

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
;
Run Code Online (Sandbox Code Playgroud)

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

编辑

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

我只更新了第二个例子.

  • 最后一个例子 - 如果`check_value`为0,则存在除零误差的风险,即使对于'运算符'没有除法的行也是如此,因为系统可能决定运行所有计算. (2认同)