-1

Suppose I am a bank:

I have a table with a set of user identities called user_identity, and another user_balance with a list of every balance a user has ever had.

A new entry is created in user_balance every time a user deposits or withdraws money from their account. Each entry has the following fields:

  1. timestamp - the date of the recorded balance
  2. id - unique identifier
  3. userId - id of the user who owns the account
  4. amountCents - dollar amount in cents of the balance
  5. relatedTransferId - unique identifier of the withdrawal or deposit that led there to be a new balance created
  6. previousBalanceId - unique identifier of the balance that came before it

I want to write two scripts:

  1. One that returns the sum of all the money currently stored across all accounts
  2. One that returns a list of all users and their current balance

Here is my attempt at writing the second one:

SELECT 
    user_balance."amountCents" * (1/100) AS balance, 
    "user"."identityId",
    user_identity."firstName",
    user_identity."lastName",
    user_balance.timestamp
FROM user_balance
JOIN user_identity
    ON user_identity.id = user_balance."userId"
ORDER BY 1;

I don't know how to select only the most recent balance for a given user. Any and all help would be very appreciated!

user_balance sample table (notice how there may be more than one entry per user id because there is an entry for each time the balance changes!):

            timestamp           |     userId      | amountCents
--------------------------------+-----------------+--------------
  2021-05-12 07:02:05.088+00:00 | u_2przr9gcn52sm |       20607
  2021-05-12 17:08:05.552+00:00 | u_ysvzqzs7f862  |           0
  2021-05-19 00:40:29.62+00:00  | u_y9eyf0j3b5i5  |      407454
  2021-05-16 21:47:34.123+00:00 | u_jze8wwmuuudk  |       66500
  2021-05-14 08:01:03.929+00:00 | u_22cyb1sctel5k |     3881602
  2021-05-17 05:01:02.711+00:00 | u_22cyb1sctel5k |     3435703

user_identity sample table:

         id        |         firstName          |      lastName
-------------------+----------------------------+----------------------
  ui_104xy9vczsrmy | John                       | Doe
  ui_10holeidg2ydt | John                       | Doe
  ui_10no0d6mtvdfi | John                       | Doe

Desired result:

      firstName    |         lastName           |      currentBalance
-------------------+----------------------------+----------------------
  John             | Doe                        | 3000
  John             | Doe                        | 2000
  John             | Doe                        | 1000

(where currentBalance in the final table is the balance associated with the most recent timestamp inside the user_balance table).

Ken White
  • 123,280
  • 14
  • 225
  • 444
veex
  • 1
  • 1

1 Answers1

0

You can use ROW_NUMBER() on a table expression to identify the rows you want and exclude the other ones.

For example:

select
  i.firstName,
  i.lastName,
  x.amountCents as currentBalance
from user_identity i
left join (
  select b.*,
    row_number() over(partition by b.userId 
                      order by b.timestamp desc) as rn
  from user_balance b
) x on x.id = i.userId
where x.rn = 1
The Impaler
  • 45,731
  • 9
  • 39
  • 76