3

我有一个表格来跟踪用户的每日得分。它看起来大致是这样的:

CREATE TABLE `DailyScores` (
  `player_id` INTEGER NOT NULL,
  `day_id` INTEGER NOT NULL,
  `score` DOUBLE NOT NULL
);

我还有一个看起来像这样的玩家表:

CREATE TABLE `Players` (
  `player_id` INTEGER NOT NULL,
  `weighted_score` DOUBLE NOT NULL
);

现在,玩家 weighted_score 将每天从玩家历史数据中重新计算。我可以分几次执行此操作,如下所示:

-- 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;

这处理了可能某天玩家没有得分条目的情况。

但是,我想将 UPDATE 重写为更像这样:

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;

但是我认为如果缺少分数,这将失败。有没有办法让缺失天数的值为 0?

4

2 回答 2

3

使用该COALESCE()功能。它返回它的第一个参数,它不是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);

你也必须做一个LEFT JOIN,因为当玩家没有玩时,DailyScores 中可能没有记录。

于 2012-07-17T09:40:06.213 回答
1

尝试使用而LEFT JOIN不是设置为 0JOINDEFAULT

编辑

LEFT JOIN是您的第一个问题的正确解决方案,第二个您需要INSERT- 解决此问题的最佳方法是使用INSERT... ON DUPLICATE KEY UPDATE,所以:

INSERT INTO table(cols) VALUES(values) ON DUPLICATE KEY UPDATE score=....
于 2012-07-17T09:30:46.970 回答