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

0に設定するLEFT JOIN代わりに使用してみてくださいJOINDEFAULT

編集

LEFT JOINは最初の問題の正しい解決策であり、2番目の問題は必要ですINSERT-これを回避する最良の方法はINSERT...を使用することですON DUPLICATE KEY UPDATE

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