I'm trying to build an append-only data model in Postgres, using the following schema:
CREATE TABLE IF NOT EXISTS account (
id UUID DEFAULT uuid_generate_v4(),
user_id INT NOT NULL,
currency_id INT NOT NULL,
balance INT NOT NULL,
version INT NOT NULL DEFAULT 1,
PRIMARY KEY(user_id, currency_id, version)
);
The idea is to have n
users, owning m
accounts. Each account is connected to a certain type of currency and can have a balance. Changes to the balance are persisted by adding a new row to the table (as opposed to updating the current row) and increasing the version
field by 1.
The latest balance of a user would always be found by
SELECT balance FROM account WHERE user_id=? ORDER BY version DESC
with a full history of balance changes.
I should be able to solve this using multiple queries in a transaction (if exists, read version, then insert new row with version+1
). But I was wondering if there was a more clever way of designing the table structure itself (something like a SERIAL
that would only increment on inserts in the same unique constraints).
I assume it probably won't be as straight forward as this, but I thought I'd ask.
last_updated
field and query by that for the latest version? If you use aSERIAL
- then you can use a window function to pick out the last one per user per currency_id... but theSERIAL
will be for them all - I'd go withlast_updated
- it corresponds to a physical reality.WHERE user_id=?
NotWHERE user_id = ? AND currency_id = ?
? PK is on(user_id, currency_id, version)
...