Home > other >  Get the sum of values per date while obtaining recent value per date?
Get the sum of values per date while obtaining recent value per date?

Time:09-17

I have a table, movements, that shows the user's use of their card. It's something like this:

movementdate expense deposit balance
2021-07-09 19:23:49 0 2 2
2021-07-09 20:40:13 0 6 8
2021-07-09 13:50:01 0 2 10
2021-07-10 11:50:31 5 0 5
2021-07-10 12:59:15 0 5 10
2021-07-10 18:01:39 10 0 0

It shows their deposits and expenses, and also shows their final balance. I have this query that gets the total of deposits and expenses per day;

select EXTRACT(day FROM m.movementdate) as d, EXTRACT(month FROM m.movementdate) as m, 
       EXTRACT(year FROM m.movementdate) as y, sum(m.expense) as TotalExpense, 
       sum (m.deposit) as TotalDeposit
from movements m 
group by 3,2,1

But I want to get also the last record of their balance per day.

something like this:

Date TotalExpense TotalDeposit Balance
2021-07-09 0 10 10
2021-07-10 15 5 0

How could I get this last part? I have found some ways to get the last balance of the day, but I can't figure out how to include it in the same query.

CodePudding user response:

another method to desired achieve the result is using window function row_number()

Here is the db<>fiddle

with cte as
(
  select 
    movementdate::date as dt,
    EXTRACT(day FROM movementdate) as d,
    EXTRACT(month FROM movementdate) as m, 
    EXTRACT(year FROM movementdate) as y,
    sum(expense) over (partition by movementdate::date) as expense,
    sum(deposit) over (partition by movementdate::date) as deposit,
    balance,
    row_number() over (partition by movementdate::date order by movementdate desc) as rn
  from movements
)

select 
  dt,
  d, 
  m, 
  y, 
  expense, 
  deposit, 
  balance
from cte
where rn = 1
order by
  1, 2, 3

output:

*-------------------------------------------------------*
|  dt          d    m   y     expense   deposit  balance|
*-------------------------------------------------------*
| 2021-07-09    9   7   2021    0         10       8    |
| 2021-07-10    10  7   2021    15         5       0    |
*-------------------------------------------------------*

CodePudding user response:

One method uses arrays:

select EXTRACT(day FROM m.movementdate) as d,
       EXTRACT(month FROM m.movementdate) as m, 
       EXTRACT(year FROM m.movementdate) as y,
       sum(m.expense) as TotalExpense, 
       sum (m.deposit) as TotalDeposit,
       (array_agg(m.balance order by m.movementdate desc))[1] as balance
from movements m 
group by 3,2,1;

I would also suggest that you use m.movementdate::date instead of defining the first three columns.

CodePudding user response:

Another option is to use PostgreSQL LATERAL Subquery

Something like:

WITH movements_per_day AS (
  select m.movementdate::date AS dt
     , EXTRACT(day FROM m.movementdate) as d
     , EXTRACT(month FROM m.movementdate) as m
     , EXTRACT(year FROM m.movementdate) as y
     , sum(m.expense) as TotalExpense
     , sum (m.deposit) as TotalDeposit
  from movements m
  group by 1,2,3,4
)
SELECT movements_per_day.*, last_movement.balance
  FROM movements_per_day
  CROSS JOIN LATERAL (
    SELECT movements.balance
    FROM movements
    WHERE movements.movement_date::date = movements_per_day.dt
    ORDER BY movements.movementdate DESC 
    LIMIT 1
  ) AS last_movement

As the other answers suggest, it's a bit simpler to use the m.movementdate::date instead of the first three columns.

  • Related