英文:
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 < 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<0 then 0 else create_duration end as create_duration_0
,case when paid_duration <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) < 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<0 then 0 else a end
from (select first_created-coalesce(submitted_time::date)) as alias(a) )
as create_duration
,(select case when a<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<0 then 0 else create_duration end as create_duration_0
,case when paid_duration <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) < 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<0 then 0 else a end
from (select first_created-coalesce(submitted_time::date)) as alias(a) )
as create_duration
,(select case when a<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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论