减去不同表的两列
Subtract two columns of different tables
我有两个不相关的表:
contribution(id,amount, create_at, user_id)
solicitude(id, amount, create_at, status_id, type_id, user_id)
我需要减去用户的贡献金额和关心金额之和,但结果不能为负。
我该怎么做?函数或查询?
我试过这个查询:
SELECT sum(contribution.amount)
- (SELECT sum(solicitude.amount)
FROM solicitude
WHERE user_id = 1 AND status_id = 1) as total
FROM contribution
WHERE contribution.user_id = 1
你必须加入表格
SELECT sum(c.amount) - s.total
FROM contribution c inner join (SELECT user_id, sum(solicitude.amount) total
FROM solicitude GROUP BY c.user_id HAVING user_id = 1 AND status_id = 1 )s
on c.user_id=s.user_id GROUP BY c.user_id,s.total HAVING c.user_id = 1
编辑:我忘记了别名
您可以添加一个外部查询来检查总值:
SELECT CASE WHEN total > 0 THEN total ELSE 0 END AS total
FROM (
SELECT
sum(contribution.amount) - (SELECT sum(solicitude.amount)
FROM solicitude
WHERE user_id = 1 AND status_id = 1) as total
FROM contribution
WHERE
contribution .user_id = 1
) alias;
这个解决方案没问题,但我建议使用另一种方法。检查此查询的工作原理:
with contribution as (
select user_id, sum(amount) as amount from contribution
group by 1),
solicitude as (
select user_id, sum(amount) as amount from solicitude
where status_id = 1
group by 1)
select
c.user_id, c.amount as contribution, s.amount as solitude,
case when c.amount > s.amount then c.amount - s.amount else 0 end as total
from contribution c
join solicitude s on c.user_id = s.user_id;
出于好奇,我对这个设置做了一个简单的测试:
create table public.solicitude (
id integer,
amount numeric,
create_at timestamp without time zone,
status_id integer,
type_id integer,
user_id integer
);
create table public.contribution (
id integer,
amount numeric,
create_at timestamp without time zone,
user_id integer
);
insert into contribution (user_id, amount)
select (random()* 50)::int, (random()* 100)::int
from generate_series(1, 4000000);
insert into solicitude (user_id, amount, status_id)
select (random()* 50)::int, (random()* 100)::int, 1
from generate_series(1, 4000000);
结果(毫秒):
Erwin's solution with greatest(): 922, 905, 922, 904, 904, 904, 905, 912, 905, 922
My solution with an outer query: 796, 795, 814, 814, 815, 795, 815, 796, 815, 796
我将您的评论 but that result can't to be negative
解释为对 return 0 的要求,而不是负面结果。简单的解决方案是 GREATEST()
:
SELECT GREATEST(sum(amount)
- (SELECT sum(amount)
FROM solicitude
WHERE status_id = 1
AND user_id = 1), 0) AS total
FROM contribution
WHERE user_id = 1;
否则,我保留了您的原始查询,这很好。
对于可能导致无法对行进行 returned 的其他情况,我将替换为 two 子选择。但是使用聚合函数 保证 结果行,即使给定的 user_id
根本找不到。比较:
如果减法的结果是NULL
(因为没有找到行或者总和是NULL
),GREATEST()
也会return0
.
我有两个不相关的表:
contribution(id,amount, create_at, user_id)
solicitude(id, amount, create_at, status_id, type_id, user_id)
我需要减去用户的贡献金额和关心金额之和,但结果不能为负。
我该怎么做?函数或查询?
我试过这个查询:
SELECT sum(contribution.amount)
- (SELECT sum(solicitude.amount)
FROM solicitude
WHERE user_id = 1 AND status_id = 1) as total
FROM contribution
WHERE contribution.user_id = 1
你必须加入表格
SELECT sum(c.amount) - s.total
FROM contribution c inner join (SELECT user_id, sum(solicitude.amount) total
FROM solicitude GROUP BY c.user_id HAVING user_id = 1 AND status_id = 1 )s
on c.user_id=s.user_id GROUP BY c.user_id,s.total HAVING c.user_id = 1
编辑:我忘记了别名
您可以添加一个外部查询来检查总值:
SELECT CASE WHEN total > 0 THEN total ELSE 0 END AS total
FROM (
SELECT
sum(contribution.amount) - (SELECT sum(solicitude.amount)
FROM solicitude
WHERE user_id = 1 AND status_id = 1) as total
FROM contribution
WHERE
contribution .user_id = 1
) alias;
这个解决方案没问题,但我建议使用另一种方法。检查此查询的工作原理:
with contribution as (
select user_id, sum(amount) as amount from contribution
group by 1),
solicitude as (
select user_id, sum(amount) as amount from solicitude
where status_id = 1
group by 1)
select
c.user_id, c.amount as contribution, s.amount as solitude,
case when c.amount > s.amount then c.amount - s.amount else 0 end as total
from contribution c
join solicitude s on c.user_id = s.user_id;
出于好奇,我对这个设置做了一个简单的测试:
create table public.solicitude (
id integer,
amount numeric,
create_at timestamp without time zone,
status_id integer,
type_id integer,
user_id integer
);
create table public.contribution (
id integer,
amount numeric,
create_at timestamp without time zone,
user_id integer
);
insert into contribution (user_id, amount)
select (random()* 50)::int, (random()* 100)::int
from generate_series(1, 4000000);
insert into solicitude (user_id, amount, status_id)
select (random()* 50)::int, (random()* 100)::int, 1
from generate_series(1, 4000000);
结果(毫秒):
Erwin's solution with greatest(): 922, 905, 922, 904, 904, 904, 905, 912, 905, 922
My solution with an outer query: 796, 795, 814, 814, 815, 795, 815, 796, 815, 796
我将您的评论 but that result can't to be negative
解释为对 return 0 的要求,而不是负面结果。简单的解决方案是 GREATEST()
:
SELECT GREATEST(sum(amount)
- (SELECT sum(amount)
FROM solicitude
WHERE status_id = 1
AND user_id = 1), 0) AS total
FROM contribution
WHERE user_id = 1;
否则,我保留了您的原始查询,这很好。
对于可能导致无法对行进行 returned 的其他情况,我将替换为 two 子选择。但是使用聚合函数 保证 结果行,即使给定的 user_id
根本找不到。比较:
如果减法的结果是NULL
(因为没有找到行或者总和是NULL
),GREATEST()
也会return0
.