将 PostgreSQL 中计算出的负值替换为 0。

huangapple go评论54阅读模式
英文:

Replace calculated negative values with 0 in PostgreSQL

问题

select  *,
        case
            when first_created-coalesce(submitted_time::date) < 0 THEN 0
            else first_created-coalesce(submitted_time::date)
        end as create_duration,
        case
            when last_paid-coalesce(submitted_time::date) < 0 THEN 0
            else last_paid-coalesce(submitted_time::date)
        end as paid_duration
from my_table;
英文:

I have a table my_table:

case_id    first_created  last_paid       submitted_time
   3456    2021-01-27     2021-01-29      2021-01-26 21:34:36.566023+00:00
   7891    2021-08-02     2021-09-16      2022-10-26 19:49:14.135585+00:00
   1245    2021-09-13     None            2022-10-31 02:03:59.620348+00:00
   9073    None           None            2021-09-12 10:25:30.845687+00:00
   6891    2021-08-03     2021-09-17      None

I created 2 new variables:

select *,
       first_created-coalesce(submitted_time::date) as create_duration,
       last_paid-coalesce(submitted_time::date) as paid_duration 
from my_table;

The output:

  case_id    first_created  last_paid       submitted_time               create_duration paid_duration
   3456    2021-01-27     2021-01-29      2021-01-26 21:34:36.566023+00:00     1                3
   7891    2021-08-02     2021-09-16      2022-10-26 19:49:14.135585+00:00     -450            -405
   1245    2021-09-13     null            2022-10-31 02:03:59.620348+00:00     -412            null
   9073    None           None            2021-09-12 10:25:30.845687+00:00     null           null
   6891    2021-08-03     2021-09-17      null                                 null            null

My question is how can I replace new variables' value with 0, if it is smaller than 0?

The ideal output should look like:

  case_id    first_created  last_paid       submitted_time               create_duration paid_duration
   3456    2021-01-27     2021-01-29      2021-01-26 21:34:36.566023+00:00     1                3
   7891    2021-08-02     2021-09-16      2022-10-26 19:49:14.135585+00:00     0                0
   1245    2021-09-13     null            2022-10-31 02:03:59.620348+00:00     0               null
   9073    None           None            2021-09-12 10:25:30.845687+00:00     null             null
   6891    2021-08-03     2021-09-17      null                                 null             null

My code:

select  *,
        first_created-coalesce(submitted_time::date) as create_duration,
        last_paid-coalesce(submitted_time::date) as paid_duration, 
        case
            when create_duration &lt; 0 THEN 0
            else create_duration
        end as QuantityText
from my_table

答案1

得分: 8

greatest(yourvalue,0)

给定 yourvalue 小于 0,将 0 作为较大的值返回:

select *
  ,greatest(0,first_created-coalesce(submitted_time::date)) as create_duration
  ,greatest(0,last_paid    -coalesce(submitted_time::date)) as paid_duration
from my_table;

这也会将 null 值更改为 0


case 语句

如果希望保留 null 结果,可以使用常规的 case 语句。为了给你的计算取别名,你需要将其放在子查询或公共表表达式(cte)中:

select *
  ,case when create_duration&lt;0 then 0 else create_duration end as create_duration_0
  ,case when paid_duration  &lt;0 then 0 else paid_duration   end as paid_duration_0
from (
    select *
      ,first_created-coalesce(submitted_time::date) as create_duration
      ,last_paid    -coalesce(submitted_time::date) as paid_duration
    from my_table ) as subquery;

(n+abs(n))/2

如果将一个数字与其绝对值相加,然后除以两(求平均),如果这个数字是正数,你将得到相同的数;如果是负数,你将得到零,因为负数总是会通过其绝对值平衡自己:

  • (-1+abs(-1))/2 = (-1+1)/2 = 0/2 = 0
  • ( 1+abs( 1))/2 = ( 1+1)/2 = 2/2 = 1
select *
  ,(create_duration + abs(create_duration)) / 2 as create_duration_0
  ,(paid_duration   + abs(paid_duration)  ) / 2 as paid_duration_0
from (
    select *
      ,first_created-coalesce(submitted_time::date) as create_duration,
      ,last_paid    -coalesce(submitted_time::date) as paid_duration
    from my_table ) as subquery;

根据此演示,这比 case 稍微快一些,大约和 greatest() 一样快,而且不影响 null 值。


