sql 年底取得余额

sql get balance at end of year

我有一个 一年 的交易 table,如果值为负或贷方交易值为正,则金额表示借方交易。

现在在给定的月份,如果借记记录数小于3或者一个月的借记总和小于100,那么我想收取5的费用。

我想在 postgre 中构建并sql查询:

select sum(amount), count(1), date_part('month', date) as month from transactions where amount < 0 group by month;

我可以按月获取记录,但我不知道如何进一步进行并获得结果。

这种方法怎么样?

SELECT
  SUM(
    CASE 
      WHEN usage.amount_s > 100
        OR usage.event_c > 3
        THEN 0 
      ELSE 5
    END
  ) AS YEAR_FEE
FROM (SELECT 1 AS month UNION
      SELECT 2 UNION
      SELECT 3 UNION
      SELECT 4 UNION
      SELECT 5 UNION
      SELECT 6 UNION
      SELECT 7 UNION
      SELECT 8 UNION
      SELECT 9 UNION
      SELECT 10 UNION
      SELECT 11 UNION
      SELECT 12
) months
  LEFT OUTER JOIN
 (
  SELECT 
    sum(amount) AS amount_s,
    count(1) event_c,
    date_part('month', date) AS month
  FROM transactions
  WHERE amount < 0
  GROUP BY month
) usage ON months.month = usage.month;

您可以从使用 generate_series() 生成月份系列开始。然后将其与交易的聚合查询结合起来,最后在外部查询中实现业务逻辑:

select sum(t.balance) 
    - 5 * count(*) filter(where coalesce(t.cnt, 0) < 3 or coalesce(t.debit, 0) < 100) as balance
from generate_series(date '2020-01-01', date '2020-12-01', '1 month') as d(dt)
left join (
    select date_trunc('month', date) as dt, count(*) cnt, sum(amount) as balance,
        sum(-amount) filter(where amount < 0) as debit
    from transactions t 
    group by date_trunc('month', date)
) t on t.dt = d.dt

Demo on DB Fiddle:

| balance |
| ------: |
|    2746 |

首先,您必须使用 returns 所有月份 (1-12) 的结果集,并通过 LEFT 加入您的 table.
然后聚合得到每个月的金额之和,条件聚合从符合条件的月份减去5。
最后用SUM()window函数对每个月的结果求和:

SELECT DISTINCT SUM(
         COALESCE(SUM(t.Amount), 0) -
         CASE 
           WHEN SUM((t.Amount < 0)::int) < 3 
             OR SUM(CASE WHEN t.Amount < 0 THEN -t.Amount ELSE 0 END) < 100 THEN 5 
           ELSE 0  
         END
       ) OVER () total
FROM generate_series(1, 12, 1) m(month) LEFT JOIN transactions t 
ON m.month = date_part('month', t.date) AND date_part('year', t.date) = 2020
GROUP BY m.month

参见demo
结果:

> | total |
> | ----: |
> |  2746 |

我想你可以使用 having 子句。

Select ( sum(a.total) - (12- count(b.cnt ))*5 ) as result From  
(Select sum(amount) as total , 'A' as name from  transactions  ) as a  left join  
(Select  count(amount) as cnt  , 'A' as name
From transactions 
where amount <0 
group by month(date) 
having not(count(amount) <3 or  sum(amount) >-100) ) as b 
on a.name = b.name