I have a table tracking daily scores by users. It looks roughly like this:
CREATE TABLE `DailyScores` (
`player_id` INTEGER NOT NULL,
`day_id` INTEGER NOT NULL,
`score` DOUBLE NOT NULL
);
I also have a player table that looks like this:
CREATE TABLE `Players` (
`player_id` INTEGER NOT NULL,
`weighted_score` DOUBLE NOT NULL
);
Now the players weighted_score is to be recalculated daily from the players historical data. I can do this in several passes, something like this:
-- Clear out the old values
UPDATE Players SET Players.weighted_score = 0;
-- Then several times with different @weight and @day values
UPDATE Players p JOIN DailyScores ds
ON p.player_id = ds.id
WHERE ds.day_id = @day
SET p.weighted_score = p.weighted_score + @weight * ds.score;
This handles the case that there may be a day that a player does not have a score entry for.
However I'd like to rewrite the UPDATE to be more like this:
UPDATE Players p
JOIN DailyScores ds1 ON p.player_id = ds1.id
JOIN DailyScores ds2 ON p.player_id = ds2.id
JOIN DailyScores ds3 ON p.player_id = ds3.id
WHERE
ds1.day_id = @day1 AND
ds2.day_id = @day2 AND
ds3.day_id = @day3
SET p.weighted_score = @w1 * ds1.score + @w2 * ds2.score + @w3 * ds3.score;
But I think this will fail if there is a missing score. Is there anyway to make the values for the missing days be 0?
Use the COALESCE() function. It returns the first of its parameters which is not NULL.
UPDATE Players p
LEFT JOIN DailyScores ds1 ON ( p.player_id = ds1.id AND ds1.day_id = @day1)
LEFT JOIN DailyScores ds2 ON ( p.player_id = ds2.id AND ds2.day_id = @day2)
LEFT JOIN DailyScores ds3 ON ( p.player_id = ds3.id AND ds3.day_id = @day3)
SET p.weighted_score =
@w1 * COALESCE(ds1.score, 0) +
@w2 * COALESCE(ds2.score, 0) +
@w3 * COALESCE(ds3.score, 0);
Also you have to do a LEFT JOIN since there may be no record in DailyScores when the player didn't play.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With