1

我需要一个 SQL 查询来确定随机获胜者。每个用户都有自己的获胜几率。winning_odds 值越高,用户获胜的机会就越大。下面看一下表结构:

id    email            winning_odds
1     test@test.com    3
2     test2@test.com   5
3     test3@test.com   2
4     test4@test.com   1
5     test5@test.com   9

MySQL 数据库。表大约有 100000 行。只有一个赢家,一次。电子邮件是独一无二的。有人有解决方案吗?

谢谢。

4

4 回答 4

1

Select email from user order by winning_odds*rand() limit 1

于 2012-11-07T20:21:44.027 回答
1

我真的很喜欢这个问题,我正在发布 postgresql 的答案。

select 
    *, generate_series(1, mytable.winning_odds) 
from 
    mytable 
order by 
    random() 
limit 1;

这就是它的工作原理。对于您牌桌的每一行,我们将该行复制 N 次作为您的获胜几率。

所以你首先得到并且不限制查询结果:

  5 | test5@test.com |    9 | 9
  2 | test2@test.com |    5 | 3
  3 | test3@test.com |    2 | 1
  1 | test@test.com  |    3 | 1
  5 | test5@test.com |    9 | 5
  1 | test@test.com  |    3 | 3
  5 | test5@test.com |    9 | 2
  2 | test2@test.com |    5 | 4
  2 | test2@test.com |    5 | 5
  5 | test5@test.com |    9 | 1
  4 | test4@test.com |    1 | 1
  5 | test5@test.com |    9 | 7
  5 | test5@test.com |    9 | 4
  5 | test5@test.com |    9 | 6
  2 | test2@test.com |    5 | 1
  5 | test5@test.com |    9 | 8
  3 | test3@test.com |    2 | 2
  1 | test@test.com  |    3 | 2
  2 | test2@test.com |    5 | 2
  5 | test5@test.com |    9 | 3

现在,随机选择生成表的任何行将反映您的winning_odds 字段的概率。

您所要做的就是随机订购并获得第一条记录。

 9 | test5@test.com |    9 | 2 

问候

于 2012-11-07T20:46:56.143 回答
1

我推测“赔率”不是整数,并且您希望具有“9”的东西比“1”的可能性高 9 倍。

正确的方法是使用累积总和。然后在累积和的最小值和最大值之间生成一个随机值,并选择该范围内的记录。以下查询在 MySQL 中执行此操作:

select t.*
from (select t.*,
             coalesce((select sum(odds) from t t2 where t2.id < t.id), 0) as cumsum,
             const.sumodds
      from t cross join
           (select rand()*sum(odds) as val from t) const
     ) t
where val between cumsum and cumsum + t.odds

然而,这是一个非等值连接,在 MySQL 中可能会非常昂贵。其他数据库能够在单个查询中进行累积和。MySQL 没有有效的方法来做到这一点。

如何优化查询取决于问题中的某些其他因素。“赔率”有多少种不同的值?可以使用临时表吗?

我现在没有时间写出解决方案,但是有一种更有效的方法。Y想法是将问题分成两个搜索。第一个将找出哪个“赔率”值获胜。第二个将找出哪一行获胜。

以下是详细信息:

(1) 将数据按赔率汇总成表格。该表将有 11 行,并包含每行的“赔率”和“计数”。

(2) 计算每一行的“count*odds”之和,第一行从0开始。您可以使用上述查询作为指导,因为这是少量数据,它会快速运行。

(3) 计算一个随机数为rand()*<sum of all odds>。现在,找到数字在 cumsum 和 cumsum+odds 之间的赔率。

(4) 现在返回原始表并发出查询,例如:

select *
from t
where odds = <winning odds>
order by rand()
limit 1
于 2012-11-07T20:58:26.113 回答
0

如果我正确理解了这个问题,您是在问如何从表中选择随机记录。这应该有效:

SELECT * 
FROM   tableName
ORDER BY RAND() LIMIT 0,1;

现在仍然清楚您打算如何使用winning_odds 值。

于 2012-11-07T20:18:04.380 回答