注意,select * 会提取下面的所有内容,所以你最终会看到 create_duration 以及 create_duration_0 - 你可以通过在外部查询中明确列出所需的输出列来摆脱它。你也可以重写它,不使用子查询/公共表表达式,重复计算,这样看起来不太好看,但在大多数情况下,查询优化器会注意到重复计算,并只评估一次。

select *
  ,case when first_created-coalesce(submitted_time::date) &lt; 0
        then 0
        else first_created-coalesce(submitted_time::date)
   end as create_duration
  ,(abs(last_paid-coalesce(submitted_time::date))
    +   last_paid-coalesce(submitted_time::date) )/2 
       as paid_duration
from my_table;

或者使用 标量子查询

select *
  ,(select case when a&lt;0 then 0 else a end 
    from (select first_created-coalesce(submitted_time::date)) as alias(a) ) 
    as create_duration
  ,(select case when a&lt;0 then 0 else a end 
    from (select last_paid-coalesce(submitted_time::date)) as alias(a) ) 
    as paid_duration
from my_table;

这些在这种情况下并不会有所帮助,但了解它们是很有用的。

英文:

greatest(yourvalue,0)

Given yourvalue lower than 0, 0 will be returned as the greater value:

select *
  ,greatest(0,first_created-coalesce(submitted_time::date)) as create_duration
  ,greatest(0,last_paid    -coalesce(submitted_time::date)) as paid_duration
from my_table;

This will also change null values to 0.


case statement

If you wish to keep the null results, you can resort to a regular case statement. In order to alias your calculation you'll have to put it in a subquery or a cte:

select *
  ,case when create_duration&lt;0 then 0 else create_duration end as create_duration_0
  ,case when paid_duration  &lt;0 then 0 else paid_duration   end as paid_duration_0
from (
    select *
      ,first_created-coalesce(submitted_time::date) as create_duration
      ,last_paid    -coalesce(submitted_time::date) as paid_duration
    from my_table ) as subquery;

(n+abs(n))/2

If you sum a number with its absolute value, then divide by two (average them out), you'll get that same number if it was positive, or you'll get zero if it was negative because a negative number will always balance itself out with its absolute value:

  • (-1+abs(-1))/2 = (-1+1)/2 = 0/2 = 0
  • ( 1+abs( 1))/2 = ( 1+1)/2 = 2/2 = 1
select *
  ,(create_duration + abs(create_duration)) / 2 as create_duration_0
  ,(paid_duration   + abs(paid_duration)  ) / 2 as paid_duration_0
from (
    select *
      ,first_created-coalesce(submitted_time::date) as create_duration,
      ,last_paid    -coalesce(submitted_time::date) as paid_duration
    from my_table ) as subquery;

Which according to this demo, is slightly faster than case and about as fast as greatest(), without affecting null values.


Note that select * pulls everything from below, so you'll end up seeing create_duration as well as create_duration_0 - you can get rid of it by listing your desired output columns explicitly in the outer query. You can also rewrite it without subquery/cte, repeating the calculation, which will look ugly but in most cases planner will notice the repetition and evaluate it only once

select *
  ,case when first_created-coalesce(submitted_time::date) &lt; 0
        then 0
        else first_created-coalesce(submitted_time::date)
   end as create_duration
  ,(abs(last_paid-coalesce(submitted_time::date))
    +   last_paid-coalesce(submitted_time::date) )/2 
       as paid_duration
from my_table;

or using a scalar subquery

select *
  ,(select case when a&lt;0 then 0 else a end 
    from (select first_created-coalesce(submitted_time::date)) as alias(a) ) 
    as create_duration
  ,(select case when a&lt;0 then 0 else a end 
    from (select last_paid-coalesce(submitted_time::date)) as alias(a) ) 
    as paid_duration
from my_table;

Neither of which help with anything in this case but are good to know.

答案2

得分: 1

如果您计划将SQL数据库连接到ASP.NET应用程序,您可以创建一个C#脚本来查询您的数据库,并使用以下内容:

Parameters.AddWithValue('要更改的数据', '0');

然而,如果您不是在使用SQL数据库与ASP.NET应用程序,则这将无法运行。

英文:

If you are planning on attaching your SQL Database to an ASP.NET app, you could create a c# script to query your database, and use the following:

Parameters.AddWithValue(‘Data You want to change’ ‘0’);

However, if your not using your SQL database with a ASP.NET app, this will not work.

huangapple
  • 本文由 发表于 2023年2月7日 04:28:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75366240.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定