Reputation: 16349
I am adding a new feature to a project that uses a PostgreSQL database.
There is a table in the database called brew_sessions
- this has a column called condition_date
.
brew_sessions
is connected to a recipes
table through brew_sessions.recipe_id = recipes.id
. recipes
is then connected to another table called recipe_fermentation_steps
through recipes.id = recipe_fermentation_steps.recipe_id
.
I am wanting to run an update statement to set the status
field on the brew_sessions
field to 30 when the condition_date
is less than or equal to a calculated number of days from the condition_date
value.
This value is the sum of recipe_fermentation_steps.time
.
For example:
SELECT
brew_sessions.id,
SUM(recipe_fermentation_steps.time)
FROM brew_sessions
INNER JOIN recipes ON brew_sessions.recipe_id = recipes.id
INNER JOIN recipe_fermentation_steps ON recipes.id = recipe_fermentation_steps.recipe_id
GROUP BY brew_sessions.id
This has led me to the below query:
UPDATE brew_sessions
SET status = 30 FROM recipes
INNER JOIN recipe_fermentation_steps ON recipes.id = recipe_fermentation_steps.recipe_id
WHERE brew_sessions.recipe_id = recipes.id
AND brew_sessions.condition_date
<= CURRENT_TIMESTAMP - INTERVAL '1 day' * SUM(recipe_fermentation_steps.time)
However, this doesn't run as you cannot use an aggregate function in a WHERE
.
How do I write the above correctly?
Upvotes: 1
Views: 240
Reputation: 658072
You can use a subquery. Like:
UPDATE brew_sessions b
SET status = 30
FROM (
SELECT recipe_id, SUM(time) AS sum_time
FROM recipe_fermentation_steps
GROUP BY 1
) f
WHERE b.recipe_id = f.recipe_id
AND b.condition_date <= CURRENT_TIMESTAMP - INTERVAL '1 day' * f.sum_time;
If referential integrity is enforced with FK constraints, you do not need to involve the table recipes
at all.
The approach is questionable, though. Typically, you do not write functionally dependent values or values depending on the current time into tables. Use a VIEW
(or MATERIALIZED VIEW
) or similar for that.
Upvotes: 1