2012-07-17 109 views
2

我有一个表跟踪每个用户的日常分数。它看起来大致是这样的:如何做一个缺省行的缺省值的mysql连接

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?

回答

1

使用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没有记录,当球员没有发挥。

+0

已修复,以便它实际上行为正确。 – 2012-08-07 07:22:52

1

尝试使用LEFT JOIN代替JOINDEFAULT设置为0

编辑

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

INSERT INTO table(cols) VALUES(values) ON DUPLICATE KEY UPDATE score=....