Let's say I have a table called t in Postgres:
id | group_name | state
-----------------------------
1 | group1 | 0
2 | group1 | 0
3 | group1 | 0
I need to update the state of a row by ID, while also returning some things:
- The old state
- The remaining number of rows in the same group that have
state= 0
I've got a query to do this as follows:
UPDATE t AS updated SET state = 1
FROM t as original
WHERE
updated.id = original.id AND
updated.id = :some_id
RETURNING
updated.state AS new_state,
original.state AS old_state,
(
SELECT COUNT(*) FROM t
WHERE
group_name = updated.group_name AND
state = 0
) as remaining_count;
However, it seems like the subquery within RETURNING is executed before the update has completed, leaving me with a remaining_count that is off by 1.
Additionally, I'm not sure how this behaves when concurrent queries are run. If we update two of these rows at the same time, is it possible that they would both return the same remaining_count?
Is there a more elegant solution to this? Perhaps some sort of window/aggregate function?