postgresql 减去不同表的两列

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30856311/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 01:56:04  来源:igfitidea点击:

Subtract two columns of different tables

sqlpostgresqlsumaggregate-functionssubtraction

提问by Nelson Jean Pierre

I have two unrelated tables:

我有两个不相关的表:

contribution(id,amount, create_at, user_id)

solicitude(id, amount, create_at, status_id, type_id, user_id)

I need to subtract the sum of the amount of the contribution and of the solicitude from a user, but that result can't to be negative.

我需要减去用户的贡献和关心的总和,但结果不能是负数。

How can I do this? Function or query?
I tried this query:

我怎样才能做到这一点?函数还是查询?
我试过这个查询:

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

采纳答案by Erwin Brandstetter

I interpret your remark but that result can't to be negativeas requirement to return 0 instead of negative results. The simple solution is GREATEST():

我将您的评论解释but that result can't to be negative为要求返回 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;

Otherwise, I kept your original query, which is fine.

否则,我保留了您的原始查询,这很好。

For other cases with the possible result that no row could be returned I would replace with twosub-selects. But the use of the aggregate function guaranteesa result row, even if the given user_idis not found at all. Compare:

对于可能导致无法返回任何行的其他情况,我将替换为两个子选择。但是使用聚合函数可以保证结果行,即使user_id根本找不到给定的行。比较:

If the result of the subtraction would be NULL(because no row is found or the sum is NULL), GREATEST()will also return 0.

如果减法的结果是NULL(因为没有找到行或总和是NULL),GREATEST()也将返回0

回答by klin

You can add an outer query to check the total value:

您可以添加外部查询来检查总值:

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;

This solution is OK, but I suggest an alternative approach. Check how this query works:

这个解决方案没问题,但我建议另一种方法。检查此查询的工作原理:

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;


I made a simple test, just out of curiosity, on this setup:

出于好奇,我对这个设置做了一个简单的测试:

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

Results (msecs):

结果(毫秒):

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

回答by jurhas

You have to join the tables

你必须加入表格

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 

EDIT: I forgot an alias

编辑:我忘记了别名