I have an INSERT ... ON CONFLICT (primary_key) DO UPDATE
query in a PostgreSQL 12 database.
It requires me to do the same calculation for multiple columns in the update clause. The calculation isn't too complex, but I would prefer not to maintain it in two places. The calculation contains a reference to both the conflicting row and to the EXCLUDED
virtual table.
Is there any way to perform this calculation once and assign its result to a temporary variable within a single query expression?
The full query is:
INSERT INTO table_name(id, refreshed_at, tokens) VALUES ('id', CURRENT_TIMESTAMP, 60)
ON CONFLICT (id) DO UPDATE SET
tokens = GREATEST(
-1,
LEAST(
GREATEST(0, table_name.tokens)
+ EXTRACT(epoch FROM EXCLUDED.refreshed_at)
- EXTRACT(epoch FROM table_name.refreshed_at),
100
) - 1
),
refreshed_at = CASE
WHEN (
GREATEST(0, table_name.tokens)
+ EXTRACT(epoch FROM EXCLUDED.refreshed_at)
- EXTRACT(epoch FROM table_name.refreshed_at)
) > 0 THEN EXCLUDED.refreshed_at
ELSE table_name.refreshed_at
END
RETURNING tokens >= 0;
The tokens
column is calculated from the column's prior value the difference in seconds between the time of query and the last time the column was updated. The refreshed_at
column should only be changed if the tokens
column value was updated, so the same calculation has to be performed in both SET
clauses.