Как установить отрицательный результат на ноль, не вводя формулу дважды

Я знаю, как установить отрицательное значение в ноль:

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, которые предоставляют значения для определенных учетных записей.

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
3
0
122
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете попробовать следующие подходы:

  • 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)

Используйте 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

Результат:

Ответ принят как подходящий

Это можно сделать с помощью простого подзапроса, например.

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, все они создают один и тот же план выполнения, поэтому выбор того, что использовать, на самом деле зависит от того, какой из них более понятен для вас.

Спасибо, подзапрос теперь мой путь. подход перекрестного применения также очень интересен.

askolotl 17.12.2020 13:06

Другие вопросы по теме