【问题标题】:How do I select all matches in a database that have two particular players?如何选择数据库中包含两个特定球员的所有比赛?
【发布时间】:2014-09-09 15:15:37
【问题描述】:

情况:

比赛有 10 名球员,每队 5 名。总共有 100 名球员,每场比赛可以有任何球员在十个位置中的任何一个。给定两个玩家,我需要提取以下内容:

  1. 玩家 A 和玩家 B 结盟了多少场比赛?
  2. 他们赢了多少?
  3. 玩家 A 和玩家 B 的对手有多少场比赛?
  4. 玩家 A 赢了多少?

我当前的方法(太慢,可能不起作用):

我已经制作了三个表格,“players”、“matches”和“matches_players”,它们将比赛映射到其中的球员。 matchs 中的“winning_team”列表示哪支球队获胜(0 = A 队,1 = B 队),matches_players 表中的“position”列表示球员在阵容中的哪个位置。 0-4 属于 A 队,5-9 属于 B 队。


玩家


player_id
43179582
63260623
31250276
54829050
22257854
etc...

匹配


match_id     winning_team
95824317     0
06236326     0
02763125     1
90505482     0
78544325     1
etc...

matches_players


relation_id     match_id     player_id     position
1               95824317     43179582      1
2               95824317     63260623      5
3               06236326     43179582      7
4               06236326     54829050      0
5               06236326     22257854      4
etc...

这是我用于查找同一支球队中英雄的比赛和获胜次数的语句(经过 12 多个小时的冲浪并试图理解 SQL):

SELECT
COUNT(*) AS match_count,
SUM(CASE WHEN team = winning_team THEN 1 ELSE 0 END) AS win_count
FROM
    (SELECT
    matches.match_id,
    (CASE WHEN position < 5 THEN 0 ELSE 1 END) AS team,
    winning_team
    FROM matches INNER JOIN matches_players ON matches.match_id = matches_players.match_id
    WHERE player_id = [____] OR player_id = [____]
    GROUP BY match_id, team HAVING COUNT(*) = 2)
AS pair_matches

它似乎有效,但速度非常慢(250,000 场比赛超过 90 秒),理想情况下,我希望对方团队在同一个查询中得到结果(这应该比两个单独的查询更快,不是吗?)查询更快/更好?是否存在数据库设计缺陷?

我真的很感谢任何帮助家伙。欢迎任何领域的建议。谢谢。

【问题讨论】:

  • 在一场给定的比赛中,你如何知道球员所在的球队?
  • 为了速度...我会先研究索引。虽然可能是一个逻辑问题...如果您尝试按某些字段分组,但排除其他字段(获胜团队不在您的分组中),大多数数据库将返回错误。当其他数据库返回错误时,MySQL 似乎只是随机返回一个。
  • 他们的球队可以通过他们在matches_players表中的“位置”找到。 0-4 的位置表示他们在 A 队,5-9 表示 B 队。第十二,match_id 和 player_id 字段被索引并具有链接表的外键。你的意思是我需要索引其他列?我会将winning_team 添加到 GROUP BY 中,看看是否有帮助。

标签: mysql sql


【解决方案1】:

我认为应该这样做或者至少给你一个提示

-- How many matches were player A and player B allies?
select DISTINCT (match_id) from MATCHES_PLAYERS where PLAYER_ID='43179582' or PLAYER_ID='63260623' group by MATCH_ID;

-- How many of these did they win?
select  PLAYER_ID, count(WINNING_TEAM)
from 
(select  PLAYER_ID, WINNING_TEAM, POsition from MATCHES_PLAYERS mp, matches m where mp.MATCH_ID=m.MATCH_ID and position<=4 and WINNING_TEAM=0
union all
select PLAYER_ID, WINNING_TEAM, POsition from MATCHES_PLAYERS mp, matches m where mp.MATCH_ID=m.MATCH_ID and position>4 and WINNING_TEAM=1)
group by PLAYER_id;

-- How many matches were player A and player B opponents?
select mp1.*, m.WINNING_TEAM, mp2.PLAYER_ID as opponent from MATCHES_PLAYERS mp1, MATCHES_PLAYERS mp2, matches m where mp1.MATCH_ID=m.MATCH_ID and  mp1.MATCH_ID=mp2.MATCH_ID and mp1.PLAYER_ID!=mp2.PLAYER_ID and (mp1.PLAYER_id in (43179582, 63260623) and mp2.player_id in (43179582, 63260623))
select DISTINCT mp1.MATCH_ID from MATCHES_PLAYERS mp1, MATCHES_PLAYERS mp2, matches m where mp1.MATCH_ID=m.MATCH_ID and  mp1.MATCH_ID=mp2.MATCH_ID and mp1.PLAYER_ID!=mp2.PLAYER_ID and (mp1.PLAYER_id in (43179582, 63260623) and mp2.player_id in (43179582, 63260623))

