Reputation: 539
I have a SQL query in PHP that recalculates the average rating when the user cancels his vote:
$delete_vote = $conn->prepare("UPDATE table SET
votes = votes - 1,
total_value = total_value - :recall_vote,
average = (total_value * 10) / (total_votes * 10)
WHERE id=id");
The problem is with the recalculation of the average vote. Even if I set the default value for the column 'total_value' and for 'average' as zero, if the query in question has only one vote, and that vote is being recalled, the average value will be set to null instead of 0, as I wish it to be. One possible way of solving this would be to retrieve these two values from the database, check if they're null, and then have them changed to 0--but that's a bit of a hassle. So instead, I want to know if there's a simpler solution.
Another thing I've tried is to add a zero to the calculation, hoping that the null would convert to 0:
$vote_count = $conn->prepare("UPDATE table SET
total_votes = (0 + total_votes) + 1
That doesn't work either. Is there a simple solution to this?
Upvotes: 0
Views: 133
Reputation: 1270391
I totally do not understand your where
clause -- which would almost always evaluate to true.
The correct syntax to use is the ANSI standard COALESCE()
or CASE
which are available in almost all databases. You could write this as:
UPDATE table
SET votes = votes - 1,
total_value = total_value - :recall_vote,
average = COALESCE((total_value * 10) / NULLIF(total_votes * 10, 0), 0)
WHERE id = $id -- something other than `id`
I think I would be inclined to be explicit:
UPDATE table
SET votes = votes - 1,
total_value = total_value - :recall_vote,
average = (CASE WHEN total_votes > 0
THEN total_value / total_votes
ELSE 0
END)
WHERE id = $id -- something other than `id`
By the way, why are you multiplying by 10 in both the numerator and denominator? Seems unnecessary.
Upvotes: 1
Reputation: 5776
Since you're using PHP, I'm assuming you're using MySQL with it. But I think every RDBMS has a similar function... In MySQL you can define a fallback value for when a value is NULL
. If the value isn't NULL
, it will return the original value:
IFNULL(something, 0)
Besides that, slightly offtopic maybe; I usually try to avoid denormalisation like you did by saving the average - which in most cases can be calculated when querying the database. But this depends on the situation.
Upvotes: 1