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.
 
    