sql - 基于列值的算术/逻辑运算

标签 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 Incorrect syntax near 'check_value'.

最佳答案

很好的问题。

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

  1. 只有five arithmetic operators .
  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);

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

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_Unknowner,他指出了我除以零错误的漏洞。我用过NULLIF将 0 替换为 null,从而避免错误。

我只更新了第二个示例。

关于sql - 基于列值的算术/逻辑运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35334076/

相关文章:

尽管没有包含 0 的列,但仍遇到 TSQL 除以零

sql - 具有多个结果的子查询,SQL Server

java - 如何在JAVA(ResultSet)中检查合并查询是否成功?

c# - 使用 c# 将表数据从 oracle 复制到 SQL Server?

sql-server - 更改 SQL Server 中的非聚集索引以添加更多包含的列

sql-server - SQL Server Windows 身份验证

sql - SSRS - 将静态 null 添加到参数查询

sql - 动态 SQL - 执行时间长 - 仅限第一次

sql - 使用 SQL 将列的格式更改为百分比

sql - SQL 中的递归 - 公用表表达式与 WHILE