获取随机未使用组合的SQL查询

获取随机未使用组合的SQL查询,sql,database,Sql,Database,背景: 我想创建一个数据库,可以运行1对1的比赛。它需要跟踪每场比赛谁赢谁输以及对那场比赛的任何评论,并随机决定下一场独特的比赛 规则: 有x个玩家。每个玩家最终将与其他玩家玩一次,实际上涵盖所有可能的独特玩家组合 包含示例数据的数据库表: 问题: 如何有效地查询以获得尚未发生的单个随机匹配? 主要的问题是玩家的数量会随着时间的推移而增加。现在在我的示例数据中,我只有4名球员,剩下6场可能的比赛 Alex,Bob Alex,Chris Alex,Dave Bob,Chris Bob,Dave C

背景:

我想创建一个数据库,可以运行1对1的比赛。它需要跟踪每场比赛谁赢谁输以及对那场比赛的任何评论,并随机决定下一场独特的比赛

规则:

有x个玩家。每个玩家最终将与其他玩家玩一次,实际上涵盖所有可能的独特玩家组合

包含示例数据的数据库表:

问题:

如何有效地查询以获得尚未发生的单个随机匹配? 主要的问题是玩家的数量会随着时间的推移而增加。现在在我的示例数据中,我只有4名球员,剩下6场可能的比赛

Alex,Bob
Alex,Chris
Alex,Dave
Bob,Chris
Bob,Dave
Chris,Dave
这将是足够小,只需继续抓取2个随机数字,对应于球员的id,然后检查匹配表,如果已经发生了匹配。如果有:再多拿两个,重复这个过程。如果还没有,那就把它作为下一场比赛。然而,如果我有10000名球员,那将是49995000场可能的比赛,这将变得太慢


有人能为我指出一个更有效的查询的正确方向吗?如果数据库设计有助于提高效率,我愿意接受更改。

尽管数据集很大,但只要返回一个键,使用该键就会停止额外的处理。一种可能是使用如下查询返回下一个匹配项

SELECT * FROM Players p1, Players p2 WHERE p1.ID <> p2.ID AND (p1.ID, p2.ID) NOT IN (Select WinnerID, LoserID FROM Matches) AND (p2.ID, p1.ID) NOT IN (Select WinnerID, LoserID FROM Matches) LIMIT 1

如果你在每个可能的配对和已经玩过的配对之间进行外部连接,然后过滤掉已经玩过的配对,剩下的配对还没有玩过。选择一个随机的是一个简单的排序:

SELECT p1.Name, p2.Name FROM
  Players p1
  JOIN Players p2 ON (
    p1.ID < p2.ID
  )
  LEFT JOIN Matches ON (
       (WinnerId = p1.ID AND LoserId = p2.ID)
    OR (WinnerId = p2.ID AND LoserId = p1.ID)
  )
WHERE Matches.ID IS NULL
ORDER BY RAND()
LIMIT 1;
编辑


如下文所述,上述限制语法是特定于MySQL的。您可能需要为您的SQL实现使用适当的语法-让我们知道它是什么,如果需要,有人可以提供建议。我知道,在微软的SQL Server和Oracle中,你的谷歌搜索可能和我的一样好

我想知道为什么你需要随机挑选两名球员。先生成可能匹配的整个列表,然后添加WinnerId列,怎么样?对于下一场比赛,只需选择没有WiNeNID设置的第一行。

< P>对于你的问题,你想用一个随机的顺序来考虑球员B的所有2个元素子集。 例如,其他答案建议在各种条件下使用SQL联接。如果您真的需要处理10000名玩家,那么使用一种高效的组合生成算法可能是一种数据库密集度较低的解决方案。我发现前面的答案列出了一些来自TAOCP第4卷的答案。对于2元素子集的情况,按照字典顺序在播放器ID上进行简单的双嵌套循环即可:

for player_a in 1..num_players:
  for player_b in player_a+1..num_players:
    handle a vs. b
对于B部分,可以使用第二个表将播放器1..n映射为整数1..n的洗牌。在完成比赛过程之前,请保持此无序映射。您可以使用

要跟踪此问题实例中的位置,可能需要定期将组合生成器的状态保存到数据库中。这可能比仅从原始表中找出序列中的位置要快


正如你提到的,以这种方式处理10000名球员的比赛结果是需要处理近5000万场比赛。你可以考虑一个比赛结构,不要求每个球员和其他球员竞争。例如,如果一个Beats B和B跳过C,那么您可能不必考虑Beats C是否适用于您的场景,这样的快捷方式可以节省大量的时间。p> 我给出的答案的更好版本。删除我的并提升你的。限制?这个问题没有被标记为:好点。我已经更新了这一点,我还没有决定使用SQL实现,所以您的MySQL示例很好。如果我用别的东西,我会像你建议的那样用谷歌搜索。
for player_a in 1..num_players:
  for player_b in player_a+1..num_players:
    handle a vs. b