我正在尝试在单个 SQL 查询中实现 Elo 评级计算,但无法使其工作。我找到了一篇关于如何使用 Postgres 的文章,但我不使用 SQLite。另外,我的表架构有点不同:
CREATE TABLE teams (
name TEXT NOT NULL PRIMARY KEY
)
CREATE TABLE games (
"winner_team" TEXT REFERENCES teams,
"loser_team" TEXT REFERENCES teams
)
到目前为止,我有以下代码(为了简化问题,我在这里只查看获胜团队,并将 elo 加 1,而不是进行完整计算):
WITH RECURSIVE elo_ratings(current_game_num, team, previous_elo, new_elo) AS (
-- Initialize all teams with the default elo
SELECT
0 AS game_number,
name,
1000.0 AS previous_elo,
1000.0 AS new_elo
FROM teams
UNION
SELECT
rowid AS game_number,
winner_team,
elo_ratings.new_elo as previous_elo,
elo_ratings.new_elo + 1
FROM games
JOIN elo_ratings ON current_game_num == games.rowid - 1
LIMIT 10000
)
SELECT *
FROM elo_ratings
但是使用这段代码,就有一个全局的
elo_rating
,而不是每个玩家都有一个不同的。
这如何才能完成?
我还无法想出一个纯 SQL 解决方案,但有办法使用 JSON 对象作为中间“表”来实现它。这实际上可能是一个更好的解决方案。
WITH RECURSIVE elo_ratings(current_game_num, elo_map, utc) AS (
SELECT
0 AS game_number,
-- Track all elo ratings in a JSON object
-- (initialized to 1000 here)
json_group_object(name, 1000.0) as elo_map,
'1970-01-01T00:00:00Z'
FROM teams
UNION
SELECT
rowid AS game_number,
-- Apply elo rating changes to JSON object
json_patch(
json_patch(
elo_map,
json_object(
winner_team,
elo_map->>winner_team + (32 * (1 -
((pow(10, elo_map->>winner_team / 400)) /
(pow(10, elo_map->>winner_team / 400) + pow(10, elo_map->>loser_team / 400)))
)
)
)
),
json_object(
loser_team,
elo_map->>loser_team + (32 * (0 -
((pow(10, elo_map->>loser_team / 400)) /
(pow(10, elo_map->>winner_team / 400) + pow(10, elo_map->>loser_team/ 400)))
)
)
)
),
games.utc
FROM games
JOIN elo_ratings ON current_game_num == games.rowid - 1
ORDER BY games.utc
)
SELECT DISTINCT key, value
FROM (SELECT * FROM elo_ratings ORDER BY current_game_num DESC LIMIT 1), json_each(elo_map)
ORDER BY value DESC