I have the following table in Postgres:
CREATE TABLE avg (
user_id INT,
numer DOUBLE PRECISION,
denom DOUBLE PRECISION,
frac DOUBLE PRECISION
);
I want to accomplish the following, and I'm having a hard time getting this into one query. Basically I want to be able to update some averages atomically, by separately updating the numerator and denominator, then compute and update the average frac
in the same operation, based on the new values:
- Given params
a
andb
, I want to find the row for a givenuser_id
, then I want to donumer += a
anddenom += b
, and calculatefrac = numer / denom
from the new values ofnumer
anddenom
, then update the values ofnumer
,denom
, andfrac
in this row. - However, if there is no row for the requested
user_id
, or if there is a row, but the values ofnumer
anddenom
are null, then I want to assume that the value of those sums is zero, in other words a new row should be inserted into the table, or an update operation should be performed if there is a row but the values are null, with the result being to setnumer = a
,denom = b
, andfrac = a / b
for theuser_id
. - I want to ensure this all happens atomically.
There may be multiple numerators and denominators in a given table, hence the need to be able to do both insert (if the row doesn't exist) or update (if the row exists but the initial values of a specific numerator/denominator pair are null).
1 Answer 1
The best practice is not to store redundant data in a database. My solution would be
CREATE TABLE real_avg (
user_id bigint PRIMARY KEY,
numer double precision,
denom double precision
);
CREATE VIEW avg
AS SELECT user_id, numer, denom,
numer / denom AS frac
FROM real_avg;
Then you can perform your desired operation as follows:
INSERT INTO avg (user_id, numer, denom)
VALUES (1, 100, 50)
ON CONFLICT (user_id) DO UPDATE
SET numer = avg.numer + EXCLUDED.numer,
denom = avg.denom + EXCLUDED.denom;
If you insist on using a redundant table column, use a generated column that is automatically updated:
CREATE TABLE real_avg (
user_id bigint PRIMARY KEY,
numer double precision,
denom double precision,
frac double precision GENERATED ALWAYS AS (numer / denom) STORED
);
-
Thank you, this is super helpful!Luke Hutchison– Luke Hutchison2024年02月05日 21:48:01 +00:00Commented Feb 5, 2024 at 21:48
Explore related questions
See similar questions with these tags.