Postgres中2个表中的sum的递归查询

时间:2017-06-26 21:37:46

标签: postgresql sum recursive-query

我有2个表,我需要制作一个带分页(限制和偏移)的过滤器:

  1. res_partner(id,name,parent_id)(250k行)
  2. account_invoice(id,amount_untaxed,partner_id,created_date)(700k行)
  3. 一个合作伙伴可以有很多孩子,还有很多帐户发票。

    我需要让所有客户和总发票(amount_untaxed的总和)在一段时间内与他和他们的孩子相关联。 例如:

    res_partner

    id ---   name ---   parent_id
    
    1  ---    Jon 
    
    2 ---      Snow ----   1
    
    3  ---    Sam    -----   2
    

    account_invoice

    id     ---  amount_untaxed --- partner_id --- created_date
    
    1 ------------------ 5.00 ---------1--------------'2015-09-29 21:37:39.427189'
    
    2 ------------------ 7.00 ---------2--------------'2015-09-29 21:37:39.427189'
    
    3 ------------------ 3.00 ---------3--------------'2015-09-29 21:37:39.427189'
    
    4 ------------------ 9.00 ---------1--------------'2015-09-29 21:37:39.427189'
    

    我希望得到:

    res_partner --- amount
    
    1 -----------------24
    
    2 -----------------10
    
    3 -----------------3
    

2 个答案:

答案 0 :(得分:1)

您可以使用递归存储过程来计算每条记录的值。

CREATE OR REPLACE FUNCTION fnTree(pid int)
RETURNS numeric 
AS $$
DECLARE total numeric;
BEGIN
      WITH RECURSIVE tree(id, parent_id) AS 
      (
          SELECT id, parent_id 
          FROM   res_partner 
          WHERE  id = pid
         UNION ALL
          SELECT rp.id, rp.parent_id
          FROM   res_partner rp 
          JOIN   tree 
          ON     rp.parent_id = tree.id
      )
      SELECT sum(amount_untaxed) into total
      FROM   account_invoice ai
      WHERE  partner_id in (SELECT id FROM tree);
      RETURN total;
END;
$$ 
LANGUAGE plpgsql;
select id, fnTree(id)
from   res_partner;
id | fntree
-: | -----:
 1 |  24.00
 2 |  10.00
 3 |   3.00

dbfiddle here

答案 1 :(得分:0)

以下是单一SQL查询的方法,它使用WITH RECURSIVE,整数数组,包含运算符(<@),数组连接运算符(||)和转换的函数结果集的数组unnest()

WITH RECURSIVE内,我们建立&#34;路径&#34;对于每条记录,然后计算金额总和:

with recursive res(id, name, parent_id, path) as (
  select id, name, parent_id, array[id]
  from res_partner
  where parent_id is null

  union all

  select
    r2.id, r2.name, r2.parent_id, array[r2.id] || res.path
  from res_partner r2
  join res on res.id = r2.parent_id
)
select
  id as res_partner,
  --path, -- uncomment to debug
  (
    select sum(amount_untaxed)
    from account_invoice
    where
      partner_id in (
        select id
        from res r_in
        where r_out.path <@ r_in.path
      )
  ) as amount
from res r_out;