【问题标题】:How to set a negative result to zero without typing the formula twice如何在不输入两次公式的情况下将负结果设置为零
【发布时间】:2021-03-22 16:29:35
【问题描述】:

我知道如何将负值设置为零:

select case when (formula) < 0 then 0 else (formula) end as result from tab

但是如果“公式”是一个很长的公式呢?然后我必须输入两次。有没有办法在不输入两次公式的情况下达到相同的结果?

我的实际情况是这样的:

select
  sum
  ( 
      case when 
      (t1.x + t2.x + t3.x) * t4.p - (t5.x + t6.x + t7.x) * t8.p ) < 0
      then 0 
      else 
      (t1.x + t2.x + t3.x) * t4.p - (t5.x + t6.x + t7.x) * t8.p )
      end
  ) as result
from 
     t1 
     left join t2 on t1.x = t2.x 
     left join t3 on t1.x = t3.x 
     ... etc ....

t2、t3、t4 等来自为某些帐户提供价值的 cte 报表。

【问题讨论】:

    标签: sql sql-server tsql sql-server-2014


    【解决方案1】:

    您可以尝试以下方法:

    • VALUES 表值构造函数和MAX 聚合函数。
    • APPLY 运算符和 MAX 聚合函数。

    T-SQL:

    SELECT (SELECT MAX(result) FROM (VALUES (0), (tab.x)) v(result)) AS result
    FROM (VALUES
       (2 - 3),
       (4 + 5)
    ) tab (x)
    
    SELECT apl.result
    FROM (VALUES
       (2 - 3),
       (4 + 5)
    ) tab (x)
    CROSS APPLY (SELECT MAX(x) FROM (VALUES (0), (tab.x)) v (x)) apl (result)
    

    以下示例基于问题中的代码,是一个可能的解决方案:

    SELECT x INTO t1 FROM (VALUES (-1), (1)) v (x)
    SELECT x INTO t2 FROM (VALUES (-1), (1)) v (x)
    SELECT x INTO t3 FROM (VALUES (-1), (1)) v (x)
    
    SELECT SUM(a.result)
    FROM t1 
    LEFT JOIN t2 ON t1.x = t2.x 
    LEFT JOIN t3 ON t1.x = t3.x
    CROSS APPLY (
       SELECT MAX(x) FROM (VALUES (0), (t1.x + t2.x + t3.x)) v (x)
    ) a (result)
    

    【讨论】:

      【解决方案2】:

      这可以使用简单的子查询来完成,例如

      select
          sum
          ( 
              case when ForumulaResult < 0
              then 0 
              else ForumulaResult
              end
          ) as result
      from (
          select
              (t1.x + t2.x + t3.x) * t4.p - (t5.x + t6.x + t7.x) * t8.p) as ForumulaResult
          from t1 
          left join t2 on t1.x = t2.x 
          left join t3 on t1.x = t3.x 
          -- ... etc ....
      ) x;
      

      或使用cross apply

      select
          sum
          ( 
              case when ForumulaResult < 0
              then 0 
              else ForumulaResult
              end
          ) as result
      from t1 
      left join t2 on t1.x = t2.x 
      left join t3 on t1.x = t3.x 
      cross apply (select (t1.x + t2.x + t3.x) * t4.p - (t5.x + t6.x + t7.x) * t8.p ) as ForumulaResult) x
      

      或者使用已经显示的 CTE...虽然您表明您已经有一个 CTE 生成起始数据...所以它可能更难组合。

      从表面上看,@Han 提供的简单数据,它们都产生相同的执行计划,所以选择使用哪个更清楚。

      【讨论】:

      • 谢谢,子查询现在是我要走的路。交叉应用方法也很有趣。
      【解决方案3】:

      使用CTE

      DECLARE @Table1 TABLE
      (
          ID INT,
          A INT,
          B INT
      );
      
      DECLARE @Table2 TABLE
      (
          ID INT,
          C INT,
          D INT
      );
      
      INSERT @Table1 VALUES
          ( 1,  1,  2),
          ( 2,  3, -4),
          ( 3, -5, -6);
      
      INSERT @Table2 VALUES
          ( 1, -7,  8),
          ( 2,  9, 10),
          ( 3, 11, 12);
          
      WITH query (Formula)
      AS
      (
          SELECT (A + B) * (C - D) AS Formula
              FROM @Table1 T1 INNER JOIN @Table2 T2 ON T1.ID = T2.ID
      )
      SELECT Formula, CASE WHEN Formula < 0 THEN 0 ELSE Formula END AS Result
          FROM query
      

      结果:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多