-- How many of these did player A win?
select
mp1.*, m.WINNING_TEAM, mp2.PLAYER_ID as opponent
from MATCHES_PLAYERS mp1, MATCHES_PLAYERS mp2, matches m
where mp1.MATCH_ID=m.MATCH_ID
and mp1.MATCH_ID=mp2.MATCH_ID
and mp1.PLAYER_ID!=mp2.PLAYER_ID
and
(
   mp1.PLAYER_id=43179582
   and mp2.player_id=63260623
)
and mp1.position<=4
and m.WINNING_TEAM=0

【讨论】:

  • 我现在(一年多后)才看到这个答案。这个问题早就解决了,我现在在 SQL 方面好多了,但我只是想感谢您投入时间。对不起,我以前没有看到它。这在当时会很有帮助。
【解决方案2】:

我认为接受的答案有误(在“玩家 A 和 B 的盟友有多少场比赛?”部分)

我的答案使用子查询和 ROUND(position/4) 将位置 0..3 转换为团队 0,并从位置 4..7 转换为团队 1。

首先,此脚本创建表(Oracle SQL 风格)。索引仅在主键上自动创建:

CREATE TABLE players(player_id NUMBER PRIMARY KEY);
CREATE TABLE matches(match_id NUMBER PRIMARY KEY, winning_team NUMBER(1) CHECK(winning_team IN (0, 1)));
CREATE TABLE matches_players(relation_id NUMBER PRIMARY KEY, match_id NUMBER NOT NULL REFERENCES matches(match_id), player_id NUMBER NOT NULL REFERENCES players(player_id), position NUMBER NOT NULL CHECK(position < 8));

让我们加载一些数据:

INSERT INTO players
SELECT 43179582 FROM DUAL
UNION ALL SELECT 63260623 FROM DUAL
UNION ALL SELECT 31250276 FROM DUAL
UNION ALL SELECT 54829050 FROM DUAL
UNION ALL SELECT 22257854 FROM DUAL
;

-- match_id     winning_team
INSERT INTO matches
SELECT 95824317, 0 FROM DUAL
UNION ALL SELECT 06236326, 0 FROM DUAL
UNION ALL SELECT 02763125, 1 FROM DUAL
UNION ALL SELECT 90505482, 0 FROM DUAL
UNION ALL SELECT 78544325, 1 FROM DUAL
;

-- relation_id     match_id     player_id     position
DELETE matches_players;
INSERT INTO matches_players
SELECT 1, 95824317, 43179582, 1 FROM DUAL
UNION ALL SELECT 2, 95824317, 63260623, 5 FROM DUAL
UNION ALL SELECT 3, 06236326, 43179582, 7 FROM DUAL
UNION ALL SELECT 4, 06236326, 54829050, 0 FROM DUAL
UNION ALL SELECT 5, 06236326, 22257854, 4 FROM DUAL
UNION ALL SELECT 6, 06236326, 63260623, 4 FROM DUAL
;

然后,这些是查询:

-- How many matches were player A and player B allies?
SELECT COUNT(*) FROM matches_players mp WHERE player_id = 63260623
AND (match_id, ROUND(position/4)) IN (
    SELECT match_id, ROUND(position/4) FROM matches_players WHERE player_id = 22257854
);

-- How many of these did they win?
SELECT COUNT(*) FROM matches_players mp WHERE player_id = 63260623
AND (match_id, ROUND(position/4)) IN (
    SELECT match_id, ROUND(position/4) FROM matches_players WHERE player_id = 22257854
)
AND EXISTS(SELECT NULL FROM matches m WHERE m.match_id = mp.match_id AND m.winning_team = ROUND(mp.position/4))
;

-- How many matches were player A and player B opponents?
SELECT COUNT(*) FROM matches_players mp WHERE player_id = 63260623
AND (match_id, ROUND(position/4)) IN (
    SELECT match_id, -(ROUND(position/4) - 1) FROM matches_players WHERE player_id = 54829050
);

-- How many of these did player A win?
SELECT COUNT(*) FROM matches_players mp WHERE player_id = 54829050
AND (match_id, ROUND(position/4)) IN (
    SELECT match_id, -(ROUND(position/4) - 1) FROM matches_players WHERE player_id = 63260623
)
AND EXISTS(SELECT NULL FROM matches m WHERE m.match_id = mp.match_id AND m.winning_team = ROUND(mp.position/4))
;

如果您想加快查询速度,可以在 position 和winning_team 上创建索引:

CREATE INDEX matches_idx ON matches(winning_team);
CREATE INDEX matches_players_idx ON matches_players(ROUND(position/4));

如果你想要超高速并且你的数据库引擎支持位图索引,你可以试试:

CREATE BITMAP INDEX matches_idx ON matches(winning_team);
CREATE BITMAP INDEX matches_players_idx ON matches_players(ROUND(position/4));

【讨论】:

  • 感谢您花时间回答。不幸的是,该项目早已不复存在。不过,我可能很快就会做类似的事情,所以它可能会派上用场。只是好奇,你为什么回复这么老的帖子?
  • 因为这是一个临时问题:D
猜你喜欢
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多